Skip to content

Commit e93fa6e

Browse files
authored
Escape quotes in URL parameters (#10)
1 parent 94e84f0 commit e93fa6e

File tree

1 file changed

+18
-2
lines changed

1 file changed

+18
-2
lines changed

src/dataverse_sdk/odata.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
class ODataClient:
1111
"""Dataverse Web API client: CRUD, SQL-over-API, and table metadata helpers."""
1212

13+
@staticmethod
14+
def _escape_odata_quotes(value: str) -> str:
15+
"""Escape single quotes for OData queries (by doubling them)."""
16+
return value.replace("'", "''")
17+
1318
def __init__(self, auth, base_url: str, config=None) -> None:
1419
self.auth = auth
1520
self.base_url = (base_url or "").rstrip("/")
@@ -97,9 +102,11 @@ def _logical_from_entity_set(self, entity_set: str) -> str:
97102
if cached:
98103
return cached
99104
url = f"{self.api}/EntityDefinitions"
105+
# Escape single quotes in entity set name
106+
es_escaped = self._escape_odata_quotes(es)
100107
params = {
101108
"$select": "LogicalName,EntitySetName",
102-
"$filter": f"EntitySetName eq '{es}'",
109+
"$filter": f"EntitySetName eq '{es_escaped}'",
103110
}
104111
r = self._request("get", url, headers=self._headers(), params=params)
105112
r.raise_for_status()
@@ -167,6 +174,13 @@ def _format_key(self, key: str) -> str:
167174
k = key.strip()
168175
if k.startswith("(") and k.endswith(")"):
169176
return k
177+
# Escape single quotes in alternate key values
178+
if "=" in k and "'" in k:
179+
def esc(match):
180+
# match.group(1) is the key, match.group(2) is the value
181+
return f"{match.group(1)}='{self._escape_odata_quotes(match.group(2))}'"
182+
k = re.sub(r"(\w+)=\'([^\']*)\'", esc, k)
183+
return f"({k})"
170184
if len(k) == 36 and "-" in k:
171185
return f"({k})"
172186
return f"({k})"
@@ -360,9 +374,11 @@ def _to_pascal(self, name: str) -> str:
360374

361375
def _get_entity_by_schema(self, schema_name: str) -> Optional[Dict[str, Any]]:
362376
url = f"{self.api}/EntityDefinitions"
377+
# Escape single quotes in schema name
378+
schema_escaped = self._escape_odata_quotes(schema_name)
363379
params = {
364380
"$select": "MetadataId,LogicalName,SchemaName,EntitySetName",
365-
"$filter": f"SchemaName eq '{schema_name}'",
381+
"$filter": f"SchemaName eq '{schema_escaped}'",
366382
}
367383
r = self._request("get", url, headers=self._headers(), params=params)
368384
r.raise_for_status()

0 commit comments

Comments
 (0)