Skip to content

Commit 38909a0

Browse files
committed
Merge branch 'stable' into stable-to-develop
2 parents 7824c4a + 5744946 commit 38909a0

File tree

14 files changed

+697
-189
lines changed

14 files changed

+697
-189
lines changed

backend/infrahub/core/diff/combiner.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ def _combine_relationships(
342342

343343
def _copy_node_without_parents(self, node: EnrichedDiffNode) -> EnrichedDiffNode:
344344
rels_without_parents = {replace(r, nodes=set()) for r in node.relationships}
345+
for rel in rels_without_parents:
346+
rel.reset_summaries()
345347
node_without_parents = replace(node, relationships=rels_without_parents)
346348
return deepcopy(node_without_parents)
347349

@@ -351,15 +353,11 @@ def _combine_nodes(self, node_pairs: list[NodePair]) -> set[EnrichedDiffNode]:
351353
if node_pair.earlier is None:
352354
if node_pair.later is not None:
353355
copied = self._copy_node_without_parents(node_pair.later)
354-
for rel in copied.relationships:
355-
rel.reset_summaries()
356356
combined_nodes.add(copied)
357357
continue
358358
if node_pair.later is None:
359359
if node_pair.earlier is not None:
360360
copied = self._copy_node_without_parents(node_pair.earlier)
361-
for rel in copied.relationships:
362-
rel.reset_summaries()
363361
combined_nodes.add(copied)
364362
continue
365363
combined_attributes = self._combine_attributes(

backend/infrahub/core/diff/coordinator.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
from .data_check_synchronizer import DiffDataCheckSynchronizer
3131
from .enricher.aggregated import AggregatedDiffEnricher
3232
from .enricher.labels import DiffLabelsEnricher
33-
from .enricher.summary_counts import DiffSummaryCountsEnricher
3433
from .repository.repository import DiffRepository
3534

3635

@@ -66,7 +65,6 @@ def __init__(
6665
diff_combiner: DiffCombiner,
6766
conflicts_enricher: ConflictsEnricher,
6867
labels_enricher: DiffLabelsEnricher,
69-
summary_counts_enricher: DiffSummaryCountsEnricher,
7068
data_check_synchronizer: DiffDataCheckSynchronizer,
7169
conflict_transferer: DiffConflictTransferer,
7270
) -> None:
@@ -76,7 +74,6 @@ def __init__(
7674
self.diff_combiner = diff_combiner
7775
self.conflicts_enricher = conflicts_enricher
7876
self.labels_enricher = labels_enricher
79-
self.summary_counts_enricher = summary_counts_enricher
8077
self.data_check_synchronizer = data_check_synchronizer
8178
self.conflict_transferer = conflict_transferer
8279
self.lock_registry = lock.registry
@@ -152,10 +149,6 @@ async def update_branch_diff(self, base_branch: Branch, diff_branch: Branch) ->
152149
tracking_id=tracking_id,
153150
force_branch_refresh=False,
154151
)
155-
if isinstance(enriched_diffs, EnrichedDiffs):
156-
await self.summary_counts_enricher.enrich(enriched_diff_root=enriched_diffs.base_branch_diff)
157-
await self.summary_counts_enricher.enrich(enriched_diff_root=enriched_diffs.diff_branch_diff)
158-
159152
await self.diff_repo.save(enriched_diffs=enriched_diffs)
160153
await self._update_core_data_checks(enriched_diff=enriched_diffs.diff_branch_diff)
161154
log.info(f"Branch diff update complete for {base_branch.name} - {diff_branch.name}")
@@ -183,9 +176,6 @@ async def create_or_update_arbitrary_timeframe_diff(
183176
tracking_id=tracking_id,
184177
force_branch_refresh=False,
185178
)
186-
if isinstance(enriched_diffs, EnrichedDiffs):
187-
await self.summary_counts_enricher.enrich(enriched_diff_root=enriched_diffs.base_branch_diff)
188-
await self.summary_counts_enricher.enrich(enriched_diff_root=enriched_diffs.diff_branch_diff)
189179

190180
await self.diff_repo.save(enriched_diffs=enriched_diffs)
191181
await self._update_core_data_checks(enriched_diff=enriched_diffs.diff_branch_diff)
@@ -228,8 +218,6 @@ async def recalculate(
228218
earlier=current_branch_diff, later=enriched_diffs.diff_branch_diff
229219
)
230220

231-
await self.summary_counts_enricher.enrich(enriched_diff_root=enriched_diffs.base_branch_diff)
232-
await self.summary_counts_enricher.enrich(enriched_diff_root=enriched_diffs.diff_branch_diff)
233221
await self.diff_repo.save(enriched_diffs=enriched_diffs)
234222
await self._update_core_data_checks(enriched_diff=enriched_diffs.diff_branch_diff)
235223
log.info(f"Diff recalculation complete for {base_branch.name} - {diff_branch.name}")

backend/infrahub/core/diff/query/save.py

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa
3737
SET diff_root.diff_branch = diff_root_map.diff_branch
3838
SET diff_root.from_time = diff_root_map.from_time
3939
SET diff_root.to_time = diff_root_map.to_time
40-
SET diff_root.num_added = diff_root_map.num_added
41-
SET diff_root.num_updated = diff_root_map.num_updated
42-
SET diff_root.num_removed = diff_root_map.num_removed
43-
SET diff_root.num_conflicts = diff_root_map.num_conflicts
44-
SET diff_root.contains_conflict = diff_root_map.contains_conflict
4540
SET diff_root.tracking_id = diff_root_map.tracking_id
4641
RETURN diff_root
4742
}
@@ -68,11 +63,6 @@ def _build_diff_root_params(self, enriched_diffs: EnrichedDiffs | EnrichedDiffsM
6863
"to_time": enriched_diff.to_time.to_string(),
6964
"uuid": enriched_diff.uuid,
7065
"tracking_id": enriched_diff.tracking_id.serialize() if enriched_diff.tracking_id else None,
71-
"num_added": enriched_diff.num_added,
72-
"num_updated": enriched_diff.num_updated,
73-
"num_removed": enriched_diff.num_removed,
74-
"num_conflicts": enriched_diff.num_conflicts,
75-
"contains_conflict": enriched_diff.contains_conflict,
7666
}
7767
)
7868
return {"diff_root_list": diff_root_list}
@@ -96,7 +86,12 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa
9686
WITH root_uuid, node_map
9787
MATCH (diff_root {uuid: root_uuid})
9888
MERGE (diff_root)-[:DIFF_HAS_NODE]->(diff_node:DiffNode {uuid: node_map.node_properties.uuid})
99-
SET diff_node = node_map.node_properties
89+
SET
90+
diff_node.kind = node_map.node_properties.kind,
91+
diff_node.label = node_map.node_properties.label,
92+
diff_node.changed_at = node_map.node_properties.changed_at,
93+
diff_node.action = node_map.node_properties.action,
94+
diff_node.path_identifier = node_map.node_properties.path_identifier
10095
// -------------------------
10196
// add/remove node-level conflict
10297
// -------------------------
@@ -324,11 +319,6 @@ def _build_diff_attribute_params(self, enriched_attribute: EnrichedDiffAttribute
324319
"changed_at": enriched_attribute.changed_at.to_string(),
325320
"action": enriched_attribute.action.value,
326321
"path_identifier": enriched_attribute.path_identifier,
327-
"num_added": enriched_attribute.num_added,
328-
"num_updated": enriched_attribute.num_updated,
329-
"num_removed": enriched_attribute.num_removed,
330-
"num_conflicts": enriched_attribute.num_conflicts,
331-
"contains_conflict": enriched_attribute.contains_conflict,
332322
},
333323
"properties": property_props,
334324
}
@@ -349,11 +339,6 @@ def _build_diff_single_relationship_params(
349339
"peer_id": enriched_single_relationship.peer_id,
350340
"peer_label": enriched_single_relationship.peer_label,
351341
"path_identifier": enriched_single_relationship.path_identifier,
352-
"num_added": enriched_single_relationship.num_added,
353-
"num_updated": enriched_single_relationship.num_updated,
354-
"num_removed": enriched_single_relationship.num_removed,
355-
"num_conflicts": enriched_single_relationship.num_conflicts,
356-
"contains_conflict": enriched_single_relationship.contains_conflict,
357342
},
358343
"conflict_params": conflict_params,
359344
"properties": property_props,
@@ -375,11 +360,6 @@ def _build_diff_relationship_params(self, enriched_relationship: EnrichedDiffRel
375360
else None,
376361
"action": enriched_relationship.action,
377362
"path_identifier": enriched_relationship.path_identifier,
378-
"num_added": enriched_relationship.num_added,
379-
"num_updated": enriched_relationship.num_updated,
380-
"num_removed": enriched_relationship.num_removed,
381-
"num_conflicts": enriched_relationship.num_conflicts,
382-
"contains_conflict": enriched_relationship.contains_conflict,
383363
},
384364
"relationships": single_relationship_props,
385365
}
@@ -402,11 +382,6 @@ def _build_diff_node_params(self, enriched_node: EnrichedDiffNode) -> dict[str,
402382
"changed_at": enriched_node.changed_at.to_string() if enriched_node.changed_at else None,
403383
"action": enriched_node.action.value,
404384
"path_identifier": enriched_node.path_identifier,
405-
"num_added": enriched_node.num_added,
406-
"num_updated": enriched_node.num_updated,
407-
"num_removed": enriched_node.num_removed,
408-
"num_conflicts": enriched_node.num_conflicts,
409-
"contains_conflict": enriched_node.contains_conflict,
410385
},
411386
"conflict_params": conflict_params,
412387
"attributes": attribute_props,
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
from typing import Any
2+
3+
from infrahub.core.query import Query, QueryType
4+
from infrahub.database import InfrahubDatabase
5+
6+
from ..model.path import TrackingId
7+
8+
9+
class DiffSummaryCountsEnricherQuery(Query):
10+
"""Update summary counters for a given diff"""
11+
12+
name = "diff_summary_count_enricher"
13+
type = QueryType.WRITE
14+
insert_return = False
15+
16+
def __init__(
17+
self,
18+
diff_branch_name: str,
19+
tracking_id: TrackingId | None = None,
20+
diff_id: str | None = None,
21+
node_uuids: list[str] | None = None,
22+
**kwargs: Any,
23+
) -> None:
24+
super().__init__(**kwargs)
25+
if (diff_id is None and tracking_id is None) or (diff_id and tracking_id):
26+
raise ValueError("EnrichedDiffAllConflictsQuery requires one and only one of `tracking_id` or `diff_id`")
27+
self.diff_branch_name = diff_branch_name
28+
self.tracking_id = tracking_id
29+
self.diff_id = diff_id
30+
if self.tracking_id is None and self.diff_id is None:
31+
raise RuntimeError("tracking_id or diff_id is required")
32+
self.node_uuids = node_uuids
33+
34+
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None:
35+
self.params = {
36+
"diff_branch_name": self.diff_branch_name,
37+
"diff_id": self.diff_id,
38+
"tracking_id": self.tracking_id.serialize() if self.tracking_id else None,
39+
"node_uuids": self.node_uuids,
40+
}
41+
query = """
42+
MATCH (root:DiffRoot)
43+
WHERE ($diff_id IS NOT NULL AND root.uuid = $diff_id)
44+
OR ($tracking_id IS NOT NULL AND root.tracking_id = $tracking_id AND root.diff_branch = $diff_branch_name)
45+
MATCH (root)-[:DIFF_HAS_NODE]->(dn:DiffNode)
46+
WHERE $node_uuids IS NULL OR dn.uuid IN $node_uuids
47+
CALL {
48+
// ----------------------
49+
// handle attribute count updates
50+
// ----------------------
51+
WITH dn
52+
MATCH (dn)-[:DIFF_HAS_ATTRIBUTE]->(da:DiffAttribute)
53+
CALL {
54+
WITH da
55+
OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty)-[:DIFF_HAS_CONFLICT]->(dc:DiffConflict)
56+
WITH da, count(dc) AS num_conflicts
57+
SET da.num_conflicts = num_conflicts
58+
SET da.contains_conflict = (num_conflicts > 0)
59+
}
60+
CALL {
61+
WITH da
62+
OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "added"})
63+
WITH da, count(dp.action) AS num_added
64+
SET da.num_added = num_added
65+
}
66+
CALL {
67+
WITH da
68+
OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "updated"})
69+
WITH da, count(dp.action) AS num_updated
70+
SET da.num_updated = num_updated
71+
}
72+
CALL {
73+
WITH da
74+
OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "removed"})
75+
WITH da, count(dp.action) AS num_removed
76+
SET da.num_removed = num_removed
77+
}
78+
}
79+
CALL {
80+
WITH dn
81+
MATCH (dn)-[:DIFF_HAS_RELATIONSHIP]->(dr:DiffRelationship)
82+
CALL {
83+
// ----------------------
84+
// handle relationship element count updates
85+
// ----------------------
86+
WITH dr
87+
MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement)
88+
CALL {
89+
WITH dre
90+
OPTIONAL MATCH (dre)-[*..4]->(dc:DiffConflict)
91+
WITH dre, count(dc) AS num_conflicts
92+
SET dre.num_conflicts = num_conflicts
93+
SET dre.contains_conflict = (num_conflicts > 0)
94+
}
95+
CALL {
96+
WITH dre
97+
OPTIONAL MATCH (dre)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "added"})
98+
WITH dre, count(dp.action) AS num_added
99+
SET dre.num_added = num_added
100+
}
101+
CALL {
102+
WITH dre
103+
OPTIONAL MATCH (dre)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "updated"})
104+
WITH dre, count(dp.action) AS num_updated
105+
SET dre.num_updated = num_updated
106+
}
107+
CALL {
108+
WITH dre
109+
OPTIONAL MATCH (dre)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "removed"})
110+
WITH dre, count(dp.action) AS num_removed
111+
SET dre.num_removed = num_removed
112+
}
113+
}
114+
// ----------------------
115+
// handle relationship count updates
116+
// ----------------------
117+
OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(conflict_dre:DiffRelationshipElement {contains_conflict: TRUE})
118+
WITH dr, sum(conflict_dre.num_conflicts) AS num_conflicts
119+
SET dr.num_conflicts = num_conflicts
120+
SET dr.contains_conflict = (num_conflicts > 0)
121+
WITH dr
122+
CALL {
123+
WITH dr
124+
OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement {action: "added"})
125+
WITH dr, count(dre.action) AS num_added
126+
SET dr.num_added = num_added
127+
}
128+
CALL {
129+
WITH dr
130+
OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement {action: "updated"})
131+
WITH dr, count(dre.action) AS num_updated
132+
SET dr.num_updated = num_updated
133+
}
134+
CALL {
135+
WITH dr
136+
OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement {action: "removed"})
137+
WITH dr, count(dre.action) AS num_removed
138+
SET dr.num_removed = num_removed
139+
}
140+
}
141+
// ----------------------
142+
// handle node count updates
143+
// ----------------------
144+
WITH root, dn, coalesce(dn.num_conflicts, 0) AS previous_num_conflicts
145+
CALL {
146+
// ----------------------
147+
// handle node num_conflicts update
148+
// ----------------------
149+
WITH dn
150+
OPTIONAL MATCH (dn)-[:DIFF_HAS_ATTRIBUTE]->(da:DiffAttribute {contains_conflict: TRUE})
151+
RETURN sum(da.num_conflicts) AS num_conflicts
152+
UNION ALL
153+
WITH dn
154+
OPTIONAL MATCH (dn)-[:DIFF_HAS_RELATIONSHIP]->(dr:DiffRelationship {contains_conflict: TRUE})
155+
RETURN sum(dr.num_conflicts) AS num_conflicts
156+
UNION ALL
157+
WITH dn
158+
OPTIONAL MATCH (dn)-[:DIFF_HAS_CONFLICT]->(dc:DiffConflict)
159+
RETURN count(dc) AS num_conflicts
160+
}
161+
WITH root, dn, previous_num_conflicts, sum(num_conflicts) AS updated_num_conflicts
162+
SET dn.num_conflicts = updated_num_conflicts
163+
SET dn.contains_conflict = (updated_num_conflicts > 0)
164+
WITH root, dn, updated_num_conflicts - previous_num_conflicts AS num_conflicts_delta
165+
CALL {
166+
// ----------------------
167+
// handle node added/updated/removed updates
168+
// ----------------------
169+
WITH dn
170+
OPTIONAL MATCH (dn)-[:DIFF_HAS_ATTRIBUTE]->(da:DiffAttribute)
171+
WITH dn, collect(da.action) AS attr_actions
172+
OPTIONAL MATCH (dn)-[:DIFF_HAS_RELATIONSHIP]->(dr:DiffRelationship)
173+
WITH dn, attr_actions, collect(dr.action) AS rel_actions
174+
WITH dn, attr_actions + rel_actions AS actions
175+
WITH dn, reduce(counts = [0,0,0], a IN actions |
176+
CASE
177+
WHEN a = "added" THEN [counts[0] + 1, counts[1], counts[2]]
178+
WHEN a = "updated" THEN [counts[0], counts[1] + 1, counts[2]]
179+
WHEN a = "removed" THEN [counts[0], counts[1], counts[2] + 1]
180+
ELSE counts
181+
END
182+
) AS action_counts
183+
WITH dn, action_counts[0] AS num_added, action_counts[1] AS num_updated, action_counts[2] AS num_removed
184+
SET dn.num_added = num_added
185+
SET dn.num_updated = num_updated
186+
SET dn.num_removed = num_removed
187+
}
188+
// ----------------------
189+
// handle conflict updates for parent nodes
190+
// ----------------------
191+
WITH root, dn, num_conflicts_delta
192+
CALL {
193+
WITH dn, num_conflicts_delta
194+
OPTIONAL MATCH (dn)-[:DIFF_HAS_RELATIONSHIP|DIFF_HAS_NODE*1..]->(parent_node:DiffNode)
195+
SET parent_node.num_conflicts = parent_node.num_conflicts + num_conflicts_delta
196+
SET parent_node.contains_conflict = (parent_node.num_conflicts > 0)
197+
}
198+
// ----------------------
199+
// handle root count updates
200+
// ----------------------
201+
WITH root, sum(num_conflicts_delta) AS total_conflicts_delta
202+
CALL {
203+
WITH root, total_conflicts_delta
204+
SET root.num_conflicts = coalesce(root.num_conflicts, 0) + total_conflicts_delta
205+
SET root.contains_conflict = root.num_conflicts > 0
206+
WITH root
207+
OPTIONAL MATCH (root)-[:DIFF_HAS_NODE]->(dn:DiffNode {action: "added"})
208+
WITH root, count(dn.action) AS num_added
209+
SET root.num_added = num_added
210+
WITH root
211+
OPTIONAL MATCH (root)-[:DIFF_HAS_NODE]->(dn:DiffNode {action: "updated"})
212+
WITH root, count(dn.action) AS num_updated
213+
SET root.num_updated = num_updated
214+
WITH root
215+
OPTIONAL MATCH (root)-[:DIFF_HAS_NODE]->(dn:DiffNode {action: "removed"})
216+
WITH root, count(dn.action) AS num_removed
217+
SET root.num_removed = num_removed
218+
}
219+
"""
220+
self.add_to_query(query)

0 commit comments

Comments
 (0)