infrahub-server 1.3.0a0__py3-none-any.whl → 1.3.0b2__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/tasks.py +4 -11
- infrahub/branch/__init__.py +0 -0
- infrahub/branch/tasks.py +29 -0
- infrahub/branch/triggers.py +22 -0
- infrahub/cli/db.py +2 -2
- infrahub/computed_attribute/gather.py +3 -1
- infrahub/computed_attribute/tasks.py +23 -29
- infrahub/core/attribute.py +3 -3
- infrahub/core/constants/__init__.py +10 -0
- infrahub/core/constants/database.py +1 -0
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/convert_object_type/conversion.py +1 -1
- infrahub/core/diff/query/save.py +67 -40
- infrahub/core/diff/query/time_range_query.py +0 -1
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/migrations/graph/__init__.py +6 -0
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +0 -2
- infrahub/core/migrations/graph/m029_duplicates_cleanup.py +662 -0
- infrahub/core/migrations/graph/m030_illegal_edges.py +82 -0
- infrahub/core/migrations/query/attribute_add.py +13 -9
- infrahub/core/migrations/query/attribute_rename.py +2 -4
- infrahub/core/migrations/query/delete_element_in_schema.py +16 -11
- infrahub/core/migrations/query/node_duplicate.py +16 -15
- infrahub/core/migrations/query/relationship_duplicate.py +16 -12
- infrahub/core/migrations/schema/node_attribute_remove.py +1 -2
- infrahub/core/migrations/schema/node_remove.py +16 -14
- infrahub/core/node/__init__.py +74 -14
- infrahub/core/node/base.py +1 -1
- infrahub/core/node/resource_manager/ip_address_pool.py +6 -2
- infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -2
- infrahub/core/node/resource_manager/number_pool.py +31 -5
- infrahub/core/node/standard.py +6 -1
- infrahub/core/path.py +1 -1
- infrahub/core/protocols.py +10 -0
- infrahub/core/query/node.py +1 -1
- infrahub/core/query/relationship.py +4 -6
- infrahub/core/query/standard_node.py +19 -5
- infrahub/core/relationship/constraints/peer_relatives.py +72 -0
- infrahub/core/relationship/model.py +1 -1
- infrahub/core/schema/attribute_parameters.py +129 -5
- infrahub/core/schema/attribute_schema.py +62 -14
- infrahub/core/schema/basenode_schema.py +2 -2
- infrahub/core/schema/definitions/core/__init__.py +16 -2
- infrahub/core/schema/definitions/core/group.py +45 -0
- infrahub/core/schema/definitions/core/resource_pool.py +29 -0
- infrahub/core/schema/definitions/internal.py +25 -4
- infrahub/core/schema/generated/attribute_schema.py +12 -5
- infrahub/core/schema/generated/relationship_schema.py +6 -1
- infrahub/core/schema/manager.py +7 -2
- infrahub/core/schema/schema_branch.py +69 -5
- infrahub/core/validators/__init__.py +8 -0
- infrahub/core/validators/attribute/choices.py +0 -1
- infrahub/core/validators/attribute/enum.py +0 -1
- infrahub/core/validators/attribute/kind.py +0 -1
- infrahub/core/validators/attribute/length.py +0 -1
- infrahub/core/validators/attribute/min_max.py +118 -0
- infrahub/core/validators/attribute/number_pool.py +106 -0
- infrahub/core/validators/attribute/optional.py +0 -2
- infrahub/core/validators/attribute/regex.py +0 -1
- infrahub/core/validators/enum.py +5 -0
- infrahub/core/validators/tasks.py +1 -1
- infrahub/database/__init__.py +16 -4
- infrahub/database/validation.py +100 -0
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +2 -0
- infrahub/dependencies/builder/constraint/relationship_manager/peer_relatives.py +8 -0
- infrahub/dependencies/builder/diff/deserializer.py +1 -1
- infrahub/dependencies/registry.py +2 -0
- infrahub/events/models.py +1 -1
- infrahub/git/base.py +5 -3
- infrahub/git/integrator.py +102 -3
- infrahub/graphql/mutations/main.py +1 -1
- infrahub/graphql/mutations/resource_manager.py +54 -6
- infrahub/graphql/queries/resource_manager.py +7 -1
- infrahub/graphql/queries/task.py +10 -0
- infrahub/graphql/resolvers/many_relationship.py +1 -1
- infrahub/graphql/resolvers/resolver.py +2 -2
- infrahub/graphql/resolvers/single_relationship.py +1 -1
- infrahub/graphql/types/task_log.py +3 -2
- infrahub/menu/menu.py +8 -7
- infrahub/message_bus/operations/refresh/registry.py +3 -3
- infrahub/patch/queries/delete_duplicated_edges.py +40 -29
- infrahub/pools/number.py +5 -3
- infrahub/pools/registration.py +22 -0
- infrahub/pools/tasks.py +56 -0
- infrahub/schema/__init__.py +0 -0
- infrahub/schema/tasks.py +27 -0
- infrahub/schema/triggers.py +23 -0
- infrahub/task_manager/task.py +44 -4
- infrahub/trigger/catalogue.py +4 -0
- infrahub/trigger/models.py +5 -4
- infrahub/trigger/setup.py +26 -2
- infrahub/trigger/tasks.py +1 -1
- infrahub/types.py +6 -0
- infrahub/webhook/tasks.py +6 -9
- infrahub/workflows/catalogue.py +27 -1
- infrahub_sdk/client.py +43 -10
- infrahub_sdk/node/__init__.py +39 -0
- infrahub_sdk/node/attribute.py +122 -0
- infrahub_sdk/node/constants.py +21 -0
- infrahub_sdk/{node.py → node/node.py} +50 -749
- infrahub_sdk/node/parsers.py +15 -0
- infrahub_sdk/node/property.py +24 -0
- infrahub_sdk/node/related_node.py +266 -0
- infrahub_sdk/node/relationship.py +302 -0
- infrahub_sdk/protocols.py +112 -0
- infrahub_sdk/protocols_base.py +34 -2
- infrahub_sdk/query_groups.py +13 -2
- infrahub_sdk/schema/main.py +1 -0
- infrahub_sdk/schema/repository.py +16 -0
- infrahub_sdk/spec/object.py +1 -1
- infrahub_sdk/store.py +1 -1
- infrahub_sdk/testing/schemas/car_person.py +1 -0
- {infrahub_server-1.3.0a0.dist-info → infrahub_server-1.3.0b2.dist-info}/METADATA +3 -3
- {infrahub_server-1.3.0a0.dist-info → infrahub_server-1.3.0b2.dist-info}/RECORD +122 -100
- {infrahub_server-1.3.0a0.dist-info → infrahub_server-1.3.0b2.dist-info}/WHEEL +1 -1
- infrahub_testcontainers/container.py +239 -64
- infrahub_testcontainers/docker-compose-cluster.test.yml +321 -0
- infrahub_testcontainers/docker-compose.test.yml +1 -0
- infrahub_testcontainers/helpers.py +15 -1
- infrahub_testcontainers/plugin.py +9 -0
- infrahub/patch/queries/consolidate_duplicated_nodes.py +0 -106
- {infrahub_server-1.3.0a0.dist-info → infrahub_server-1.3.0b2.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.3.0a0.dist-info → infrahub_server-1.3.0b2.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Sequence
|
|
4
|
+
|
|
5
|
+
from infrahub.core.migrations.shared import GraphMigration, MigrationResult
|
|
6
|
+
from infrahub.log import get_logger
|
|
7
|
+
|
|
8
|
+
from ...query import Query, QueryType
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from infrahub.database import InfrahubDatabase
|
|
12
|
+
|
|
13
|
+
log = get_logger()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DeletePosthumousEdges(Query):
|
|
17
|
+
name = "delete_posthumous_edges_query"
|
|
18
|
+
type = QueryType.WRITE
|
|
19
|
+
insert_return = False
|
|
20
|
+
|
|
21
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
22
|
+
query = """
|
|
23
|
+
// ------------
|
|
24
|
+
// find deleted nodes
|
|
25
|
+
// ------------
|
|
26
|
+
MATCH (n:Node)-[e:IS_PART_OF]->(:Root)
|
|
27
|
+
WHERE e.status = "deleted" OR e.to IS NOT NULL
|
|
28
|
+
WITH DISTINCT n, e.branch AS delete_branch, e.branch_level AS delete_branch_level, CASE
|
|
29
|
+
WHEN e.status = "deleted" THEN e.from
|
|
30
|
+
ELSE e.to
|
|
31
|
+
END AS delete_time
|
|
32
|
+
// ------------
|
|
33
|
+
// find the edges added to the deleted node after the delete time
|
|
34
|
+
// ------------
|
|
35
|
+
MATCH (n)-[added_e]-(peer)
|
|
36
|
+
WHERE added_e.from > delete_time
|
|
37
|
+
AND type(added_e) <> "IS_PART_OF"
|
|
38
|
+
// if the node was deleted on a branch (delete_branch_level > 1), and then updated on main/global (added_e.branch_level = 1), we can ignore it
|
|
39
|
+
AND added_e.branch_level >= delete_branch_level
|
|
40
|
+
AND (added_e.branch = delete_branch OR delete_branch_level = 1)
|
|
41
|
+
WITH DISTINCT n, delete_branch, delete_time, added_e, peer
|
|
42
|
+
// ------------
|
|
43
|
+
// get the branched_from for the branch on which the node was deleted
|
|
44
|
+
// ------------
|
|
45
|
+
CALL (added_e) {
|
|
46
|
+
MATCH (b:Branch {name: added_e.branch})
|
|
47
|
+
RETURN b.branched_from AS added_e_branched_from
|
|
48
|
+
}
|
|
49
|
+
// ------------
|
|
50
|
+
// account for the following situations, given that the edge update time is after the node delete time
|
|
51
|
+
// - deleted on main/global, updated on branch
|
|
52
|
+
// - illegal if the delete is before branch.branched_from
|
|
53
|
+
// - deleted on branch, updated on branch
|
|
54
|
+
// - illegal
|
|
55
|
+
// ------------
|
|
56
|
+
WITH n, delete_branch, delete_time, added_e, peer
|
|
57
|
+
WHERE delete_branch = added_e.branch
|
|
58
|
+
OR delete_time < added_e_branched_from
|
|
59
|
+
DELETE added_e
|
|
60
|
+
// --------------
|
|
61
|
+
// the peer _should_ only be an Attribute, but I want to make sure we don't
|
|
62
|
+
// inadvertently delete Root or an AttributeValue or a Boolean
|
|
63
|
+
// --------------
|
|
64
|
+
WITH peer
|
|
65
|
+
WHERE "Attribute" IN labels(peer)
|
|
66
|
+
DETACH DELETE peer
|
|
67
|
+
"""
|
|
68
|
+
self.add_to_query(query)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Migration030(GraphMigration):
|
|
72
|
+
"""
|
|
73
|
+
Edges could have been added to Nodes after the Node was deleted, so we need to hard-delete those illegal edges
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
name: str = "030_delete_illegal_edges"
|
|
77
|
+
minimum_version: int = 29
|
|
78
|
+
queries: Sequence[type[Query]] = [DeletePosthumousEdges]
|
|
79
|
+
|
|
80
|
+
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
81
|
+
result = MigrationResult()
|
|
82
|
+
return result
|
|
@@ -62,28 +62,32 @@ class AttributeAddQuery(Query):
|
|
|
62
62
|
WITH av, is_protected_value, is_visible_value
|
|
63
63
|
MATCH p = (n:%(node_kind)s)
|
|
64
64
|
CALL (n) {
|
|
65
|
-
MATCH (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
MATCH (:Root)<-[r:IS_PART_OF]-(n)
|
|
66
|
+
WHERE %(branch_filter)s
|
|
67
|
+
WITH n, r AS is_part_of_e
|
|
68
|
+
OPTIONAL MATCH (n)-[r:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name })
|
|
69
|
+
WHERE %(branch_filter)s
|
|
70
|
+
WITH is_part_of_e, r AS has_attr_e
|
|
71
|
+
RETURN is_part_of_e, has_attr_e
|
|
72
|
+
ORDER BY has_attr_e.branch_level DESC, has_attr_e.from ASC, is_part_of_e.branch_level DESC, is_part_of_e.from ASC
|
|
70
73
|
LIMIT 1
|
|
71
74
|
}
|
|
72
|
-
WITH
|
|
73
|
-
WHERE
|
|
75
|
+
WITH n, is_part_of_e, has_attr_e, av, is_protected_value, is_visible_value
|
|
76
|
+
WHERE is_part_of_e.status = "active" AND (has_attr_e IS NULL OR has_attr_e.status = "deleted")
|
|
74
77
|
CREATE (a:Attribute { name: $attr_name, branch_support: $branch_support })
|
|
75
78
|
CREATE (n)-[:HAS_ATTRIBUTE $rel_props ]->(a)
|
|
76
79
|
CREATE (a)-[:HAS_VALUE $rel_props ]->(av)
|
|
77
80
|
CREATE (a)-[:IS_PROTECTED $rel_props]->(is_protected_value)
|
|
78
81
|
CREATE (a)-[:IS_VISIBLE $rel_props]->(is_visible_value)
|
|
79
82
|
%(uuid_generation)s
|
|
80
|
-
FOREACH (i in CASE WHEN
|
|
81
|
-
SET
|
|
83
|
+
FOREACH (i in CASE WHEN has_attr_e.status = "deleted" THEN [1] ELSE [] END |
|
|
84
|
+
SET has_attr_e.to = $current_time
|
|
82
85
|
)
|
|
83
86
|
""" % {
|
|
84
87
|
"branch_filter": branch_filter,
|
|
85
88
|
"node_kind": self.node_kind,
|
|
86
89
|
"uuid_generation": db.render_uuid_generation(node_label="a", node_attr="uuid"),
|
|
87
90
|
}
|
|
91
|
+
|
|
88
92
|
self.add_to_query(query)
|
|
89
93
|
self.return_labels = ["n.uuid", "a.uuid"]
|
|
@@ -55,7 +55,6 @@ class AttributeRenameQuery(Query):
|
|
|
55
55
|
@staticmethod
|
|
56
56
|
def _render_sub_query_per_rel_type_update_active(rel_type: str, rel_def: FieldInfo) -> str:
|
|
57
57
|
subquery = [
|
|
58
|
-
"WITH peer_node, rb, active_attr",
|
|
59
58
|
"WITH peer_node, rb, active_attr",
|
|
60
59
|
f'WHERE type(rb) = "{rel_type}"',
|
|
61
60
|
]
|
|
@@ -72,7 +71,6 @@ class AttributeRenameQuery(Query):
|
|
|
72
71
|
@staticmethod
|
|
73
72
|
def _render_sub_query_per_rel_type_create_new(rel_type: str, rel_def: FieldInfo) -> str:
|
|
74
73
|
subquery = [
|
|
75
|
-
"WITH peer_node, rb, active_attr, new_attr",
|
|
76
74
|
"WITH peer_node, rb, active_attr, new_attr",
|
|
77
75
|
f'WHERE type(rb) = "{rel_type}"',
|
|
78
76
|
]
|
|
@@ -158,7 +156,7 @@ class AttributeRenameQuery(Query):
|
|
|
158
156
|
}
|
|
159
157
|
WITH a1 as active_attr, r1 as rb, p1 as peer_node, new_attr
|
|
160
158
|
WHERE rb.status = "active"
|
|
161
|
-
CALL {
|
|
159
|
+
CALL (peer_node, rb, active_attr, new_attr){
|
|
162
160
|
%(sub_query_create_all)s
|
|
163
161
|
}
|
|
164
162
|
WITH p2 as peer_node, rb, new_attr, active_attr
|
|
@@ -167,7 +165,7 @@ class AttributeRenameQuery(Query):
|
|
|
167
165
|
|
|
168
166
|
if not (self.branch.is_default or self.branch.is_global):
|
|
169
167
|
query = """
|
|
170
|
-
CALL {
|
|
168
|
+
CALL (peer_node, rb, active_attr) {
|
|
171
169
|
%(sub_query_update_all)s
|
|
172
170
|
}
|
|
173
171
|
WITH p2 as peer_node, rb, new_attr
|
|
@@ -55,7 +55,6 @@ class DeleteElementInSchemaQuery(Query):
|
|
|
55
55
|
@staticmethod
|
|
56
56
|
def _render_sub_query_per_rel_type(rel_name: str, rel_type: str, direction: GraphRelDirection) -> str:
|
|
57
57
|
subquery = [
|
|
58
|
-
f"WITH peer_node, {rel_name}, element_to_delete",
|
|
59
58
|
f"WITH peer_node, {rel_name}, element_to_delete",
|
|
60
59
|
f'WHERE type({rel_name}) = "{rel_type}"',
|
|
61
60
|
]
|
|
@@ -67,28 +66,32 @@ class DeleteElementInSchemaQuery(Query):
|
|
|
67
66
|
return "\n".join(subquery)
|
|
68
67
|
|
|
69
68
|
@classmethod
|
|
70
|
-
def _render_sub_query_out(cls) -> str:
|
|
69
|
+
def _render_sub_query_out(cls) -> tuple[str, str]:
|
|
70
|
+
rel_name = "rel_outband"
|
|
71
|
+
sub_query_out_args = f"peer_node, {rel_name}, element_to_delete"
|
|
71
72
|
sub_queries_out = [
|
|
72
73
|
cls._render_sub_query_per_rel_type(
|
|
73
|
-
rel_name=
|
|
74
|
+
rel_name=rel_name, rel_type=rel_type, direction=GraphRelDirection.OUTBOUND
|
|
74
75
|
)
|
|
75
76
|
for rel_type, rel_def in GraphNodeRelationships.model_fields.items()
|
|
76
77
|
if rel_def.default.direction in [GraphRelDirection.OUTBOUND, GraphRelDirection.EITHER]
|
|
77
78
|
]
|
|
78
79
|
sub_query_out = "\nUNION\n".join(sub_queries_out)
|
|
79
|
-
return sub_query_out
|
|
80
|
+
return sub_query_out, sub_query_out_args
|
|
80
81
|
|
|
81
82
|
@classmethod
|
|
82
|
-
def _render_sub_query_in(cls) -> str:
|
|
83
|
+
def _render_sub_query_in(cls) -> tuple[str, str]:
|
|
84
|
+
rel_name = "rel_inband"
|
|
85
|
+
sub_query_in_args = f"peer_node, {rel_name}, element_to_delete"
|
|
83
86
|
sub_queries_in = [
|
|
84
87
|
cls._render_sub_query_per_rel_type(
|
|
85
|
-
rel_name=
|
|
88
|
+
rel_name=rel_name, rel_type=rel_type, direction=GraphRelDirection.INBOUND
|
|
86
89
|
)
|
|
87
90
|
for rel_type, rel_def in GraphNodeRelationships.model_fields.items()
|
|
88
91
|
if rel_def.default.direction in [GraphRelDirection.INBOUND, GraphRelDirection.EITHER]
|
|
89
92
|
]
|
|
90
93
|
sub_query_in = "\nUNION\n".join(sub_queries_in)
|
|
91
|
-
return sub_query_in
|
|
94
|
+
return sub_query_in, sub_query_in_args
|
|
92
95
|
|
|
93
96
|
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
94
97
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
|
|
@@ -108,8 +111,8 @@ class DeleteElementInSchemaQuery(Query):
|
|
|
108
111
|
"from": self.at.to_string(),
|
|
109
112
|
}
|
|
110
113
|
|
|
111
|
-
sub_query_out = self._render_sub_query_out()
|
|
112
|
-
sub_query_in = self._render_sub_query_in()
|
|
114
|
+
sub_query_out, sub_query_out_args = self._render_sub_query_out()
|
|
115
|
+
sub_query_in, sub_query_in_args = self._render_sub_query_in()
|
|
113
116
|
|
|
114
117
|
self.add_to_query(self.render_match())
|
|
115
118
|
self.add_to_query(self.render_where())
|
|
@@ -138,7 +141,7 @@ class DeleteElementInSchemaQuery(Query):
|
|
|
138
141
|
}
|
|
139
142
|
WITH n1 as element_to_delete, rel_outband1 as rel_outband, p1 as peer_node
|
|
140
143
|
WHERE rel_outband.status = "active"
|
|
141
|
-
CALL {
|
|
144
|
+
CALL (%(sub_query_out_args)s) {
|
|
142
145
|
%(sub_query_out)s
|
|
143
146
|
}
|
|
144
147
|
WITH p2 as peer_node, rel_outband, element_to_delete
|
|
@@ -157,7 +160,7 @@ class DeleteElementInSchemaQuery(Query):
|
|
|
157
160
|
}
|
|
158
161
|
WITH n1 as element_to_delete, rel_inband1 as rel_inband, p1 as peer_node
|
|
159
162
|
WHERE rel_inband.status = "active"
|
|
160
|
-
CALL {
|
|
163
|
+
CALL (%(sub_query_in_args)s) {
|
|
161
164
|
%(sub_query_in)s
|
|
162
165
|
}
|
|
163
166
|
WITH p2 as peer_node, rel_inband, element_to_delete
|
|
@@ -169,5 +172,7 @@ class DeleteElementInSchemaQuery(Query):
|
|
|
169
172
|
"branch_filter": branch_filter,
|
|
170
173
|
"sub_query_out": sub_query_out,
|
|
171
174
|
"sub_query_in": sub_query_in,
|
|
175
|
+
"sub_query_out_args": sub_query_out_args,
|
|
176
|
+
"sub_query_in_args": sub_query_in_args,
|
|
172
177
|
}
|
|
173
178
|
self.add_to_query(query)
|
|
@@ -47,7 +47,6 @@ class NodeDuplicateQuery(Query):
|
|
|
47
47
|
@staticmethod
|
|
48
48
|
def _render_sub_query_per_rel_type(rel_name: str, rel_type: str, rel_dir: GraphRelDirection) -> str:
|
|
49
49
|
subquery = [
|
|
50
|
-
f"WITH peer_node, {rel_name}, active_node, new_node",
|
|
51
50
|
f"WITH peer_node, {rel_name}, active_node, new_node",
|
|
52
51
|
f'WHERE type({rel_name}) = "{rel_type}"',
|
|
53
52
|
]
|
|
@@ -81,28 +80,28 @@ class NodeDuplicateQuery(Query):
|
|
|
81
80
|
return "\n".join(subquery)
|
|
82
81
|
|
|
83
82
|
@classmethod
|
|
84
|
-
def _render_sub_query_out(cls) -> str:
|
|
83
|
+
def _render_sub_query_out(cls) -> tuple[str, str]:
|
|
84
|
+
rel_name = "rel_outband"
|
|
85
|
+
sub_query_out_args = f"peer_node, {rel_name}, active_node, new_node"
|
|
85
86
|
sub_queries_out = [
|
|
86
|
-
cls._render_sub_query_per_rel_type(
|
|
87
|
-
rel_name="rel_outband", rel_type=rel_type, rel_dir=GraphRelDirection.OUTBOUND
|
|
88
|
-
)
|
|
87
|
+
cls._render_sub_query_per_rel_type(rel_name=rel_name, rel_type=rel_type, rel_dir=GraphRelDirection.OUTBOUND)
|
|
89
88
|
for rel_type, field_info in GraphNodeRelationships.model_fields.items()
|
|
90
89
|
if field_info.default.direction in (GraphRelDirection.OUTBOUND, GraphRelDirection.EITHER)
|
|
91
90
|
]
|
|
92
91
|
sub_query_out = "\nUNION\n".join(sub_queries_out)
|
|
93
|
-
return sub_query_out
|
|
92
|
+
return sub_query_out, sub_query_out_args
|
|
94
93
|
|
|
95
94
|
@classmethod
|
|
96
|
-
def _render_sub_query_in(cls) -> str:
|
|
95
|
+
def _render_sub_query_in(cls) -> tuple[str, str]:
|
|
96
|
+
rel_name = "rel_inband"
|
|
97
|
+
sub_query_in_args = f"peer_node, {rel_name}, active_node, new_node"
|
|
97
98
|
sub_queries_in = [
|
|
98
|
-
cls._render_sub_query_per_rel_type(
|
|
99
|
-
rel_name="rel_inband", rel_type=rel_type, rel_dir=GraphRelDirection.INBOUND
|
|
100
|
-
)
|
|
99
|
+
cls._render_sub_query_per_rel_type(rel_name=rel_name, rel_type=rel_type, rel_dir=GraphRelDirection.INBOUND)
|
|
101
100
|
for rel_type, field_info in GraphNodeRelationships.model_fields.items()
|
|
102
101
|
if field_info.default.direction in (GraphRelDirection.INBOUND, GraphRelDirection.EITHER)
|
|
103
102
|
]
|
|
104
103
|
sub_query_in = "\nUNION\n".join(sub_queries_in)
|
|
105
|
-
return sub_query_in
|
|
104
|
+
return sub_query_in, sub_query_in_args
|
|
106
105
|
|
|
107
106
|
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
108
107
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
|
|
@@ -126,8 +125,8 @@ class NodeDuplicateQuery(Query):
|
|
|
126
125
|
"from": self.at.to_string(),
|
|
127
126
|
}
|
|
128
127
|
|
|
129
|
-
sub_query_out = self._render_sub_query_out()
|
|
130
|
-
sub_query_in = self._render_sub_query_in()
|
|
128
|
+
sub_query_out, sub_query_out_args = self._render_sub_query_out()
|
|
129
|
+
sub_query_in, sub_query_in_args = self._render_sub_query_in()
|
|
131
130
|
|
|
132
131
|
self.add_to_query(self.render_match())
|
|
133
132
|
|
|
@@ -155,7 +154,7 @@ class NodeDuplicateQuery(Query):
|
|
|
155
154
|
}
|
|
156
155
|
WITH n1 as active_node, rel_outband1 as rel_outband, p1 as peer_node, new_node
|
|
157
156
|
WHERE rel_outband.status = "active" AND rel_outband.to IS NULL
|
|
158
|
-
CALL {
|
|
157
|
+
CALL (%(sub_query_out_args)s) {
|
|
159
158
|
%(sub_query_out)s
|
|
160
159
|
}
|
|
161
160
|
WITH p2 as peer_node, rel_outband, active_node, new_node
|
|
@@ -174,7 +173,7 @@ class NodeDuplicateQuery(Query):
|
|
|
174
173
|
}
|
|
175
174
|
WITH n1 as active_node, rel_inband1 as rel_inband, p1 as peer_node, new_node
|
|
176
175
|
WHERE rel_inband.status = "active" AND rel_inband.to IS NULL
|
|
177
|
-
CALL {
|
|
176
|
+
CALL (%(sub_query_in_args)s) {
|
|
178
177
|
%(sub_query_in)s
|
|
179
178
|
}
|
|
180
179
|
WITH p2 as peer_node, rel_inband, active_node, new_node
|
|
@@ -188,5 +187,7 @@ class NodeDuplicateQuery(Query):
|
|
|
188
187
|
"labels": ":".join(self.new_node.labels),
|
|
189
188
|
"sub_query_out": sub_query_out,
|
|
190
189
|
"sub_query_in": sub_query_in,
|
|
190
|
+
"sub_query_out_args": sub_query_out_args,
|
|
191
|
+
"sub_query_in_args": sub_query_in_args,
|
|
191
192
|
}
|
|
192
193
|
self.add_to_query(query)
|
|
@@ -47,7 +47,6 @@ class RelationshipDuplicateQuery(Query):
|
|
|
47
47
|
@staticmethod
|
|
48
48
|
def _render_sub_query_per_rel_type(rel_name: str, rel_type: str, direction: GraphRelDirection) -> str:
|
|
49
49
|
subquery = [
|
|
50
|
-
f"WITH peer_node, {rel_name}, active_rel, new_rel",
|
|
51
50
|
f"WITH peer_node, {rel_name}, active_rel, new_rel",
|
|
52
51
|
f'WHERE type({rel_name}) = "{rel_type}"',
|
|
53
52
|
]
|
|
@@ -61,28 +60,32 @@ class RelationshipDuplicateQuery(Query):
|
|
|
61
60
|
return "\n".join(subquery)
|
|
62
61
|
|
|
63
62
|
@classmethod
|
|
64
|
-
def _render_sub_query_out(cls) -> str:
|
|
63
|
+
def _render_sub_query_out(cls) -> tuple[str, str]:
|
|
64
|
+
rel_name = "rel_outband"
|
|
65
|
+
sub_query_out_args = f"peer_node, {rel_name}, active_rel, new_rel"
|
|
65
66
|
sub_queries_out = [
|
|
66
67
|
cls._render_sub_query_per_rel_type(
|
|
67
|
-
rel_name=
|
|
68
|
+
rel_name=rel_name, rel_type=rel_type, direction=GraphRelDirection.OUTBOUND
|
|
68
69
|
)
|
|
69
70
|
for rel_type, rel_def in GraphRelationshipRelationships.model_fields.items()
|
|
70
71
|
if rel_def.default.direction in [GraphRelDirection.OUTBOUND, GraphRelDirection.EITHER]
|
|
71
72
|
]
|
|
72
73
|
sub_query_out = "\nUNION\n".join(sub_queries_out)
|
|
73
|
-
return sub_query_out
|
|
74
|
+
return sub_query_out, sub_query_out_args
|
|
74
75
|
|
|
75
76
|
@classmethod
|
|
76
|
-
def _render_sub_query_in(cls) -> str:
|
|
77
|
+
def _render_sub_query_in(cls) -> tuple[str, str]:
|
|
78
|
+
rel_name = "rel_inband"
|
|
79
|
+
sub_query_in_args = f"peer_node, {rel_name}, active_rel, new_rel"
|
|
77
80
|
sub_queries_in = [
|
|
78
81
|
cls._render_sub_query_per_rel_type(
|
|
79
|
-
rel_name=
|
|
82
|
+
rel_name=rel_name, rel_type=rel_type, direction=GraphRelDirection.INBOUND
|
|
80
83
|
)
|
|
81
84
|
for rel_type, rel_def in GraphRelationshipRelationships.model_fields.items()
|
|
82
85
|
if rel_def.default.direction in [GraphRelDirection.INBOUND, GraphRelDirection.EITHER]
|
|
83
86
|
]
|
|
84
87
|
sub_query_in = "\nUNION\n".join(sub_queries_in)
|
|
85
|
-
return sub_query_in
|
|
88
|
+
return sub_query_in, sub_query_in_args
|
|
86
89
|
|
|
87
90
|
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
88
91
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
|
|
@@ -109,12 +112,11 @@ class RelationshipDuplicateQuery(Query):
|
|
|
109
112
|
"from": self.at.to_string(),
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
sub_query_out = self._render_sub_query_out()
|
|
113
|
-
sub_query_in = self._render_sub_query_in()
|
|
115
|
+
sub_query_out, sub_query_out_args = self._render_sub_query_out()
|
|
116
|
+
sub_query_in, sub_query_in_args = self._render_sub_query_in()
|
|
114
117
|
|
|
115
118
|
self.add_to_query(self.render_match())
|
|
116
119
|
|
|
117
|
-
# ruff: noqa: E501
|
|
118
120
|
query = """
|
|
119
121
|
CALL (source, rel, destination) {
|
|
120
122
|
MATCH path = (source)-[r1:IS_RELATED]-(rel)-[r2:IS_RELATED]-(destination)
|
|
@@ -138,7 +140,7 @@ class RelationshipDuplicateQuery(Query):
|
|
|
138
140
|
}
|
|
139
141
|
WITH n1 as active_rel, rel_inband1 as rel_inband, p1 as peer_node, new_rel
|
|
140
142
|
WHERE rel_inband.status = "active"
|
|
141
|
-
CALL {
|
|
143
|
+
CALL (%(sub_query_in_args)s) {
|
|
142
144
|
%(sub_query_in)s
|
|
143
145
|
}
|
|
144
146
|
WITH p2 as peer_node, rel_inband, active_rel, new_rel
|
|
@@ -157,7 +159,7 @@ class RelationshipDuplicateQuery(Query):
|
|
|
157
159
|
}
|
|
158
160
|
WITH n1 as active_rel, rel_outband1 as rel_outband, p1 as peer_node, new_rel
|
|
159
161
|
WHERE rel_outband.status = "active"
|
|
160
|
-
CALL {
|
|
162
|
+
CALL (%(sub_query_out_args)s) {
|
|
161
163
|
%(sub_query_out)s
|
|
162
164
|
}
|
|
163
165
|
WITH p2 as peer_node, rel_outband, active_rel, new_rel
|
|
@@ -169,5 +171,7 @@ class RelationshipDuplicateQuery(Query):
|
|
|
169
171
|
"branch_filter": branch_filter,
|
|
170
172
|
"sub_query_out": sub_query_out,
|
|
171
173
|
"sub_query_in": sub_query_in,
|
|
174
|
+
"sub_query_in_args": sub_query_in_args,
|
|
175
|
+
"sub_query_out_args": sub_query_out_args,
|
|
172
176
|
}
|
|
173
177
|
self.add_to_query(query)
|
|
@@ -50,7 +50,6 @@ class NodeAttributeRemoveMigrationQuery01(AttributeMigrationQuery):
|
|
|
50
50
|
|
|
51
51
|
def render_sub_query_per_rel_type(rel_type: str, rel_def: FieldInfo) -> str:
|
|
52
52
|
subquery = [
|
|
53
|
-
"WITH peer_node, rb, active_attr",
|
|
54
53
|
"WITH peer_node, rb, active_attr",
|
|
55
54
|
f'WHERE type(rb) = "{rel_type}"',
|
|
56
55
|
]
|
|
@@ -105,7 +104,7 @@ class NodeAttributeRemoveMigrationQuery01(AttributeMigrationQuery):
|
|
|
105
104
|
}
|
|
106
105
|
WITH a1 as active_attr, r1 as rb, p1 as peer_node
|
|
107
106
|
WHERE rb.status = "active"
|
|
108
|
-
CALL {
|
|
107
|
+
CALL (peer_node, rb, active_attr) {
|
|
109
108
|
%(sub_query_all)s
|
|
110
109
|
}
|
|
111
110
|
WITH p2 as peer_node, rb, active_attr
|
|
@@ -21,7 +21,6 @@ class NodeRemoveMigrationBaseQuery(MigrationQuery):
|
|
|
21
21
|
rel_def: FieldInfo,
|
|
22
22
|
) -> str:
|
|
23
23
|
subquery = [
|
|
24
|
-
f"WITH peer_node, {rel_name}, active_node",
|
|
25
24
|
f"WITH peer_node, {rel_name}, active_node",
|
|
26
25
|
f'WHERE type({rel_name}) = "{rel_type}"',
|
|
27
26
|
]
|
|
@@ -59,7 +58,6 @@ class NodeRemoveMigrationBaseQuery(MigrationQuery):
|
|
|
59
58
|
|
|
60
59
|
node_remove_query = self.render_node_remove_query(branch_filter=branch_filter)
|
|
61
60
|
|
|
62
|
-
# ruff: noqa: E501
|
|
63
61
|
query = """
|
|
64
62
|
// Find all the active nodes
|
|
65
63
|
MATCH (node:%(node_kind)s)
|
|
@@ -90,7 +88,7 @@ class NodeRemoveMigrationQueryIn(NodeRemoveMigrationBaseQuery):
|
|
|
90
88
|
insert_return: bool = False
|
|
91
89
|
|
|
92
90
|
def render_node_remove_query(self, branch_filter: str) -> str:
|
|
93
|
-
sub_query = self.render_sub_query_in()
|
|
91
|
+
sub_query, sub_query_args = self.render_sub_query_in()
|
|
94
92
|
query = """
|
|
95
93
|
// Process Inbound Relationship
|
|
96
94
|
WITH active_node
|
|
@@ -104,27 +102,29 @@ class NodeRemoveMigrationQueryIn(NodeRemoveMigrationBaseQuery):
|
|
|
104
102
|
}
|
|
105
103
|
WITH n1 as active_node, rel_inband1 as rel_inband, p1 as peer_node
|
|
106
104
|
WHERE rel_inband.status = "active"
|
|
107
|
-
CALL {
|
|
105
|
+
CALL (%(sub_query_args)s) {
|
|
108
106
|
%(sub_query)s
|
|
109
107
|
}
|
|
110
108
|
WITH p2 as peer_node, rel_inband, active_node
|
|
111
109
|
FOREACH (i in CASE WHEN rel_inband.branch IN ["-global-", $branch] THEN [1] ELSE [] END |
|
|
112
110
|
SET rel_inband.to = $current_time
|
|
113
111
|
)
|
|
114
|
-
""" % {"sub_query": sub_query, "branch_filter": branch_filter}
|
|
112
|
+
""" % {"sub_query": sub_query, "sub_query_args": sub_query_args, "branch_filter": branch_filter}
|
|
115
113
|
return query
|
|
116
114
|
|
|
117
|
-
def render_sub_query_in(self) -> str:
|
|
115
|
+
def render_sub_query_in(self) -> tuple[str, str]:
|
|
116
|
+
rel_name = "rel_inband"
|
|
117
|
+
sub_query_in_args = f"peer_node, {rel_name}, active_node"
|
|
118
118
|
sub_queries_in = [
|
|
119
119
|
self.render_sub_query_per_rel_type(
|
|
120
|
-
rel_name=
|
|
120
|
+
rel_name=rel_name,
|
|
121
121
|
rel_type=rel_type,
|
|
122
122
|
rel_def=rel_def,
|
|
123
123
|
)
|
|
124
124
|
for rel_type, rel_def in GraphNodeRelationships.model_fields.items()
|
|
125
125
|
]
|
|
126
126
|
sub_query_in = "\nUNION\n".join(sub_queries_in)
|
|
127
|
-
return sub_query_in
|
|
127
|
+
return sub_query_in, sub_query_in_args
|
|
128
128
|
|
|
129
129
|
def get_nbr_migrations_executed(self) -> int:
|
|
130
130
|
return 0
|
|
@@ -135,7 +135,7 @@ class NodeRemoveMigrationQueryOut(NodeRemoveMigrationBaseQuery):
|
|
|
135
135
|
insert_return: bool = False
|
|
136
136
|
|
|
137
137
|
def render_node_remove_query(self, branch_filter: str) -> str:
|
|
138
|
-
sub_query = self.render_sub_query_out()
|
|
138
|
+
sub_query, sub_query_args = self.render_sub_query_out()
|
|
139
139
|
query = """
|
|
140
140
|
// Process Outbound Relationship
|
|
141
141
|
WITH active_node
|
|
@@ -149,27 +149,29 @@ class NodeRemoveMigrationQueryOut(NodeRemoveMigrationBaseQuery):
|
|
|
149
149
|
}
|
|
150
150
|
WITH n1 as active_node, rel_outband1 as rel_outband, p1 as peer_node
|
|
151
151
|
WHERE rel_outband.status = "active"
|
|
152
|
-
CALL {
|
|
152
|
+
CALL (%(sub_query_args)s) {
|
|
153
153
|
%(sub_query)s
|
|
154
154
|
}
|
|
155
155
|
FOREACH (i in CASE WHEN rel_outband.branch IN ["-global-", $branch] THEN [1] ELSE [] END |
|
|
156
156
|
SET rel_outband.to = $current_time
|
|
157
157
|
)
|
|
158
|
-
""" % {"sub_query": sub_query, "branch_filter": branch_filter}
|
|
158
|
+
""" % {"sub_query": sub_query, "sub_query_args": sub_query_args, "branch_filter": branch_filter}
|
|
159
159
|
|
|
160
160
|
return query
|
|
161
161
|
|
|
162
|
-
def render_sub_query_out(self) -> str:
|
|
162
|
+
def render_sub_query_out(self) -> tuple[str, str]:
|
|
163
|
+
rel_name = "rel_outband"
|
|
164
|
+
sub_query_out_args = f"peer_node, {rel_name}, active_node"
|
|
163
165
|
sub_queries_out = [
|
|
164
166
|
self.render_sub_query_per_rel_type(
|
|
165
|
-
rel_name=
|
|
167
|
+
rel_name=rel_name,
|
|
166
168
|
rel_type=rel_type,
|
|
167
169
|
rel_def=rel_def,
|
|
168
170
|
)
|
|
169
171
|
for rel_type, rel_def in GraphNodeRelationships.model_fields.items()
|
|
170
172
|
]
|
|
171
173
|
sub_query_out = "\nUNION\n".join(sub_queries_out)
|
|
172
|
-
return sub_query_out
|
|
174
|
+
return sub_query_out, sub_query_out_args
|
|
173
175
|
|
|
174
176
|
def get_nbr_migrations_executed(self) -> int:
|
|
175
177
|
return self.num_of_results
|