infrahub-server 1.2.9rc0__py3-none-any.whl → 1.3.0a0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- infrahub/actions/constants.py +86 -0
- infrahub/actions/gather.py +114 -0
- infrahub/actions/models.py +241 -0
- infrahub/actions/parsers.py +104 -0
- infrahub/actions/schema.py +382 -0
- infrahub/actions/tasks.py +126 -0
- infrahub/actions/triggers.py +21 -0
- infrahub/cli/db.py +1 -2
- infrahub/computed_attribute/models.py +13 -0
- infrahub/computed_attribute/tasks.py +48 -26
- infrahub/config.py +9 -0
- infrahub/core/account.py +24 -47
- infrahub/core/attribute.py +53 -14
- infrahub/core/branch/models.py +8 -9
- infrahub/core/branch/tasks.py +0 -2
- infrahub/core/constants/infrahubkind.py +8 -0
- infrahub/core/constraint/node/runner.py +1 -1
- infrahub/core/convert_object_type/__init__.py +0 -0
- infrahub/core/convert_object_type/conversion.py +122 -0
- infrahub/core/convert_object_type/schema_mapping.py +56 -0
- infrahub/core/diff/calculator.py +65 -11
- infrahub/core/diff/combiner.py +38 -31
- infrahub/core/diff/coordinator.py +44 -28
- infrahub/core/diff/data_check_synchronizer.py +3 -2
- infrahub/core/diff/enricher/hierarchy.py +36 -27
- infrahub/core/diff/ipam_diff_parser.py +5 -4
- infrahub/core/diff/merger/merger.py +46 -16
- infrahub/core/diff/merger/serializer.py +1 -0
- infrahub/core/diff/model/field_specifiers_map.py +64 -0
- infrahub/core/diff/model/path.py +58 -58
- infrahub/core/diff/parent_node_adder.py +14 -16
- infrahub/core/diff/query/all_conflicts.py +1 -5
- infrahub/core/diff/query/artifact.py +10 -20
- infrahub/core/diff/query/diff_get.py +3 -6
- infrahub/core/diff/query/drop_nodes.py +42 -0
- infrahub/core/diff/query/field_specifiers.py +8 -7
- infrahub/core/diff/query/field_summary.py +2 -4
- infrahub/core/diff/query/filters.py +15 -1
- infrahub/core/diff/query/merge.py +284 -101
- infrahub/core/diff/query/save.py +26 -34
- infrahub/core/diff/query/summary_counts_enricher.py +34 -54
- infrahub/core/diff/query_parser.py +55 -65
- infrahub/core/diff/repository/deserializer.py +38 -24
- infrahub/core/diff/repository/repository.py +31 -12
- infrahub/core/diff/tasks.py +3 -3
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/manager.py +14 -11
- infrahub/core/migrations/graph/__init__.py +2 -0
- infrahub/core/migrations/graph/m003_relationship_parent_optional.py +1 -2
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +2 -4
- infrahub/core/migrations/graph/m019_restore_rels_to_time.py +11 -22
- infrahub/core/migrations/graph/m020_duplicate_edges.py +3 -6
- infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +1 -2
- infrahub/core/migrations/graph/m024_missing_hierarchy_backfill.py +1 -2
- infrahub/core/migrations/graph/m027_delete_isolated_nodes.py +50 -0
- infrahub/core/migrations/graph/m028_delete_diffs.py +38 -0
- infrahub/core/migrations/query/attribute_add.py +1 -2
- infrahub/core/migrations/query/attribute_rename.py +3 -6
- infrahub/core/migrations/query/delete_element_in_schema.py +3 -6
- infrahub/core/migrations/query/node_duplicate.py +3 -6
- infrahub/core/migrations/query/relationship_duplicate.py +3 -6
- infrahub/core/migrations/schema/node_attribute_remove.py +3 -6
- infrahub/core/migrations/schema/node_remove.py +3 -6
- infrahub/core/models.py +29 -2
- infrahub/core/node/__init__.py +18 -4
- infrahub/core/node/create.py +211 -0
- infrahub/core/protocols.py +51 -0
- infrahub/core/protocols_base.py +3 -0
- infrahub/core/query/__init__.py +2 -2
- infrahub/core/query/branch.py +27 -17
- infrahub/core/query/diff.py +186 -81
- infrahub/core/query/ipam.py +10 -20
- infrahub/core/query/node.py +65 -49
- infrahub/core/query/relationship.py +156 -58
- infrahub/core/query/resource_manager.py +1 -2
- infrahub/core/query/subquery.py +4 -6
- infrahub/core/relationship/model.py +4 -1
- infrahub/core/schema/__init__.py +2 -1
- infrahub/core/schema/attribute_parameters.py +36 -0
- infrahub/core/schema/attribute_schema.py +83 -8
- infrahub/core/schema/basenode_schema.py +25 -1
- infrahub/core/schema/definitions/core/__init__.py +21 -0
- infrahub/core/schema/definitions/internal.py +13 -3
- infrahub/core/schema/generated/attribute_schema.py +9 -3
- infrahub/core/schema/schema_branch.py +15 -7
- infrahub/core/validators/__init__.py +5 -1
- infrahub/core/validators/attribute/choices.py +1 -2
- infrahub/core/validators/attribute/enum.py +1 -2
- infrahub/core/validators/attribute/kind.py +1 -2
- infrahub/core/validators/attribute/length.py +13 -6
- infrahub/core/validators/attribute/optional.py +1 -2
- infrahub/core/validators/attribute/regex.py +5 -5
- infrahub/core/validators/attribute/unique.py +1 -3
- infrahub/core/validators/determiner.py +18 -2
- infrahub/core/validators/enum.py +7 -0
- infrahub/core/validators/node/hierarchy.py +3 -6
- infrahub/core/validators/query.py +1 -3
- infrahub/core/validators/relationship/count.py +6 -12
- infrahub/core/validators/relationship/optional.py +2 -4
- infrahub/core/validators/relationship/peer.py +3 -8
- infrahub/core/validators/tasks.py +1 -1
- infrahub/core/validators/uniqueness/query.py +12 -9
- infrahub/database/__init__.py +1 -3
- infrahub/events/group_action.py +1 -0
- infrahub/graphql/analyzer.py +139 -18
- infrahub/graphql/app.py +1 -1
- infrahub/graphql/loaders/node.py +1 -1
- infrahub/graphql/loaders/peers.py +1 -1
- infrahub/graphql/manager.py +4 -0
- infrahub/graphql/mutations/action.py +164 -0
- infrahub/graphql/mutations/convert_object_type.py +62 -0
- infrahub/graphql/mutations/main.py +24 -175
- infrahub/graphql/mutations/proposed_change.py +21 -18
- infrahub/graphql/queries/convert_object_type_mapping.py +36 -0
- infrahub/graphql/queries/diff/tree.py +2 -1
- infrahub/graphql/queries/relationship.py +1 -1
- infrahub/graphql/resolvers/many_relationship.py +4 -4
- infrahub/graphql/resolvers/resolver.py +4 -4
- infrahub/graphql/resolvers/single_relationship.py +2 -2
- infrahub/graphql/schema.py +6 -0
- infrahub/graphql/subscription/graphql_query.py +2 -2
- infrahub/graphql/types/branch.py +1 -1
- infrahub/menu/menu.py +31 -0
- infrahub/message_bus/messages/__init__.py +0 -10
- infrahub/message_bus/operations/__init__.py +0 -8
- infrahub/message_bus/operations/refresh/registry.py +1 -1
- infrahub/patch/queries/consolidate_duplicated_nodes.py +3 -6
- infrahub/patch/queries/delete_duplicated_edges.py +5 -10
- infrahub/prefect_server/models.py +1 -19
- infrahub/proposed_change/models.py +68 -3
- infrahub/proposed_change/tasks.py +907 -30
- infrahub/task_manager/models.py +10 -6
- infrahub/telemetry/database.py +1 -1
- infrahub/telemetry/tasks.py +1 -1
- infrahub/trigger/catalogue.py +2 -0
- infrahub/trigger/models.py +29 -3
- infrahub/trigger/setup.py +51 -15
- infrahub/trigger/tasks.py +4 -5
- infrahub/types.py +1 -1
- infrahub/webhook/models.py +2 -1
- infrahub/workflows/catalogue.py +85 -0
- infrahub/workflows/initialization.py +1 -3
- infrahub_sdk/timestamp.py +2 -2
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/METADATA +4 -4
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/RECORD +153 -146
- infrahub_testcontainers/container.py +0 -1
- infrahub_testcontainers/docker-compose.test.yml +4 -4
- infrahub_testcontainers/helpers.py +8 -2
- infrahub_testcontainers/performance_test.py +6 -3
- infrahub/message_bus/messages/check_generator_run.py +0 -26
- infrahub/message_bus/messages/finalize_validator_execution.py +0 -15
- infrahub/message_bus/messages/proposed_change/base_with_diff.py +0 -16
- infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +0 -11
- infrahub/message_bus/messages/request_generatordefinition_check.py +0 -20
- infrahub/message_bus/messages/request_proposedchange_pipeline.py +0 -23
- infrahub/message_bus/operations/check/__init__.py +0 -3
- infrahub/message_bus/operations/check/generator.py +0 -156
- infrahub/message_bus/operations/finalize/__init__.py +0 -3
- infrahub/message_bus/operations/finalize/validator.py +0 -133
- infrahub/message_bus/operations/requests/__init__.py +0 -9
- infrahub/message_bus/operations/requests/generator_definition.py +0 -140
- infrahub/message_bus/operations/requests/proposed_change.py +0 -629
- /infrahub/{message_bus/messages/proposed_change → actions}/__init__.py +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/entry_points.txt +0 -0
infrahub/core/diff/query/save.py
CHANGED
|
@@ -30,8 +30,7 @@ class EnrichedDiffRootsUpsertQuery(Query):
|
|
|
30
30
|
query = """
|
|
31
31
|
UNWIND $diff_root_list AS diff_root_map
|
|
32
32
|
WITH diff_root_map
|
|
33
|
-
CALL {
|
|
34
|
-
WITH diff_root_map
|
|
33
|
+
CALL (diff_root_map) {
|
|
35
34
|
MERGE (diff_root:DiffRoot {uuid: diff_root_map.uuid})
|
|
36
35
|
SET diff_root.base_branch = diff_root_map.base_branch
|
|
37
36
|
SET diff_root.diff_branch = diff_root_map.diff_branch
|
|
@@ -43,8 +42,7 @@ CALL {
|
|
|
43
42
|
WITH DISTINCT diff_root AS diff_root
|
|
44
43
|
WITH collect(diff_root) AS diff_roots
|
|
45
44
|
WHERE SIZE(diff_roots) = 2
|
|
46
|
-
CALL {
|
|
47
|
-
WITH diff_roots
|
|
45
|
+
CALL (diff_roots) {
|
|
48
46
|
WITH diff_roots[0] AS base_diff_node, diff_roots[1] AS branch_diff_node
|
|
49
47
|
MERGE (base_diff_node)-[:DIFF_HAS_PARTNER]-(branch_diff_node)
|
|
50
48
|
SET (base_diff_node).partner_uuid = (branch_diff_node).uuid
|
|
@@ -85,18 +83,20 @@ UNWIND $node_details_list AS node_details
|
|
|
85
83
|
WITH
|
|
86
84
|
node_details.root_uuid AS root_uuid,
|
|
87
85
|
node_details.node_map AS node_map,
|
|
88
|
-
toString(node_details.node_map.node_properties.uuid) AS node_uuid
|
|
86
|
+
toString(node_details.node_map.node_properties.uuid) AS node_uuid,
|
|
87
|
+
node_details.node_map.node_properties.db_id AS node_db_id
|
|
89
88
|
MERGE (diff_root:DiffRoot {uuid: root_uuid})
|
|
90
|
-
MERGE (diff_root)-[:DIFF_HAS_NODE]->(diff_node:DiffNode {uuid: node_uuid})
|
|
89
|
+
MERGE (diff_root)-[:DIFF_HAS_NODE]->(diff_node:DiffNode {uuid: node_uuid, db_id: node_db_id})
|
|
91
90
|
WITH root_uuid, node_map, diff_node, (node_map.conflict_params IS NOT NULL) AS has_node_conflict
|
|
92
91
|
SET
|
|
93
92
|
diff_node.kind = node_map.node_properties.kind,
|
|
94
93
|
diff_node.label = node_map.node_properties.label,
|
|
95
94
|
diff_node.changed_at = node_map.node_properties.changed_at,
|
|
96
95
|
diff_node.action = node_map.node_properties.action,
|
|
96
|
+
diff_node.is_node_kind_migration = node_map.node_properties.is_node_kind_migration,
|
|
97
97
|
diff_node.path_identifier = node_map.node_properties.path_identifier
|
|
98
98
|
WITH root_uuid, node_map, diff_node, has_node_conflict
|
|
99
|
-
CALL {
|
|
99
|
+
CALL (diff_node) {
|
|
100
100
|
// -------------------------
|
|
101
101
|
// delete parent-child relationships for included nodes, they will be added in EnrichedNodesLinkQuery
|
|
102
102
|
// -------------------------
|
|
@@ -105,43 +105,38 @@ CALL {
|
|
|
105
105
|
DELETE parent_rel
|
|
106
106
|
}
|
|
107
107
|
OPTIONAL MATCH (diff_node)-[:DIFF_HAS_CONFLICT]->(current_node_conflict:DiffConflict)
|
|
108
|
-
CALL {
|
|
108
|
+
CALL (diff_node, current_node_conflict, has_node_conflict) {
|
|
109
109
|
// -------------------------
|
|
110
110
|
// create a node-level conflict, if necessary
|
|
111
111
|
// -------------------------
|
|
112
112
|
WITH diff_node, current_node_conflict, has_node_conflict
|
|
113
|
-
WITH diff_node, current_node_conflict, has_node_conflict
|
|
114
113
|
WHERE current_node_conflict IS NULL AND has_node_conflict = TRUE
|
|
115
114
|
CREATE (diff_node)-[:DIFF_HAS_CONFLICT]->(:DiffConflict)
|
|
116
115
|
}
|
|
117
|
-
CALL {
|
|
116
|
+
CALL (current_node_conflict, has_node_conflict) {
|
|
118
117
|
// -------------------------
|
|
119
118
|
// delete a node-level conflict, if necessary
|
|
120
119
|
// -------------------------
|
|
121
120
|
WITH current_node_conflict, has_node_conflict
|
|
122
|
-
WITH current_node_conflict, has_node_conflict
|
|
123
121
|
WHERE current_node_conflict IS NOT NULL AND has_node_conflict = FALSE
|
|
124
122
|
DETACH DELETE current_node_conflict
|
|
125
123
|
}
|
|
126
124
|
WITH root_uuid, node_map, diff_node, has_node_conflict, node_map.conflict_params AS node_conflict_params
|
|
127
|
-
CALL {
|
|
125
|
+
CALL (diff_node, has_node_conflict, node_conflict_params) {
|
|
128
126
|
// -------------------------
|
|
129
127
|
// set the properties of the node-level conflict, if necessary
|
|
130
128
|
// -------------------------
|
|
131
129
|
WITH diff_node, has_node_conflict, node_conflict_params
|
|
132
|
-
WITH diff_node, has_node_conflict, node_conflict_params
|
|
133
130
|
WHERE has_node_conflict = TRUE
|
|
134
131
|
OPTIONAL MATCH (diff_node)-[:DIFF_HAS_CONFLICT]->(node_conflict:DiffConflict)
|
|
135
132
|
SET node_conflict = node_conflict_params
|
|
136
133
|
}
|
|
137
|
-
CALL {
|
|
134
|
+
CALL (diff_node, node_map) {
|
|
138
135
|
// -------------------------
|
|
139
136
|
// remove stale attributes for this node
|
|
140
137
|
// -------------------------
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
WITH diff_node, node_map
|
|
144
|
-
WITH diff_node, %(attr_name_list_comp)s AS attr_names
|
|
138
|
+
CALL (diff_node, node_map) {
|
|
139
|
+
WITH %(attr_name_list_comp)s AS attr_names
|
|
145
140
|
OPTIONAL MATCH (diff_node)-[:DIFF_HAS_ATTRIBUTE]->(attr_to_delete:DiffAttribute)
|
|
146
141
|
WHERE NOT (attr_to_delete.name IN attr_names)
|
|
147
142
|
OPTIONAL MATCH (attr_to_delete)-[*..6]->(next_to_delete)
|
|
@@ -161,9 +156,8 @@ CALL {
|
|
|
161
156
|
// -------------------------
|
|
162
157
|
// remove stale properties for this attribute
|
|
163
158
|
// -------------------------
|
|
164
|
-
CALL {
|
|
165
|
-
WITH
|
|
166
|
-
WITH diff_attribute, %(attr_props_list_comp)s AS prop_types
|
|
159
|
+
CALL (diff_attribute, node_attribute) {
|
|
160
|
+
WITH %(attr_props_list_comp)s AS prop_types
|
|
167
161
|
OPTIONAL MATCH (diff_attribute)-[:DIFF_HAS_PROPERTY]->(prop_to_delete:DiffProperty)
|
|
168
162
|
WHERE NOT (prop_to_delete.property_type IN prop_types)
|
|
169
163
|
OPTIONAL MATCH (prop_to_delete)-[*..4]->(next_to_delete)
|
|
@@ -190,9 +184,8 @@ CALL {
|
|
|
190
184
|
// -------------------------
|
|
191
185
|
// remove stale relationships for this node
|
|
192
186
|
// -------------------------
|
|
193
|
-
CALL {
|
|
194
|
-
WITH
|
|
195
|
-
WITH diff_node, %(rel_name_list_comp)s AS rel_names
|
|
187
|
+
CALL (diff_node, node_map) {
|
|
188
|
+
WITH %(rel_name_list_comp)s AS rel_names
|
|
196
189
|
OPTIONAL MATCH (diff_node)-[:DIFF_HAS_RELATIONSHIP]->(rel_to_delete:DiffRelationship)
|
|
197
190
|
WHERE NOT (rel_to_delete.name IN rel_names)
|
|
198
191
|
OPTIONAL MATCH (rel_to_delete)-[*..8]->(next_to_delete)
|
|
@@ -210,9 +203,8 @@ SET diff_relationship = node_relationship.node_properties
|
|
|
210
203
|
// remove stale elements for this relationship group
|
|
211
204
|
// -------------------------
|
|
212
205
|
WITH diff_relationship, node_relationship
|
|
213
|
-
CALL {
|
|
214
|
-
WITH
|
|
215
|
-
WITH diff_relationship, %(rel_peers_list_comp)s AS rel_peers
|
|
206
|
+
CALL (diff_relationship, node_relationship) {
|
|
207
|
+
WITH %(rel_peers_list_comp)s AS rel_peers
|
|
216
208
|
OPTIONAL MATCH (diff_relationship)-[:DIFF_HAS_ELEMENT]->(element_to_delete:DiffRelationshipElement)
|
|
217
209
|
WHERE NOT (element_to_delete.peer_id IN rel_peers)
|
|
218
210
|
OPTIONAL MATCH (element_to_delete)-[*..6]->(next_to_delete)
|
|
@@ -245,9 +237,8 @@ FOREACH (i in CASE WHEN has_element_conflict = TRUE THEN [1] ELSE [] END |
|
|
|
245
237
|
// remove stale properties for this relationship element
|
|
246
238
|
// -------------------------
|
|
247
239
|
WITH diff_relationship_element, node_single_relationship
|
|
248
|
-
CALL {
|
|
249
|
-
WITH
|
|
250
|
-
WITH diff_relationship_element, %(element_props_list_comp)s AS element_props
|
|
240
|
+
CALL (diff_relationship_element, node_single_relationship) {
|
|
241
|
+
WITH %(element_props_list_comp)s AS element_props
|
|
251
242
|
OPTIONAL MATCH (diff_relationship_element)-[:DIFF_HAS_PROPERTY]->(property_to_delete:DiffProperty)
|
|
252
243
|
WHERE NOT (property_to_delete.property_type IN element_props)
|
|
253
244
|
OPTIONAL MATCH (property_to_delete)-[*..4]->(next_to_delete)
|
|
@@ -401,6 +392,8 @@ FOREACH (i in CASE WHEN has_property_conflict = TRUE THEN [1] ELSE [] END |
|
|
|
401
392
|
"node_properties": {
|
|
402
393
|
"uuid": enriched_node.uuid,
|
|
403
394
|
"kind": enriched_node.kind,
|
|
395
|
+
"db_id": enriched_node.identifier.db_id,
|
|
396
|
+
"is_node_kind_migration": enriched_node.is_node_kind_migration,
|
|
404
397
|
"label": enriched_node.label,
|
|
405
398
|
"changed_at": enriched_node.changed_at.to_string() if enriched_node.changed_at else None,
|
|
406
399
|
"action": enriched_node.action.value,
|
|
@@ -447,10 +440,9 @@ WITH keys($parent_node_map) AS child_node_uuids
|
|
|
447
440
|
MATCH (diff_root:DiffRoot {uuid: $root_uuid})
|
|
448
441
|
MATCH (diff_root)-[:DIFF_HAS_NODE]->(child_node:DiffNode)
|
|
449
442
|
WHERE child_node.uuid IN child_node_uuids
|
|
450
|
-
CALL {
|
|
451
|
-
WITH
|
|
452
|
-
WITH
|
|
453
|
-
WITH diff_root, child_node, sub_map, keys(sub_map) AS relationship_names
|
|
443
|
+
CALL (diff_root, child_node) {
|
|
444
|
+
WITH $parent_node_map[child_node.uuid] AS sub_map
|
|
445
|
+
WITH sub_map, keys(sub_map) AS relationship_names
|
|
454
446
|
MATCH (child_node)-[:DIFF_HAS_RELATIONSHIP]->(diff_rel_group:DiffRelationship)
|
|
455
447
|
WHERE diff_rel_group.name IN relationship_names
|
|
456
448
|
WITH diff_root, diff_rel_group, toString(sub_map[diff_rel_group.name]) AS parent_uuid
|
|
@@ -46,70 +46,59 @@ WHERE ($diff_id IS NOT NULL AND root.uuid = $diff_id)
|
|
|
46
46
|
OR ($tracking_id IS NOT NULL AND root.tracking_id = $tracking_id AND root.diff_branch = $diff_branch_name)
|
|
47
47
|
MATCH (root)-[:DIFF_HAS_NODE]->(dn:DiffNode)
|
|
48
48
|
WHERE $node_uuids IS NULL OR dn.uuid IN $node_uuids
|
|
49
|
-
CALL {
|
|
49
|
+
CALL (dn) {
|
|
50
50
|
// ----------------------
|
|
51
51
|
// handle attribute count updates
|
|
52
52
|
// ----------------------
|
|
53
|
-
WITH dn
|
|
54
53
|
MATCH (dn)-[:DIFF_HAS_ATTRIBUTE]->(da:DiffAttribute)
|
|
55
|
-
CALL {
|
|
56
|
-
WITH da
|
|
54
|
+
CALL (da) {
|
|
57
55
|
OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty)-[:DIFF_HAS_CONFLICT]->(dc:DiffConflict)
|
|
58
|
-
WITH
|
|
56
|
+
WITH count(dc) AS num_conflicts
|
|
59
57
|
SET da.num_conflicts = num_conflicts
|
|
60
58
|
SET da.contains_conflict = (num_conflicts > 0)
|
|
61
59
|
}
|
|
62
|
-
CALL {
|
|
63
|
-
WITH da
|
|
60
|
+
CALL (da) {
|
|
64
61
|
OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "added"})
|
|
65
|
-
WITH
|
|
62
|
+
WITH count(dp.action) AS num_added
|
|
66
63
|
SET da.num_added = num_added
|
|
67
64
|
}
|
|
68
|
-
CALL {
|
|
69
|
-
WITH da
|
|
65
|
+
CALL (da) {
|
|
70
66
|
OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "updated"})
|
|
71
|
-
WITH
|
|
67
|
+
WITH count(dp.action) AS num_updated
|
|
72
68
|
SET da.num_updated = num_updated
|
|
73
69
|
}
|
|
74
|
-
CALL {
|
|
75
|
-
WITH da
|
|
70
|
+
CALL (da) {
|
|
76
71
|
OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "removed"})
|
|
77
|
-
WITH
|
|
72
|
+
WITH count(dp.action) AS num_removed
|
|
78
73
|
SET da.num_removed = num_removed
|
|
79
74
|
}
|
|
80
75
|
}
|
|
81
|
-
CALL {
|
|
82
|
-
WITH dn
|
|
76
|
+
CALL (dn) {
|
|
83
77
|
MATCH (dn)-[:DIFF_HAS_RELATIONSHIP]->(dr:DiffRelationship)
|
|
84
|
-
CALL {
|
|
78
|
+
CALL (dr) {
|
|
85
79
|
// ----------------------
|
|
86
80
|
// handle relationship element count updates
|
|
87
81
|
// ----------------------
|
|
88
|
-
WITH dr
|
|
89
82
|
MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement)
|
|
90
|
-
CALL {
|
|
91
|
-
WITH dre
|
|
83
|
+
CALL (dre) {
|
|
92
84
|
OPTIONAL MATCH (dre)-[*..4]->(dc:DiffConflict)
|
|
93
|
-
WITH
|
|
85
|
+
WITH count(dc) AS num_conflicts
|
|
94
86
|
SET dre.num_conflicts = num_conflicts
|
|
95
87
|
SET dre.contains_conflict = (num_conflicts > 0)
|
|
96
88
|
}
|
|
97
|
-
CALL {
|
|
98
|
-
WITH dre
|
|
89
|
+
CALL (dre) {
|
|
99
90
|
OPTIONAL MATCH (dre)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "added"})
|
|
100
|
-
WITH
|
|
91
|
+
WITH count(dp.action) AS num_added
|
|
101
92
|
SET dre.num_added = num_added
|
|
102
93
|
}
|
|
103
|
-
CALL {
|
|
104
|
-
WITH dre
|
|
94
|
+
CALL (dre) {
|
|
105
95
|
OPTIONAL MATCH (dre)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "updated"})
|
|
106
|
-
WITH
|
|
96
|
+
WITH count(dp.action) AS num_updated
|
|
107
97
|
SET dre.num_updated = num_updated
|
|
108
98
|
}
|
|
109
|
-
CALL {
|
|
110
|
-
WITH dre
|
|
99
|
+
CALL (dre) {
|
|
111
100
|
OPTIONAL MATCH (dre)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "removed"})
|
|
112
|
-
WITH
|
|
101
|
+
WITH count(dp.action) AS num_removed
|
|
113
102
|
SET dre.num_removed = num_removed
|
|
114
103
|
}
|
|
115
104
|
}
|
|
@@ -121,22 +110,19 @@ CALL {
|
|
|
121
110
|
SET dr.num_conflicts = num_conflicts
|
|
122
111
|
SET dr.contains_conflict = (num_conflicts > 0)
|
|
123
112
|
WITH dr
|
|
124
|
-
CALL {
|
|
125
|
-
WITH dr
|
|
113
|
+
CALL (dr) {
|
|
126
114
|
OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement {action: "added"})
|
|
127
|
-
WITH
|
|
115
|
+
WITH count(dre.action) AS num_added
|
|
128
116
|
SET dr.num_added = num_added
|
|
129
117
|
}
|
|
130
|
-
CALL {
|
|
131
|
-
WITH dr
|
|
118
|
+
CALL (dr) {
|
|
132
119
|
OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement {action: "updated"})
|
|
133
|
-
WITH
|
|
120
|
+
WITH count(dre.action) AS num_updated
|
|
134
121
|
SET dr.num_updated = num_updated
|
|
135
122
|
}
|
|
136
|
-
CALL {
|
|
137
|
-
WITH dr
|
|
123
|
+
CALL (dr) {
|
|
138
124
|
OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement {action: "removed"})
|
|
139
|
-
WITH
|
|
125
|
+
WITH count(dre.action) AS num_removed
|
|
140
126
|
SET dr.num_removed = num_removed
|
|
141
127
|
}
|
|
142
128
|
}
|
|
@@ -189,19 +175,16 @@ WHERE $node_uuids IS NULL OR dn.uuid IN $node_uuids
|
|
|
189
175
|
// handle node count updates
|
|
190
176
|
// ----------------------
|
|
191
177
|
WITH root, dn, coalesce(dn.num_conflicts, 0) AS previous_num_conflicts
|
|
192
|
-
CALL {
|
|
178
|
+
CALL (dn) {
|
|
193
179
|
// ----------------------
|
|
194
180
|
// handle node num_conflicts update
|
|
195
181
|
// ----------------------
|
|
196
|
-
WITH dn
|
|
197
182
|
OPTIONAL MATCH (dn)-[:DIFF_HAS_ATTRIBUTE]->(da:DiffAttribute {contains_conflict: TRUE})
|
|
198
183
|
RETURN sum(da.num_conflicts) AS num_conflicts
|
|
199
184
|
UNION ALL
|
|
200
|
-
WITH dn
|
|
201
185
|
OPTIONAL MATCH (dn)-[:DIFF_HAS_RELATIONSHIP]->(dr:DiffRelationship {contains_conflict: TRUE})
|
|
202
186
|
RETURN sum(dr.num_conflicts) AS num_conflicts
|
|
203
187
|
UNION ALL
|
|
204
|
-
WITH dn
|
|
205
188
|
OPTIONAL MATCH (dn)-[:DIFF_HAS_CONFLICT]->(dc:DiffConflict)
|
|
206
189
|
RETURN count(dc) AS num_conflicts
|
|
207
190
|
}
|
|
@@ -209,17 +192,16 @@ WITH root, dn, previous_num_conflicts, sum(num_conflicts) AS updated_num_conflic
|
|
|
209
192
|
SET dn.num_conflicts = updated_num_conflicts
|
|
210
193
|
SET dn.contains_conflict = (updated_num_conflicts > 0)
|
|
211
194
|
WITH root, dn, updated_num_conflicts - previous_num_conflicts AS num_conflicts_delta
|
|
212
|
-
CALL {
|
|
195
|
+
CALL (dn) {
|
|
213
196
|
// ----------------------
|
|
214
197
|
// handle node added/updated/removed updates
|
|
215
198
|
// ----------------------
|
|
216
|
-
WITH dn
|
|
217
199
|
OPTIONAL MATCH (dn)-[:DIFF_HAS_ATTRIBUTE]->(da:DiffAttribute)
|
|
218
|
-
WITH
|
|
200
|
+
WITH collect(da.action) AS attr_actions
|
|
219
201
|
OPTIONAL MATCH (dn)-[:DIFF_HAS_RELATIONSHIP]->(dr:DiffRelationship)
|
|
220
|
-
WITH
|
|
221
|
-
WITH
|
|
222
|
-
WITH
|
|
202
|
+
WITH attr_actions, collect(dr.action) AS rel_actions
|
|
203
|
+
WITH attr_actions + rel_actions AS actions
|
|
204
|
+
WITH reduce(counts = [0,0,0], a IN actions |
|
|
223
205
|
CASE
|
|
224
206
|
WHEN a = "added" THEN [counts[0] + 1, counts[1], counts[2]]
|
|
225
207
|
WHEN a = "updated" THEN [counts[0], counts[1] + 1, counts[2]]
|
|
@@ -227,7 +209,7 @@ CALL {
|
|
|
227
209
|
ELSE counts
|
|
228
210
|
END
|
|
229
211
|
) AS action_counts
|
|
230
|
-
WITH
|
|
212
|
+
WITH action_counts[0] AS num_added, action_counts[1] AS num_updated, action_counts[2] AS num_removed
|
|
231
213
|
SET dn.num_added = num_added
|
|
232
214
|
SET dn.num_updated = num_updated
|
|
233
215
|
SET dn.num_removed = num_removed
|
|
@@ -236,8 +218,7 @@ CALL {
|
|
|
236
218
|
// handle conflict updates for parent nodes
|
|
237
219
|
// ----------------------
|
|
238
220
|
WITH root, dn, num_conflicts_delta
|
|
239
|
-
CALL {
|
|
240
|
-
WITH dn, num_conflicts_delta
|
|
221
|
+
CALL (dn, num_conflicts_delta) {
|
|
241
222
|
OPTIONAL MATCH (dn)-[:DIFF_HAS_RELATIONSHIP|DIFF_HAS_NODE*1..]->(parent_node:DiffNode)
|
|
242
223
|
SET parent_node.num_conflicts = parent_node.num_conflicts + num_conflicts_delta
|
|
243
224
|
SET parent_node.contains_conflict = (parent_node.num_conflicts > 0)
|
|
@@ -246,8 +227,7 @@ CALL {
|
|
|
246
227
|
// handle root count updates
|
|
247
228
|
// ----------------------
|
|
248
229
|
WITH root, sum(num_conflicts_delta) AS total_conflicts_delta
|
|
249
|
-
CALL {
|
|
250
|
-
WITH root, total_conflicts_delta
|
|
230
|
+
CALL (root, total_conflicts_delta) {
|
|
251
231
|
SET root.num_conflicts = coalesce(root.num_conflicts, 0) + total_conflicts_delta
|
|
252
232
|
SET root.contains_conflict = root.num_conflicts > 0
|
|
253
233
|
WITH root
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from collections import defaultdict
|
|
4
3
|
from dataclasses import dataclass, field
|
|
5
4
|
from typing import TYPE_CHECKING, Any
|
|
6
5
|
from uuid import uuid4
|
|
@@ -15,6 +14,7 @@ from infrahub.core.constants import (
|
|
|
15
14
|
from infrahub.core.constants.database import DatabaseEdgeType
|
|
16
15
|
from infrahub.core.timestamp import Timestamp
|
|
17
16
|
|
|
17
|
+
from .model.field_specifiers_map import NodeFieldSpecifierMap
|
|
18
18
|
from .model.path import (
|
|
19
19
|
DatabasePath,
|
|
20
20
|
DiffAttribute,
|
|
@@ -23,6 +23,7 @@ from .model.path import (
|
|
|
23
23
|
DiffRelationship,
|
|
24
24
|
DiffRoot,
|
|
25
25
|
DiffSingleRelationship,
|
|
26
|
+
NodeIdentifier,
|
|
26
27
|
)
|
|
27
28
|
|
|
28
29
|
if TYPE_CHECKING:
|
|
@@ -394,8 +395,7 @@ class DiffRelationshipIntermediate:
|
|
|
394
395
|
@dataclass
|
|
395
396
|
class DiffNodeIntermediate(TrackedStatusUpdates):
|
|
396
397
|
force_action: DiffAction | None
|
|
397
|
-
|
|
398
|
-
kind: str
|
|
398
|
+
identifier: NodeIdentifier
|
|
399
399
|
db_id: str
|
|
400
400
|
from_time: Timestamp
|
|
401
401
|
status: RelationshipStatus
|
|
@@ -403,6 +403,14 @@ class DiffNodeIntermediate(TrackedStatusUpdates):
|
|
|
403
403
|
# {(name, identifier): DiffRelationshipIntermediate}
|
|
404
404
|
relationships_by_identifier: dict[tuple[str, str], DiffRelationshipIntermediate] = field(default_factory=dict)
|
|
405
405
|
|
|
406
|
+
@property
|
|
407
|
+
def uuid(self) -> str:
|
|
408
|
+
return self.identifier.uuid
|
|
409
|
+
|
|
410
|
+
@property
|
|
411
|
+
def kind(self) -> str:
|
|
412
|
+
return self.identifier.kind
|
|
413
|
+
|
|
406
414
|
def to_diff_node(self, from_time: Timestamp, include_unchanged: bool) -> DiffNode:
|
|
407
415
|
attributes = []
|
|
408
416
|
for attr in self.attributes_by_name.values():
|
|
@@ -424,8 +432,7 @@ class DiffNodeIntermediate(TrackedStatusUpdates):
|
|
|
424
432
|
if self.force_action:
|
|
425
433
|
action = self.force_action
|
|
426
434
|
return DiffNode(
|
|
427
|
-
|
|
428
|
-
kind=self.kind,
|
|
435
|
+
identifier=self.identifier,
|
|
429
436
|
changed_at=changed_at,
|
|
430
437
|
action=action,
|
|
431
438
|
attributes=attributes,
|
|
@@ -441,11 +448,11 @@ class DiffNodeIntermediate(TrackedStatusUpdates):
|
|
|
441
448
|
class DiffRootIntermediate:
|
|
442
449
|
uuid: str
|
|
443
450
|
branch: str
|
|
444
|
-
|
|
451
|
+
nodes_by_identifier: dict[NodeIdentifier, DiffNodeIntermediate] = field(default_factory=dict)
|
|
445
452
|
|
|
446
453
|
def to_diff_root(self, from_time: Timestamp, to_time: Timestamp, include_unchanged: bool) -> DiffRoot:
|
|
447
454
|
nodes = []
|
|
448
|
-
for node in self.
|
|
455
|
+
for node in self.nodes_by_identifier.values():
|
|
449
456
|
if node.is_empty:
|
|
450
457
|
continue
|
|
451
458
|
diff_node = node.to_diff_node(from_time=from_time, include_unchanged=include_unchanged)
|
|
@@ -462,7 +469,7 @@ class DiffQueryParser:
|
|
|
462
469
|
schema_manager: SchemaManager,
|
|
463
470
|
from_time: Timestamp,
|
|
464
471
|
to_time: Timestamp | None = None,
|
|
465
|
-
previous_node_field_specifiers:
|
|
472
|
+
previous_node_field_specifiers: NodeFieldSpecifierMap | None = None,
|
|
466
473
|
) -> None:
|
|
467
474
|
self.base_branch_name = base_branch.name
|
|
468
475
|
self.diff_branch_name = diff_branch.name
|
|
@@ -476,9 +483,9 @@ class DiffQueryParser:
|
|
|
476
483
|
self.diff_branched_from_time = Timestamp(diff_branch.get_branched_from())
|
|
477
484
|
self._diff_root_by_branch: dict[str, DiffRootIntermediate] = {}
|
|
478
485
|
self._final_diff_root_by_branch: dict[str, DiffRoot] = {}
|
|
479
|
-
self._previous_node_field_specifiers = previous_node_field_specifiers or
|
|
480
|
-
self._new_node_field_specifiers:
|
|
481
|
-
self._current_node_field_specifiers:
|
|
486
|
+
self._previous_node_field_specifiers = previous_node_field_specifiers or NodeFieldSpecifierMap()
|
|
487
|
+
self._new_node_field_specifiers: NodeFieldSpecifierMap | None = None
|
|
488
|
+
self._current_node_field_specifiers: NodeFieldSpecifierMap | None = None
|
|
482
489
|
|
|
483
490
|
def get_branches(self) -> set[str]:
|
|
484
491
|
return set(self._final_diff_root_by_branch.keys())
|
|
@@ -490,51 +497,40 @@ class DiffQueryParser:
|
|
|
490
497
|
return self._final_diff_root_by_branch[branch]
|
|
491
498
|
return DiffRoot(from_time=self.from_time, to_time=self.to_time, uuid=str(uuid4()), branch=branch, nodes=[])
|
|
492
499
|
|
|
493
|
-
def get_diff_node_field_specifiers(self) ->
|
|
500
|
+
def get_diff_node_field_specifiers(self) -> NodeFieldSpecifierMap:
|
|
501
|
+
node_field_specifiers_map = NodeFieldSpecifierMap()
|
|
494
502
|
if self.diff_branch_name not in self._diff_root_by_branch:
|
|
495
|
-
return
|
|
496
|
-
node_field_specifiers_map: dict[str, set[str]] = defaultdict(set)
|
|
503
|
+
return node_field_specifiers_map
|
|
497
504
|
diff_root = self._diff_root_by_branch[self.diff_branch_name]
|
|
498
|
-
for node in diff_root.
|
|
505
|
+
for node in diff_root.nodes_by_identifier.values():
|
|
499
506
|
for attribute_name in node.attributes_by_name:
|
|
500
|
-
node_field_specifiers_map
|
|
507
|
+
node_field_specifiers_map.add_entry(node_uuid=node.uuid, kind=node.kind, field_name=attribute_name)
|
|
501
508
|
for relationship_diff in node.relationships_by_identifier.values():
|
|
502
|
-
node_field_specifiers_map
|
|
509
|
+
node_field_specifiers_map.add_entry(
|
|
510
|
+
node_uuid=node.uuid, kind=node.kind, field_name=relationship_diff.identifier
|
|
511
|
+
)
|
|
503
512
|
return node_field_specifiers_map
|
|
504
513
|
|
|
505
|
-
def
|
|
506
|
-
self, node_specifiers: dict[str, set[str]], node_specifiers_to_remove: dict[str, set[str]]
|
|
507
|
-
) -> dict[str, set[str]]:
|
|
508
|
-
final_node_specifiers: dict[str, set[str]] = defaultdict(set)
|
|
509
|
-
for node_uuid, field_names_set in node_specifiers.items():
|
|
510
|
-
specifiers_to_remove = node_specifiers_to_remove.get(node_uuid, set())
|
|
511
|
-
final_specifiers = field_names_set - specifiers_to_remove
|
|
512
|
-
if final_specifiers:
|
|
513
|
-
final_node_specifiers[node_uuid] = final_specifiers
|
|
514
|
-
return final_node_specifiers
|
|
515
|
-
|
|
516
|
-
def get_new_node_field_specifiers(self) -> dict[str, set[str]]:
|
|
514
|
+
def get_new_node_field_specifiers(self) -> NodeFieldSpecifierMap:
|
|
517
515
|
if self._new_node_field_specifiers is not None:
|
|
518
516
|
return self._new_node_field_specifiers
|
|
519
517
|
branch_node_specifiers = self.get_diff_node_field_specifiers()
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
)
|
|
523
|
-
self._new_node_field_specifiers = new_node_field_specifiers
|
|
524
|
-
return new_node_field_specifiers
|
|
518
|
+
self._new_node_field_specifiers = branch_node_specifiers - self._previous_node_field_specifiers
|
|
519
|
+
return self._new_node_field_specifiers
|
|
525
520
|
|
|
526
|
-
def get_current_node_field_specifiers(self) ->
|
|
521
|
+
def get_current_node_field_specifiers(self) -> NodeFieldSpecifierMap:
|
|
527
522
|
if self._current_node_field_specifiers is not None:
|
|
528
523
|
return self._current_node_field_specifiers
|
|
529
524
|
new_node_field_specifiers = self.get_new_node_field_specifiers()
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
)
|
|
533
|
-
self._current_node_field_specifiers = current_node_field_specifiers
|
|
534
|
-
return current_node_field_specifiers
|
|
525
|
+
self._current_node_field_specifiers = self._previous_node_field_specifiers - new_node_field_specifiers
|
|
526
|
+
return self._current_node_field_specifiers
|
|
535
527
|
|
|
536
528
|
def read_result(self, query_result: QueryResult) -> None:
|
|
537
|
-
|
|
529
|
+
try:
|
|
530
|
+
path = query_result.get_path(label="diff_path")
|
|
531
|
+
except ValueError:
|
|
532
|
+
# the path was null, so nothing to read
|
|
533
|
+
return
|
|
538
534
|
database_path = DatabasePath.from_cypher_path(cypher_path=path)
|
|
539
535
|
self._parse_path(database_path=database_path)
|
|
540
536
|
self._current_node_field_specifiers = None
|
|
@@ -565,11 +561,12 @@ class DiffQueryParser:
|
|
|
565
561
|
return self._diff_root_by_branch[branch]
|
|
566
562
|
|
|
567
563
|
def _get_diff_node(self, database_path: DatabasePath, diff_root: DiffRootIntermediate) -> DiffNodeIntermediate:
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
564
|
+
identifier = NodeIdentifier(
|
|
565
|
+
uuid=database_path.node_id, kind=database_path.node_kind, db_id=database_path.node_db_id
|
|
566
|
+
)
|
|
567
|
+
if identifier not in diff_root.nodes_by_identifier:
|
|
568
|
+
diff_root.nodes_by_identifier[identifier] = DiffNodeIntermediate(
|
|
569
|
+
identifier=identifier,
|
|
573
570
|
db_id=database_path.node_db_id,
|
|
574
571
|
from_time=database_path.node_changed_at,
|
|
575
572
|
status=database_path.node_status,
|
|
@@ -577,20 +574,7 @@ class DiffQueryParser:
|
|
|
577
574
|
if database_path.node_branch_support is BranchSupportType.AGNOSTIC
|
|
578
575
|
else None,
|
|
579
576
|
)
|
|
580
|
-
diff_node = diff_root.
|
|
581
|
-
# special handling for nodes that have their kind updated, which results in 2 nodes with the same uuid
|
|
582
|
-
if diff_node.db_id != database_path.node_db_id and (
|
|
583
|
-
database_path.node_changed_at > diff_node.from_time
|
|
584
|
-
or (
|
|
585
|
-
database_path.node_changed_at >= diff_node.from_time
|
|
586
|
-
and (diff_node.status, database_path.node_status)
|
|
587
|
-
== (RelationshipStatus.DELETED, RelationshipStatus.ACTIVE)
|
|
588
|
-
)
|
|
589
|
-
):
|
|
590
|
-
diff_node.kind = database_path.node_kind
|
|
591
|
-
diff_node.db_id = database_path.node_db_id
|
|
592
|
-
diff_node.from_time = database_path.node_changed_at
|
|
593
|
-
diff_node.status = database_path.node_status
|
|
577
|
+
diff_node = diff_root.nodes_by_identifier[identifier]
|
|
594
578
|
diff_node.track_database_path(database_path=database_path)
|
|
595
579
|
return diff_node
|
|
596
580
|
|
|
@@ -634,7 +618,9 @@ class DiffQueryParser:
|
|
|
634
618
|
from_time = self.from_time
|
|
635
619
|
if branch_name == self.base_branch_name:
|
|
636
620
|
new_node_field_specifiers = self.get_new_node_field_specifiers()
|
|
637
|
-
if
|
|
621
|
+
if new_node_field_specifiers.has_entry(
|
|
622
|
+
node_uuid=diff_node.uuid, kind=diff_node.kind, field_name=attribute_name
|
|
623
|
+
):
|
|
638
624
|
from_time = self.diff_branched_from_time
|
|
639
625
|
if attribute_name not in diff_node.attributes_by_name:
|
|
640
626
|
diff_node.attributes_by_name[attribute_name] = DiffAttributeIntermediate(
|
|
@@ -678,7 +664,9 @@ class DiffQueryParser:
|
|
|
678
664
|
from_time = self.from_time
|
|
679
665
|
if branch_name == self.base_branch_name:
|
|
680
666
|
new_node_field_specifiers = self.get_new_node_field_specifiers()
|
|
681
|
-
if
|
|
667
|
+
if new_node_field_specifiers.has_entry(
|
|
668
|
+
node_uuid=diff_node.uuid, kind=diff_node.kind, field_name=relationship_schema.get_identifier()
|
|
669
|
+
):
|
|
682
670
|
from_time = self.diff_branched_from_time
|
|
683
671
|
diff_relationship = DiffRelationshipIntermediate(
|
|
684
672
|
name=relationship_schema.name,
|
|
@@ -700,8 +688,10 @@ class DiffQueryParser:
|
|
|
700
688
|
branch_diff_root = self._diff_root_by_branch.get(branch)
|
|
701
689
|
if not branch_diff_root:
|
|
702
690
|
continue
|
|
703
|
-
for
|
|
704
|
-
|
|
691
|
+
base_diff_nodes_by_uuid = {n.uuid: n for n in base_diff_root.nodes_by_identifier.values()}
|
|
692
|
+
for identifier, diff_node in branch_diff_root.nodes_by_identifier.items():
|
|
693
|
+
# changes on a base branch node with a given UUID should apply to all diff branch nodes with that UUID
|
|
694
|
+
base_diff_node = base_diff_nodes_by_uuid.get(identifier.uuid)
|
|
705
695
|
if not base_diff_node:
|
|
706
696
|
continue
|
|
707
697
|
self._apply_attribute_previous_values(diff_node=diff_node, base_diff_node=base_diff_node)
|
|
@@ -771,7 +761,7 @@ class DiffQueryParser:
|
|
|
771
761
|
base_diff_root = self._diff_root_by_branch.get(self.base_branch_name)
|
|
772
762
|
if not base_diff_root:
|
|
773
763
|
return
|
|
774
|
-
for node_diff in base_diff_root.
|
|
764
|
+
for node_diff in base_diff_root.nodes_by_identifier.values():
|
|
775
765
|
for attribute_diff in node_diff.attributes_by_name.values():
|
|
776
766
|
for property_diff in attribute_diff.properties_by_type.values():
|
|
777
767
|
ordered_diff_values = property_diff.get_ordered_values_asc()
|