infrahub-server 1.4.13__py3-none-any.whl → 1.5.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 +208 -16
- infrahub/api/artifact.py +3 -0
- infrahub/api/diff/diff.py +1 -1
- infrahub/api/internal.py +2 -0
- infrahub/api/query.py +2 -0
- infrahub/api/schema.py +27 -3
- infrahub/auth.py +5 -5
- infrahub/cli/__init__.py +2 -0
- infrahub/cli/db.py +160 -157
- infrahub/cli/dev.py +118 -0
- infrahub/cli/upgrade.py +56 -9
- infrahub/computed_attribute/tasks.py +19 -7
- infrahub/config.py +7 -2
- infrahub/core/attribute.py +35 -24
- infrahub/core/branch/enums.py +1 -1
- infrahub/core/branch/models.py +9 -5
- infrahub/core/branch/needs_rebase_status.py +11 -0
- infrahub/core/branch/tasks.py +72 -10
- infrahub/core/changelog/models.py +2 -10
- infrahub/core/constants/__init__.py +4 -0
- infrahub/core/constants/infrahubkind.py +1 -0
- infrahub/core/convert_object_type/object_conversion.py +201 -0
- infrahub/core/convert_object_type/repository_conversion.py +89 -0
- infrahub/core/convert_object_type/schema_mapping.py +27 -3
- infrahub/core/diff/model/path.py +4 -0
- infrahub/core/diff/payload_builder.py +1 -1
- infrahub/core/diff/query/artifact.py +1 -0
- infrahub/core/diff/query/field_summary.py +1 -0
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/initialization.py +7 -4
- infrahub/core/manager.py +3 -81
- infrahub/core/migrations/__init__.py +3 -0
- infrahub/core/migrations/exceptions.py +4 -0
- infrahub/core/migrations/graph/__init__.py +11 -10
- infrahub/core/migrations/graph/load_schema_branch.py +21 -0
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +1 -1
- infrahub/core/migrations/graph/m037_index_attr_vals.py +11 -30
- infrahub/core/migrations/graph/m039_ipam_reconcile.py +9 -7
- infrahub/core/migrations/graph/m042_profile_attrs_in_db.py +147 -0
- infrahub/core/migrations/graph/m043_create_hfid_display_label_in_db.py +164 -0
- infrahub/core/migrations/graph/m044_backfill_hfid_display_label_in_db.py +864 -0
- infrahub/core/migrations/query/__init__.py +7 -8
- infrahub/core/migrations/query/attribute_add.py +8 -6
- infrahub/core/migrations/query/attribute_remove.py +134 -0
- infrahub/core/migrations/runner.py +54 -0
- infrahub/core/migrations/schema/attribute_kind_update.py +9 -3
- infrahub/core/migrations/schema/attribute_supports_profile.py +90 -0
- infrahub/core/migrations/schema/node_attribute_add.py +26 -5
- infrahub/core/migrations/schema/node_attribute_remove.py +13 -109
- infrahub/core/migrations/schema/node_kind_update.py +2 -1
- infrahub/core/migrations/schema/node_remove.py +2 -1
- infrahub/core/migrations/schema/placeholder_dummy.py +3 -2
- infrahub/core/migrations/shared.py +66 -19
- infrahub/core/models.py +2 -2
- infrahub/core/node/__init__.py +207 -54
- infrahub/core/node/create.py +53 -49
- infrahub/core/node/lock_utils.py +124 -0
- infrahub/core/node/node_property_attribute.py +230 -0
- infrahub/core/node/resource_manager/ip_address_pool.py +2 -1
- infrahub/core/node/resource_manager/ip_prefix_pool.py +2 -1
- infrahub/core/node/resource_manager/number_pool.py +2 -1
- infrahub/core/node/standard.py +1 -1
- infrahub/core/property.py +11 -0
- infrahub/core/protocols.py +8 -1
- infrahub/core/query/attribute.py +82 -15
- infrahub/core/query/ipam.py +16 -4
- infrahub/core/query/node.py +66 -188
- infrahub/core/query/relationship.py +44 -26
- infrahub/core/query/subquery.py +0 -8
- infrahub/core/relationship/model.py +69 -24
- infrahub/core/schema/__init__.py +56 -0
- infrahub/core/schema/attribute_schema.py +4 -2
- infrahub/core/schema/basenode_schema.py +42 -2
- infrahub/core/schema/definitions/core/__init__.py +2 -0
- infrahub/core/schema/definitions/core/check.py +1 -1
- infrahub/core/schema/definitions/core/generator.py +2 -0
- infrahub/core/schema/definitions/core/group.py +16 -2
- infrahub/core/schema/definitions/core/repository.py +7 -0
- infrahub/core/schema/definitions/core/transform.py +1 -1
- infrahub/core/schema/definitions/internal.py +12 -3
- infrahub/core/schema/generated/attribute_schema.py +2 -2
- infrahub/core/schema/generated/base_node_schema.py +6 -1
- infrahub/core/schema/manager.py +3 -0
- infrahub/core/schema/node_schema.py +1 -0
- infrahub/core/schema/relationship_schema.py +0 -1
- infrahub/core/schema/schema_branch.py +295 -10
- infrahub/core/schema/schema_branch_display.py +135 -0
- infrahub/core/schema/schema_branch_hfid.py +120 -0
- infrahub/core/validators/aggregated_checker.py +1 -1
- infrahub/database/graph.py +21 -0
- infrahub/display_labels/__init__.py +0 -0
- infrahub/display_labels/gather.py +48 -0
- infrahub/display_labels/models.py +240 -0
- infrahub/display_labels/tasks.py +192 -0
- infrahub/display_labels/triggers.py +22 -0
- infrahub/events/branch_action.py +27 -1
- infrahub/events/group_action.py +1 -1
- infrahub/events/node_action.py +1 -1
- infrahub/generators/constants.py +7 -0
- infrahub/generators/models.py +38 -12
- infrahub/generators/tasks.py +34 -16
- infrahub/git/base.py +38 -1
- infrahub/git/integrator.py +22 -14
- infrahub/graphql/api/dependencies.py +2 -4
- infrahub/graphql/api/endpoints.py +16 -6
- infrahub/graphql/app.py +2 -4
- infrahub/graphql/initialization.py +2 -3
- infrahub/graphql/manager.py +213 -137
- infrahub/graphql/middleware.py +12 -0
- infrahub/graphql/mutations/branch.py +16 -0
- infrahub/graphql/mutations/computed_attribute.py +110 -3
- infrahub/graphql/mutations/convert_object_type.py +44 -13
- infrahub/graphql/mutations/display_label.py +118 -0
- infrahub/graphql/mutations/generator.py +25 -7
- infrahub/graphql/mutations/hfid.py +125 -0
- infrahub/graphql/mutations/ipam.py +73 -41
- infrahub/graphql/mutations/main.py +61 -178
- infrahub/graphql/mutations/profile.py +195 -0
- infrahub/graphql/mutations/proposed_change.py +8 -1
- infrahub/graphql/mutations/relationship.py +2 -2
- infrahub/graphql/mutations/repository.py +22 -83
- infrahub/graphql/mutations/resource_manager.py +2 -2
- infrahub/graphql/mutations/webhook.py +1 -1
- infrahub/graphql/queries/resource_manager.py +1 -1
- infrahub/graphql/registry.py +173 -0
- infrahub/graphql/resolvers/resolver.py +2 -0
- infrahub/graphql/schema.py +8 -1
- infrahub/graphql/schema_sort.py +170 -0
- infrahub/graphql/types/branch.py +4 -1
- infrahub/graphql/types/enums.py +3 -0
- infrahub/groups/tasks.py +1 -1
- infrahub/hfid/__init__.py +0 -0
- infrahub/hfid/gather.py +48 -0
- infrahub/hfid/models.py +240 -0
- infrahub/hfid/tasks.py +191 -0
- infrahub/hfid/triggers.py +22 -0
- infrahub/lock.py +119 -42
- infrahub/locks/__init__.py +0 -0
- infrahub/locks/tasks.py +37 -0
- infrahub/patch/plan_writer.py +2 -2
- infrahub/permissions/constants.py +2 -0
- infrahub/profiles/__init__.py +0 -0
- infrahub/profiles/node_applier.py +101 -0
- infrahub/profiles/queries/__init__.py +0 -0
- infrahub/profiles/queries/get_profile_data.py +98 -0
- infrahub/profiles/tasks.py +63 -0
- infrahub/proposed_change/tasks.py +24 -5
- infrahub/repositories/__init__.py +0 -0
- infrahub/repositories/create_repository.py +113 -0
- infrahub/server.py +9 -1
- infrahub/services/__init__.py +8 -5
- infrahub/services/adapters/workflow/worker.py +5 -2
- infrahub/task_manager/event.py +5 -0
- infrahub/task_manager/models.py +7 -0
- infrahub/tasks/registry.py +6 -4
- infrahub/trigger/catalogue.py +4 -0
- infrahub/trigger/models.py +2 -0
- infrahub/trigger/setup.py +13 -4
- infrahub/trigger/tasks.py +6 -0
- infrahub/webhook/models.py +1 -1
- infrahub/workers/dependencies.py +3 -1
- infrahub/workers/infrahub_async.py +5 -1
- infrahub/workflows/catalogue.py +118 -3
- infrahub/workflows/initialization.py +21 -0
- infrahub/workflows/models.py +17 -2
- infrahub_sdk/branch.py +17 -8
- infrahub_sdk/checks.py +1 -1
- infrahub_sdk/client.py +376 -95
- infrahub_sdk/config.py +29 -2
- infrahub_sdk/convert_object_type.py +61 -0
- infrahub_sdk/ctl/branch.py +3 -0
- infrahub_sdk/ctl/check.py +2 -3
- infrahub_sdk/ctl/cli_commands.py +20 -12
- infrahub_sdk/ctl/config.py +8 -2
- infrahub_sdk/ctl/generator.py +6 -3
- infrahub_sdk/ctl/graphql.py +184 -0
- infrahub_sdk/ctl/repository.py +39 -1
- infrahub_sdk/ctl/schema.py +40 -10
- infrahub_sdk/ctl/task.py +110 -0
- infrahub_sdk/ctl/utils.py +4 -0
- infrahub_sdk/ctl/validate.py +5 -3
- infrahub_sdk/diff.py +4 -5
- infrahub_sdk/exceptions.py +2 -0
- infrahub_sdk/generator.py +7 -1
- infrahub_sdk/graphql/__init__.py +12 -0
- infrahub_sdk/graphql/constants.py +1 -0
- infrahub_sdk/graphql/plugin.py +85 -0
- infrahub_sdk/graphql/query.py +77 -0
- infrahub_sdk/{graphql.py → graphql/renderers.py} +88 -75
- infrahub_sdk/graphql/utils.py +40 -0
- infrahub_sdk/node/attribute.py +2 -0
- infrahub_sdk/node/node.py +28 -20
- infrahub_sdk/node/relationship.py +1 -3
- infrahub_sdk/playback.py +1 -2
- infrahub_sdk/protocols.py +54 -6
- infrahub_sdk/pytest_plugin/plugin.py +7 -4
- infrahub_sdk/pytest_plugin/utils.py +40 -0
- infrahub_sdk/repository.py +1 -2
- infrahub_sdk/schema/__init__.py +70 -4
- infrahub_sdk/schema/main.py +1 -0
- infrahub_sdk/schema/repository.py +8 -0
- infrahub_sdk/spec/models.py +7 -0
- infrahub_sdk/spec/object.py +54 -6
- infrahub_sdk/spec/processors/__init__.py +0 -0
- infrahub_sdk/spec/processors/data_processor.py +10 -0
- infrahub_sdk/spec/processors/factory.py +34 -0
- infrahub_sdk/spec/processors/range_expand_processor.py +56 -0
- infrahub_sdk/spec/range_expansion.py +118 -0
- infrahub_sdk/task/models.py +6 -4
- infrahub_sdk/timestamp.py +18 -6
- infrahub_sdk/transforms.py +1 -1
- {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/METADATA +9 -10
- {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/RECORD +221 -165
- infrahub_testcontainers/container.py +114 -2
- infrahub_testcontainers/docker-compose-cluster.test.yml +5 -0
- infrahub_testcontainers/docker-compose.test.yml +5 -0
- infrahub_testcontainers/models.py +2 -2
- infrahub_testcontainers/performance_test.py +4 -4
- infrahub/core/convert_object_type/conversion.py +0 -134
- {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/entry_points.txt +0 -0
infrahub/core/query/attribute.py
CHANGED
|
@@ -133,7 +133,7 @@ class AttributeUpdateNodePropertyQuery(AttributeQuery):
|
|
|
133
133
|
def __init__(
|
|
134
134
|
self,
|
|
135
135
|
prop_name: str,
|
|
136
|
-
prop_id: str,
|
|
136
|
+
prop_id: str | None = None,
|
|
137
137
|
**kwargs: Any,
|
|
138
138
|
):
|
|
139
139
|
self.prop_name = prop_name
|
|
@@ -144,6 +144,8 @@ class AttributeUpdateNodePropertyQuery(AttributeQuery):
|
|
|
144
144
|
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
145
145
|
at = self.at or self.attr.at
|
|
146
146
|
|
|
147
|
+
branch_filter, branch_params = self.branch.get_query_filter_path(at=at)
|
|
148
|
+
self.params.update(branch_params)
|
|
147
149
|
self.params["attr_uuid"] = self.attr.id
|
|
148
150
|
self.params["branch"] = self.branch.name
|
|
149
151
|
self.params["branch_level"] = self.branch.hierarchy_level
|
|
@@ -151,21 +153,92 @@ class AttributeUpdateNodePropertyQuery(AttributeQuery):
|
|
|
151
153
|
self.params["prop_name"] = self.prop_name
|
|
152
154
|
self.params["prop_id"] = self.prop_id
|
|
153
155
|
|
|
154
|
-
|
|
156
|
+
rel_label = f"HAS_{self.prop_name.upper()}"
|
|
155
157
|
|
|
156
|
-
|
|
158
|
+
if self.branch.is_default or self.branch.is_global:
|
|
159
|
+
node_query = """
|
|
160
|
+
MATCH (np:Node { uuid: $prop_id })-[r:IS_PART_OF]->(:Root)
|
|
161
|
+
WHERE r.branch IN $branch0
|
|
162
|
+
AND r.status = "active"
|
|
163
|
+
AND r.from <= $at AND (r.to IS NULL OR r.to > $at)
|
|
164
|
+
WITH np
|
|
165
|
+
LIMIT 1
|
|
157
166
|
"""
|
|
167
|
+
else:
|
|
168
|
+
node_query = """
|
|
169
|
+
MATCH (np:Node { uuid: $prop_id })-[r:IS_PART_OF]->(:Root)
|
|
170
|
+
WHERE %(branch_filter)s
|
|
171
|
+
ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
|
|
172
|
+
LIMIT 1
|
|
173
|
+
WITH np
|
|
174
|
+
WHERE r.status = "active"
|
|
175
|
+
""" % {"branch_filter": branch_filter}
|
|
176
|
+
self.add_to_query(node_query)
|
|
177
|
+
|
|
178
|
+
attr_query = """
|
|
158
179
|
MATCH (a:Attribute { uuid: $attr_uuid })
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
% rel_name
|
|
163
|
-
)
|
|
180
|
+
CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "active", from: $at }]->(np)
|
|
181
|
+
""" % {"rel_label": rel_label}
|
|
182
|
+
self.add_to_query(attr_query)
|
|
164
183
|
|
|
165
|
-
self.add_to_query(query)
|
|
166
184
|
self.return_labels = ["a", "np", "r"]
|
|
167
185
|
|
|
168
186
|
|
|
187
|
+
class AttributeClearNodePropertyQuery(AttributeQuery):
|
|
188
|
+
name = "attribute_clear_node_property"
|
|
189
|
+
type: QueryType = QueryType.WRITE
|
|
190
|
+
insert_return: bool = False
|
|
191
|
+
|
|
192
|
+
def __init__(
|
|
193
|
+
self,
|
|
194
|
+
prop_name: str,
|
|
195
|
+
prop_id: str | None = None,
|
|
196
|
+
**kwargs: Any,
|
|
197
|
+
):
|
|
198
|
+
self.prop_name = prop_name
|
|
199
|
+
self.prop_id = prop_id
|
|
200
|
+
|
|
201
|
+
super().__init__(**kwargs)
|
|
202
|
+
|
|
203
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
204
|
+
at = self.at or self.attr.at
|
|
205
|
+
|
|
206
|
+
branch_filter, branch_params = self.branch.get_query_filter_path(at=at)
|
|
207
|
+
self.params.update(branch_params)
|
|
208
|
+
self.params["attr_uuid"] = self.attr.id
|
|
209
|
+
self.params["branch"] = self.branch.name
|
|
210
|
+
self.params["branch_level"] = self.branch.hierarchy_level
|
|
211
|
+
self.params["at"] = at.to_string()
|
|
212
|
+
self.params["prop_name"] = self.prop_name
|
|
213
|
+
self.params["prop_id"] = self.prop_id
|
|
214
|
+
|
|
215
|
+
rel_label = f"HAS_{self.prop_name.upper()}"
|
|
216
|
+
query = """
|
|
217
|
+
MATCH (a:Attribute { uuid: $attr_uuid })-[r:%(rel_label)s]->(np:Node { uuid: $prop_id })
|
|
218
|
+
WITH DISTINCT a, np
|
|
219
|
+
CALL (a, np) {
|
|
220
|
+
MATCH (a)-[r:%(rel_label)s]->(np)
|
|
221
|
+
WHERE %(branch_filter)s
|
|
222
|
+
ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
|
|
223
|
+
LIMIT 1
|
|
224
|
+
RETURN r AS property_edge
|
|
225
|
+
}
|
|
226
|
+
WITH a, np, property_edge
|
|
227
|
+
WHERE property_edge.status = "active"
|
|
228
|
+
CALL (property_edge) {
|
|
229
|
+
WITH property_edge
|
|
230
|
+
WHERE property_edge.branch = $branch
|
|
231
|
+
SET property_edge.to = $at
|
|
232
|
+
}
|
|
233
|
+
CALL (a, np, property_edge) {
|
|
234
|
+
WITH property_edge
|
|
235
|
+
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)
|
|
237
|
+
}
|
|
238
|
+
""" % {"branch_filter": branch_filter, "rel_label": rel_label}
|
|
239
|
+
self.add_to_query(query)
|
|
240
|
+
|
|
241
|
+
|
|
169
242
|
class AttributeGetQuery(AttributeQuery):
|
|
170
243
|
name = "attribute_get"
|
|
171
244
|
type: QueryType = QueryType.READ
|
|
@@ -204,7 +277,6 @@ async def default_attribute_query_filter(
|
|
|
204
277
|
param_prefix: str | None = None,
|
|
205
278
|
db: InfrahubDatabase | None = None, # noqa: ARG001
|
|
206
279
|
partial_match: bool = False,
|
|
207
|
-
support_profiles: bool = False,
|
|
208
280
|
) -> tuple[list[QueryElement], dict[str, Any], list[str]]:
|
|
209
281
|
"""Generate Query String Snippet to filter the right node."""
|
|
210
282
|
attribute_value_label = GraphAttributeValueNode.get_default_label()
|
|
@@ -251,9 +323,6 @@ async def default_attribute_query_filter(
|
|
|
251
323
|
query_where.append(f"toString(av.{filter_name}) =~ ${param_prefix}_{filter_name}")
|
|
252
324
|
elif filter_name == "isnull":
|
|
253
325
|
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
254
|
-
elif support_profiles:
|
|
255
|
-
query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
|
|
256
|
-
query_where.append(f"(av.{filter_name} = ${param_prefix}_{filter_name} OR av.is_default)")
|
|
257
326
|
else:
|
|
258
327
|
query_filter.append(
|
|
259
328
|
QueryNode(
|
|
@@ -271,8 +340,6 @@ async def default_attribute_query_filter(
|
|
|
271
340
|
if attribute_kind and attribute_kind == "List":
|
|
272
341
|
query_params[f"{param_prefix}_{filter_name}"] = build_regex_attrs(values=filter_value)
|
|
273
342
|
query_where.append(f"toString(av.value) =~ ${param_prefix}_{filter_name}")
|
|
274
|
-
elif support_profiles:
|
|
275
|
-
query_where.append(f"(av.value IN ${param_prefix}_value OR av.is_default)")
|
|
276
343
|
else:
|
|
277
344
|
query_where.append(f"av.value IN ${param_prefix}_value")
|
|
278
345
|
query_params[f"{param_prefix}_value"] = filter_value
|
infrahub/core/query/ipam.py
CHANGED
|
@@ -450,12 +450,23 @@ class IPPrefixReconcileQuery(Query):
|
|
|
450
450
|
// ------------------
|
|
451
451
|
CALL (ip_node) {
|
|
452
452
|
OPTIONAL MATCH parent_prefix_path = (ip_node)-[r1:IS_RELATED]->(:Relationship {name: "parent__child"})-[r2:IS_RELATED]->(current_parent:%(ip_prefix_kind)s)
|
|
453
|
-
WHERE
|
|
453
|
+
WHERE $is_prefix = TRUE
|
|
454
|
+
AND all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
|
|
454
455
|
RETURN current_parent, (r1.status = "active" AND r2.status = "active") AS parent_is_active
|
|
455
456
|
ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
|
|
456
457
|
LIMIT 1
|
|
457
458
|
}
|
|
458
|
-
WITH ip_namespace, ip_node, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as
|
|
459
|
+
WITH ip_namespace, ip_node, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as prefix_parent
|
|
460
|
+
CALL (ip_node) {
|
|
461
|
+
OPTIONAL MATCH parent_prefix_path = (ip_node)-[r1:IS_RELATED]->(:Relationship {name: "ip_prefix__ip_address"})<-[r2:IS_RELATED]-(current_parent:%(ip_prefix_kind)s)
|
|
462
|
+
WHERE $is_prefix = FALSE
|
|
463
|
+
AND all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
|
|
464
|
+
RETURN current_parent, (r1.status = "active" AND r2.status = "active") AS parent_is_active
|
|
465
|
+
ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
|
|
466
|
+
LIMIT 1
|
|
467
|
+
}
|
|
468
|
+
WITH ip_namespace, ip_node, prefix_parent, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as address_parent
|
|
469
|
+
WITH ip_namespace, ip_node, COALESCE(prefix_parent, address_parent) AS current_parent
|
|
459
470
|
""" % {
|
|
460
471
|
"branch_filter": branch_filter,
|
|
461
472
|
"ip_prefix_kind": InfrahubKind.IPPREFIX,
|
|
@@ -467,7 +478,7 @@ class IPPrefixReconcileQuery(Query):
|
|
|
467
478
|
// Get prefix node's current prefix children, if any exist
|
|
468
479
|
// ------------------
|
|
469
480
|
CALL (ip_node) {
|
|
470
|
-
OPTIONAL MATCH child_prefix_path = (ip_node)<-[r1:IS_RELATED]-(:Relationship {name: "parent__child"})<-[r2:IS_RELATED]-(current_prefix_child:%(ip_prefix_kind)s)
|
|
481
|
+
OPTIONAL MATCH child_prefix_path = (ip_node:%(ip_prefix_kind)s)<-[r1:IS_RELATED]-(:Relationship {name: "parent__child"})<-[r2:IS_RELATED]-(current_prefix_child:%(ip_prefix_kind)s)
|
|
471
482
|
WHERE all(r IN relationships(child_prefix_path) WHERE (%(branch_filter)s))
|
|
472
483
|
WITH current_prefix_child, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
473
484
|
ORDER BY current_prefix_child.uuid, r1.branch_level DESC, r1.from DESC, r2.branch_level DESC, r2.from DESC
|
|
@@ -479,7 +490,7 @@ class IPPrefixReconcileQuery(Query):
|
|
|
479
490
|
// Get prefix node's current address children, if any exist
|
|
480
491
|
// ------------------
|
|
481
492
|
CALL (ip_node) {
|
|
482
|
-
OPTIONAL MATCH child_address_path = (ip_node)-[r1:IS_RELATED]
|
|
493
|
+
OPTIONAL MATCH child_address_path = (ip_node:%(ip_prefix_kind)s)-[r1:IS_RELATED]->(:Relationship {name: "ip_prefix__ip_address"})<-[r2:IS_RELATED]-(current_address_child:%(ip_address_kind)s)
|
|
483
494
|
WHERE all(r IN relationships(child_address_path) WHERE (%(branch_filter)s))
|
|
484
495
|
WITH current_address_child, (r1.status = "active" AND r2.status = "active") AS is_active
|
|
485
496
|
ORDER BY current_address_child.uuid, r1.branch_level DESC, r1.from DESC, r2.branch_level DESC, r2.from DESC
|
|
@@ -688,6 +699,7 @@ class IPPrefixReconcileQuery(Query):
|
|
|
688
699
|
"ip_address_attribute_kind": ADDRESS_ATTRIBUTE_LABEL,
|
|
689
700
|
}
|
|
690
701
|
self.add_to_query(get_new_children_query)
|
|
702
|
+
self.order_by = ["ip_node.uuid"]
|
|
691
703
|
self.return_labels = ["ip_node", "current_parent", "current_children", "new_parent", "new_children"]
|
|
692
704
|
|
|
693
705
|
def _get_uuid_from_query(self, node_name: str) -> str | None:
|
infrahub/core/query/node.py
CHANGED
|
@@ -11,6 +11,7 @@ from infrahub import config
|
|
|
11
11
|
from infrahub.core import registry
|
|
12
12
|
from infrahub.core.constants import (
|
|
13
13
|
GLOBAL_BRANCH_NAME,
|
|
14
|
+
PROFILE_NODE_RELATIONSHIP_IDENTIFIER,
|
|
14
15
|
AttributeDBNodeType,
|
|
15
16
|
RelationshipDirection,
|
|
16
17
|
RelationshipHierarchyDirection,
|
|
@@ -43,7 +44,6 @@ class NodeToProcess:
|
|
|
43
44
|
|
|
44
45
|
node_id: str
|
|
45
46
|
node_uuid: str
|
|
46
|
-
profile_uuids: list[str]
|
|
47
47
|
|
|
48
48
|
updated_at: str
|
|
49
49
|
|
|
@@ -142,9 +142,22 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
142
142
|
attributes_ipnetwork: list[AttributeCreateData] = []
|
|
143
143
|
attributes_indexed: list[AttributeCreateData] = []
|
|
144
144
|
|
|
145
|
+
if self.node.has_display_label():
|
|
146
|
+
attributes_indexed.append(
|
|
147
|
+
self.node._display_label.get_node_attribute(node=self.node, at=at).get_create_data(
|
|
148
|
+
node_schema=self.node.get_schema()
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
if self.node.has_human_friendly_id():
|
|
152
|
+
attributes_indexed.append(
|
|
153
|
+
self.node._human_friendly_id.get_node_attribute(node=self.node, at=at).get_create_data(
|
|
154
|
+
node_schema=self.node.get_schema()
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
|
|
145
158
|
for attr_name in self.node._attributes:
|
|
146
159
|
attr: BaseAttribute = getattr(self.node, attr_name)
|
|
147
|
-
attr_data = attr.get_create_data()
|
|
160
|
+
attr_data = attr.get_create_data(node_schema=self.node.get_schema())
|
|
148
161
|
node_type = attr.get_db_node_type()
|
|
149
162
|
|
|
150
163
|
if AttributeDBNodeType.IPHOST in node_type:
|
|
@@ -610,6 +623,7 @@ class NodeListGetAttributeQuery(Query):
|
|
|
610
623
|
|
|
611
624
|
async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG002
|
|
612
625
|
self.params["ids"] = self.ids
|
|
626
|
+
self.params["profile_relationship_name"] = PROFILE_NODE_RELATIONSHIP_IDENTIFIER
|
|
613
627
|
|
|
614
628
|
branch_filter, branch_params = self.branch.get_query_filter_path(
|
|
615
629
|
at=self.at, branch_agnostic=self.branch_agnostic
|
|
@@ -618,6 +632,7 @@ class NodeListGetAttributeQuery(Query):
|
|
|
618
632
|
|
|
619
633
|
query = """
|
|
620
634
|
MATCH (n:Node) WHERE n.uuid IN $ids
|
|
635
|
+
WITH n, exists((n)-[:IS_RELATED]-(:Relationship {name: $profile_relationship_name})) AS might_use_profile
|
|
621
636
|
MATCH (n)-[:HAS_ATTRIBUTE]-(a:Attribute)
|
|
622
637
|
"""
|
|
623
638
|
if self.fields:
|
|
@@ -628,27 +643,36 @@ class NodeListGetAttributeQuery(Query):
|
|
|
628
643
|
|
|
629
644
|
query = """
|
|
630
645
|
CALL (n, a) {
|
|
631
|
-
MATCH (n)-[r:HAS_ATTRIBUTE]
|
|
646
|
+
MATCH (n)-[r:HAS_ATTRIBUTE]-(a:Attribute)
|
|
632
647
|
WHERE %(branch_filter)s
|
|
633
|
-
RETURN r
|
|
648
|
+
RETURN r AS r1
|
|
649
|
+
ORDER BY r.branch_level DESC, r.from DESC
|
|
650
|
+
LIMIT 1
|
|
651
|
+
}
|
|
652
|
+
WITH n, r1, a, might_use_profile
|
|
653
|
+
WHERE r1.status = "active"
|
|
654
|
+
WITH n, r1, a, might_use_profile
|
|
655
|
+
CALL (a, might_use_profile) {
|
|
656
|
+
OPTIONAL MATCH (a)-[r:HAS_SOURCE]->(:CoreProfile)
|
|
657
|
+
WHERE might_use_profile = TRUE AND %(branch_filter)s
|
|
658
|
+
RETURN r.status = "active" AS has_active_profile
|
|
634
659
|
ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
|
|
635
660
|
LIMIT 1
|
|
636
661
|
}
|
|
637
|
-
WITH
|
|
638
|
-
WHERE is_active = TRUE
|
|
662
|
+
WITH *, has_active_profile = TRUE AS is_from_profile
|
|
639
663
|
CALL (a) {
|
|
640
|
-
MATCH (a)-[r:HAS_VALUE]
|
|
664
|
+
MATCH (a)-[r:HAS_VALUE]-(av:AttributeValue)
|
|
641
665
|
WHERE %(branch_filter)s
|
|
642
|
-
RETURN
|
|
643
|
-
ORDER BY r.branch_level DESC, r.from DESC
|
|
666
|
+
RETURN r as r2, av
|
|
667
|
+
ORDER BY r.branch_level DESC, r.from DESC
|
|
644
668
|
LIMIT 1
|
|
645
669
|
}
|
|
646
|
-
WITH n, a, av,
|
|
670
|
+
WITH n, r1, a, r2, av, is_from_profile
|
|
647
671
|
WHERE r2.status = "active"
|
|
648
672
|
""" % {"branch_filter": branch_filter}
|
|
649
673
|
self.add_to_query(query)
|
|
650
674
|
|
|
651
|
-
self.return_labels = ["n", "a", "av", "r2"]
|
|
675
|
+
self.return_labels = ["n", "a", "av", "r1", "r2", "is_from_profile"]
|
|
652
676
|
|
|
653
677
|
# Add Is_Protected and Is_visible
|
|
654
678
|
query = """
|
|
@@ -673,16 +697,32 @@ CALL (a) {
|
|
|
673
697
|
|
|
674
698
|
if self.include_source:
|
|
675
699
|
query = """
|
|
676
|
-
|
|
677
|
-
|
|
700
|
+
CALL (a) {
|
|
701
|
+
OPTIONAL MATCH (a)-[rel_source:HAS_SOURCE]-(source)
|
|
702
|
+
WHERE all(r IN [rel_source] WHERE ( %(branch_filter)s ))
|
|
703
|
+
RETURN source, rel_source
|
|
704
|
+
ORDER BY rel_source.branch_level DESC, rel_source.from DESC, rel_source.status ASC
|
|
705
|
+
LIMIT 1
|
|
706
|
+
}
|
|
707
|
+
WITH *,
|
|
708
|
+
CASE WHEN rel_source.status = "active" THEN source ELSE NULL END AS source,
|
|
709
|
+
CASE WHEN rel_source.status = "active" THEN rel_source ELSE NULL END AS rel_source
|
|
678
710
|
""" % {"branch_filter": branch_filter}
|
|
679
711
|
self.add_to_query(query)
|
|
680
712
|
self.return_labels.extend(["source", "rel_source"])
|
|
681
713
|
|
|
682
714
|
if self.include_owner:
|
|
683
715
|
query = """
|
|
684
|
-
|
|
685
|
-
|
|
716
|
+
CALL (a) {
|
|
717
|
+
OPTIONAL MATCH (a)-[rel_owner:HAS_OWNER]-(owner)
|
|
718
|
+
WHERE all(r IN [rel_owner] WHERE ( %(branch_filter)s ))
|
|
719
|
+
RETURN owner, rel_owner
|
|
720
|
+
ORDER BY rel_owner.branch_level DESC, rel_owner.from DESC, rel_owner.status ASC
|
|
721
|
+
LIMIT 1
|
|
722
|
+
}
|
|
723
|
+
WITH *,
|
|
724
|
+
CASE WHEN rel_owner.status = "active" THEN owner ELSE NULL END AS owner,
|
|
725
|
+
CASE WHEN rel_owner.status = "active" THEN rel_owner ELSE NULL END AS rel_owner
|
|
686
726
|
""" % {"branch_filter": branch_filter}
|
|
687
727
|
self.add_to_query(query)
|
|
688
728
|
self.return_labels.extend(["owner", "rel_owner"])
|
|
@@ -713,6 +753,7 @@ CALL (a) {
|
|
|
713
753
|
def _extract_attribute_data(self, result: QueryResult) -> AttributeFromDB:
|
|
714
754
|
attr = result.get_node("a")
|
|
715
755
|
attr_value = result.get_node("av")
|
|
756
|
+
is_from_profile = result.get_as_type(label="is_from_profile", return_type=bool)
|
|
716
757
|
|
|
717
758
|
data = AttributeFromDB(
|
|
718
759
|
name=attr.get("name"),
|
|
@@ -724,6 +765,7 @@ CALL (a) {
|
|
|
724
765
|
updated_at=result.get_rel("r2").get("from"),
|
|
725
766
|
value=attr_value.get("value"),
|
|
726
767
|
is_default=attr_value.get("is_default"),
|
|
768
|
+
is_from_profile=is_from_profile,
|
|
727
769
|
content=attr_value._properties,
|
|
728
770
|
branch=self.branch.name,
|
|
729
771
|
flag_properties={
|
|
@@ -948,6 +990,8 @@ class NodeListGetInfoQuery(Query):
|
|
|
948
990
|
at=self.at, branch_agnostic=self.branch_agnostic
|
|
949
991
|
)
|
|
950
992
|
self.params.update(branch_params)
|
|
993
|
+
self.params["ids"] = self.ids
|
|
994
|
+
self.order_by = ["n.uuid"]
|
|
951
995
|
|
|
952
996
|
query = """
|
|
953
997
|
MATCH p = (root:Root)<-[:IS_PART_OF]-(n:Node)
|
|
@@ -961,16 +1005,11 @@ class NodeListGetInfoQuery(Query):
|
|
|
961
1005
|
}
|
|
962
1006
|
WITH n1 as n, r1 as rb
|
|
963
1007
|
WHERE rb.status = "active"
|
|
964
|
-
OPTIONAL MATCH profile_path = (n)-[:IS_RELATED]->(profile_r:Relationship)<-[:IS_RELATED]-(profile:Node)-[:IS_PART_OF]->(:Root)
|
|
965
|
-
WHERE profile_r.name = "node__profile"
|
|
966
|
-
AND profile.namespace = "Profile"
|
|
967
|
-
AND all(r in relationships(profile_path) WHERE %(branch_filter)s and r.status = "active")
|
|
968
1008
|
""" % {"branch_filter": branch_filter}
|
|
969
1009
|
|
|
970
1010
|
self.add_to_query(query)
|
|
971
|
-
self.params["ids"] = self.ids
|
|
972
1011
|
|
|
973
|
-
self.return_labels = ["
|
|
1012
|
+
self.return_labels = ["n", "rb"]
|
|
974
1013
|
|
|
975
1014
|
async def get_nodes(self, db: InfrahubDatabase, duplicate: bool = False) -> AsyncIterator[NodeToProcess]:
|
|
976
1015
|
"""Return all the node objects as NodeToProcess."""
|
|
@@ -984,24 +1023,11 @@ class NodeListGetInfoQuery(Query):
|
|
|
984
1023
|
schema=schema,
|
|
985
1024
|
node_id=result.get_node("n").element_id,
|
|
986
1025
|
node_uuid=result.get_node("n").get("uuid"),
|
|
987
|
-
profile_uuids=[str(puuid) for puuid in result.get("profile_uuids")],
|
|
988
1026
|
updated_at=result.get_rel("rb").get("from"),
|
|
989
1027
|
branch=node_branch,
|
|
990
1028
|
labels=list(result.get_node("n").labels),
|
|
991
1029
|
)
|
|
992
1030
|
|
|
993
|
-
def get_profile_ids_by_node_id(self) -> dict[str, list[str]]:
|
|
994
|
-
profile_id_map: dict[str, list[str]] = {}
|
|
995
|
-
for result in self.results:
|
|
996
|
-
node_id = result.get_node("n").get("uuid")
|
|
997
|
-
profile_ids = result.get("profile_uuids")
|
|
998
|
-
if not node_id or not profile_ids:
|
|
999
|
-
continue
|
|
1000
|
-
if node_id not in profile_id_map:
|
|
1001
|
-
profile_id_map[node_id] = []
|
|
1002
|
-
profile_id_map[node_id].extend(profile_ids)
|
|
1003
|
-
return profile_id_map
|
|
1004
|
-
|
|
1005
1031
|
|
|
1006
1032
|
class FieldAttributeRequirementType(Enum):
|
|
1007
1033
|
FILTER = "filter"
|
|
@@ -1018,7 +1044,7 @@ class FieldAttributeRequirement:
|
|
|
1018
1044
|
types: list[FieldAttributeRequirementType] = dataclass_field(default_factory=list)
|
|
1019
1045
|
|
|
1020
1046
|
@property
|
|
1021
|
-
def
|
|
1047
|
+
def is_attribute_value(self) -> bool:
|
|
1022
1048
|
return bool(self.field and self.field.is_attribute and self.field_attr_name in ("value", "values", "isnull"))
|
|
1023
1049
|
|
|
1024
1050
|
@property
|
|
@@ -1029,26 +1055,10 @@ class FieldAttributeRequirement:
|
|
|
1029
1055
|
def is_order(self) -> bool:
|
|
1030
1056
|
return FieldAttributeRequirementType.ORDER in self.types
|
|
1031
1057
|
|
|
1032
|
-
@property
|
|
1033
|
-
def is_default_query_variable(self) -> str:
|
|
1034
|
-
return f"attr{self.index}_is_default"
|
|
1035
|
-
|
|
1036
1058
|
@property
|
|
1037
1059
|
def node_value_query_variable(self) -> str:
|
|
1038
1060
|
return f"attr{self.index}_node_value"
|
|
1039
1061
|
|
|
1040
|
-
@property
|
|
1041
|
-
def profile_value_query_variable(self) -> str:
|
|
1042
|
-
return f"attr{self.index}_profile_value"
|
|
1043
|
-
|
|
1044
|
-
@property
|
|
1045
|
-
def profile_final_value_query_variable(self) -> str:
|
|
1046
|
-
return f"attr{self.index}_final_profile_value"
|
|
1047
|
-
|
|
1048
|
-
@property
|
|
1049
|
-
def final_value_query_variable(self) -> str:
|
|
1050
|
-
return f"attr{self.index}_final_value"
|
|
1051
|
-
|
|
1052
1062
|
@property
|
|
1053
1063
|
def comparison_operator(self) -> str:
|
|
1054
1064
|
if self.field_attr_name == "isnull":
|
|
@@ -1184,7 +1194,6 @@ class NodeGetListQuery(Query):
|
|
|
1184
1194
|
self.params["node_ids"] = self.filters["ids"]
|
|
1185
1195
|
|
|
1186
1196
|
field_attribute_requirements = self._get_field_requirements(disable_order=disable_order)
|
|
1187
|
-
use_profiles = any(far for far in field_attribute_requirements if far.supports_profile)
|
|
1188
1197
|
await self._add_node_filter_attributes(
|
|
1189
1198
|
db=db, field_attribute_requirements=field_attribute_requirements, branch_filter=branch_filter
|
|
1190
1199
|
)
|
|
@@ -1196,21 +1205,11 @@ class NodeGetListQuery(Query):
|
|
|
1196
1205
|
for far in field_attribute_requirements:
|
|
1197
1206
|
if not far.is_order:
|
|
1198
1207
|
continue
|
|
1199
|
-
if far.supports_profile:
|
|
1200
|
-
self.order_by.append(far.final_value_query_variable)
|
|
1201
|
-
continue
|
|
1202
1208
|
self.order_by.append(far.node_value_query_variable)
|
|
1203
1209
|
|
|
1204
1210
|
# Always order by uuid to guarantee pagination, see https://github.com/opsmill/infrahub/pull/4704.
|
|
1205
1211
|
self.order_by.append("n.uuid")
|
|
1206
1212
|
|
|
1207
|
-
if use_profiles:
|
|
1208
|
-
await self._add_profiles_per_node_query(db=db, branch_filter=branch_filter)
|
|
1209
|
-
await self._add_profile_attributes(
|
|
1210
|
-
db=db, field_attribute_requirements=field_attribute_requirements, branch_filter=branch_filter
|
|
1211
|
-
)
|
|
1212
|
-
await self._add_profile_rollups(field_attribute_requirements=field_attribute_requirements)
|
|
1213
|
-
|
|
1214
1213
|
self._add_final_filter(field_attribute_requirements=field_attribute_requirements)
|
|
1215
1214
|
|
|
1216
1215
|
async def _add_node_filter_attributes(
|
|
@@ -1228,8 +1227,6 @@ class NodeGetListQuery(Query):
|
|
|
1228
1227
|
|
|
1229
1228
|
for far in field_attribute_requirements:
|
|
1230
1229
|
extra_tail_properties = {far.node_value_query_variable: "value"}
|
|
1231
|
-
if far.supports_profile:
|
|
1232
|
-
extra_tail_properties[far.is_default_query_variable] = "is_default"
|
|
1233
1230
|
subquery, subquery_params, subquery_result_name = await build_subquery_filter(
|
|
1234
1231
|
db=db,
|
|
1235
1232
|
field=far.field,
|
|
@@ -1240,7 +1237,6 @@ class NodeGetListQuery(Query):
|
|
|
1240
1237
|
branch=self.branch,
|
|
1241
1238
|
subquery_idx=far.index,
|
|
1242
1239
|
partial_match=self.partial_match,
|
|
1243
|
-
support_profiles=far.supports_profile,
|
|
1244
1240
|
extra_tail_properties=extra_tail_properties,
|
|
1245
1241
|
)
|
|
1246
1242
|
for query_var in extra_tail_properties:
|
|
@@ -1280,9 +1276,6 @@ class NodeGetListQuery(Query):
|
|
|
1280
1276
|
for far in field_attribute_requirements:
|
|
1281
1277
|
if far.field is None:
|
|
1282
1278
|
continue
|
|
1283
|
-
extra_tail_properties = {}
|
|
1284
|
-
if far.supports_profile:
|
|
1285
|
-
extra_tail_properties[far.is_default_query_variable] = "is_default"
|
|
1286
1279
|
|
|
1287
1280
|
subquery, subquery_params, _ = await build_subquery_order(
|
|
1288
1281
|
db=db,
|
|
@@ -1293,11 +1286,7 @@ class NodeGetListQuery(Query):
|
|
|
1293
1286
|
branch=self.branch,
|
|
1294
1287
|
subquery_idx=far.index,
|
|
1295
1288
|
result_prefix=far.node_value_query_variable,
|
|
1296
|
-
support_profiles=far.supports_profile,
|
|
1297
|
-
extra_tail_properties=extra_tail_properties,
|
|
1298
1289
|
)
|
|
1299
|
-
for query_var in extra_tail_properties:
|
|
1300
|
-
self._track_variable(query_var)
|
|
1301
1290
|
self._track_variable(far.node_value_query_variable)
|
|
1302
1291
|
with_str = ", ".join(self._get_tracked_variables())
|
|
1303
1292
|
|
|
@@ -1311,122 +1300,11 @@ class NodeGetListQuery(Query):
|
|
|
1311
1300
|
self.add_to_query(sort_query)
|
|
1312
1301
|
self.params.update(sort_params)
|
|
1313
1302
|
|
|
1314
|
-
async def _add_profiles_per_node_query(self, db: InfrahubDatabase, branch_filter: str) -> None:
|
|
1315
|
-
with_str = ", ".join(self._get_tracked_variables())
|
|
1316
|
-
froms_str = db.render_list_comprehension(items="relationships(profile_path)", item_name="from")
|
|
1317
|
-
profiles_per_node_query = (
|
|
1318
|
-
"""
|
|
1319
|
-
CALL (n) {
|
|
1320
|
-
OPTIONAL MATCH profile_path = (n)-[:IS_RELATED]->(profile_r:Relationship)<-[:IS_RELATED]-(maybe_profile_n:Node)-[:IS_PART_OF]->(:Root)
|
|
1321
|
-
WHERE profile_r.name = "node__profile"
|
|
1322
|
-
AND all(r in relationships(profile_path) WHERE %(branch_filter)s)
|
|
1323
|
-
WITH
|
|
1324
|
-
maybe_profile_n,
|
|
1325
|
-
profile_path,
|
|
1326
|
-
reduce(br_lvl = 0, r in relationships(profile_path) | br_lvl + r.branch_level) AS branch_level,
|
|
1327
|
-
%(froms_str)s AS froms,
|
|
1328
|
-
all(r in relationships(profile_path) WHERE r.status = "active") AS is_active
|
|
1329
|
-
RETURN maybe_profile_n, is_active, branch_level, froms
|
|
1330
|
-
}
|
|
1331
|
-
WITH %(with_str)s, maybe_profile_n, branch_level, froms, is_active
|
|
1332
|
-
ORDER BY n.uuid, maybe_profile_n.uuid, branch_level DESC, froms[-1] DESC, froms[-2] DESC, froms[-3] DESC
|
|
1333
|
-
WITH %(with_str)s, maybe_profile_n, collect(is_active) as ordered_is_actives
|
|
1334
|
-
WITH %(with_str)s, CASE
|
|
1335
|
-
WHEN ordered_is_actives[0] = True THEN maybe_profile_n ELSE NULL
|
|
1336
|
-
END AS profile_n
|
|
1337
|
-
CALL (profile_n) {
|
|
1338
|
-
OPTIONAL MATCH profile_priority_path = (profile_n)-[pr1:HAS_ATTRIBUTE]->(a:Attribute)-[pr2:HAS_VALUE]->(av:AttributeValue)
|
|
1339
|
-
WHERE a.name = "profile_priority"
|
|
1340
|
-
AND all(r in relationships(profile_priority_path) WHERE %(branch_filter)s and r.status = "active")
|
|
1341
|
-
RETURN av.value as profile_priority
|
|
1342
|
-
ORDER BY pr1.branch_level + pr2.branch_level DESC, pr2.from DESC, pr1.from DESC
|
|
1343
|
-
LIMIT 1
|
|
1344
|
-
}
|
|
1345
|
-
WITH %(with_str)s, profile_n, profile_priority
|
|
1346
|
-
"""
|
|
1347
|
-
) % {"branch_filter": branch_filter, "with_str": with_str, "froms_str": froms_str}
|
|
1348
|
-
self.add_to_query(profiles_per_node_query)
|
|
1349
|
-
self._track_variable("profile_n")
|
|
1350
|
-
self._track_variable("profile_priority")
|
|
1351
|
-
|
|
1352
|
-
async def _add_profile_attributes(
|
|
1353
|
-
self, db: InfrahubDatabase, field_attribute_requirements: list[FieldAttributeRequirement], branch_filter: str
|
|
1354
|
-
) -> None:
|
|
1355
|
-
attributes_queries: list[str] = []
|
|
1356
|
-
attributes_params: dict[str, Any] = {}
|
|
1357
|
-
profile_attributes = [far for far in field_attribute_requirements if far.supports_profile]
|
|
1358
|
-
|
|
1359
|
-
for profile_attr in profile_attributes:
|
|
1360
|
-
if not profile_attr.field:
|
|
1361
|
-
continue
|
|
1362
|
-
subquery, subquery_params, _ = await build_subquery_order(
|
|
1363
|
-
db=db,
|
|
1364
|
-
field=profile_attr.field,
|
|
1365
|
-
node_alias="profile_n",
|
|
1366
|
-
name=profile_attr.field_name,
|
|
1367
|
-
order_by=profile_attr.field_attr_name,
|
|
1368
|
-
branch_filter=branch_filter,
|
|
1369
|
-
branch=self.branch,
|
|
1370
|
-
subquery_idx=profile_attr.index,
|
|
1371
|
-
result_prefix=profile_attr.profile_value_query_variable,
|
|
1372
|
-
support_profiles=False,
|
|
1373
|
-
)
|
|
1374
|
-
attributes_params.update(subquery_params)
|
|
1375
|
-
self._track_variable(profile_attr.profile_value_query_variable)
|
|
1376
|
-
with_str = ", ".join(self._get_tracked_variables())
|
|
1377
|
-
|
|
1378
|
-
attributes_queries.append("CALL (profile_n) {")
|
|
1379
|
-
attributes_queries.append(subquery)
|
|
1380
|
-
attributes_queries.append("}")
|
|
1381
|
-
attributes_queries.append(f"WITH {with_str}")
|
|
1382
|
-
|
|
1383
|
-
self.add_to_query(attributes_queries)
|
|
1384
|
-
self.params.update(attributes_params)
|
|
1385
|
-
|
|
1386
|
-
async def _add_profile_rollups(self, field_attribute_requirements: list[FieldAttributeRequirement]) -> None:
|
|
1387
|
-
profile_attributes = [far for far in field_attribute_requirements if far.supports_profile]
|
|
1388
|
-
profile_value_collects = []
|
|
1389
|
-
for profile_attr in profile_attributes:
|
|
1390
|
-
self._untrack_variable(profile_attr.profile_value_query_variable)
|
|
1391
|
-
profile_value_collects.append(
|
|
1392
|
-
f"""head(
|
|
1393
|
-
reduce(
|
|
1394
|
-
non_null_values = [], v in collect({profile_attr.profile_value_query_variable}) |
|
|
1395
|
-
CASE WHEN v IS NOT NULL AND v <> "NULL" THEN non_null_values + [v] ELSE non_null_values END
|
|
1396
|
-
)
|
|
1397
|
-
) as {profile_attr.profile_final_value_query_variable}"""
|
|
1398
|
-
)
|
|
1399
|
-
self._untrack_variable("profile_n")
|
|
1400
|
-
self._untrack_variable("profile_priority")
|
|
1401
|
-
profile_rollup_with_str = ", ".join(self._get_tracked_variables() + profile_value_collects)
|
|
1402
|
-
profile_rollup_query = f"""
|
|
1403
|
-
ORDER BY n.uuid, profile_priority ASC, profile_n.uuid ASC
|
|
1404
|
-
WITH {profile_rollup_with_str}
|
|
1405
|
-
"""
|
|
1406
|
-
self.add_to_query(profile_rollup_query)
|
|
1407
|
-
for profile_attr in profile_attributes:
|
|
1408
|
-
self._track_variable(profile_attr.profile_final_value_query_variable)
|
|
1409
|
-
|
|
1410
|
-
final_value_with = []
|
|
1411
|
-
for profile_attr in profile_attributes:
|
|
1412
|
-
final_value_with.append(f"""
|
|
1413
|
-
CASE
|
|
1414
|
-
WHEN {profile_attr.is_default_query_variable} AND {profile_attr.profile_final_value_query_variable} IS NOT NULL
|
|
1415
|
-
THEN {profile_attr.profile_final_value_query_variable}
|
|
1416
|
-
ELSE {profile_attr.node_value_query_variable}
|
|
1417
|
-
END AS {profile_attr.final_value_query_variable}
|
|
1418
|
-
""")
|
|
1419
|
-
self._untrack_variable(profile_attr.is_default_query_variable)
|
|
1420
|
-
self._untrack_variable(profile_attr.profile_final_value_query_variable)
|
|
1421
|
-
self._untrack_variable(profile_attr.node_value_query_variable)
|
|
1422
|
-
final_value_with_str = ", ".join(self._get_tracked_variables() + final_value_with)
|
|
1423
|
-
self.add_to_query(f"WITH {final_value_with_str}")
|
|
1424
|
-
|
|
1425
1303
|
def _add_final_filter(self, field_attribute_requirements: list[FieldAttributeRequirement]) -> None:
|
|
1426
1304
|
where_parts = []
|
|
1427
1305
|
where_str = ""
|
|
1428
1306
|
for far in field_attribute_requirements:
|
|
1429
|
-
if not far.is_filter or not far.
|
|
1307
|
+
if not far.is_filter or not far.is_attribute_value:
|
|
1430
1308
|
continue
|
|
1431
1309
|
var_name = f"final_attr_value{far.index}"
|
|
1432
1310
|
self.params[var_name] = far.field_attr_comparison_value
|
|
@@ -1435,11 +1313,11 @@ class NodeGetListQuery(Query):
|
|
|
1435
1313
|
# If the any filter is an array/list
|
|
1436
1314
|
var_array = f"{var_name}_array"
|
|
1437
1315
|
where_parts.append(
|
|
1438
|
-
f"any({var_array} IN ${var_name} WHERE toLower(toString({far.
|
|
1316
|
+
f"any({var_array} IN ${var_name} WHERE toLower(toString({far.node_value_query_variable})) CONTAINS toLower({var_array}))"
|
|
1439
1317
|
)
|
|
1440
1318
|
else:
|
|
1441
1319
|
where_parts.append(
|
|
1442
|
-
f"toLower(toString({far.
|
|
1320
|
+
f"toLower(toString({far.node_value_query_variable})) CONTAINS toLower(toString(${var_name}))"
|
|
1443
1321
|
)
|
|
1444
1322
|
continue
|
|
1445
1323
|
if far.field and isinstance(far.field, AttributeSchema) and far.field.kind == "List":
|
|
@@ -1448,10 +1326,10 @@ class NodeGetListQuery(Query):
|
|
|
1448
1326
|
else:
|
|
1449
1327
|
self.params[var_name] = build_regex_attrs(values=[far.field_attr_comparison_value])
|
|
1450
1328
|
|
|
1451
|
-
where_parts.append(f"toString({far.
|
|
1329
|
+
where_parts.append(f"toString({far.node_value_query_variable}) =~ ${var_name}")
|
|
1452
1330
|
continue
|
|
1453
1331
|
|
|
1454
|
-
where_parts.append(f"{far.
|
|
1332
|
+
where_parts.append(f"{far.node_value_query_variable} {far.comparison_operator} ${var_name}")
|
|
1455
1333
|
if where_parts:
|
|
1456
1334
|
where_str = "WHERE " + " AND ".join(where_parts)
|
|
1457
1335
|
self.add_to_query(where_str)
|