Skip to content

Commit 438b823

Browse files
authored
fix error in peer count query (#5843)
1 parent 7a0b12d commit 438b823

File tree

3 files changed

+58
-15
lines changed

3 files changed

+58
-15
lines changed

backend/infrahub/core/query/relationship.py

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # pylint: d
583583
query = """
584584
MATCH (source_node:Node)%(arrow_left_start)s[:IS_RELATED]%(arrow_left_end)s(rl:Relationship { name: $rel_identifier })
585585
WHERE source_node.uuid IN $source_ids
586+
WITH DISTINCT source_node, rl
586587
CALL {
587588
WITH rl, source_node
588589
MATCH path = (source_node)%(path)s(peer:Node)
@@ -659,10 +660,23 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # pylint: d
659660
# QUERY Properties
660661
# ----------------------------------------------------------------------------
661662
query = """
662-
MATCH (rl)-[rel_is_visible:IS_VISIBLE]-(is_visible)
663-
MATCH (rl)-[rel_is_protected:IS_PROTECTED]-(is_protected)
664-
WHERE all(r IN [ rel_is_visible, rel_is_protected] WHERE (%s))
665-
""" % (branch_filter,)
663+
CALL {
664+
WITH rl
665+
MATCH (rl)-[r:IS_VISIBLE]-(is_visible)
666+
WHERE %(branch_filter)s
667+
RETURN r AS rel_is_visible, is_visible
668+
ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
669+
LIMIT 1
670+
}
671+
CALL {
672+
WITH rl
673+
MATCH (rl)-[r:IS_PROTECTED]-(is_protected)
674+
WHERE %(branch_filter)s
675+
RETURN r AS rel_is_protected, is_protected
676+
ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
677+
LIMIT 1
678+
}
679+
""" % {"branch_filter": branch_filter}
666680

667681
self.add_to_query(query)
668682

@@ -672,20 +686,24 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # pylint: d
672686
# We must query them one by one otherwise the second one won't return
673687
for node_prop in ["source", "owner"]:
674688
query = """
675-
WITH %s
676-
OPTIONAL MATCH (rl)-[rel_%s:HAS_%s]-(%s)
677-
WHERE all(r IN [ rel_%s ] WHERE (%s))
678-
""" % (
679-
",".join(self.return_labels),
680-
node_prop,
681-
node_prop.upper(),
682-
node_prop,
683-
node_prop,
684-
branch_filter,
685-
)
689+
CALL {
690+
WITH rl
691+
OPTIONAL MATCH (rl)-[r:HAS_%(node_prop_type)s]-(%(node_prop)s)
692+
WHERE %(branch_filter)s
693+
RETURN r AS rel_%(node_prop)s, %(node_prop)s
694+
ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
695+
LIMIT 1
696+
}
697+
""" % {
698+
"node_prop": node_prop,
699+
"node_prop_type": node_prop.upper(),
700+
"branch_filter": branch_filter,
701+
}
686702
self.add_to_query(query)
687703
self.update_return_labels([f"rel_{node_prop}", node_prop])
688704

705+
self.add_to_query("WITH " + ",".join(self.return_labels))
706+
689707
# ----------------------------------------------------------------------------
690708
# ORDER Results
691709
# ----------------------------------------------------------------------------

backend/tests/unit/core/diff/test_diff_and_merge.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ async def test_diff_and_merge_with_relationship_property_conflict(
301301
car_camry_main: Node,
302302
conflict_selection: ConflictSelection,
303303
):
304+
person_schema = db.schema.get(name="TestPerson", duplicate=False)
305+
cars_rel_schema = person_schema.get_relationship(name="cars")
304306
branch2 = await create_branch(db=db, branch_name="branch2")
305307
car_main = await NodeManager.get_one(db=db, id=car_accord_main.id)
306308
await car_main.owner.update(db=db, data={"id": person_john_main.id, "_relation__owner": person_alfred_main.id})
@@ -333,6 +335,16 @@ async def test_diff_and_merge_with_relationship_property_conflict(
333335
if conflict_selection is ConflictSelection.DIFF_BRANCH:
334336
assert owner_prop.id == person_jane_main.id
335337

338+
john_car_count = await NodeManager.count_peers(
339+
db=db,
340+
ids=[person_john_main.id],
341+
source_kind="TestPerson",
342+
filters={},
343+
schema=cars_rel_schema,
344+
branch=branch2,
345+
)
346+
assert john_car_count == 1
347+
336348
await diff_merger.rollback(at=at)
337349

338350
rolled_back_car = await NodeManager.get_one(db=db, id=car_accord_main.id, include_owner=True)
@@ -615,6 +627,8 @@ async def test_update_individual_relationship_properties_one_at_a_time(
615627
car_accord_main,
616628
car_camry_main,
617629
):
630+
person_schema = db.schema.get(name="TestPerson", duplicate=False)
631+
cars_rel_schema = person_schema.get_relationship(name="cars")
618632
branch2 = await create_branch(db=db, branch_name="branch2")
619633
car_branch = await NodeManager.get_one(db=db, branch=branch2, id=car_accord_main.id)
620634
await car_branch.owner.update(db=db, data={"id": person_john_main.id, "_relation__is_protected": True})
@@ -640,6 +654,16 @@ async def test_update_individual_relationship_properties_one_at_a_time(
640654
assert owner_rel.is_protected is True
641655
assert owner_rel.is_visible is False
642656

657+
john_car_count = await NodeManager.count_peers(
658+
db=db,
659+
ids=[person_john_main.id],
660+
source_kind="TestPerson",
661+
filters={},
662+
schema=cars_rel_schema,
663+
branch=branch2,
664+
)
665+
assert john_car_count == 1
666+
643667
await diff_merger.rollback(at=at)
644668

645669
# validate that the properties were correctly rolled back

changelog/+peer-count.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix error in query to count the number of peers for a given cardinality-many relationship logic that could result in the count being multiplied by a power of 2 if changes were made to the relationship during a merge

0 commit comments

Comments
 (0)