Skip to content

Commit 5af3f29

Browse files
author
Saurabh Badenkal
committed
Rename BatchResult.created_ids to entity_ids
The OData-EntityId header is returned by both POST (create) and PATCH (update) operations, not just creates. The name created_ids was misleading. entity_ids accurately reflects that it collects GUIDs from the standard OData-EntityId response header across all successful operations that return it (creates and updates). GET and DELETE operations do not return this header. For CreateMultiple/UpsertMultiple bulk action responses, callers access IDs via response.data['Ids'] as documented in the property's docstring. Updated all references across src, tests, examples, README, and SKILL files.
1 parent 26c7437 commit 5af3f29

9 files changed

Lines changed: 43 additions & 42 deletions

File tree

.claude/skills/dataverse-sdk-use/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ print(f"Succeeded: {len(result.succeeded)}, Failed: {len(result.failed)}")
407407
- `result.succeeded` -- responses with 2xx status codes
408408
- `result.failed` -- responses with non-2xx status codes
409409
- `result.has_errors` -- True if any response failed
410-
- `result.created_ids` -- GUIDs from successful create operations
410+
- `result.entity_ids` -- GUIDs from successful create operations
411411

412412
**Batch limitations:**
413413
- Maximum 1000 operations per batch

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ with batch.changeset() as cs:
461461
"primarycontactid@odata.bind": contact_ref,
462462
})
463463
result = batch.execute()
464-
print(f"Created {len(result.created_ids)} records atomically")
464+
print(f"Created {len(result.entity_ids)} records atomically")
465465
```
466466

467467
**Table metadata and SQL queries in a batch:**

examples/advanced/batch.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
result = batch.execute()
5252

5353
print(f"[OK] Total: {len(result.responses)}, Succeeded: {len(result.succeeded)}, Failed: {len(result.failed)}")
54-
for guid in result.created_ids:
54+
for guid in result.entity_ids:
5555
print(f"[OK] Created: {guid}")
5656
for item in result.failed:
5757
print(f"[ERR] {item.status_code}: {item.error_message}")
@@ -93,7 +93,7 @@
9393
for item in result.failed:
9494
print(f" {item.status_code}: {item.error_message}")
9595
else:
96-
print(f"[OK] {len(result.created_ids)} records created atomically")
96+
print(f"[OK] {len(result.entity_ids)} records created atomically")
9797

9898

9999
# ---------------------------------------------------------------------------
@@ -194,7 +194,7 @@
194194
batch.dataframe.create("account", df)
195195
result = batch.execute()
196196
print(f"[OK] DataFrame create: {len(result.succeeded)} succeeded")
197-
created_ids = list(result.created_ids)
197+
created_ids = list(result.entity_ids)
198198

199199
# Update records from a DataFrame
200200
if len(created_ids) >= 2:

examples/advanced/walkthrough.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ def _run_walkthrough(client):
357357
},
358358
)
359359
result = batch.execute()
360-
batch_ids = list(result.created_ids)
360+
batch_ids = list(result.entity_ids)
361361
print(
362362
f"[OK] Batch create: {len(result.succeeded)} operations in one HTTP request, {len(batch_ids)} records created"
363363
)
@@ -390,7 +390,7 @@ def _run_walkthrough(client):
390390
cs.records.update(table_name, cs_ref, {"new_Completed": True})
391391
result = batch.execute()
392392
if not result.has_errors:
393-
batch_ids.extend(result.created_ids)
393+
batch_ids.extend(result.entity_ids)
394394
print(f"[OK] Changeset: {len(result.succeeded)} operations committed atomically")
395395
else:
396396
for item in result.failed:

examples/basic/functional_testing.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ def test_batch_all_operations(client: DataverseClient, table_info: Dict[str, Any
497497
],
498498
)
499499
result = batch.execute()
500-
all_ids = list(result.created_ids)
500+
all_ids = list(result.entity_ids)
501501
if result.has_errors:
502502
for item in result.failed:
503503
print(f"[WARN] {item.status_code}: {item.error_message}")
@@ -572,7 +572,7 @@ def test_batch_all_operations(client: DataverseClient, table_info: Dict[str, Any
572572
for item in result.failed:
573573
print(f"[WARN] Changeset error {item.status_code}: {item.error_message}")
574574
else:
575-
new_id = next(iter(result.created_ids), None)
575+
new_id = next(iter(result.entity_ids), None)
576576
if new_id:
577577
all_ids[-1] = new_id # replace deleted id with the new one
578578
print(f"[OK] {len(result.succeeded)} ops committed atomically (create + update + delete)")
@@ -598,15 +598,15 @@ def test_batch_all_operations(client: DataverseClient, table_info: Dict[str, Any
598598
# 404 to the outer batch HTTP status (which some environments do).
599599
result = batch.execute(continue_on_error=True)
600600
if result.has_errors:
601-
leaked = list(result.created_ids)
601+
leaked = list(result.entity_ids)
602602
if not leaked:
603603
print("[OK] Changeset rollback verified: changeset failed, no records created")
604604
else:
605605
print(f"[WARN] Changeset failed but {len(leaked)} IDs leaked — queuing for cleanup")
606606
all_ids.extend(leaked)
607607
else:
608608
print("[WARN] Expected rollback but changeset succeeded (unexpected)")
609-
all_ids.extend(result.created_ids)
609+
all_ids.extend(result.entity_ids)
610610

611611
# -------------------------------------------------------------------
612612
# [6/11] TWO CHANGESETS — Content-IDs are unique across the entire batch
@@ -639,7 +639,7 @@ def test_batch_all_operations(client: DataverseClient, table_info: Dict[str, Any
639639
for item in result.failed:
640640
print(f"[WARN] Two-changeset error {item.status_code}: {item.error_message}")
641641
else:
642-
cs_ids = list(result.created_ids)
642+
cs_ids = list(result.entity_ids)
643643
all_ids.extend(cs_ids)
644644
print(
645645
f"[OK] Both changesets committed — {len(cs_ids)} records created "
@@ -678,7 +678,7 @@ def test_batch_all_operations(client: DataverseClient, table_info: Dict[str, Any
678678
for item in result.failed:
679679
print(f"[WARN] Chaining error {item.status_code}: {item.error_message}")
680680
else:
681-
chain_ids = list(result.created_ids)
681+
chain_ids = list(result.entity_ids)
682682
all_ids.extend(chain_ids)
683683
print(f"[OK] Both records created and updated via content-ID refs " f"{ref_a} and {ref_b}: {chain_ids}")
684684

@@ -727,7 +727,7 @@ def test_batch_all_operations(client: DataverseClient, table_info: Dict[str, Any
727727
if result.has_errors:
728728
print(f"[WARN] Upsert failed as expected (no alternate key configured): {result.failed[0].status_code}")
729729
else:
730-
upsert_ids = list(result.created_ids)
730+
upsert_ids = list(result.entity_ids)
731731
all_ids.extend(upsert_ids)
732732
print(f"[OK] Upsert succeeded: {len(upsert_ids)} record(s) — alternate key was accepted")
733733
except Exception as e:

src/PowerPlatform/Dataverse/claude_skill/dataverse-sdk-use/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ print(f"Succeeded: {len(result.succeeded)}, Failed: {len(result.failed)}")
407407
- `result.succeeded` -- responses with 2xx status codes
408408
- `result.failed` -- responses with non-2xx status codes
409409
- `result.has_errors` -- True if any response failed
410-
- `result.created_ids` -- GUIDs from successful create operations
410+
- `result.entity_ids` -- GUIDs from successful create operations
411411

412412
**Batch limitations:**
413413
- Maximum 1000 operations per batch

src/PowerPlatform/Dataverse/models/batch.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ class BatchResult:
6464
6565
result = client.batch.new().execute()
6666
print(f"Succeeded: {len(result.succeeded)}, Failed: {len(result.failed)}")
67-
for guid in result.created_ids:
68-
print(f"[OK] Created: {guid}")
67+
for guid in result.entity_ids:
68+
print(f"[OK] entity_id: {guid}")
6969
"""
7070

7171
responses: List[BatchItemResponse] = field(default_factory=list)
@@ -86,12 +86,13 @@ def has_errors(self) -> bool:
8686
return any(not r.is_success for r in self.responses)
8787

8888
@property
89-
def created_ids(self) -> List[str]:
89+
def entity_ids(self) -> List[str]:
9090
"""GUIDs extracted from ``OData-EntityId`` headers of successful responses.
9191
9292
Returns entity IDs from any successful (2xx) response that includes an
93-
``OData-EntityId`` header. Individual ``POST`` creates return this
94-
header with the new record's GUID.
93+
``OData-EntityId`` header. Both individual ``POST`` (create) and
94+
``PATCH`` (update) operations return this header with the record's GUID.
95+
``GET`` and ``DELETE`` operations do not.
9596
9697
.. note::
9798
``CreateMultiple`` and ``UpsertMultiple`` action responses do **not**

tests/unit/data/test_batch_edge_cases.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def test_successful_changeset_returns_all_items(self):
182182

183183
self.assertFalse(result.has_errors)
184184
self.assertEqual(len(result.succeeded), 3)
185-
self.assertEqual(len(result.created_ids), 3)
185+
self.assertEqual(len(result.entity_ids), 3)
186186
# Verify content-IDs were extracted
187187
content_ids = [r.content_id for r in result.responses]
188188
self.assertEqual(content_ids, ["1", "2", "3"])
@@ -518,7 +518,7 @@ def test_mixed_success_and_failure(self):
518518
self.assertEqual(len(result.succeeded), 2)
519519
self.assertEqual(len(result.failed), 1)
520520
self.assertEqual(result.failed[0].error_code, "0x80040237")
521-
self.assertEqual(len(result.created_ids), 2)
521+
self.assertEqual(len(result.entity_ids), 2)
522522

523523

524524
# ---------------------------------------------------------------------------
@@ -603,24 +603,24 @@ def test_absolute_urls_in_batch_parts(self):
603603
class TestBatchResultProperties(unittest.TestCase):
604604
"""Verify computed properties of BatchResult."""
605605

606-
def test_created_ids_only_from_201_and_204(self):
607-
"""created_ids should include entity_ids from all 2xx (including 201 and 204)."""
606+
def test_entity_ids_only_from_201_and_204(self):
607+
"""entity_ids should include entity_ids from all 2xx (including 201 and 204)."""
608608
responses = [
609609
BatchItemResponse(status_code=201, entity_id="id-201"),
610610
BatchItemResponse(status_code=204, entity_id="id-204"),
611611
BatchItemResponse(status_code=200, entity_id=None), # GET success, no entity_id
612612
BatchItemResponse(status_code=400, entity_id=None),
613613
]
614614
result = BatchResult(responses=responses)
615-
self.assertEqual(result.created_ids, ["id-201", "id-204"])
615+
self.assertEqual(result.entity_ids, ["id-201", "id-204"])
616616

617617
def test_empty_batch_result_properties(self):
618618
"""Empty BatchResult has correct defaults."""
619619
result = BatchResult()
620620
self.assertEqual(result.succeeded, [])
621621
self.assertEqual(result.failed, [])
622622
self.assertFalse(result.has_errors)
623-
self.assertEqual(result.created_ids, [])
623+
self.assertEqual(result.entity_ids, [])
624624

625625
def test_all_success_no_errors(self):
626626
"""All 2xx responses means has_errors is False."""
@@ -643,10 +643,10 @@ def test_single_failure_makes_has_errors_true(self):
643643
self.assertTrue(result.has_errors)
644644
self.assertEqual(len(result.failed), 1)
645645

646-
def test_created_ids_from_create_multiple_not_in_created_ids(self):
647-
"""CreateMultiple IDs are in data['Ids'], NOT in created_ids property.
646+
def test_entity_ids_from_create_multiple_not_in_created_ids(self):
647+
"""CreateMultiple IDs are in data['Ids'], NOT in entity_ids property.
648648
649-
created_ids only returns entity_id from OData-EntityId headers.
649+
entity_ids only returns entity_id from OData-EntityId headers.
650650
Callers access CreateMultiple IDs via response.data['Ids'] directly.
651651
"""
652652
responses = [
@@ -658,17 +658,17 @@ def test_created_ids_from_create_multiple_not_in_created_ids(self):
658658
),
659659
]
660660
result = BatchResult(responses=responses)
661-
# created_ids does NOT include bulk IDs (no OData-EntityId header)
662-
self.assertEqual(result.created_ids, [])
661+
# entity_ids does NOT include bulk IDs (no OData-EntityId header)
662+
self.assertEqual(result.entity_ids, [])
663663
# Callers access them from the response data
664664
self.assertEqual(result.succeeded[0].data["Ids"], ["guid-1", "guid-2", "guid-3"])
665665

666-
def test_created_ids_only_from_odata_entity_id_header(self):
667-
"""created_ids only collects entity_id from OData-EntityId headers."""
666+
def test_entity_ids_only_from_odata_entity_id_header(self):
667+
"""entity_ids only collects entity_id from OData-EntityId headers."""
668668
responses = [
669669
# Single create: entity_id from header
670670
BatchItemResponse(status_code=204, entity_id="single-id"),
671-
# CreateMultiple: Ids from body (not in created_ids)
671+
# CreateMultiple: Ids from body (not in entity_ids)
672672
BatchItemResponse(
673673
status_code=200,
674674
entity_id=None,
@@ -677,7 +677,7 @@ def test_created_ids_only_from_odata_entity_id_header(self):
677677
]
678678
result = BatchResult(responses=responses)
679679
# Only the header-based entity_id
680-
self.assertEqual(result.created_ids, ["single-id"])
680+
self.assertEqual(result.entity_ids, ["single-id"])
681681
# Bulk IDs accessed via response.data
682682
self.assertEqual(result.responses[1].data["Ids"], ["bulk-id-1", "bulk-id-2"])
683683

@@ -693,7 +693,7 @@ def test_bulk_ids_accessible_via_response_data(self):
693693
]
694694
result = BatchResult(responses=responses)
695695
# Collect all IDs from both sources (what a caller would do)
696-
all_ids = list(result.created_ids)
696+
all_ids = list(result.entity_ids)
697697
for resp in result.succeeded:
698698
if resp.data and isinstance(resp.data.get("Ids"), list):
699699
all_ids.extend(resp.data["Ids"])
@@ -740,7 +740,7 @@ def test_create_multiple_response_parsed(self):
740740
# But data should contain the Ids array
741741
self.assertEqual(result.succeeded[0].data["Ids"], ["aaa-111", "bbb-222", "ccc-333"])
742742
# created_ids won't have these (no OData-EntityId header)
743-
self.assertEqual(result.created_ids, [])
743+
self.assertEqual(result.entity_ids, [])
744744
# Callers access bulk IDs via response.data["Ids"]
745745
bulk_ids = result.succeeded[0].data["Ids"]
746746
self.assertEqual(len(bulk_ids), 3)
@@ -784,8 +784,8 @@ def test_mixed_single_and_bulk_creates(self):
784784

785785
self.assertFalse(result.has_errors)
786786
self.assertEqual(len(result.succeeded), 2)
787-
# created_ids only has the individual create's entity_id
788-
self.assertEqual(result.created_ids, [single_guid])
787+
# entity_ids only has the individual create's entity_id
788+
self.assertEqual(result.entity_ids, [single_guid])
789789
# CreateMultiple IDs are in the second response's data
790790
self.assertEqual(result.responses[1].data["Ids"], ["bulk-1", "bulk-2"])
791791

tests/unit/test_batch_operations.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ def test_has_errors_false(self):
439439
)
440440
self.assertFalse(result.has_errors)
441441

442-
def test_created_ids(self):
442+
def test_entity_ids(self):
443443
result = BatchResult(
444444
responses=[
445445
BatchItemResponse(status_code=201, entity_id="guid-1"),
@@ -448,15 +448,15 @@ def test_created_ids(self):
448448
BatchItemResponse(status_code=400),
449449
]
450450
)
451-
self.assertEqual(result.created_ids, ["guid-1", "guid-2"])
451+
self.assertEqual(result.entity_ids, ["guid-1", "guid-2"])
452452

453453
def test_empty_result(self):
454454
result = BatchResult()
455455
self.assertEqual(result.responses, [])
456456
self.assertEqual(result.succeeded, [])
457457
self.assertEqual(result.failed, [])
458458
self.assertFalse(result.has_errors)
459-
self.assertEqual(result.created_ids, [])
459+
self.assertEqual(result.entity_ids, [])
460460

461461

462462
if __name__ == "__main__":

0 commit comments

Comments
 (0)