Skip to content

Commit 76525ff

Browse files
author
Saurabh Badenkal
committed
Fix: add ManyToOneRelationships to list_table_relationships
_list_table_relationships now fetches all 3 relationship types: - OneToManyRelationships (incoming: where table is referenced) - ManyToOneRelationships (outgoing: where table has a lookup) <-- NEW - ManyToManyRelationships This was critical for sql_joins() and odata_expands() which need outgoing lookups. Without ManyToOne, custom table lookups were invisible to the helpers. Also fixed: create_lookup_field requires lowercase logical names (not SchemaName) -- documented in copilot-instructions. Live-validated: 47/47 SQL tests passed on Aurora VM. Unit tests: 756 passed.
1 parent 86f9c37 commit 76525ff

2 files changed

Lines changed: 29 additions & 17 deletions

File tree

src/PowerPlatform/Dataverse/data/_relationships.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,9 @@ def _list_table_relationships(
184184
) -> List[Dict[str, Any]]:
185185
"""List all relationships for a specific table.
186186
187-
Issues ``GET EntityDefinitions({MetadataId})/OneToManyRelationships``
188-
and ``GET EntityDefinitions({MetadataId})/ManyToManyRelationships``,
187+
Issues ``GET EntityDefinitions({MetadataId})/OneToManyRelationships``,
188+
``GET EntityDefinitions({MetadataId})/ManyToOneRelationships``, and
189+
``GET EntityDefinitions({MetadataId})/ManyToManyRelationships``,
189190
then combines the results.
190191
191192
:param table_schema_name: Schema name of the table (e.g. ``"account"``).
@@ -222,12 +223,14 @@ def _list_table_relationships(
222223
params["$select"] = ",".join(select)
223224

224225
one_to_many_url = f"{self.api}/EntityDefinitions({metadata_id})/OneToManyRelationships"
226+
many_to_one_url = f"{self.api}/EntityDefinitions({metadata_id})/ManyToOneRelationships"
225227
many_to_many_url = f"{self.api}/EntityDefinitions({metadata_id})/ManyToManyRelationships"
226228

227229
r1 = self._request("get", one_to_many_url, headers=self._headers(), params=params)
228-
r2 = self._request("get", many_to_many_url, headers=self._headers(), params=params)
230+
r2 = self._request("get", many_to_one_url, headers=self._headers(), params=params)
231+
r3 = self._request("get", many_to_many_url, headers=self._headers(), params=params)
229232

230-
return r1.json().get("value", []) + r2.json().get("value", [])
233+
return r1.json().get("value", []) + r2.json().get("value", []) + r3.json().get("value", [])
231234

232235
def _extract_id_from_header(self, header_value: Optional[str]) -> Optional[str]:
233236
"""

tests/unit/data/test_relationships.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -402,52 +402,60 @@ def _make_response(self, value):
402402
return r
403403

404404
def test_uses_one_to_many_and_many_to_many_urls(self):
405-
"""Test that both OneToMany and ManyToMany URLs are queried."""
405+
"""Test that OneToMany, ManyToOne, and ManyToMany URLs are queried."""
406406
self.client._mock_request.side_effect = [
407407
self._make_response([]),
408408
self._make_response([]),
409+
self._make_response([]),
409410
]
410411

411412
self.client._list_table_relationships("account")
412413

413414
calls = self.client._mock_request.call_args_list
414-
self.assertEqual(len(calls), 2)
415-
self.assertIn("OneToManyRelationships", calls[0][0][1])
416-
self.assertIn("ManyToManyRelationships", calls[1][0][1])
415+
self.assertEqual(len(calls), 3)
416+
urls = [call[0][1] for call in calls]
417+
self.assertTrue(any("OneToManyRelationships" in u for u in urls))
418+
self.assertTrue(any("ManyToOneRelationships" in u for u in urls))
419+
self.assertTrue(any("ManyToManyRelationships" in u for u in urls))
417420

418421
def test_uses_metadata_id_in_urls(self):
419-
"""Test that the entity MetadataId is used in both URLs."""
422+
"""Test that the entity MetadataId is used in all three URLs."""
420423
self.client._mock_request.side_effect = [
421424
self._make_response([]),
422425
self._make_response([]),
426+
self._make_response([]),
423427
]
424428

425429
self.client._list_table_relationships("account")
426430

427431
calls = self.client._mock_request.call_args_list
428-
self.assertIn("ent-guid-1", calls[0][0][1])
429-
self.assertIn("ent-guid-1", calls[1][0][1])
432+
for call in calls:
433+
self.assertIn("ent-guid-1", call[0][1])
430434

431435
def test_combines_one_to_many_and_many_to_many_results(self):
432-
"""Test that results from both sub-requests are combined."""
436+
"""Test that results from all three sub-requests are combined."""
433437
one_to_many = [{"SchemaName": "rel_1tm", "MetadataId": "r1"}]
434-
many_to_many = [{"SchemaName": "rel_mtm", "MetadataId": "r2"}]
438+
many_to_one = [{"SchemaName": "rel_mt1", "MetadataId": "r2"}]
439+
many_to_many = [{"SchemaName": "rel_mtm", "MetadataId": "r3"}]
435440
self.client._mock_request.side_effect = [
436441
self._make_response(one_to_many),
442+
self._make_response(many_to_one),
437443
self._make_response(many_to_many),
438444
]
439445

440446
result = self.client._list_table_relationships("account")
441447

442-
self.assertEqual(len(result), 2)
448+
self.assertEqual(len(result), 3)
443449
self.assertEqual(result[0]["SchemaName"], "rel_1tm")
444-
self.assertEqual(result[1]["SchemaName"], "rel_mtm")
450+
self.assertEqual(result[1]["SchemaName"], "rel_mt1")
451+
self.assertEqual(result[2]["SchemaName"], "rel_mtm")
445452

446453
def test_filter_param_is_forwarded(self):
447-
"""Test that $filter is sent to both sub-requests."""
454+
"""Test that $filter is sent to all three sub-requests."""
448455
self.client._mock_request.side_effect = [
449456
self._make_response([]),
450457
self._make_response([]),
458+
self._make_response([]),
451459
]
452460

453461
self.client._list_table_relationships("account", filter="IsManaged eq false")
@@ -458,10 +466,11 @@ def test_filter_param_is_forwarded(self):
458466
self.assertEqual(params["$filter"], "IsManaged eq false")
459467

460468
def test_select_param_is_forwarded(self):
461-
"""Test that $select is sent to both sub-requests."""
469+
"""Test that $select is sent to all three sub-requests."""
462470
self.client._mock_request.side_effect = [
463471
self._make_response([]),
464472
self._make_response([]),
473+
self._make_response([]),
465474
]
466475

467476
self.client._list_table_relationships("account", select=["SchemaName", "MetadataId"])

0 commit comments

Comments
 (0)