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
|
@@ -20,6 +20,7 @@ class DiffMergeQuery(Query):
|
|
|
20
20
|
node_diff_dicts: dict[str, Any],
|
|
21
21
|
at: Timestamp,
|
|
22
22
|
target_branch: Branch,
|
|
23
|
+
migrated_kinds_id_map: dict[str, str],
|
|
23
24
|
**kwargs: Any,
|
|
24
25
|
) -> None:
|
|
25
26
|
super().__init__(**kwargs)
|
|
@@ -27,6 +28,7 @@ class DiffMergeQuery(Query):
|
|
|
27
28
|
self.at = at
|
|
28
29
|
self.target_branch = target_branch
|
|
29
30
|
self.source_branch_name = self.branch.name
|
|
31
|
+
self.migrated_kinds_id_map = migrated_kinds_id_map
|
|
30
32
|
|
|
31
33
|
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
32
34
|
self.params = {
|
|
@@ -35,37 +37,45 @@ class DiffMergeQuery(Query):
|
|
|
35
37
|
"branch_level": self.target_branch.hierarchy_level,
|
|
36
38
|
"target_branch": self.target_branch.name,
|
|
37
39
|
"source_branch": self.source_branch_name,
|
|
40
|
+
"migrated_kinds_id_map": self.migrated_kinds_id_map,
|
|
41
|
+
"migrated_kinds_uuids": list(self.migrated_kinds_id_map.keys()),
|
|
38
42
|
}
|
|
39
43
|
# ruff: noqa: E501
|
|
40
44
|
query = """
|
|
41
45
|
UNWIND $node_diff_dicts AS node_diff_map
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
WITH node_diff_map, node_diff_map.uuid IN $migrated_kinds_uuids AS is_node_kind_migration
|
|
47
|
+
WITH node_diff_map, is_node_kind_migration, CASE
|
|
48
|
+
WHEN $migrated_kinds_uuids IS NULL THEN NULL
|
|
49
|
+
WHEN is_node_kind_migration THEN $migrated_kinds_id_map[node_diff_map.uuid]
|
|
50
|
+
ELSE NULL
|
|
51
|
+
END AS node_db_id
|
|
52
|
+
CALL (node_diff_map, node_db_id) {
|
|
44
53
|
MATCH (n:Node {uuid: node_diff_map.uuid})
|
|
54
|
+
WHERE node_db_id IS NULL
|
|
55
|
+
OR %(id_func)s(n) = node_db_id
|
|
45
56
|
RETURN n
|
|
46
57
|
}
|
|
47
|
-
WITH n, node_diff_map
|
|
48
|
-
CALL {
|
|
49
|
-
WITH
|
|
50
|
-
WITH n, node_diff_map, CASE
|
|
58
|
+
WITH n, node_diff_map, is_node_kind_migration
|
|
59
|
+
CALL (n, node_diff_map, is_node_kind_migration) {
|
|
60
|
+
WITH CASE
|
|
51
61
|
WHEN node_diff_map.action = "ADDED" THEN "active"
|
|
52
62
|
WHEN node_diff_map.action = "REMOVED" THEN "deleted"
|
|
53
63
|
ELSE NULL
|
|
54
64
|
END AS node_rel_status
|
|
55
|
-
CALL {
|
|
65
|
+
CALL (n, node_diff_map, is_node_kind_migration, node_rel_status) {
|
|
56
66
|
// ------------------------------
|
|
57
67
|
// only make IS_PART_OF updates if node is ADDED or REMOVED
|
|
58
68
|
// ------------------------------
|
|
59
|
-
WITH
|
|
60
|
-
WITH n, node_diff_map, node_rel_status
|
|
69
|
+
WITH node_rel_status
|
|
61
70
|
WHERE node_rel_status IS NOT NULL
|
|
71
|
+
// nodes with a migrated kind are handled in DiffMergeMigratedKindsQuery
|
|
72
|
+
AND is_node_kind_migration = FALSE
|
|
62
73
|
MATCH (root:Root)
|
|
63
74
|
// ------------------------------
|
|
64
75
|
// set IS_PART_OF.to, optionally, target branch
|
|
65
76
|
// ------------------------------
|
|
66
77
|
WITH root, n, node_rel_status
|
|
67
|
-
CALL {
|
|
68
|
-
WITH root, n, node_rel_status
|
|
78
|
+
CALL (root, n, node_rel_status) {
|
|
69
79
|
OPTIONAL MATCH (root)<-[target_r_root:IS_PART_OF {branch: $target_branch, status: "active"}]-(n)
|
|
70
80
|
WHERE node_rel_status = "deleted"
|
|
71
81
|
AND target_r_root.from <= $at AND target_r_root.to IS NULL
|
|
@@ -75,13 +85,12 @@ CALL {
|
|
|
75
85
|
// create new IS_PART_OF relationship on target_branch
|
|
76
86
|
// ------------------------------
|
|
77
87
|
WITH root, n, node_rel_status
|
|
78
|
-
CALL {
|
|
79
|
-
WITH root, n, node_rel_status
|
|
88
|
+
CALL (root, n, node_rel_status) {
|
|
80
89
|
OPTIONAL MATCH (root)<-[r_root:IS_PART_OF {branch: $target_branch}]-(n)
|
|
81
90
|
WHERE r_root.status = node_rel_status
|
|
82
91
|
AND r_root.from <= $at
|
|
83
92
|
AND (r_root.to >= $at OR r_root.to IS NULL)
|
|
84
|
-
WITH
|
|
93
|
+
WITH r_root
|
|
85
94
|
WHERE r_root IS NULL
|
|
86
95
|
CREATE (root)
|
|
87
96
|
<-[:IS_PART_OF { branch: $target_branch, branch_level: $branch_level, from: $at, status: node_rel_status }]
|
|
@@ -90,12 +99,10 @@ CALL {
|
|
|
90
99
|
// ------------------------------
|
|
91
100
|
// shortcut to delete all attributes and relationships for this node if the node is deleted
|
|
92
101
|
// ------------------------------
|
|
93
|
-
CALL {
|
|
94
|
-
WITH n, node_rel_status
|
|
102
|
+
CALL (n, node_rel_status) {
|
|
95
103
|
WITH n, node_rel_status
|
|
96
104
|
WHERE node_rel_status = "deleted"
|
|
97
|
-
CALL {
|
|
98
|
-
WITH n
|
|
105
|
+
CALL (n) {
|
|
99
106
|
OPTIONAL MATCH (n)-[rel1:IS_RELATED]-(:Relationship)-[rel2]-(p)
|
|
100
107
|
WHERE (p.uuid IS NULL OR n.uuid <> p.uuid)
|
|
101
108
|
AND rel1.branch = $target_branch
|
|
@@ -104,7 +111,6 @@ CALL {
|
|
|
104
111
|
AND rel2.status = "active"
|
|
105
112
|
RETURN rel1, rel2
|
|
106
113
|
UNION
|
|
107
|
-
WITH n
|
|
108
114
|
OPTIONAL MATCH (n)-[rel1:HAS_ATTRIBUTE]->(:Attribute)-[rel2]->()
|
|
109
115
|
WHERE type(rel2) <> "HAS_ATTRIBUTE"
|
|
110
116
|
AND rel1.branch = $target_branch
|
|
@@ -113,7 +119,7 @@ CALL {
|
|
|
113
119
|
AND rel2.status = "active"
|
|
114
120
|
RETURN rel1, rel2
|
|
115
121
|
}
|
|
116
|
-
WITH
|
|
122
|
+
WITH rel1, rel2
|
|
117
123
|
WHERE rel1.to IS NULL
|
|
118
124
|
AND rel2.to IS NULL
|
|
119
125
|
AND rel1.from <= $at
|
|
@@ -124,10 +130,8 @@ CALL {
|
|
|
124
130
|
// and delete HAS_OWNER and HAS_SOURCE edges to this node if the node is deleted
|
|
125
131
|
// ------------------------------
|
|
126
132
|
WITH n
|
|
127
|
-
CALL {
|
|
128
|
-
|
|
129
|
-
CALL {
|
|
130
|
-
WITH n
|
|
133
|
+
CALL (n) {
|
|
134
|
+
CALL (n) {
|
|
131
135
|
MATCH (n)<-[rel:HAS_OWNER]-()
|
|
132
136
|
WHERE rel.branch = $target_branch
|
|
133
137
|
AND rel.status = "active"
|
|
@@ -147,9 +151,8 @@ CALL {
|
|
|
147
151
|
}
|
|
148
152
|
}
|
|
149
153
|
WITH n, node_diff_map
|
|
150
|
-
CALL {
|
|
151
|
-
WITH
|
|
152
|
-
WITH n, CASE
|
|
154
|
+
CALL (n, node_diff_map) {
|
|
155
|
+
WITH CASE
|
|
153
156
|
WHEN node_diff_map.attributes IS NULL OR node_diff_map.attributes = [] THEN [NULL]
|
|
154
157
|
ELSE node_diff_map.attributes
|
|
155
158
|
END AS attribute_maps
|
|
@@ -157,15 +160,13 @@ CALL {
|
|
|
157
160
|
// ------------------------------
|
|
158
161
|
// handle updates for attributes under this node
|
|
159
162
|
// ------------------------------
|
|
160
|
-
CALL {
|
|
161
|
-
WITH
|
|
162
|
-
WITH n, attribute_diff_map.name AS attr_name, CASE
|
|
163
|
+
CALL (n, attribute_diff_map) {
|
|
164
|
+
WITH attribute_diff_map.name AS attr_name, CASE
|
|
163
165
|
WHEN attribute_diff_map.action = "ADDED" THEN "active"
|
|
164
166
|
WHEN attribute_diff_map.action = "REMOVED" THEN "deleted"
|
|
165
167
|
ELSE NULL
|
|
166
168
|
END AS attr_rel_status
|
|
167
|
-
CALL {
|
|
168
|
-
WITH n, attr_name
|
|
169
|
+
CALL (n, attr_name) {
|
|
169
170
|
OPTIONAL MATCH (n)-[has_attr:HAS_ATTRIBUTE]->(a:Attribute {name: attr_name})
|
|
170
171
|
WHERE has_attr.branch IN [$source_branch, $target_branch]
|
|
171
172
|
RETURN a
|
|
@@ -176,8 +177,7 @@ CALL {
|
|
|
176
177
|
// ------------------------------
|
|
177
178
|
// set HAS_ATTRIBUTE.to on target branch if necessary
|
|
178
179
|
// ------------------------------
|
|
179
|
-
CALL {
|
|
180
|
-
WITH n, attr_rel_status, a
|
|
180
|
+
CALL (n, attr_rel_status, a) {
|
|
181
181
|
OPTIONAL MATCH (n)
|
|
182
182
|
-[target_r_attr:HAS_ATTRIBUTE {branch: $target_branch, status: "active"}]
|
|
183
183
|
->(a)
|
|
@@ -189,15 +189,14 @@ CALL {
|
|
|
189
189
|
// ------------------------------
|
|
190
190
|
// conditionally create new HAS_ATTRIBUTE relationship on target_branch, if necessary
|
|
191
191
|
// ------------------------------
|
|
192
|
-
CALL {
|
|
193
|
-
WITH n, attr_rel_status, a
|
|
192
|
+
CALL (n, attr_rel_status, a) {
|
|
194
193
|
WITH n, attr_rel_status, a
|
|
195
194
|
WHERE a IS NOT NULL
|
|
196
195
|
OPTIONAL MATCH (n)-[r_attr:HAS_ATTRIBUTE {branch: $target_branch}]->(a)
|
|
197
196
|
WHERE r_attr.status = attr_rel_status
|
|
198
197
|
AND r_attr.from <= $at
|
|
199
198
|
AND (r_attr.to >= $at OR r_attr.to IS NULL)
|
|
200
|
-
WITH
|
|
199
|
+
WITH r_attr
|
|
201
200
|
WHERE r_attr IS NULL
|
|
202
201
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: $target_branch, branch_level: $branch_level, from: $at, status: attr_rel_status }]->(a)
|
|
203
202
|
}
|
|
@@ -206,34 +205,39 @@ CALL {
|
|
|
206
205
|
RETURN 1 AS done
|
|
207
206
|
}
|
|
208
207
|
WITH n, node_diff_map
|
|
209
|
-
CALL {
|
|
210
|
-
WITH n,node_diff_map
|
|
208
|
+
CALL (n, node_diff_map) {
|
|
211
209
|
UNWIND node_diff_map.relationships AS relationship_diff_map
|
|
212
210
|
// ------------------------------
|
|
213
211
|
// handle updates for relationships under this node
|
|
214
212
|
// ------------------------------
|
|
215
|
-
CALL {
|
|
216
|
-
WITH
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
213
|
+
CALL (n, relationship_diff_map) {
|
|
214
|
+
WITH
|
|
215
|
+
relationship_diff_map.peer_id AS rel_peer_id, relationship_diff_map.name AS rel_name,
|
|
216
|
+
CASE
|
|
217
|
+
WHEN relationship_diff_map.action = "ADDED" THEN "active"
|
|
218
|
+
WHEN relationship_diff_map.action = "REMOVED" THEN "deleted"
|
|
219
|
+
ELSE NULL
|
|
220
|
+
END AS related_rel_status,
|
|
221
|
+
CASE
|
|
222
|
+
WHEN $migrated_kinds_uuids IS NULL THEN NULL
|
|
223
|
+
WHEN relationship_diff_map.peer_id IN $migrated_kinds_uuids THEN $migrated_kinds_id_map[relationship_diff_map.peer_id]
|
|
224
|
+
ELSE NULL
|
|
225
|
+
END AS rel_peer_db_id
|
|
222
226
|
// ------------------------------
|
|
223
227
|
// determine the directions of each IS_RELATED
|
|
224
228
|
// ------------------------------
|
|
225
|
-
CALL {
|
|
226
|
-
WITH n, rel_name, rel_peer_id, related_rel_status
|
|
229
|
+
CALL (n, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status) {
|
|
227
230
|
MATCH (n)
|
|
228
231
|
-[source_r_rel_1:IS_RELATED]
|
|
229
232
|
-(r:Relationship {name: rel_name})
|
|
230
233
|
-[source_r_rel_2:IS_RELATED]
|
|
231
|
-
-(:Node {uuid: rel_peer_id})
|
|
232
|
-
WHERE
|
|
234
|
+
-(rel_peer:Node {uuid: rel_peer_id})
|
|
235
|
+
WHERE (rel_peer_db_id IS NULL OR %(id_func)s(rel_peer) = rel_peer_db_id)
|
|
236
|
+
AND source_r_rel_1.branch IN [$source_branch, $target_branch]
|
|
233
237
|
AND source_r_rel_2.branch IN [$source_branch, $target_branch]
|
|
234
238
|
AND source_r_rel_1.from <= $at AND source_r_rel_1.to IS NULL
|
|
235
239
|
AND source_r_rel_2.from <= $at AND source_r_rel_2.to IS NULL
|
|
236
|
-
WITH
|
|
240
|
+
WITH r, source_r_rel_1, source_r_rel_2
|
|
237
241
|
ORDER BY source_r_rel_1.branch_level DESC, source_r_rel_2.branch_level DESC, source_r_rel_1.from DESC, source_r_rel_2.from DESC
|
|
238
242
|
LIMIT 1
|
|
239
243
|
RETURN r, CASE
|
|
@@ -247,27 +251,27 @@ CALL {
|
|
|
247
251
|
source_r_rel_1.hierarchy AS r1_hierarchy,
|
|
248
252
|
source_r_rel_2.hierarchy AS r2_hierarchy
|
|
249
253
|
}
|
|
250
|
-
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status
|
|
251
|
-
CALL {
|
|
252
|
-
WITH n, rel_name, rel_peer_id, related_rel_status
|
|
254
|
+
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status
|
|
255
|
+
CALL (n, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status) {
|
|
253
256
|
OPTIONAL MATCH (n)
|
|
254
257
|
-[target_r_rel_1:IS_RELATED {branch: $target_branch, status: "active"}]
|
|
255
258
|
-(:Relationship {name: rel_name})
|
|
256
259
|
-[target_r_rel_2:IS_RELATED {branch: $target_branch, status: "active"}]
|
|
257
|
-
-(:Node {uuid: rel_peer_id})
|
|
260
|
+
-(rel_peer:Node {uuid: rel_peer_id})
|
|
258
261
|
WHERE related_rel_status = "deleted"
|
|
262
|
+
AND (rel_peer_db_id IS NULL OR %(id_func)s(rel_peer) = rel_peer_db_id)
|
|
259
263
|
AND target_r_rel_1.from <= $at AND target_r_rel_1.to IS NULL
|
|
260
264
|
AND target_r_rel_2.from <= $at AND target_r_rel_2.to IS NULL
|
|
261
265
|
SET target_r_rel_1.to = $at
|
|
262
266
|
SET target_r_rel_2.to = $at
|
|
263
267
|
}
|
|
264
|
-
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status
|
|
268
|
+
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status
|
|
265
269
|
// ------------------------------
|
|
266
270
|
// conditionally create new IS_RELATED relationships on target_branch, if necessary
|
|
267
271
|
// ------------------------------
|
|
268
|
-
CALL {
|
|
269
|
-
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status
|
|
272
|
+
CALL (n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status) {
|
|
270
273
|
MATCH (p:Node {uuid: rel_peer_id})
|
|
274
|
+
WHERE rel_peer_db_id IS NULL OR %(id_func)s(p) = rel_peer_db_id
|
|
271
275
|
OPTIONAL MATCH (n)
|
|
272
276
|
-[r_rel_1:IS_RELATED {branch: $target_branch, status: related_rel_status}]
|
|
273
277
|
-(:Relationship {name: rel_name})
|
|
@@ -277,38 +281,34 @@ CALL {
|
|
|
277
281
|
AND (r_rel_1.to >= $at OR r_rel_1.to IS NULL)
|
|
278
282
|
AND r_rel_2.from <= $at
|
|
279
283
|
AND (r_rel_2.to >= $at OR r_rel_2.to IS NULL)
|
|
280
|
-
WITH
|
|
284
|
+
WITH p, r_rel_1, r_rel_2
|
|
281
285
|
WHERE r_rel_1 IS NULL
|
|
282
286
|
AND r_rel_2 IS NULL
|
|
283
287
|
// ------------------------------
|
|
284
288
|
// create IS_RELATED relationships with directions maintained from source
|
|
285
289
|
// ------------------------------
|
|
286
|
-
CALL {
|
|
287
|
-
WITH n, r, r1_dir, r1_hierarchy, related_rel_status
|
|
290
|
+
CALL (n, r, r1_dir, r1_hierarchy, related_rel_status) {
|
|
288
291
|
WITH n, r, r1_dir, r1_hierarchy, related_rel_status
|
|
289
292
|
WHERE r1_dir = "r"
|
|
290
293
|
CREATE (n)
|
|
291
294
|
-[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r1_hierarchy}]
|
|
292
295
|
->(r)
|
|
293
296
|
}
|
|
294
|
-
CALL {
|
|
295
|
-
WITH n, r, r1_dir, r1_hierarchy, related_rel_status
|
|
297
|
+
CALL (n, r, r1_dir, r1_hierarchy, related_rel_status) {
|
|
296
298
|
WITH n, r, r1_dir, r1_hierarchy, related_rel_status
|
|
297
299
|
WHERE r1_dir = "l"
|
|
298
300
|
CREATE (n)
|
|
299
301
|
<-[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r1_hierarchy}]
|
|
300
302
|
-(r)
|
|
301
303
|
}
|
|
302
|
-
CALL {
|
|
303
|
-
WITH r, p, r2_dir, r2_hierarchy, related_rel_status
|
|
304
|
+
CALL (r, p, r2_dir, r2_hierarchy, related_rel_status) {
|
|
304
305
|
WITH r, p, r2_dir, r2_hierarchy, related_rel_status
|
|
305
306
|
WHERE r2_dir = "r"
|
|
306
307
|
CREATE (r)
|
|
307
308
|
-[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r2_hierarchy}]
|
|
308
309
|
->(p)
|
|
309
310
|
}
|
|
310
|
-
CALL {
|
|
311
|
-
WITH r, p, r2_dir, r2_hierarchy, related_rel_status
|
|
311
|
+
CALL (r, p, r2_dir, r2_hierarchy, related_rel_status) {
|
|
312
312
|
WITH r, p, r2_dir, r2_hierarchy, related_rel_status
|
|
313
313
|
WHERE r2_dir = "l"
|
|
314
314
|
CREATE (r)
|
|
@@ -320,7 +320,7 @@ CALL {
|
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
322
|
RETURN 1 AS done
|
|
323
|
-
"""
|
|
323
|
+
""" % {"id_func": db.get_id_function_name()}
|
|
324
324
|
self.add_to_query(query=query)
|
|
325
325
|
|
|
326
326
|
|
|
@@ -334,6 +334,7 @@ class DiffMergePropertiesQuery(Query):
|
|
|
334
334
|
property_diff_dicts: dict[str, Any],
|
|
335
335
|
at: Timestamp,
|
|
336
336
|
target_branch: Branch,
|
|
337
|
+
migrated_kinds_id_map: dict[str, str],
|
|
337
338
|
**kwargs: Any,
|
|
338
339
|
) -> None:
|
|
339
340
|
super().__init__(**kwargs)
|
|
@@ -341,6 +342,7 @@ class DiffMergePropertiesQuery(Query):
|
|
|
341
342
|
self.at = at
|
|
342
343
|
self.target_branch = target_branch
|
|
343
344
|
self.source_branch_name = self.branch.name
|
|
345
|
+
self.migrated_kinds_id_map = migrated_kinds_id_map
|
|
344
346
|
|
|
345
347
|
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
346
348
|
self.params = {
|
|
@@ -349,59 +351,70 @@ class DiffMergePropertiesQuery(Query):
|
|
|
349
351
|
"branch_level": self.target_branch.hierarchy_level,
|
|
350
352
|
"target_branch": self.target_branch.name,
|
|
351
353
|
"source_branch": self.source_branch_name,
|
|
354
|
+
"migrated_kinds_id_map": self.migrated_kinds_id_map,
|
|
355
|
+
"migrated_kinds_uuids": list(self.migrated_kinds_id_map.keys()),
|
|
352
356
|
}
|
|
353
357
|
query = """
|
|
354
358
|
UNWIND $property_diff_dicts AS attr_rel_prop_diff
|
|
355
|
-
|
|
359
|
+
WITH attr_rel_prop_diff, CASE
|
|
360
|
+
WHEN $migrated_kinds_uuids IS NULL THEN NULL
|
|
361
|
+
WHEN attr_rel_prop_diff.node_uuid IN $migrated_kinds_uuids THEN $migrated_kinds_id_map[attr_rel_prop_diff.node_uuid]
|
|
362
|
+
ELSE NULL
|
|
363
|
+
END AS node_db_id,
|
|
364
|
+
CASE
|
|
365
|
+
WHEN $migrated_kinds_uuids IS NULL THEN NULL
|
|
366
|
+
WHEN attr_rel_prop_diff.peer_uuid IN $migrated_kinds_uuids THEN $migrated_kinds_id_map[attr_rel_prop_diff.peer_uuid]
|
|
367
|
+
ELSE NULL
|
|
368
|
+
END AS peer_db_id
|
|
369
|
+
CALL (attr_rel_prop_diff, node_db_id, peer_db_id) {
|
|
356
370
|
// ------------------------------
|
|
357
371
|
// find the Attribute node
|
|
358
372
|
// ------------------------------
|
|
359
|
-
|
|
360
|
-
CALL {
|
|
361
|
-
WITH attr_rel_prop_diff
|
|
373
|
+
CALL (attr_rel_prop_diff, node_db_id) {
|
|
362
374
|
OPTIONAL MATCH (n:Node {uuid: attr_rel_prop_diff.node_uuid})
|
|
363
375
|
-[has_attr:HAS_ATTRIBUTE]
|
|
364
376
|
->(attr:Attribute {name: attr_rel_prop_diff.attribute_name})
|
|
365
377
|
WHERE attr_rel_prop_diff.attribute_name IS NOT NULL
|
|
378
|
+
AND (node_db_id IS NULL OR %(id_func)s(n) = node_db_id)
|
|
366
379
|
AND has_attr.branch IN [$source_branch, $target_branch]
|
|
367
380
|
RETURN attr
|
|
368
381
|
ORDER BY has_attr.from DESC
|
|
369
382
|
LIMIT 1
|
|
370
383
|
}
|
|
371
|
-
CALL {
|
|
372
|
-
WITH attr_rel_prop_diff
|
|
384
|
+
CALL (attr_rel_prop_diff, node_db_id, peer_db_id) {
|
|
373
385
|
OPTIONAL MATCH (n:Node {uuid: attr_rel_prop_diff.node_uuid})
|
|
374
386
|
-[r1:IS_RELATED]
|
|
375
387
|
-(rel:Relationship {name: attr_rel_prop_diff.relationship_id})
|
|
376
388
|
-[r2:IS_RELATED]
|
|
377
|
-
-(:Node {uuid: attr_rel_prop_diff.peer_uuid})
|
|
389
|
+
-(rel_peer:Node {uuid: attr_rel_prop_diff.peer_uuid})
|
|
378
390
|
WHERE attr_rel_prop_diff.relationship_id IS NOT NULL
|
|
391
|
+
AND (node_db_id IS NULL OR %(id_func)s(n) = node_db_id)
|
|
392
|
+
AND (peer_db_id IS NULL OR %(id_func)s(rel_peer) = peer_db_id)
|
|
379
393
|
AND r1.branch IN [$source_branch, $target_branch]
|
|
380
394
|
AND r2.branch IN [$source_branch, $target_branch]
|
|
381
395
|
RETURN rel
|
|
382
396
|
ORDER BY r1.branch_level DESC, r2.branch_level DESC, r1.from DESC, r2.from DESC
|
|
383
397
|
LIMIT 1
|
|
384
398
|
}
|
|
385
|
-
WITH attr_rel_prop_diff, COALESCE(attr, rel) AS attr_rel
|
|
399
|
+
WITH attr_rel_prop_diff, COALESCE(attr, rel) AS attr_rel, peer_db_id
|
|
400
|
+
WHERE attr_rel IS NOT NULL
|
|
386
401
|
UNWIND attr_rel_prop_diff.properties AS property_diff
|
|
387
402
|
// ------------------------------
|
|
388
403
|
// handle updates for properties under this attribute/relationship
|
|
389
404
|
// ------------------------------
|
|
390
|
-
CALL {
|
|
391
|
-
WITH attr_rel, property_diff
|
|
405
|
+
CALL (attr_rel, property_diff, peer_db_id) {
|
|
392
406
|
// ------------------------------
|
|
393
407
|
// identify the correct property node to link
|
|
394
408
|
// ------------------------------
|
|
395
|
-
CALL {
|
|
396
|
-
WITH attr_rel, property_diff
|
|
409
|
+
CALL (attr_rel, property_diff, peer_db_id) {
|
|
397
410
|
OPTIONAL MATCH (peer:Node {uuid: property_diff.value})
|
|
398
411
|
WHERE property_diff.property_type IN ["HAS_SOURCE", "HAS_OWNER"]
|
|
412
|
+
AND (peer_db_id IS NULL OR %(id_func)s(peer) = peer_db_id)
|
|
399
413
|
// ------------------------------
|
|
400
414
|
// the serialized diff might not include the values for IS_VISIBLE and IS_PROTECTED in
|
|
401
415
|
// some cases, so we need to figure them out here
|
|
402
416
|
// ------------------------------
|
|
403
|
-
CALL {
|
|
404
|
-
WITH attr_rel, property_diff
|
|
417
|
+
CALL (attr_rel, property_diff) {
|
|
405
418
|
OPTIONAL MATCH (attr_rel)-[r_vis_pro]->(bool:Boolean)
|
|
406
419
|
WHERE property_diff.property_type IN ["IS_VISIBLE", "IS_PROTECTED"]
|
|
407
420
|
AND r_vis_pro.branch IN [$source_branch, $target_branch]
|
|
@@ -411,12 +424,11 @@ CALL {
|
|
|
411
424
|
ORDER BY r_vis_pro.from DESC
|
|
412
425
|
LIMIT 1
|
|
413
426
|
}
|
|
414
|
-
CALL {
|
|
427
|
+
CALL (attr_rel, property_diff) {
|
|
415
428
|
// ------------------------------
|
|
416
429
|
// get the latest linked AttributeValue on the source b/c there could be multiple
|
|
417
430
|
// with different is_default values
|
|
418
431
|
// ------------------------------
|
|
419
|
-
WITH attr_rel, property_diff
|
|
420
432
|
OPTIONAL MATCH (attr_rel)-[r_attr_val:HAS_VALUE]->(av:AttributeValue)
|
|
421
433
|
WHERE property_diff.property_type = "HAS_VALUE"
|
|
422
434
|
AND (
|
|
@@ -430,7 +442,7 @@ CALL {
|
|
|
430
442
|
}
|
|
431
443
|
RETURN COALESCE (peer, bool, av) AS prop_node
|
|
432
444
|
}
|
|
433
|
-
WITH attr_rel,
|
|
445
|
+
WITH attr_rel,property_diff.property_type AS prop_type, prop_node, CASE
|
|
434
446
|
WHEN property_diff.action = "ADDED" THEN "active"
|
|
435
447
|
WHEN property_diff.action = "REMOVED" THEN "deleted"
|
|
436
448
|
ELSE NULL
|
|
@@ -438,8 +450,7 @@ CALL {
|
|
|
438
450
|
// ------------------------------
|
|
439
451
|
// set property edge.to, optionally, on target branch
|
|
440
452
|
// ------------------------------
|
|
441
|
-
CALL {
|
|
442
|
-
WITH attr_rel, prop_rel_status, prop_type
|
|
453
|
+
CALL (attr_rel, prop_rel_status, prop_type) {
|
|
443
454
|
OPTIONAL MATCH (attr_rel)
|
|
444
455
|
-[target_r_prop {branch: $target_branch}]
|
|
445
456
|
->()
|
|
@@ -450,8 +461,7 @@ CALL {
|
|
|
450
461
|
// ------------------------------
|
|
451
462
|
// check for existing edge on target_branch
|
|
452
463
|
// ------------------------------
|
|
453
|
-
CALL {
|
|
454
|
-
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
464
|
+
CALL (attr_rel, prop_rel_status, prop_type, prop_node) {
|
|
455
465
|
OPTIONAL MATCH (attr_rel)-[r_prop {branch: $target_branch}]->(prop_node)
|
|
456
466
|
WHERE type(r_prop) = prop_type
|
|
457
467
|
AND r_prop.status = prop_rel_status
|
|
@@ -459,48 +469,221 @@ CALL {
|
|
|
459
469
|
AND (r_prop.to > $at OR r_prop.to IS NULL)
|
|
460
470
|
RETURN r_prop
|
|
461
471
|
}
|
|
462
|
-
WITH attr_rel,
|
|
472
|
+
WITH attr_rel,prop_rel_status, prop_type, prop_node, r_prop
|
|
463
473
|
WHERE r_prop IS NULL
|
|
464
474
|
// ------------------------------
|
|
465
475
|
// create new edge to prop_node on target_branch, if necessary
|
|
466
476
|
// one subquery per possible edge type b/c edge type cannot be a variable
|
|
467
477
|
// ------------------------------
|
|
468
|
-
CALL {
|
|
469
|
-
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
478
|
+
CALL (attr_rel, prop_rel_status, prop_type, prop_node) {
|
|
470
479
|
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
471
480
|
WHERE prop_type = "HAS_VALUE"
|
|
472
481
|
CREATE (attr_rel)-[:HAS_VALUE { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node)
|
|
473
482
|
}
|
|
474
|
-
CALL {
|
|
475
|
-
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
483
|
+
CALL (attr_rel, prop_rel_status, prop_type, prop_node) {
|
|
476
484
|
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
477
485
|
WHERE prop_type = "HAS_SOURCE"
|
|
478
486
|
CREATE (attr_rel)-[:HAS_SOURCE { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node)
|
|
479
487
|
}
|
|
480
|
-
CALL {
|
|
481
|
-
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
488
|
+
CALL (attr_rel, prop_rel_status, prop_type, prop_node) {
|
|
482
489
|
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
483
490
|
WHERE prop_type = "HAS_OWNER"
|
|
484
491
|
CREATE (attr_rel)-[:HAS_OWNER { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node)
|
|
485
492
|
}
|
|
486
|
-
CALL {
|
|
487
|
-
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
493
|
+
CALL (attr_rel, prop_rel_status, prop_type, prop_node) {
|
|
488
494
|
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
489
495
|
WHERE prop_type = "IS_VISIBLE"
|
|
490
496
|
CREATE (attr_rel)-[:IS_VISIBLE { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node)
|
|
491
497
|
}
|
|
492
|
-
CALL {
|
|
493
|
-
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
498
|
+
CALL (attr_rel, prop_rel_status, prop_type, prop_node) {
|
|
494
499
|
WITH attr_rel, prop_rel_status, prop_type, prop_node
|
|
495
500
|
WHERE prop_type = "IS_PROTECTED"
|
|
496
501
|
CREATE (attr_rel)-[:IS_PROTECTED { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node)
|
|
497
502
|
}
|
|
498
503
|
}
|
|
499
504
|
}
|
|
500
|
-
"""
|
|
505
|
+
""" % {"id_func": db.get_id_function_name()}
|
|
501
506
|
self.add_to_query(query=query)
|
|
502
507
|
|
|
503
508
|
|
|
509
|
+
class DiffMergeMigratedKindsQuery(Query):
|
|
510
|
+
name = "diff_merge_migrated_kinds"
|
|
511
|
+
type = QueryType.WRITE
|
|
512
|
+
insert_return = False
|
|
513
|
+
|
|
514
|
+
def __init__(
|
|
515
|
+
self,
|
|
516
|
+
migrated_uuids: list[str],
|
|
517
|
+
at: Timestamp,
|
|
518
|
+
target_branch: Branch,
|
|
519
|
+
**kwargs: Any,
|
|
520
|
+
) -> None:
|
|
521
|
+
super().__init__(**kwargs)
|
|
522
|
+
self.migrated_uuids = migrated_uuids
|
|
523
|
+
self.at = at
|
|
524
|
+
self.target_branch = target_branch
|
|
525
|
+
self.source_branch_name = self.branch.name
|
|
526
|
+
|
|
527
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
528
|
+
self.params = {
|
|
529
|
+
"migrated_uuids": self.migrated_uuids,
|
|
530
|
+
"at": self.at.to_string(),
|
|
531
|
+
"branch_level": self.target_branch.hierarchy_level,
|
|
532
|
+
"target_branch": self.target_branch.name,
|
|
533
|
+
"source_branch": self.source_branch_name,
|
|
534
|
+
}
|
|
535
|
+
query = """
|
|
536
|
+
MATCH (n:Node)
|
|
537
|
+
WHERE n.uuid IN $migrated_uuids
|
|
538
|
+
CALL (n) {
|
|
539
|
+
// --------------
|
|
540
|
+
// for each migrated node (created or deleted), find its latest edges on the source branch,
|
|
541
|
+
// check if they exist on the target, create them if not
|
|
542
|
+
// --------------
|
|
543
|
+
MATCH (n)-[]-(peer)
|
|
544
|
+
WITH DISTINCT n, peer
|
|
545
|
+
CALL (n, peer) {
|
|
546
|
+
// --------------
|
|
547
|
+
// get the latest outbound edge for each type between n and peer
|
|
548
|
+
// --------------
|
|
549
|
+
MATCH (n)-[e {branch: $source_branch}]->(peer)
|
|
550
|
+
WHERE e.from <= $at AND e.to IS NULL
|
|
551
|
+
WITH e, type(e) AS edge_type
|
|
552
|
+
ORDER BY edge_type, e.from DESC
|
|
553
|
+
WITH edge_type, head(collect(e)) AS latest_source_edge
|
|
554
|
+
RETURN edge_type, latest_source_edge
|
|
555
|
+
}
|
|
556
|
+
CALL (n, peer, edge_type) {
|
|
557
|
+
// --------------
|
|
558
|
+
// for each n, peer, edge_type, get the latest edge on target
|
|
559
|
+
// --------------
|
|
560
|
+
OPTIONAL MATCH (n)-[e {branch: $target_branch}]->(peer)
|
|
561
|
+
WHERE type(e) = edge_type AND e.from <= $at
|
|
562
|
+
RETURN e AS latest_target_edge
|
|
563
|
+
ORDER BY e.from DESC
|
|
564
|
+
LIMIT 1
|
|
565
|
+
}
|
|
566
|
+
// --------------
|
|
567
|
+
// ignore edges of this type that already have the correct status on the target branch
|
|
568
|
+
// --------------
|
|
569
|
+
WITH n, peer, edge_type, latest_source_edge, latest_target_edge
|
|
570
|
+
WHERE (latest_target_edge IS NULL AND latest_source_edge.status = "active")
|
|
571
|
+
OR latest_source_edge.status <> latest_target_edge.status
|
|
572
|
+
CALL (latest_source_edge, latest_target_edge) {
|
|
573
|
+
// --------------
|
|
574
|
+
// set the to time on active target branch edges that we are setting to deleted
|
|
575
|
+
// --------------
|
|
576
|
+
WITH latest_target_edge WHERE latest_target_edge IS NOT NULL
|
|
577
|
+
AND latest_source_edge.status = "deleted"
|
|
578
|
+
AND latest_target_edge.status = "active"
|
|
579
|
+
AND latest_target_edge.to IS NULL
|
|
580
|
+
SET latest_target_edge.to = $at
|
|
581
|
+
}
|
|
582
|
+
// --------------
|
|
583
|
+
// create the outbound edges on the target branch, one subquery per possible type
|
|
584
|
+
// --------------
|
|
585
|
+
CALL (n, latest_source_edge, peer, edge_type) {
|
|
586
|
+
WITH edge_type WHERE edge_type = "IS_PART_OF"
|
|
587
|
+
CREATE (n)-[new_edge:IS_PART_OF]->(peer)
|
|
588
|
+
SET new_edge = properties(latest_source_edge)
|
|
589
|
+
SET new_edge.from = $at
|
|
590
|
+
SET new_edge.branch_level = $branch_level
|
|
591
|
+
SET new_edge.branch = $target_branch
|
|
592
|
+
}
|
|
593
|
+
CALL (n, latest_source_edge, peer, edge_type) {
|
|
594
|
+
WITH edge_type
|
|
595
|
+
WHERE edge_type = "IS_RELATED"
|
|
596
|
+
CREATE (n)-[new_edge:IS_RELATED]->(peer)
|
|
597
|
+
SET new_edge = properties(latest_source_edge)
|
|
598
|
+
SET new_edge.from = $at
|
|
599
|
+
SET new_edge.branch_level = $branch_level
|
|
600
|
+
SET new_edge.branch = $target_branch
|
|
601
|
+
}
|
|
602
|
+
CALL (n, latest_source_edge, peer, edge_type) {
|
|
603
|
+
WITH edge_type
|
|
604
|
+
WHERE edge_type = "HAS_ATTRIBUTE"
|
|
605
|
+
CREATE (n)-[new_edge:HAS_ATTRIBUTE]->(peer)
|
|
606
|
+
SET new_edge = properties(latest_source_edge)
|
|
607
|
+
SET new_edge.from = $at
|
|
608
|
+
SET new_edge.branch_level = $branch_level
|
|
609
|
+
SET new_edge.branch = $target_branch
|
|
610
|
+
}
|
|
611
|
+
// --------------
|
|
612
|
+
// do all of this again for inbound edges
|
|
613
|
+
// --------------
|
|
614
|
+
WITH DISTINCT n, peer
|
|
615
|
+
CALL (n, peer) {
|
|
616
|
+
// --------------
|
|
617
|
+
// get the latest inbound edge for each type between n and peer
|
|
618
|
+
// --------------
|
|
619
|
+
MATCH (n)<-[e {branch: $source_branch}]-(peer)
|
|
620
|
+
WHERE e.from <= $at AND e.to IS NULL
|
|
621
|
+
WITH e, type(e) AS edge_type
|
|
622
|
+
ORDER BY edge_type, e.from DESC
|
|
623
|
+
WITH edge_type, head(collect(e)) AS latest_source_edge
|
|
624
|
+
RETURN edge_type, latest_source_edge
|
|
625
|
+
}
|
|
626
|
+
CALL (n, peer, edge_type) {
|
|
627
|
+
// --------------
|
|
628
|
+
// for each n, peer, edge_type, get the latest edge on target
|
|
629
|
+
// --------------
|
|
630
|
+
OPTIONAL MATCH (n)<-[e {branch: $target_branch}]-(peer)
|
|
631
|
+
WHERE type(e) = edge_type AND e.from <= $at
|
|
632
|
+
RETURN e AS latest_target_edge
|
|
633
|
+
ORDER BY e.from DESC
|
|
634
|
+
LIMIT 1
|
|
635
|
+
}
|
|
636
|
+
// --------------
|
|
637
|
+
// ignore edges of this type that already have the correct status on the target branch
|
|
638
|
+
// --------------
|
|
639
|
+
WITH n, peer, edge_type, latest_source_edge, latest_target_edge
|
|
640
|
+
WHERE latest_target_edge IS NULL OR latest_source_edge.status <> latest_target_edge.status
|
|
641
|
+
CALL (latest_source_edge, latest_target_edge) {
|
|
642
|
+
// --------------
|
|
643
|
+
// set the to time on active target branch edges that we are setting to deleted
|
|
644
|
+
// --------------
|
|
645
|
+
WITH latest_target_edge
|
|
646
|
+
WHERE latest_target_edge IS NOT NULL
|
|
647
|
+
AND latest_source_edge.status = "deleted"
|
|
648
|
+
AND latest_target_edge.status = "active"
|
|
649
|
+
AND latest_target_edge.to IS NULL
|
|
650
|
+
SET latest_target_edge.to = $at
|
|
651
|
+
}
|
|
652
|
+
// --------------
|
|
653
|
+
// create the outbound edges on the target branch, one subquery per possible type
|
|
654
|
+
// --------------
|
|
655
|
+
CALL (n, latest_source_edge, peer, edge_type) {
|
|
656
|
+
WITH edge_type
|
|
657
|
+
WHERE edge_type = "IS_RELATED"
|
|
658
|
+
CREATE (n)<-[new_edge:IS_RELATED]-(peer)
|
|
659
|
+
SET new_edge = properties(latest_source_edge)
|
|
660
|
+
SET new_edge.from = $at
|
|
661
|
+
SET new_edge.branch_level = $branch_level
|
|
662
|
+
SET new_edge.branch = $target_branch
|
|
663
|
+
}
|
|
664
|
+
CALL (n, latest_source_edge, peer, edge_type) {
|
|
665
|
+
WITH edge_type
|
|
666
|
+
WHERE edge_type = "HAS_OWNER"
|
|
667
|
+
CREATE (n)<-[new_edge:HAS_OWNER]-(peer)
|
|
668
|
+
SET new_edge = properties(latest_source_edge)
|
|
669
|
+
SET new_edge.from = $at
|
|
670
|
+
SET new_edge.branch_level = $branch_level
|
|
671
|
+
SET new_edge.branch = $target_branch
|
|
672
|
+
}
|
|
673
|
+
CALL (n, latest_source_edge, peer, edge_type) {
|
|
674
|
+
WITH edge_type
|
|
675
|
+
WHERE edge_type = "HAS_SOURCE"
|
|
676
|
+
CREATE (n)<-[new_edge:HAS_SOURCE]-(peer)
|
|
677
|
+
SET new_edge = properties(latest_source_edge)
|
|
678
|
+
SET new_edge.from = $at
|
|
679
|
+
SET new_edge.branch_level = $branch_level
|
|
680
|
+
SET new_edge.branch = $target_branch
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
"""
|
|
684
|
+
self.add_to_query(query)
|
|
685
|
+
|
|
686
|
+
|
|
504
687
|
class DiffMergeRollbackQuery(Query):
|
|
505
688
|
name = "diff_merge_rollback"
|
|
506
689
|
type = QueryType.WRITE
|