Skip to content

Commit 14bcc83

Browse files
author
David Lee
committed
Preserve @OData keys when normalizing record keys
1 parent c1ce5f0 commit 14bcc83

1 file changed

Lines changed: 17 additions & 6 deletions

File tree

src/PowerPlatform/Dataverse/data/_odata.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,25 @@ def _normalize_cache_key(table_schema_name: str) -> str:
9292

9393
@staticmethod
9494
def _lowercase_keys(record: Dict[str, Any]) -> Dict[str, Any]:
95-
"""Convert all dictionary keys to lowercase for case-insensitive column names.
95+
"""Normalize dictionary keys to lowercase for case-insensitive column names.
9696
9797
Dataverse LogicalNames for attributes are stored lowercase, but users may
9898
provide PascalCase names (matching SchemaName). This normalizes the input.
99+
This function lowercases all string keys except OData annotation keys,
100+
which must remain case-sensitive.
99101
"""
100102
if not isinstance(record, dict):
101103
return record
102-
return {k.lower() if isinstance(k, str) else k: v for k, v in record.items()}
104+
105+
new_record = {}
106+
107+
# Preserve OData annotation keys as they are case sensitive
108+
for k, v in record.items():
109+
if isinstance(k, str) and "@odata" in k:
110+
new_record[k] = v
111+
else:
112+
new_record[k.lower() if isinstance(k, str) else k] = v
113+
return new_record
103114

104115
@staticmethod
105116
def _lowercase_list(items: Optional[List[str]]) -> Optional[List[str]]:
@@ -269,7 +280,7 @@ def _create(self, entity_set: str, table_schema_name: str, record: Dict[str, Any
269280
.. note::
270281
Relies on ``OData-EntityId`` (canonical) or ``Location`` response header. No response body parsing is performed. Raises ``RuntimeError`` if neither header contains a GUID.
271282
"""
272-
# Lowercase all keys to match Dataverse LogicalName expectations
283+
# Lowercase Dataverse attribute keys; keep OData annotation keys unchanged
273284
record = self._lowercase_keys(record)
274285
record = self._convert_labels_to_ints(table_schema_name, record)
275286
url = f"{self.api}/{entity_set}"
@@ -313,7 +324,7 @@ def _create_multiple(self, entity_set: str, table_schema_name: str, records: Lis
313324
logical_name = table_schema_name.lower()
314325
enriched: List[Dict[str, Any]] = []
315326
for r in records:
316-
# Lowercase all keys to match Dataverse LogicalName expectations
327+
# Lowercase Dataverse attribute keys; keep OData annotation keys unchanged
317328
r = self._lowercase_keys(r)
318329
r = self._convert_labels_to_ints(table_schema_name, r)
319330
if "@odata.type" in r or not need_logical:
@@ -506,7 +517,7 @@ def _update(self, table_schema_name: str, key: str, data: Dict[str, Any]) -> Non
506517
:return: ``None``
507518
:rtype: ``None``
508519
"""
509-
# Lowercase all keys to match Dataverse LogicalName expectations
520+
# Lowercase Dataverse attribute keys; keep OData annotation keys unchanged
510521
data = self._lowercase_keys(data)
511522
data = self._convert_labels_to_ints(table_schema_name, data)
512523
entity_set = self._entity_set_from_schema_name(table_schema_name)
@@ -540,7 +551,7 @@ def _update_multiple(self, entity_set: str, table_schema_name: str, records: Lis
540551
logical_name = table_schema_name.lower()
541552
enriched: List[Dict[str, Any]] = []
542553
for r in records:
543-
# Lowercase all keys to match Dataverse LogicalName expectations
554+
# Lowercase Dataverse attribute keys; keep OData annotation keys unchanged
544555
r = self._lowercase_keys(r)
545556
r = self._convert_labels_to_ints(table_schema_name, r)
546557
if "@odata.type" in r or not need_logical:

0 commit comments

Comments
 (0)