infrahub-server 1.2.9rc0__py3-none-any.whl → 1.2.11__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/computed_attribute/models.py +13 -0
- infrahub/computed_attribute/tasks.py +48 -26
- infrahub/config.py +9 -0
- infrahub/core/attribute.py +43 -2
- infrahub/core/branch/models.py +8 -9
- infrahub/core/branch/tasks.py +0 -2
- infrahub/core/constants/infrahubkind.py +1 -0
- infrahub/core/constraint/node/runner.py +1 -1
- 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/drop_nodes.py +42 -0
- infrahub/core/diff/query/field_specifiers.py +8 -7
- infrahub/core/diff/query/filters.py +15 -1
- infrahub/core/diff/query/merge.py +264 -28
- infrahub/core/diff/query/save.py +6 -2
- 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/migrations/graph/__init__.py +2 -0
- infrahub/core/migrations/graph/m027_delete_isolated_nodes.py +50 -0
- infrahub/core/migrations/graph/m028_delete_diffs.py +38 -0
- infrahub/core/node/resource_manager/ip_address_pool.py +6 -2
- infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -2
- infrahub/core/protocols.py +4 -0
- infrahub/core/query/branch.py +27 -17
- infrahub/core/query/diff.py +169 -51
- infrahub/core/query/node.py +39 -5
- infrahub/core/query/relationship.py +105 -30
- infrahub/core/query/subquery.py +2 -2
- infrahub/core/relationship/model.py +1 -1
- infrahub/core/schema/definitions/core/__init__.py +8 -1
- infrahub/core/schema/definitions/core/resource_pool.py +20 -0
- infrahub/core/schema/schema_branch.py +3 -0
- infrahub/core/validators/tasks.py +1 -1
- infrahub/core/validators/uniqueness/query.py +7 -0
- infrahub/database/__init__.py +5 -4
- infrahub/graphql/app.py +1 -1
- infrahub/graphql/loaders/node.py +1 -1
- infrahub/graphql/loaders/peers.py +1 -1
- infrahub/graphql/mutations/proposed_change.py +1 -1
- infrahub/graphql/queries/diff/tree.py +2 -1
- infrahub/graphql/queries/relationship.py +1 -1
- infrahub/graphql/queries/task.py +10 -0
- 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/subscription/graphql_query.py +2 -2
- infrahub/graphql/types/branch.py +1 -1
- infrahub/graphql/types/task_log.py +3 -2
- infrahub/message_bus/operations/refresh/registry.py +1 -1
- infrahub/task_manager/task.py +44 -4
- infrahub/telemetry/database.py +1 -1
- infrahub/telemetry/tasks.py +1 -1
- infrahub/trigger/models.py +11 -1
- infrahub/trigger/setup.py +51 -15
- infrahub/trigger/tasks.py +1 -4
- infrahub/types.py +1 -1
- infrahub/webhook/models.py +2 -1
- infrahub/workflows/catalogue.py +9 -0
- infrahub/workflows/initialization.py +1 -3
- infrahub_sdk/timestamp.py +2 -2
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.2.11.dist-info}/METADATA +3 -3
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.2.11.dist-info}/RECORD +79 -75
- infrahub_testcontainers/docker-compose.test.yml +3 -3
- infrahub_testcontainers/performance_test.py +6 -3
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.2.11.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.2.11.dist-info}/WHEEL +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.2.11.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,19 +37,29 @@ 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
|
|
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
|
|
42
52
|
CALL {
|
|
43
|
-
WITH node_diff_map
|
|
53
|
+
WITH node_diff_map, node_db_id
|
|
44
54
|
MATCH (n:Node {uuid: node_diff_map.uuid})
|
|
55
|
+
WHERE node_db_id IS NULL
|
|
56
|
+
OR %(id_func)s(n) = node_db_id
|
|
45
57
|
RETURN n
|
|
46
58
|
}
|
|
47
|
-
WITH n, node_diff_map
|
|
59
|
+
WITH n, node_diff_map, is_node_kind_migration
|
|
48
60
|
CALL {
|
|
49
|
-
WITH n, node_diff_map
|
|
50
|
-
WITH n, node_diff_map, CASE
|
|
61
|
+
WITH n, node_diff_map, is_node_kind_migration
|
|
62
|
+
WITH n, node_diff_map, is_node_kind_migration, CASE
|
|
51
63
|
WHEN node_diff_map.action = "ADDED" THEN "active"
|
|
52
64
|
WHEN node_diff_map.action = "REMOVED" THEN "deleted"
|
|
53
65
|
ELSE NULL
|
|
@@ -56,9 +68,11 @@ CALL {
|
|
|
56
68
|
// ------------------------------
|
|
57
69
|
// only make IS_PART_OF updates if node is ADDED or REMOVED
|
|
58
70
|
// ------------------------------
|
|
59
|
-
WITH n, node_diff_map, node_rel_status
|
|
60
|
-
WITH n, node_diff_map, node_rel_status
|
|
71
|
+
WITH n, node_diff_map, node_rel_status, is_node_kind_migration
|
|
72
|
+
WITH n, node_diff_map, node_rel_status, is_node_kind_migration
|
|
61
73
|
WHERE node_rel_status IS NOT NULL
|
|
74
|
+
// nodes with a migrated kind are handled in DiffMergeMigratedKindsQuery
|
|
75
|
+
AND is_node_kind_migration = FALSE
|
|
62
76
|
MATCH (root:Root)
|
|
63
77
|
// ------------------------------
|
|
64
78
|
// set IS_PART_OF.to, optionally, target branch
|
|
@@ -214,22 +228,30 @@ CALL {
|
|
|
214
228
|
// ------------------------------
|
|
215
229
|
CALL {
|
|
216
230
|
WITH n, relationship_diff_map
|
|
217
|
-
WITH
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
231
|
+
WITH
|
|
232
|
+
n, relationship_diff_map.peer_id AS rel_peer_id, relationship_diff_map.name AS rel_name,
|
|
233
|
+
CASE
|
|
234
|
+
WHEN relationship_diff_map.action = "ADDED" THEN "active"
|
|
235
|
+
WHEN relationship_diff_map.action = "REMOVED" THEN "deleted"
|
|
236
|
+
ELSE NULL
|
|
237
|
+
END AS related_rel_status,
|
|
238
|
+
CASE
|
|
239
|
+
WHEN $migrated_kinds_uuids IS NULL THEN NULL
|
|
240
|
+
WHEN relationship_diff_map.peer_id IN $migrated_kinds_uuids THEN $migrated_kinds_id_map[relationship_diff_map.peer_id]
|
|
241
|
+
ELSE NULL
|
|
242
|
+
END AS rel_peer_db_id
|
|
222
243
|
// ------------------------------
|
|
223
244
|
// determine the directions of each IS_RELATED
|
|
224
245
|
// ------------------------------
|
|
225
246
|
CALL {
|
|
226
|
-
WITH n, rel_name, rel_peer_id, related_rel_status
|
|
247
|
+
WITH n, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status
|
|
227
248
|
MATCH (n)
|
|
228
249
|
-[source_r_rel_1:IS_RELATED]
|
|
229
250
|
-(r:Relationship {name: rel_name})
|
|
230
251
|
-[source_r_rel_2:IS_RELATED]
|
|
231
|
-
-(:Node {uuid: rel_peer_id})
|
|
232
|
-
WHERE
|
|
252
|
+
-(rel_peer:Node {uuid: rel_peer_id})
|
|
253
|
+
WHERE (rel_peer_db_id IS NULL OR %(id_func)s(rel_peer) = rel_peer_db_id)
|
|
254
|
+
AND source_r_rel_1.branch IN [$source_branch, $target_branch]
|
|
233
255
|
AND source_r_rel_2.branch IN [$source_branch, $target_branch]
|
|
234
256
|
AND source_r_rel_1.from <= $at AND source_r_rel_1.to IS NULL
|
|
235
257
|
AND source_r_rel_2.from <= $at AND source_r_rel_2.to IS NULL
|
|
@@ -247,27 +269,29 @@ CALL {
|
|
|
247
269
|
source_r_rel_1.hierarchy AS r1_hierarchy,
|
|
248
270
|
source_r_rel_2.hierarchy AS r2_hierarchy
|
|
249
271
|
}
|
|
250
|
-
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status
|
|
272
|
+
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status
|
|
251
273
|
CALL {
|
|
252
|
-
WITH n, rel_name, rel_peer_id, related_rel_status
|
|
274
|
+
WITH n, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status
|
|
253
275
|
OPTIONAL MATCH (n)
|
|
254
276
|
-[target_r_rel_1:IS_RELATED {branch: $target_branch, status: "active"}]
|
|
255
277
|
-(:Relationship {name: rel_name})
|
|
256
278
|
-[target_r_rel_2:IS_RELATED {branch: $target_branch, status: "active"}]
|
|
257
|
-
-(:Node {uuid: rel_peer_id})
|
|
279
|
+
-(rel_peer:Node {uuid: rel_peer_id})
|
|
258
280
|
WHERE related_rel_status = "deleted"
|
|
281
|
+
AND (rel_peer_db_id IS NULL OR %(id_func)s(rel_peer) = rel_peer_db_id)
|
|
259
282
|
AND target_r_rel_1.from <= $at AND target_r_rel_1.to IS NULL
|
|
260
283
|
AND target_r_rel_2.from <= $at AND target_r_rel_2.to IS NULL
|
|
261
284
|
SET target_r_rel_1.to = $at
|
|
262
285
|
SET target_r_rel_2.to = $at
|
|
263
286
|
}
|
|
264
|
-
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status
|
|
287
|
+
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status
|
|
265
288
|
// ------------------------------
|
|
266
289
|
// conditionally create new IS_RELATED relationships on target_branch, if necessary
|
|
267
290
|
// ------------------------------
|
|
268
291
|
CALL {
|
|
269
|
-
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status
|
|
292
|
+
WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, rel_peer_db_id, related_rel_status
|
|
270
293
|
MATCH (p:Node {uuid: rel_peer_id})
|
|
294
|
+
WHERE rel_peer_db_id IS NULL OR %(id_func)s(p) = rel_peer_db_id
|
|
271
295
|
OPTIONAL MATCH (n)
|
|
272
296
|
-[r_rel_1:IS_RELATED {branch: $target_branch, status: related_rel_status}]
|
|
273
297
|
-(:Relationship {name: rel_name})
|
|
@@ -320,7 +344,7 @@ CALL {
|
|
|
320
344
|
}
|
|
321
345
|
}
|
|
322
346
|
RETURN 1 AS done
|
|
323
|
-
"""
|
|
347
|
+
""" % {"id_func": db.get_id_function_name()}
|
|
324
348
|
self.add_to_query(query=query)
|
|
325
349
|
|
|
326
350
|
|
|
@@ -334,6 +358,7 @@ class DiffMergePropertiesQuery(Query):
|
|
|
334
358
|
property_diff_dicts: dict[str, Any],
|
|
335
359
|
at: Timestamp,
|
|
336
360
|
target_branch: Branch,
|
|
361
|
+
migrated_kinds_id_map: dict[str, str],
|
|
337
362
|
**kwargs: Any,
|
|
338
363
|
) -> None:
|
|
339
364
|
super().__init__(**kwargs)
|
|
@@ -341,6 +366,7 @@ class DiffMergePropertiesQuery(Query):
|
|
|
341
366
|
self.at = at
|
|
342
367
|
self.target_branch = target_branch
|
|
343
368
|
self.source_branch_name = self.branch.name
|
|
369
|
+
self.migrated_kinds_id_map = migrated_kinds_id_map
|
|
344
370
|
|
|
345
371
|
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
346
372
|
self.params = {
|
|
@@ -349,53 +375,70 @@ class DiffMergePropertiesQuery(Query):
|
|
|
349
375
|
"branch_level": self.target_branch.hierarchy_level,
|
|
350
376
|
"target_branch": self.target_branch.name,
|
|
351
377
|
"source_branch": self.source_branch_name,
|
|
378
|
+
"migrated_kinds_id_map": self.migrated_kinds_id_map,
|
|
379
|
+
"migrated_kinds_uuids": list(self.migrated_kinds_id_map.keys()),
|
|
352
380
|
}
|
|
353
381
|
query = """
|
|
354
382
|
UNWIND $property_diff_dicts AS attr_rel_prop_diff
|
|
383
|
+
WITH attr_rel_prop_diff, CASE
|
|
384
|
+
WHEN $migrated_kinds_uuids IS NULL THEN NULL
|
|
385
|
+
WHEN attr_rel_prop_diff.node_uuid IN $migrated_kinds_uuids THEN $migrated_kinds_id_map[attr_rel_prop_diff.node_uuid]
|
|
386
|
+
ELSE NULL
|
|
387
|
+
END AS node_db_id,
|
|
388
|
+
CASE
|
|
389
|
+
WHEN $migrated_kinds_uuids IS NULL THEN NULL
|
|
390
|
+
WHEN attr_rel_prop_diff.peer_uuid IN $migrated_kinds_uuids THEN $migrated_kinds_id_map[attr_rel_prop_diff.peer_uuid]
|
|
391
|
+
ELSE NULL
|
|
392
|
+
END AS peer_db_id
|
|
355
393
|
CALL {
|
|
356
394
|
// ------------------------------
|
|
357
395
|
// find the Attribute node
|
|
358
396
|
// ------------------------------
|
|
359
|
-
WITH attr_rel_prop_diff
|
|
397
|
+
WITH attr_rel_prop_diff, node_db_id, peer_db_id
|
|
360
398
|
CALL {
|
|
361
|
-
WITH attr_rel_prop_diff
|
|
399
|
+
WITH attr_rel_prop_diff, node_db_id
|
|
362
400
|
OPTIONAL MATCH (n:Node {uuid: attr_rel_prop_diff.node_uuid})
|
|
363
401
|
-[has_attr:HAS_ATTRIBUTE]
|
|
364
402
|
->(attr:Attribute {name: attr_rel_prop_diff.attribute_name})
|
|
365
403
|
WHERE attr_rel_prop_diff.attribute_name IS NOT NULL
|
|
404
|
+
AND (node_db_id IS NULL OR %(id_func)s(n) = node_db_id)
|
|
366
405
|
AND has_attr.branch IN [$source_branch, $target_branch]
|
|
367
406
|
RETURN attr
|
|
368
407
|
ORDER BY has_attr.from DESC
|
|
369
408
|
LIMIT 1
|
|
370
409
|
}
|
|
371
410
|
CALL {
|
|
372
|
-
WITH attr_rel_prop_diff
|
|
411
|
+
WITH attr_rel_prop_diff, node_db_id, peer_db_id
|
|
373
412
|
OPTIONAL MATCH (n:Node {uuid: attr_rel_prop_diff.node_uuid})
|
|
374
413
|
-[r1:IS_RELATED]
|
|
375
414
|
-(rel:Relationship {name: attr_rel_prop_diff.relationship_id})
|
|
376
415
|
-[r2:IS_RELATED]
|
|
377
|
-
-(:Node {uuid: attr_rel_prop_diff.peer_uuid})
|
|
416
|
+
-(rel_peer:Node {uuid: attr_rel_prop_diff.peer_uuid})
|
|
378
417
|
WHERE attr_rel_prop_diff.relationship_id IS NOT NULL
|
|
418
|
+
AND (node_db_id IS NULL OR %(id_func)s(n) = node_db_id)
|
|
419
|
+
AND (peer_db_id IS NULL OR %(id_func)s(rel_peer) = peer_db_id)
|
|
379
420
|
AND r1.branch IN [$source_branch, $target_branch]
|
|
380
421
|
AND r2.branch IN [$source_branch, $target_branch]
|
|
381
422
|
RETURN rel
|
|
382
423
|
ORDER BY r1.branch_level DESC, r2.branch_level DESC, r1.from DESC, r2.from DESC
|
|
383
424
|
LIMIT 1
|
|
384
425
|
}
|
|
385
|
-
WITH attr_rel_prop_diff, COALESCE(attr, rel) AS attr_rel
|
|
426
|
+
WITH attr_rel_prop_diff, COALESCE(attr, rel) AS attr_rel, peer_db_id
|
|
427
|
+
WHERE attr_rel IS NOT NULL
|
|
386
428
|
UNWIND attr_rel_prop_diff.properties AS property_diff
|
|
387
429
|
// ------------------------------
|
|
388
430
|
// handle updates for properties under this attribute/relationship
|
|
389
431
|
// ------------------------------
|
|
390
432
|
CALL {
|
|
391
|
-
WITH attr_rel, property_diff
|
|
433
|
+
WITH attr_rel, property_diff, peer_db_id
|
|
392
434
|
// ------------------------------
|
|
393
435
|
// identify the correct property node to link
|
|
394
436
|
// ------------------------------
|
|
395
437
|
CALL {
|
|
396
|
-
WITH attr_rel, property_diff
|
|
438
|
+
WITH attr_rel, property_diff, peer_db_id
|
|
397
439
|
OPTIONAL MATCH (peer:Node {uuid: property_diff.value})
|
|
398
440
|
WHERE property_diff.property_type IN ["HAS_SOURCE", "HAS_OWNER"]
|
|
441
|
+
AND (peer_db_id IS NULL OR %(id_func)s(peer) = peer_db_id)
|
|
399
442
|
// ------------------------------
|
|
400
443
|
// the serialized diff might not include the values for IS_VISIBLE and IS_PROTECTED in
|
|
401
444
|
// some cases, so we need to figure them out here
|
|
@@ -497,10 +540,203 @@ CALL {
|
|
|
497
540
|
}
|
|
498
541
|
}
|
|
499
542
|
}
|
|
500
|
-
"""
|
|
543
|
+
""" % {"id_func": db.get_id_function_name()}
|
|
501
544
|
self.add_to_query(query=query)
|
|
502
545
|
|
|
503
546
|
|
|
547
|
+
class DiffMergeMigratedKindsQuery(Query):
|
|
548
|
+
name = "diff_merge_migrated_kinds"
|
|
549
|
+
type = QueryType.WRITE
|
|
550
|
+
insert_return = False
|
|
551
|
+
|
|
552
|
+
def __init__(
|
|
553
|
+
self,
|
|
554
|
+
migrated_uuids: list[str],
|
|
555
|
+
at: Timestamp,
|
|
556
|
+
target_branch: Branch,
|
|
557
|
+
**kwargs: Any,
|
|
558
|
+
) -> None:
|
|
559
|
+
super().__init__(**kwargs)
|
|
560
|
+
self.migrated_uuids = migrated_uuids
|
|
561
|
+
self.at = at
|
|
562
|
+
self.target_branch = target_branch
|
|
563
|
+
self.source_branch_name = self.branch.name
|
|
564
|
+
|
|
565
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
566
|
+
self.params = {
|
|
567
|
+
"migrated_uuids": self.migrated_uuids,
|
|
568
|
+
"at": self.at.to_string(),
|
|
569
|
+
"branch_level": self.target_branch.hierarchy_level,
|
|
570
|
+
"target_branch": self.target_branch.name,
|
|
571
|
+
"source_branch": self.source_branch_name,
|
|
572
|
+
}
|
|
573
|
+
query = """
|
|
574
|
+
MATCH (n:Node)
|
|
575
|
+
WHERE n.uuid IN $migrated_uuids
|
|
576
|
+
CALL {
|
|
577
|
+
// --------------
|
|
578
|
+
// for each migrated node (created or deleted), find its latest edges on the source branch,
|
|
579
|
+
// check if they exist on the target, create them if not
|
|
580
|
+
// --------------
|
|
581
|
+
WITH n
|
|
582
|
+
MATCH (n)-[]-(peer)
|
|
583
|
+
WITH DISTINCT n, peer
|
|
584
|
+
CALL {
|
|
585
|
+
// --------------
|
|
586
|
+
// get the latest outbound edge for each type between n and peer
|
|
587
|
+
// --------------
|
|
588
|
+
WITH n, peer
|
|
589
|
+
MATCH (n)-[e {branch: $source_branch}]->(peer)
|
|
590
|
+
WHERE e.from <= $at AND e.to IS NULL
|
|
591
|
+
WITH e, type(e) AS edge_type
|
|
592
|
+
ORDER BY edge_type, e.from DESC
|
|
593
|
+
WITH edge_type, head(collect(e)) AS latest_source_edge
|
|
594
|
+
RETURN edge_type, latest_source_edge
|
|
595
|
+
}
|
|
596
|
+
CALL {
|
|
597
|
+
// --------------
|
|
598
|
+
// for each n, peer, edge_type, get the latest edge on target
|
|
599
|
+
// --------------
|
|
600
|
+
WITH n, peer, edge_type
|
|
601
|
+
OPTIONAL MATCH (n)-[e {branch: $target_branch}]->(peer)
|
|
602
|
+
WHERE type(e) = edge_type AND e.from <= $at
|
|
603
|
+
RETURN e AS latest_target_edge
|
|
604
|
+
ORDER BY e.from DESC
|
|
605
|
+
LIMIT 1
|
|
606
|
+
}
|
|
607
|
+
// --------------
|
|
608
|
+
// ignore edges of this type that already have the correct status on the target branch
|
|
609
|
+
// --------------
|
|
610
|
+
WITH n, peer, edge_type, latest_source_edge, latest_target_edge
|
|
611
|
+
WHERE (latest_target_edge IS NULL AND latest_source_edge.status = "active")
|
|
612
|
+
OR latest_source_edge.status <> latest_target_edge.status
|
|
613
|
+
CALL {
|
|
614
|
+
// --------------
|
|
615
|
+
// set the to time on active target branch edges that we are setting to deleted
|
|
616
|
+
// --------------
|
|
617
|
+
WITH latest_source_edge, latest_target_edge
|
|
618
|
+
WITH latest_source_edge, latest_target_edge
|
|
619
|
+
WHERE latest_target_edge IS NOT NULL
|
|
620
|
+
AND latest_source_edge.status = "deleted"
|
|
621
|
+
AND latest_target_edge.status = "active"
|
|
622
|
+
AND latest_target_edge.to IS NULL
|
|
623
|
+
SET latest_target_edge.to = $at
|
|
624
|
+
}
|
|
625
|
+
// --------------
|
|
626
|
+
// create the outbound edges on the target branch, one subquery per possible type
|
|
627
|
+
// --------------
|
|
628
|
+
CALL {
|
|
629
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
630
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
631
|
+
WHERE edge_type = "IS_PART_OF"
|
|
632
|
+
CREATE (n)-[new_edge:IS_PART_OF]->(peer)
|
|
633
|
+
SET new_edge = properties(latest_source_edge)
|
|
634
|
+
SET new_edge.from = $at
|
|
635
|
+
SET new_edge.branch_level = $branch_level
|
|
636
|
+
SET new_edge.branch = $target_branch
|
|
637
|
+
}
|
|
638
|
+
CALL {
|
|
639
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
640
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
641
|
+
WHERE edge_type = "IS_RELATED"
|
|
642
|
+
CREATE (n)-[new_edge:IS_RELATED]->(peer)
|
|
643
|
+
SET new_edge = properties(latest_source_edge)
|
|
644
|
+
SET new_edge.from = $at
|
|
645
|
+
SET new_edge.branch_level = $branch_level
|
|
646
|
+
SET new_edge.branch = $target_branch
|
|
647
|
+
}
|
|
648
|
+
CALL {
|
|
649
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
650
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
651
|
+
WHERE edge_type = "HAS_ATTRIBUTE"
|
|
652
|
+
CREATE (n)-[new_edge:HAS_ATTRIBUTE]->(peer)
|
|
653
|
+
SET new_edge = properties(latest_source_edge)
|
|
654
|
+
SET new_edge.from = $at
|
|
655
|
+
SET new_edge.branch_level = $branch_level
|
|
656
|
+
SET new_edge.branch = $target_branch
|
|
657
|
+
}
|
|
658
|
+
// --------------
|
|
659
|
+
// do all of this again for inbound edges
|
|
660
|
+
// --------------
|
|
661
|
+
WITH DISTINCT n, peer
|
|
662
|
+
CALL {
|
|
663
|
+
// --------------
|
|
664
|
+
// get the latest inbound edge for each type between n and peer
|
|
665
|
+
// --------------
|
|
666
|
+
WITH n, peer
|
|
667
|
+
MATCH (n)<-[e {branch: $source_branch}]-(peer)
|
|
668
|
+
WHERE e.from <= $at AND e.to IS NULL
|
|
669
|
+
WITH e, type(e) AS edge_type
|
|
670
|
+
ORDER BY edge_type, e.from DESC
|
|
671
|
+
WITH edge_type, head(collect(e)) AS latest_source_edge
|
|
672
|
+
RETURN edge_type, latest_source_edge
|
|
673
|
+
}
|
|
674
|
+
CALL {
|
|
675
|
+
// --------------
|
|
676
|
+
// for each n, peer, edge_type, get the latest edge on target
|
|
677
|
+
// --------------
|
|
678
|
+
WITH n, peer, edge_type
|
|
679
|
+
OPTIONAL MATCH (n)<-[e {branch: $target_branch}]-(peer)
|
|
680
|
+
WHERE type(e) = edge_type AND e.from <= $at
|
|
681
|
+
RETURN e AS latest_target_edge
|
|
682
|
+
ORDER BY e.from DESC
|
|
683
|
+
LIMIT 1
|
|
684
|
+
}
|
|
685
|
+
// --------------
|
|
686
|
+
// ignore edges of this type that already have the correct status on the target branch
|
|
687
|
+
// --------------
|
|
688
|
+
WITH n, peer, edge_type, latest_source_edge, latest_target_edge
|
|
689
|
+
WHERE latest_target_edge IS NULL OR latest_source_edge.status <> latest_target_edge.status
|
|
690
|
+
CALL {
|
|
691
|
+
// --------------
|
|
692
|
+
// set the to time on active target branch edges that we are setting to deleted
|
|
693
|
+
// --------------
|
|
694
|
+
WITH latest_source_edge, latest_target_edge
|
|
695
|
+
WITH latest_source_edge, latest_target_edge
|
|
696
|
+
WHERE latest_target_edge IS NOT NULL
|
|
697
|
+
AND latest_source_edge.status = "deleted"
|
|
698
|
+
AND latest_target_edge.status = "active"
|
|
699
|
+
AND latest_target_edge.to IS NULL
|
|
700
|
+
SET latest_target_edge.to = $at
|
|
701
|
+
}
|
|
702
|
+
// --------------
|
|
703
|
+
// create the outbound edges on the target branch, one subquery per possible type
|
|
704
|
+
// --------------
|
|
705
|
+
CALL {
|
|
706
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
707
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
708
|
+
WHERE edge_type = "IS_RELATED"
|
|
709
|
+
CREATE (n)<-[new_edge:IS_RELATED]-(peer)
|
|
710
|
+
SET new_edge = properties(latest_source_edge)
|
|
711
|
+
SET new_edge.from = $at
|
|
712
|
+
SET new_edge.branch_level = $branch_level
|
|
713
|
+
SET new_edge.branch = $target_branch
|
|
714
|
+
}
|
|
715
|
+
CALL {
|
|
716
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
717
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
718
|
+
WHERE edge_type = "HAS_OWNER"
|
|
719
|
+
CREATE (n)<-[new_edge:HAS_OWNER]-(peer)
|
|
720
|
+
SET new_edge = properties(latest_source_edge)
|
|
721
|
+
SET new_edge.from = $at
|
|
722
|
+
SET new_edge.branch_level = $branch_level
|
|
723
|
+
SET new_edge.branch = $target_branch
|
|
724
|
+
}
|
|
725
|
+
CALL {
|
|
726
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
727
|
+
WITH n, latest_source_edge, peer, edge_type
|
|
728
|
+
WHERE edge_type = "HAS_SOURCE"
|
|
729
|
+
CREATE (n)<-[new_edge:HAS_SOURCE]-(peer)
|
|
730
|
+
SET new_edge = properties(latest_source_edge)
|
|
731
|
+
SET new_edge.from = $at
|
|
732
|
+
SET new_edge.branch_level = $branch_level
|
|
733
|
+
SET new_edge.branch = $target_branch
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
"""
|
|
737
|
+
self.add_to_query(query)
|
|
738
|
+
|
|
739
|
+
|
|
504
740
|
class DiffMergeRollbackQuery(Query):
|
|
505
741
|
name = "diff_merge_rollback"
|
|
506
742
|
type = QueryType.WRITE
|
infrahub/core/diff/query/save.py
CHANGED
|
@@ -85,15 +85,17 @@ UNWIND $node_details_list AS node_details
|
|
|
85
85
|
WITH
|
|
86
86
|
node_details.root_uuid AS root_uuid,
|
|
87
87
|
node_details.node_map AS node_map,
|
|
88
|
-
toString(node_details.node_map.node_properties.uuid) AS node_uuid
|
|
88
|
+
toString(node_details.node_map.node_properties.uuid) AS node_uuid,
|
|
89
|
+
node_details.node_map.node_properties.db_id AS node_db_id
|
|
89
90
|
MERGE (diff_root:DiffRoot {uuid: root_uuid})
|
|
90
|
-
MERGE (diff_root)-[:DIFF_HAS_NODE]->(diff_node:DiffNode {uuid: node_uuid})
|
|
91
|
+
MERGE (diff_root)-[:DIFF_HAS_NODE]->(diff_node:DiffNode {uuid: node_uuid, db_id: node_db_id})
|
|
91
92
|
WITH root_uuid, node_map, diff_node, (node_map.conflict_params IS NOT NULL) AS has_node_conflict
|
|
92
93
|
SET
|
|
93
94
|
diff_node.kind = node_map.node_properties.kind,
|
|
94
95
|
diff_node.label = node_map.node_properties.label,
|
|
95
96
|
diff_node.changed_at = node_map.node_properties.changed_at,
|
|
96
97
|
diff_node.action = node_map.node_properties.action,
|
|
98
|
+
diff_node.is_node_kind_migration = node_map.node_properties.is_node_kind_migration,
|
|
97
99
|
diff_node.path_identifier = node_map.node_properties.path_identifier
|
|
98
100
|
WITH root_uuid, node_map, diff_node, has_node_conflict
|
|
99
101
|
CALL {
|
|
@@ -401,6 +403,8 @@ FOREACH (i in CASE WHEN has_property_conflict = TRUE THEN [1] ELSE [] END |
|
|
|
401
403
|
"node_properties": {
|
|
402
404
|
"uuid": enriched_node.uuid,
|
|
403
405
|
"kind": enriched_node.kind,
|
|
406
|
+
"db_id": enriched_node.identifier.db_id,
|
|
407
|
+
"is_node_kind_migration": enriched_node.is_node_kind_migration,
|
|
404
408
|
"label": enriched_node.label,
|
|
405
409
|
"changed_at": enriched_node.changed_at.to_string() if enriched_node.changed_at else None,
|
|
406
410
|
"action": enriched_node.action.value,
|