infrahub-server 1.6.2__py3-none-any.whl → 1.7.0__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 -2
- infrahub/api/exceptions.py +2 -2
- infrahub/api/schema.py +3 -1
- infrahub/artifacts/tasks.py +1 -0
- infrahub/auth.py +2 -2
- infrahub/cli/db.py +54 -28
- infrahub/computed_attribute/gather.py +3 -4
- infrahub/computed_attribute/tasks.py +23 -6
- infrahub/config.py +8 -0
- infrahub/constants/enums.py +12 -0
- infrahub/core/account.py +12 -9
- infrahub/core/attribute.py +106 -108
- infrahub/core/branch/models.py +44 -71
- infrahub/core/branch/tasks.py +5 -3
- infrahub/core/changelog/diff.py +1 -20
- infrahub/core/changelog/models.py +0 -7
- infrahub/core/constants/__init__.py +17 -0
- infrahub/core/constants/database.py +0 -1
- infrahub/core/constants/schema.py +0 -1
- infrahub/core/convert_object_type/repository_conversion.py +3 -4
- infrahub/core/diff/branch_differ.py +1 -1
- infrahub/core/diff/conflict_transferer.py +1 -1
- infrahub/core/diff/data_check_synchronizer.py +4 -3
- infrahub/core/diff/enricher/cardinality_one.py +2 -2
- infrahub/core/diff/enricher/hierarchy.py +1 -1
- infrahub/core/diff/enricher/labels.py +1 -1
- infrahub/core/diff/merger/merger.py +28 -2
- infrahub/core/diff/merger/serializer.py +3 -10
- infrahub/core/diff/model/diff.py +1 -1
- infrahub/core/diff/query/merge.py +376 -135
- infrahub/core/diff/repository/repository.py +3 -1
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/constraints.py +3 -3
- infrahub/core/graph/schema.py +2 -12
- infrahub/core/ipam/reconciler.py +8 -6
- infrahub/core/ipam/utilization.py +8 -15
- infrahub/core/manager.py +133 -152
- infrahub/core/merge.py +1 -1
- infrahub/core/metadata/__init__.py +0 -0
- infrahub/core/metadata/interface.py +37 -0
- infrahub/core/metadata/model.py +31 -0
- infrahub/core/metadata/query/__init__.py +0 -0
- infrahub/core/metadata/query/node_metadata.py +301 -0
- infrahub/core/migrations/graph/__init__.py +4 -0
- infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -12
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -12
- infrahub/core/migrations/graph/m017_add_core_profile.py +5 -2
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -1
- infrahub/core/migrations/graph/m019_restore_rels_to_time.py +0 -10
- infrahub/core/migrations/graph/m020_duplicate_edges.py +0 -8
- infrahub/core/migrations/graph/m025_uniqueness_nulls.py +2 -1
- infrahub/core/migrations/graph/m026_0000_prefix_fix.py +2 -1
- infrahub/core/migrations/graph/m029_duplicates_cleanup.py +0 -1
- infrahub/core/migrations/graph/m031_check_number_attributes.py +2 -2
- infrahub/core/migrations/graph/m038_redo_0000_prefix_fix.py +2 -1
- infrahub/core/migrations/graph/m041_deleted_dup_edges.py +1 -1
- infrahub/core/migrations/graph/m049_remove_is_visible_relationship.py +53 -0
- infrahub/core/migrations/graph/m050_backfill_vertex_metadata.py +168 -0
- infrahub/core/migrations/query/__init__.py +2 -2
- infrahub/core/migrations/query/attribute_add.py +17 -6
- infrahub/core/migrations/query/attribute_remove.py +19 -5
- infrahub/core/migrations/query/attribute_rename.py +21 -5
- infrahub/core/migrations/query/node_duplicate.py +19 -4
- infrahub/core/migrations/query/schema_attribute_update.py +1 -1
- infrahub/core/migrations/schema/attribute_kind_update.py +26 -6
- infrahub/core/migrations/schema/attribute_name_update.py +1 -1
- infrahub/core/migrations/schema/attribute_supports_profile.py +5 -3
- infrahub/core/migrations/schema/models.py +3 -0
- infrahub/core/migrations/schema/node_attribute_add.py +5 -2
- infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
- infrahub/core/migrations/schema/node_kind_update.py +1 -1
- infrahub/core/migrations/schema/node_remove.py +24 -2
- infrahub/core/migrations/schema/tasks.py +4 -1
- infrahub/core/migrations/shared.py +13 -6
- infrahub/core/models.py +6 -6
- infrahub/core/node/__init__.py +157 -58
- infrahub/core/node/base.py +9 -5
- infrahub/core/node/create.py +7 -3
- infrahub/core/node/delete_validator.py +1 -1
- infrahub/core/node/standard.py +100 -14
- infrahub/core/order.py +30 -0
- infrahub/core/property.py +0 -1
- infrahub/core/protocols.py +1 -0
- infrahub/core/protocols_base.py +10 -2
- infrahub/core/query/__init__.py +11 -6
- infrahub/core/query/attribute.py +164 -49
- infrahub/core/query/branch.py +58 -70
- infrahub/core/query/delete.py +1 -1
- infrahub/core/query/diff.py +7 -7
- infrahub/core/query/ipam.py +104 -43
- infrahub/core/query/node.py +1072 -281
- infrahub/core/query/relationship.py +531 -325
- infrahub/core/query/resource_manager.py +107 -18
- infrahub/core/query/standard_node.py +25 -5
- infrahub/core/query/utils.py +2 -4
- infrahub/core/relationship/constraints/count.py +1 -1
- infrahub/core/relationship/constraints/peer_kind.py +1 -1
- infrahub/core/relationship/constraints/peer_parent.py +1 -1
- infrahub/core/relationship/constraints/peer_relatives.py +1 -1
- infrahub/core/relationship/constraints/profiles_kind.py +1 -1
- infrahub/core/relationship/constraints/profiles_removal.py +168 -0
- infrahub/core/relationship/model.py +293 -139
- infrahub/core/schema/attribute_parameters.py +28 -1
- infrahub/core/schema/attribute_schema.py +11 -17
- infrahub/core/schema/basenode_schema.py +3 -0
- infrahub/core/schema/definitions/core/__init__.py +8 -2
- infrahub/core/schema/definitions/core/account.py +10 -10
- infrahub/core/schema/definitions/core/artifact.py +14 -8
- infrahub/core/schema/definitions/core/check.py +10 -4
- infrahub/core/schema/definitions/core/generator.py +26 -6
- infrahub/core/schema/definitions/core/graphql_query.py +1 -1
- infrahub/core/schema/definitions/core/group.py +9 -2
- infrahub/core/schema/definitions/core/ipam.py +80 -10
- infrahub/core/schema/definitions/core/menu.py +41 -7
- infrahub/core/schema/definitions/core/permission.py +16 -2
- infrahub/core/schema/definitions/core/profile.py +16 -2
- infrahub/core/schema/definitions/core/propose_change.py +24 -4
- infrahub/core/schema/definitions/core/propose_change_comment.py +23 -11
- infrahub/core/schema/definitions/core/propose_change_validator.py +50 -21
- infrahub/core/schema/definitions/core/repository.py +10 -0
- infrahub/core/schema/definitions/core/resource_pool.py +8 -1
- infrahub/core/schema/definitions/core/template.py +19 -2
- infrahub/core/schema/definitions/core/transform.py +11 -5
- infrahub/core/schema/definitions/core/webhook.py +27 -9
- infrahub/core/schema/manager.py +63 -43
- infrahub/core/schema/relationship_schema.py +6 -2
- infrahub/core/schema/schema_branch.py +115 -11
- infrahub/core/task/task.py +4 -2
- infrahub/core/utils.py +3 -25
- infrahub/core/validators/aggregated_checker.py +1 -1
- infrahub/core/validators/attribute/choices.py +1 -1
- infrahub/core/validators/attribute/enum.py +1 -1
- infrahub/core/validators/attribute/kind.py +6 -3
- infrahub/core/validators/attribute/length.py +1 -1
- infrahub/core/validators/attribute/min_max.py +1 -1
- infrahub/core/validators/attribute/number_pool.py +1 -1
- infrahub/core/validators/attribute/optional.py +1 -1
- infrahub/core/validators/attribute/regex.py +1 -1
- infrahub/core/validators/determiner.py +3 -3
- infrahub/core/validators/node/attribute.py +1 -1
- infrahub/core/validators/node/relationship.py +1 -1
- infrahub/core/validators/relationship/peer.py +1 -1
- infrahub/database/__init__.py +4 -4
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +2 -0
- infrahub/dependencies/builder/constraint/relationship_manager/profiles_removal.py +8 -0
- infrahub/dependencies/registry.py +2 -0
- infrahub/display_labels/tasks.py +12 -3
- infrahub/git/integrator.py +18 -18
- infrahub/git/tasks.py +1 -1
- infrahub/git/utils.py +1 -1
- infrahub/graphql/app.py +2 -2
- infrahub/graphql/constants.py +3 -0
- infrahub/graphql/context.py +1 -1
- infrahub/graphql/field_extractor.py +1 -1
- infrahub/graphql/initialization.py +11 -0
- infrahub/graphql/loaders/account.py +134 -0
- infrahub/graphql/loaders/node.py +5 -12
- infrahub/graphql/loaders/peers.py +5 -7
- infrahub/graphql/manager.py +175 -21
- infrahub/graphql/metadata.py +91 -0
- infrahub/graphql/mutations/account.py +6 -6
- infrahub/graphql/mutations/attribute.py +0 -2
- infrahub/graphql/mutations/branch.py +9 -5
- infrahub/graphql/mutations/computed_attribute.py +1 -1
- infrahub/graphql/mutations/display_label.py +1 -1
- infrahub/graphql/mutations/hfid.py +1 -1
- infrahub/graphql/mutations/ipam.py +4 -6
- infrahub/graphql/mutations/main.py +9 -4
- infrahub/graphql/mutations/profile.py +16 -22
- infrahub/graphql/mutations/proposed_change.py +4 -4
- infrahub/graphql/mutations/relationship.py +40 -10
- infrahub/graphql/mutations/repository.py +14 -12
- infrahub/graphql/mutations/schema.py +2 -2
- infrahub/graphql/order.py +14 -0
- infrahub/graphql/queries/branch.py +62 -6
- infrahub/graphql/queries/diff/tree.py +5 -5
- infrahub/graphql/queries/resource_manager.py +25 -24
- infrahub/graphql/resolvers/account_metadata.py +84 -0
- infrahub/graphql/resolvers/ipam.py +6 -8
- infrahub/graphql/resolvers/many_relationship.py +77 -35
- infrahub/graphql/resolvers/resolver.py +59 -14
- infrahub/graphql/resolvers/single_relationship.py +87 -23
- infrahub/graphql/subscription/graphql_query.py +2 -0
- infrahub/graphql/types/__init__.py +0 -1
- infrahub/graphql/types/attribute.py +10 -5
- infrahub/graphql/types/branch.py +40 -53
- infrahub/graphql/types/enums.py +3 -0
- infrahub/graphql/types/metadata.py +28 -0
- infrahub/graphql/types/node.py +22 -2
- infrahub/graphql/types/relationship.py +10 -2
- infrahub/graphql/types/standard_node.py +12 -7
- infrahub/hfid/tasks.py +12 -3
- infrahub/lock.py +7 -0
- infrahub/menu/repository.py +1 -1
- infrahub/patch/queries/base.py +1 -1
- infrahub/pools/number.py +1 -8
- infrahub/profiles/gather.py +56 -0
- infrahub/profiles/mandatory_fields_checker.py +116 -0
- infrahub/profiles/models.py +66 -0
- infrahub/profiles/node_applier.py +154 -13
- infrahub/profiles/queries/get_profile_data.py +143 -31
- infrahub/profiles/tasks.py +79 -27
- infrahub/profiles/triggers.py +22 -0
- infrahub/proposed_change/action_checker.py +1 -1
- infrahub/proposed_change/tasks.py +4 -1
- infrahub/services/__init__.py +1 -1
- infrahub/services/adapters/cache/nats.py +1 -1
- infrahub/services/adapters/cache/redis.py +7 -0
- infrahub/tasks/artifact.py +1 -0
- infrahub/transformations/tasks.py +2 -2
- infrahub/trigger/catalogue.py +2 -0
- infrahub/trigger/models.py +1 -0
- infrahub/trigger/setup.py +3 -3
- infrahub/trigger/tasks.py +3 -0
- infrahub/validators/tasks.py +1 -0
- infrahub/webhook/gather.py +1 -1
- infrahub/webhook/models.py +1 -1
- infrahub/webhook/tasks.py +23 -7
- infrahub/workers/dependencies.py +9 -3
- infrahub/workers/infrahub_async.py +13 -4
- infrahub/workflows/catalogue.py +19 -0
- infrahub_sdk/analyzer.py +2 -2
- infrahub_sdk/branch.py +12 -39
- infrahub_sdk/checks.py +4 -4
- infrahub_sdk/client.py +36 -0
- infrahub_sdk/ctl/cli_commands.py +2 -1
- infrahub_sdk/ctl/graphql.py +15 -4
- infrahub_sdk/ctl/utils.py +2 -2
- infrahub_sdk/enums.py +6 -0
- infrahub_sdk/graphql/renderers.py +21 -0
- infrahub_sdk/graphql/utils.py +85 -0
- infrahub_sdk/node/attribute.py +12 -2
- infrahub_sdk/node/constants.py +12 -0
- infrahub_sdk/node/metadata.py +69 -0
- infrahub_sdk/node/node.py +65 -14
- infrahub_sdk/node/property.py +3 -0
- infrahub_sdk/node/related_node.py +37 -5
- infrahub_sdk/node/relationship.py +18 -1
- infrahub_sdk/operation.py +2 -2
- infrahub_sdk/schema/repository.py +1 -2
- infrahub_sdk/transforms.py +2 -2
- infrahub_sdk/types.py +18 -2
- {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/METADATA +17 -16
- {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/RECORD +252 -231
- infrahub_testcontainers/container.py +3 -3
- infrahub_testcontainers/docker-compose-cluster.test.yml +7 -7
- infrahub_testcontainers/docker-compose.test.yml +13 -5
- infrahub_testcontainers/models.py +3 -3
- infrahub_testcontainers/performance_test.py +1 -1
- infrahub/graphql/models.py +0 -6
- {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/entry_points.txt +0 -0
- {infrahub_server-1.6.2.dist-info → infrahub_server-1.7.0.dist-info}/licenses/LICENSE.txt +0 -0
infrahub/core/query/attribute.py
CHANGED
|
@@ -31,7 +31,7 @@ class AttributeQuery(Query):
|
|
|
31
31
|
at: Timestamp | str | None = None,
|
|
32
32
|
branch: Branch | None = None,
|
|
33
33
|
**kwargs: Any,
|
|
34
|
-
):
|
|
34
|
+
) -> None:
|
|
35
35
|
self.attr = attr
|
|
36
36
|
self.attr_id = attr_id or attr.db_id
|
|
37
37
|
|
|
@@ -48,13 +48,14 @@ class AttributeQuery(Query):
|
|
|
48
48
|
class AttributeUpdateValueQuery(AttributeQuery):
|
|
49
49
|
name = "attribute_update_value"
|
|
50
50
|
type: QueryType = QueryType.WRITE
|
|
51
|
-
|
|
52
|
-
raise_error_if_empty: bool =
|
|
51
|
+
insert_return: bool = False
|
|
52
|
+
raise_error_if_empty: bool = False
|
|
53
53
|
|
|
54
54
|
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
55
55
|
at = self.at or self.attr.at
|
|
56
56
|
|
|
57
57
|
self.params["attr_uuid"] = self.attr.id
|
|
58
|
+
self.params["user_id"] = self.user_id
|
|
58
59
|
self.params["branch"] = self.branch.name
|
|
59
60
|
self.params["branch_level"] = self.branch.hierarchy_level
|
|
60
61
|
self.params["at"] = at.to_string()
|
|
@@ -73,29 +74,46 @@ class AttributeUpdateValueQuery(AttributeQuery):
|
|
|
73
74
|
labels.append(GraphAttributeIPNetworkNode.get_default_label())
|
|
74
75
|
|
|
75
76
|
query = """
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
MATCH (a:Attribute { uuid: $attr_uuid })
|
|
78
|
+
MERGE (av:%(labels)s { %(props)s } )
|
|
79
|
+
WITH av, a
|
|
80
|
+
LIMIT 1
|
|
81
|
+
// ----------
|
|
82
|
+
// find the existing HAS_VALUE edge, if it exists, and set the to time and user_id
|
|
83
|
+
// ---------
|
|
84
|
+
OPTIONAL MATCH (a)-[existing_active_r:%(rel_label)s { branch: $branch, status: "active" }]->()
|
|
85
|
+
WHERE existing_active_r.to IS NULL
|
|
86
|
+
SET existing_active_r.to = $at, existing_active_r.to_user_id = $user_id
|
|
87
|
+
WITH av, a
|
|
88
|
+
LIMIT 1
|
|
89
|
+
// ----------
|
|
90
|
+
// create the new HAS_VALUE edge
|
|
91
|
+
// ---------
|
|
92
|
+
CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "active", from: $at, from_user_id: $user_id }]->(av)
|
|
93
|
+
// ----------
|
|
94
|
+
// update the Attribute node with the new timestamp and user id if we are on the default or global branch
|
|
95
|
+
// ---------
|
|
96
|
+
WITH a
|
|
97
|
+
WHERE $branch_level = 1
|
|
98
|
+
LIMIT 1
|
|
99
|
+
SET a.updated_at = $at, a.updated_by = $user_id
|
|
81
100
|
""" % {"rel_label": self.attr._rel_to_value_label, "labels": ":".join(labels), "props": ", ".join(prop_list)}
|
|
82
101
|
|
|
83
102
|
self.add_to_query(query)
|
|
84
|
-
self.return_labels = ["a", "av", "r"]
|
|
85
103
|
|
|
86
104
|
|
|
87
105
|
class AttributeUpdateFlagQuery(AttributeQuery):
|
|
88
106
|
name = "attribute_update_flag"
|
|
89
107
|
type: QueryType = QueryType.WRITE
|
|
90
|
-
|
|
91
|
-
raise_error_if_empty: bool =
|
|
108
|
+
insert_return: bool = False
|
|
109
|
+
raise_error_if_empty: bool = False
|
|
92
110
|
|
|
93
111
|
def __init__(
|
|
94
112
|
self,
|
|
95
113
|
flag_name: str,
|
|
96
114
|
**kwargs: Any,
|
|
97
115
|
) -> None:
|
|
98
|
-
SUPPORTED_FLAGS = ["
|
|
116
|
+
SUPPORTED_FLAGS = ["is_protected"]
|
|
99
117
|
|
|
100
118
|
if flag_name not in SUPPORTED_FLAGS:
|
|
101
119
|
raise ValueError(f"Only {SUPPORTED_FLAGS} are supported for now.")
|
|
@@ -108,6 +126,7 @@ class AttributeUpdateFlagQuery(AttributeQuery):
|
|
|
108
126
|
at = self.at or self.attr.at
|
|
109
127
|
|
|
110
128
|
self.params["attr_uuid"] = self.attr.id
|
|
129
|
+
self.params["user_id"] = self.user_id
|
|
111
130
|
self.params["branch"] = self.branch.name
|
|
112
131
|
self.params["branch_level"] = self.branch.hierarchy_level
|
|
113
132
|
self.params["at"] = at.to_string()
|
|
@@ -115,27 +134,44 @@ class AttributeUpdateFlagQuery(AttributeQuery):
|
|
|
115
134
|
self.params["flag_type"] = self.attr.get_kind()
|
|
116
135
|
|
|
117
136
|
query = """
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
137
|
+
MATCH (a:Attribute { uuid: $attr_uuid })
|
|
138
|
+
MERGE (flag:Boolean { value: $flag_value })
|
|
139
|
+
WITH flag, a
|
|
140
|
+
LIMIT 1
|
|
141
|
+
// ----------
|
|
142
|
+
// find the existing property edge, if it exists, and set the to time and user_id
|
|
143
|
+
// ---------
|
|
144
|
+
OPTIONAL MATCH (a)-[existing_active_r:%(flag_type)s { branch: $branch, status: "active" }]->()
|
|
145
|
+
WHERE existing_active_r.to IS NULL
|
|
146
|
+
SET existing_active_r.to = $at, existing_active_r.to_user_id = $user_id
|
|
147
|
+
// ----------
|
|
148
|
+
// create the new property edge
|
|
149
|
+
// ---------
|
|
150
|
+
WITH a, flag
|
|
151
|
+
CREATE (a)-[r:%(flag_type)s { branch: $branch, branch_level: $branch_level, status: "active", from: $at, from_user_id: $user_id }]->(flag)
|
|
152
|
+
// ----------
|
|
153
|
+
// update the Attribute node with the new timestamp and user id if we are on the default or global branch
|
|
154
|
+
// ---------
|
|
155
|
+
WITH a
|
|
156
|
+
WHERE $branch_level = 1
|
|
157
|
+
LIMIT 1
|
|
158
|
+
SET a.updated_at = $at, a.updated_by = $user_id
|
|
159
|
+
""" % {"flag_type": self.flag_name.upper()}
|
|
123
160
|
self.add_to_query(query)
|
|
124
|
-
self.return_labels = ["a", "flag", "r"]
|
|
125
161
|
|
|
126
162
|
|
|
127
163
|
class AttributeUpdateNodePropertyQuery(AttributeQuery):
|
|
128
164
|
name = "attribute_update_node_property"
|
|
129
165
|
type: QueryType = QueryType.WRITE
|
|
130
|
-
|
|
131
|
-
raise_error_if_empty: bool =
|
|
166
|
+
insert_return: bool = False
|
|
167
|
+
raise_error_if_empty: bool = False
|
|
132
168
|
|
|
133
169
|
def __init__(
|
|
134
170
|
self,
|
|
135
171
|
prop_name: str,
|
|
136
172
|
prop_id: str | None = None,
|
|
137
173
|
**kwargs: Any,
|
|
138
|
-
):
|
|
174
|
+
) -> None:
|
|
139
175
|
self.prop_name = prop_name
|
|
140
176
|
self.prop_id = prop_id
|
|
141
177
|
|
|
@@ -147,6 +183,7 @@ class AttributeUpdateNodePropertyQuery(AttributeQuery):
|
|
|
147
183
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=at)
|
|
148
184
|
self.params.update(branch_params)
|
|
149
185
|
self.params["attr_uuid"] = self.attr.id
|
|
186
|
+
self.params["user_id"] = self.user_id
|
|
150
187
|
self.params["branch"] = self.branch.name
|
|
151
188
|
self.params["branch_level"] = self.branch.hierarchy_level
|
|
152
189
|
self.params["at"] = at.to_string()
|
|
@@ -176,13 +213,29 @@ class AttributeUpdateNodePropertyQuery(AttributeQuery):
|
|
|
176
213
|
self.add_to_query(node_query)
|
|
177
214
|
|
|
178
215
|
attr_query = """
|
|
179
|
-
|
|
180
|
-
|
|
216
|
+
MATCH (a:Attribute { uuid: $attr_uuid })
|
|
217
|
+
// ----------
|
|
218
|
+
// find the existing property edge, if it exists, and set the to time and user_id
|
|
219
|
+
// ---------
|
|
220
|
+
OPTIONAL MATCH (a)-[existing_active_r:%(rel_label)s { branch: $branch, status: "active" }]->()
|
|
221
|
+
WHERE existing_active_r.to IS NULL
|
|
222
|
+
SET existing_active_r.to = $at, existing_active_r.to_user_id = $user_id
|
|
223
|
+
// ----------
|
|
224
|
+
// create the new property edge
|
|
225
|
+
// ---------
|
|
226
|
+
WITH a, np
|
|
227
|
+
LIMIT 1
|
|
228
|
+
CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "active", from: $at, from_user_id: $user_id }]->(np)
|
|
229
|
+
// ----------
|
|
230
|
+
// update the Attribute node with the new timestamp and user id if we are on the default or global branch
|
|
231
|
+
// ---------
|
|
232
|
+
WITH a
|
|
233
|
+
WHERE $branch_level = 1
|
|
234
|
+
LIMIT 1
|
|
235
|
+
SET a.updated_at = $at, a.updated_by = $user_id
|
|
181
236
|
""" % {"rel_label": rel_label}
|
|
182
237
|
self.add_to_query(attr_query)
|
|
183
238
|
|
|
184
|
-
self.return_labels = ["a", "np", "r"]
|
|
185
|
-
|
|
186
239
|
|
|
187
240
|
class AttributeClearNodePropertyQuery(AttributeQuery):
|
|
188
241
|
name = "attribute_clear_node_property"
|
|
@@ -192,11 +245,9 @@ class AttributeClearNodePropertyQuery(AttributeQuery):
|
|
|
192
245
|
def __init__(
|
|
193
246
|
self,
|
|
194
247
|
prop_name: str,
|
|
195
|
-
prop_id: str | None = None,
|
|
196
248
|
**kwargs: Any,
|
|
197
|
-
):
|
|
249
|
+
) -> None:
|
|
198
250
|
self.prop_name = prop_name
|
|
199
|
-
self.prop_id = prop_id
|
|
200
251
|
|
|
201
252
|
super().__init__(**kwargs)
|
|
202
253
|
|
|
@@ -206,15 +257,14 @@ class AttributeClearNodePropertyQuery(AttributeQuery):
|
|
|
206
257
|
branch_filter, branch_params = self.branch.get_query_filter_path(at=at)
|
|
207
258
|
self.params.update(branch_params)
|
|
208
259
|
self.params["attr_uuid"] = self.attr.id
|
|
260
|
+
self.params["user_id"] = self.user_id
|
|
209
261
|
self.params["branch"] = self.branch.name
|
|
210
262
|
self.params["branch_level"] = self.branch.hierarchy_level
|
|
211
263
|
self.params["at"] = at.to_string()
|
|
212
|
-
self.params["prop_name"] = self.prop_name
|
|
213
|
-
self.params["prop_id"] = self.prop_id
|
|
214
264
|
|
|
215
265
|
rel_label = f"HAS_{self.prop_name.upper()}"
|
|
216
266
|
query = """
|
|
217
|
-
MATCH (a:Attribute { uuid: $attr_uuid })-[r:%(rel_label)s]->(np:Node
|
|
267
|
+
MATCH (a:Attribute { uuid: $attr_uuid })-[r:%(rel_label)s]->(np:Node)
|
|
218
268
|
WITH DISTINCT a, np
|
|
219
269
|
CALL (a, np) {
|
|
220
270
|
MATCH (a)-[r:%(rel_label)s]->(np)
|
|
@@ -228,42 +278,107 @@ WHERE property_edge.status = "active"
|
|
|
228
278
|
CALL (property_edge) {
|
|
229
279
|
WITH property_edge
|
|
230
280
|
WHERE property_edge.branch = $branch
|
|
231
|
-
SET property_edge.to = $at
|
|
281
|
+
SET property_edge.to = $at, property_edge.to_user_id = $user_id
|
|
232
282
|
}
|
|
233
283
|
CALL (a, np, property_edge) {
|
|
234
284
|
WITH property_edge
|
|
235
285
|
WHERE property_edge.branch_level < $branch_level
|
|
236
|
-
CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "deleted", from: $at }]->(np)
|
|
286
|
+
CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "deleted", from: $at, from_user_id: $user_id }]->(np)
|
|
287
|
+
}
|
|
288
|
+
CALL (a) {
|
|
289
|
+
WITH a
|
|
290
|
+
WHERE $branch_level = 1
|
|
291
|
+
LIMIT 1
|
|
292
|
+
SET a.updated_at = $at, a.updated_by = $user_id
|
|
237
293
|
}
|
|
238
294
|
""" % {"branch_filter": branch_filter, "rel_label": rel_label}
|
|
239
295
|
self.add_to_query(query)
|
|
240
296
|
|
|
241
297
|
|
|
242
|
-
class
|
|
243
|
-
name = "
|
|
244
|
-
type: QueryType = QueryType.
|
|
298
|
+
class AttributeDeleteQuery(AttributeQuery):
|
|
299
|
+
name = "attribute_delete"
|
|
300
|
+
type: QueryType = QueryType.WRITE
|
|
301
|
+
insert_return: bool = False
|
|
245
302
|
|
|
246
303
|
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
247
304
|
self.params["attr_uuid"] = self.attr.id
|
|
248
|
-
self.params["
|
|
249
|
-
|
|
305
|
+
self.params["user_id"] = self.user_id
|
|
306
|
+
self.params["branch"] = self.branch.name
|
|
307
|
+
self.params["branch_level"] = self.branch.hierarchy_level
|
|
308
|
+
self.params["branched_from"] = self.branch.get_branched_from()
|
|
250
309
|
self.params["at"] = self.at.to_string()
|
|
251
310
|
|
|
252
|
-
|
|
253
|
-
self.params.update(
|
|
311
|
+
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at)
|
|
312
|
+
self.params.update(branch_params)
|
|
254
313
|
|
|
255
|
-
query =
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
314
|
+
query = """
|
|
315
|
+
MATCH (a:Attribute { uuid: $attr_uuid })
|
|
316
|
+
CALL (a) {
|
|
317
|
+
WITH a
|
|
318
|
+
WHERE $branch_level = 1
|
|
319
|
+
LIMIT 1
|
|
320
|
+
SET a.updated_at = $at, a.updated_by = $user_id
|
|
321
|
+
}
|
|
263
322
|
|
|
323
|
+
UNWIND [
|
|
324
|
+
["HAS_ATTRIBUTE", "in"],
|
|
325
|
+
["HAS_VALUE", "out"],
|
|
326
|
+
["IS_PROTECTED", "out"],
|
|
327
|
+
["HAS_SOURCE", "out"],
|
|
328
|
+
["HAS_OWNER", "out"]
|
|
329
|
+
] AS edge_details
|
|
330
|
+
WITH a, edge_details[0] AS property_type, edge_details[1] AS direction
|
|
331
|
+
CALL (a, property_type, direction) {
|
|
332
|
+
MATCH (a)-[r]-(attr_peer)
|
|
333
|
+
WHERE type(r) = property_type
|
|
334
|
+
AND (
|
|
335
|
+
(direction = "in" AND startNode(r) = attr_peer)
|
|
336
|
+
OR (direction = "out" AND startNode(r) = a)
|
|
337
|
+
)
|
|
338
|
+
AND %(branch_filter)s
|
|
339
|
+
RETURN r AS property_edge, attr_peer
|
|
340
|
+
ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
|
|
341
|
+
LIMIT 1
|
|
342
|
+
}
|
|
343
|
+
CALL (property_edge) {
|
|
344
|
+
WITH property_edge
|
|
345
|
+
WHERE property_edge.status = "active"
|
|
346
|
+
AND property_edge.branch = $branch
|
|
347
|
+
AND property_edge.to IS NULL
|
|
348
|
+
SET property_edge.to = $at, property_edge.to_user_id = $user_id
|
|
349
|
+
}
|
|
350
|
+
WITH a, property_edge, property_type, attr_peer, direction
|
|
351
|
+
CALL (a, property_type, attr_peer, direction) {
|
|
352
|
+
WITH direction
|
|
353
|
+
WHERE direction = "out"
|
|
354
|
+
CREATE (a)
|
|
355
|
+
-[r:$(property_type) { branch: $branch, branch_level: $branch_level, status: "deleted", from: $at, from_user_id: $user_id }]
|
|
356
|
+
->(attr_peer)
|
|
357
|
+
}
|
|
358
|
+
CALL (a, property_type, attr_peer, direction) {
|
|
359
|
+
WITH direction
|
|
360
|
+
WHERE direction = "in"
|
|
361
|
+
CREATE (a)
|
|
362
|
+
<-[r:$(property_type) { branch: $branch, branch_level: $branch_level, status: "deleted", from: $at, from_user_id: $user_id }]
|
|
363
|
+
-(attr_peer)
|
|
364
|
+
}
|
|
365
|
+
WITH CASE
|
|
366
|
+
WHEN property_type = "HAS_VALUE" THEN attr_peer.value
|
|
367
|
+
ELSE NULL
|
|
368
|
+
END AS property_value
|
|
369
|
+
WITH property_value
|
|
370
|
+
RETURN property_value
|
|
371
|
+
ORDER BY property_value ASC
|
|
372
|
+
LIMIT 1
|
|
373
|
+
""" % {"branch_filter": branch_filter}
|
|
264
374
|
self.add_to_query(query)
|
|
375
|
+
self.return_labels = ["property_value"]
|
|
265
376
|
|
|
266
|
-
|
|
377
|
+
def get_previous_property_value(self) -> Any:
|
|
378
|
+
result = self.get_result()
|
|
379
|
+
if result:
|
|
380
|
+
return result.get(label="property_value")
|
|
381
|
+
return None
|
|
267
382
|
|
|
268
383
|
|
|
269
384
|
async def default_attribute_query_filter(
|
infrahub/core/query/branch.py
CHANGED
|
@@ -2,7 +2,6 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
|
-
from infrahub import config
|
|
6
5
|
from infrahub.core.branch.enums import BranchStatus
|
|
7
6
|
from infrahub.core.constants import GLOBAL_BRANCH_NAME
|
|
8
7
|
from infrahub.core.query import Query, QueryType
|
|
@@ -18,7 +17,7 @@ class DeleteBranchRelationshipsQuery(Query):
|
|
|
18
17
|
|
|
19
18
|
type: QueryType = QueryType.WRITE
|
|
20
19
|
|
|
21
|
-
def __init__(self, branch_name: str, **kwargs: Any):
|
|
20
|
+
def __init__(self, branch_name: str, **kwargs: Any) -> None:
|
|
22
21
|
self.branch_name = branch_name
|
|
23
22
|
super().__init__(**kwargs)
|
|
24
23
|
|
|
@@ -70,89 +69,78 @@ CALL (vertex_id) {
|
|
|
70
69
|
self.add_to_query(query)
|
|
71
70
|
|
|
72
71
|
|
|
73
|
-
class
|
|
74
|
-
|
|
72
|
+
class RebaseBranchQuery(Query):
|
|
73
|
+
"""Rebase a branch onto the default branch by updating edge timestamps
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
WHERE r.branch = $branch_name
|
|
83
|
-
RETURN DISTINCT r
|
|
84
|
-
"""
|
|
85
|
-
self.add_to_query(query=query)
|
|
86
|
-
self.params["branch_name"] = self.branch.name
|
|
87
|
-
self.return_labels = ["r"]
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
class RebaseBranchUpdateRelationshipQuery(Query):
|
|
91
|
-
name: str = "rebase_branch_update"
|
|
75
|
+
For every edge on this branch
|
|
76
|
+
if it has a from time before $at and no to time, update it to $at
|
|
77
|
+
if it has a to time before $at, delete the edge
|
|
78
|
+
if it has a to time after $at, update the from time to $at
|
|
79
|
+
Then delete any orphaned vertices
|
|
80
|
+
"""
|
|
92
81
|
|
|
82
|
+
name: str = "rebase_branch"
|
|
93
83
|
type: QueryType = QueryType.WRITE
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
self.ids = ids
|
|
97
|
-
super().__init__(**kwargs)
|
|
84
|
+
insert_return: bool = False
|
|
85
|
+
raise_error_if_empty: bool = False
|
|
98
86
|
|
|
99
87
|
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
100
|
-
|
|
101
|
-
MATCH ()-[r]->()
|
|
102
|
-
WHERE %(id_func)s(r) IN $ids
|
|
103
|
-
SET r.from = $at
|
|
104
|
-
SET r.conflict = NULL
|
|
105
|
-
""" % {
|
|
106
|
-
"id_func": db.get_id_function_name(),
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
self.add_to_query(query=query)
|
|
110
|
-
|
|
88
|
+
self.params["branch_name"] = self.branch.name
|
|
111
89
|
self.params["at"] = self.at.to_string()
|
|
112
|
-
self.params["ids"] = [db.to_database_id(id) for id in self.ids]
|
|
113
|
-
self.return_labels = [f"{db.get_id_function_name()}(r)"]
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
class RebaseBranchDeleteRelationshipQuery(Query):
|
|
117
|
-
name: str = "rebase_branch_delete"
|
|
118
90
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
91
|
+
query = """
|
|
92
|
+
// --------------
|
|
93
|
+
// Get all edges on this branch with their source and destination vertices
|
|
94
|
+
// --------------
|
|
95
|
+
MATCH (s)-[r]-(d)
|
|
96
|
+
WHERE r.branch = $branch_name
|
|
97
|
+
WITH DISTINCT r, s, d
|
|
98
|
+
WITH r, s, d,
|
|
99
|
+
CASE
|
|
100
|
+
// No `to` and `from` <= at: update
|
|
101
|
+
WHEN r.to IS NULL AND r.from <= $at THEN TRUE
|
|
102
|
+
// Has `to` and `to` < at: delete
|
|
103
|
+
WHEN r.to IS NOT NULL AND r.to < $at THEN FALSE
|
|
104
|
+
// Has `to` and `to` >= at: update
|
|
105
|
+
ELSE TRUE
|
|
106
|
+
END AS do_update
|
|
125
107
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
query = """
|
|
135
|
-
MATCH p = (s)-[r]-(d)
|
|
136
|
-
WHERE %(id_func)s(r) IN $ids
|
|
137
|
-
DELETE r
|
|
138
|
-
WITH *
|
|
139
|
-
UNWIND nodes(p) AS n
|
|
140
|
-
MATCH (n)
|
|
141
|
-
WHERE NOT exists((n)--())
|
|
142
|
-
DELETE n
|
|
143
|
-
"""
|
|
144
|
-
query %= {
|
|
145
|
-
"id_func": db.get_id_function_name(),
|
|
146
|
-
}
|
|
108
|
+
// --------------
|
|
109
|
+
// Process updates: set from = at for relationships we're keeping
|
|
110
|
+
// --------------
|
|
111
|
+
CALL (r, do_update) {
|
|
112
|
+
WITH r, do_update
|
|
113
|
+
WHERE do_update = TRUE
|
|
114
|
+
SET r.from = $at
|
|
115
|
+
}
|
|
147
116
|
|
|
117
|
+
// --------------
|
|
118
|
+
// Delete the edges
|
|
119
|
+
// --------------
|
|
120
|
+
WITH r, s, d, do_update
|
|
121
|
+
WHERE do_update = FALSE
|
|
122
|
+
CALL (r, s, d) {
|
|
123
|
+
DELETE r
|
|
124
|
+
}
|
|
125
|
+
// --------------
|
|
126
|
+
// Clean up any orpahned nodes edges
|
|
127
|
+
// --------------
|
|
128
|
+
WITH DISTINCT s, d
|
|
129
|
+
UNWIND [s, d] AS n
|
|
130
|
+
WITH DISTINCT n
|
|
131
|
+
CALL (n) {
|
|
132
|
+
MATCH (n)
|
|
133
|
+
WHERE NOT exists((n)--())
|
|
134
|
+
DELETE n
|
|
135
|
+
}
|
|
136
|
+
"""
|
|
148
137
|
self.add_to_query(query=query)
|
|
149
138
|
|
|
150
|
-
self.params["ids"] = [db.to_database_id(id) for id in self.ids]
|
|
151
|
-
|
|
152
139
|
|
|
153
140
|
class BranchNodeGetListQuery(StandardNodeGetListQuery):
|
|
154
141
|
def __init__(self, exclude_global: bool = False, **kwargs: Any) -> None:
|
|
155
142
|
self.raw_filter = f"n.status <> '{BranchStatus.DELETING.value}'"
|
|
143
|
+
|
|
156
144
|
if exclude_global:
|
|
157
145
|
self.raw_filter += f" AND n.name <> '{GLOBAL_BRANCH_NAME}'"
|
|
158
146
|
|
infrahub/core/query/delete.py
CHANGED
|
@@ -11,7 +11,7 @@ class DeleteAfterTimeQuery(Query):
|
|
|
11
11
|
insert_return: bool = False
|
|
12
12
|
type: QueryType = QueryType.WRITE
|
|
13
13
|
|
|
14
|
-
def __init__(self, timestamp: Timestamp, **kwargs: Any):
|
|
14
|
+
def __init__(self, timestamp: Timestamp, **kwargs: Any) -> None:
|
|
15
15
|
self.timestamp = timestamp
|
|
16
16
|
super().__init__(**kwargs)
|
|
17
17
|
|
infrahub/core/query/diff.py
CHANGED
|
@@ -26,7 +26,7 @@ class DiffQuery(Query):
|
|
|
26
26
|
diff_from: Timestamp | str = None,
|
|
27
27
|
diff_to: Timestamp | str = None,
|
|
28
28
|
**kwargs,
|
|
29
|
-
):
|
|
29
|
+
) -> None:
|
|
30
30
|
"""A diff is always in the context of a branch"""
|
|
31
31
|
|
|
32
32
|
if not diff_from and branch.is_default:
|
|
@@ -59,7 +59,7 @@ class DiffCountChanges(Query):
|
|
|
59
59
|
diff_from: Timestamp,
|
|
60
60
|
diff_to: Timestamp,
|
|
61
61
|
**kwargs,
|
|
62
|
-
):
|
|
62
|
+
) -> None:
|
|
63
63
|
self.branch_names = branch_names
|
|
64
64
|
self.diff_from = diff_from
|
|
65
65
|
self.diff_to = diff_to
|
|
@@ -77,7 +77,7 @@ class DiffCountChanges(Query):
|
|
|
77
77
|
AND diff_rel.branch in $branch_names
|
|
78
78
|
AND (
|
|
79
79
|
(diff_rel.from >= $from_time AND diff_rel.from < $to_time)
|
|
80
|
-
OR (diff_rel.to >= $
|
|
80
|
+
OR (diff_rel.to >= $from_time AND diff_rel.to < $to_time)
|
|
81
81
|
)
|
|
82
82
|
AND (p.branch_support = "aware" OR q.branch_support = "aware")
|
|
83
83
|
WITH diff_rel.branch AS branch_name, count(*) AS num_changes
|
|
@@ -122,7 +122,7 @@ class DiffCalculationQuery(DiffQuery):
|
|
|
122
122
|
current_node_field_specifiers: NodeFieldSpecifierMap | None = None,
|
|
123
123
|
new_node_field_specifiers: NodeFieldSpecifierMap | None = None,
|
|
124
124
|
**kwargs: Any,
|
|
125
|
-
):
|
|
125
|
+
) -> None:
|
|
126
126
|
self.base_branch = base_branch
|
|
127
127
|
self.diff_branch_from_time = diff_branch_from_time
|
|
128
128
|
self.current_node_field_specifiers = current_node_field_specifiers
|
|
@@ -335,7 +335,7 @@ CALL (p, q, diff_rel, row_from_time) {
|
|
|
335
335
|
AND type(r_node) IN ["HAS_ATTRIBUTE", "IS_RELATED"]
|
|
336
336
|
AND any(l in labels(node) WHERE l in ["Attribute", "Relationship"])
|
|
337
337
|
AND node.branch_support IN [$branch_aware, $branch_agnostic]
|
|
338
|
-
AND type(r_prop) IN ["
|
|
338
|
+
AND type(r_prop) IN ["IS_PROTECTED", "HAS_SOURCE", "HAS_OWNER", "HAS_VALUE", "IS_RELATED"]
|
|
339
339
|
AND any(l in labels(prop) WHERE l in ["Boolean", "Node", "AttributeValue"])
|
|
340
340
|
AND (top_diff_rel.to IS NULL OR top_diff_rel.to >= r_node.from)
|
|
341
341
|
AND (r_node.to IS NULL OR r_node.to >= r_prop.from)
|
|
@@ -532,7 +532,7 @@ CALL (root, r_root, p, diff_rel, q) {
|
|
|
532
532
|
)
|
|
533
533
|
WHERE %(id_func)s(mid_r_root) = %(id_func)s(r_root)
|
|
534
534
|
AND %(id_func)s(mid_diff_rel) = %(id_func)s(diff_rel)
|
|
535
|
-
AND type(r_prop) IN ["
|
|
535
|
+
AND type(r_prop) IN ["IS_PROTECTED", "HAS_SOURCE", "HAS_OWNER", "HAS_VALUE", "IS_RELATED"]
|
|
536
536
|
AND any(l in labels(prop) WHERE l in ["Boolean", "Node", "AttributeValue"])
|
|
537
537
|
AND r_prop.from < $to_time AND r_prop.branch = mid_diff_rel.branch
|
|
538
538
|
AND (mid_diff_rel.to IS NULL OR mid_diff_rel.to >= r_prop.from)
|
|
@@ -609,7 +609,7 @@ class DiffPropertyPathsQuery(DiffCalculationQuery):
|
|
|
609
609
|
MATCH diff_rel_path = (root:Root)<-[r_root:IS_PART_OF]-(n:Node)-[r_node]-(p)-[diff_rel {branch: $branch_name}]->(q)
|
|
610
610
|
WHERE p.branch_support = $branch_aware
|
|
611
611
|
AND any(l in labels(p) WHERE l in ["Attribute", "Relationship"])
|
|
612
|
-
AND type(diff_rel) IN ["
|
|
612
|
+
AND type(diff_rel) IN ["IS_PROTECTED", "HAS_SOURCE", "HAS_OWNER", "HAS_VALUE"]
|
|
613
613
|
AND any(l in labels(q) WHERE l in ["Boolean", "Node", "AttributeValue"])
|
|
614
614
|
AND type(r_node) IN ["HAS_ATTRIBUTE", "IS_RELATED"]
|
|
615
615
|
// node ID and field name filtering first pass
|