infrahub-server 1.2.11__py3-none-any.whl → 1.3.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/constants.py +130 -0
- infrahub/actions/gather.py +114 -0
- infrahub/actions/models.py +243 -0
- infrahub/actions/parsers.py +104 -0
- infrahub/actions/schema.py +393 -0
- infrahub/actions/tasks.py +119 -0
- infrahub/actions/triggers.py +21 -0
- infrahub/branch/__init__.py +0 -0
- infrahub/branch/tasks.py +29 -0
- infrahub/branch/triggers.py +22 -0
- infrahub/cli/db.py +3 -4
- infrahub/computed_attribute/gather.py +3 -1
- infrahub/computed_attribute/tasks.py +23 -29
- infrahub/core/account.py +24 -47
- infrahub/core/attribute.py +13 -15
- infrahub/core/constants/__init__.py +10 -0
- infrahub/core/constants/database.py +1 -0
- infrahub/core/constants/infrahubkind.py +9 -0
- infrahub/core/constraint/node/runner.py +3 -1
- infrahub/core/convert_object_type/__init__.py +0 -0
- infrahub/core/convert_object_type/conversion.py +124 -0
- infrahub/core/convert_object_type/schema_mapping.py +56 -0
- infrahub/core/diff/coordinator.py +8 -1
- infrahub/core/diff/query/all_conflicts.py +1 -5
- infrahub/core/diff/query/artifact.py +10 -20
- infrahub/core/diff/query/delete_query.py +8 -4
- infrahub/core/diff/query/diff_get.py +3 -6
- infrahub/core/diff/query/field_specifiers.py +1 -1
- infrahub/core/diff/query/field_summary.py +2 -4
- infrahub/core/diff/query/merge.py +72 -125
- infrahub/core/diff/query/save.py +83 -68
- infrahub/core/diff/query/summary_counts_enricher.py +34 -54
- infrahub/core/diff/query/time_range_query.py +0 -1
- infrahub/core/diff/repository/repository.py +4 -0
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/manager.py +14 -11
- infrahub/core/migrations/graph/__init__.py +6 -0
- infrahub/core/migrations/graph/m003_relationship_parent_optional.py +1 -2
- infrahub/core/migrations/graph/m012_convert_account_generic.py +1 -1
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +2 -6
- infrahub/core/migrations/graph/m015_diff_format_update.py +1 -2
- infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -2
- infrahub/core/migrations/graph/m019_restore_rels_to_time.py +11 -22
- infrahub/core/migrations/graph/m020_duplicate_edges.py +3 -6
- infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +1 -2
- infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +2 -2
- infrahub/core/migrations/graph/m024_missing_hierarchy_backfill.py +1 -2
- infrahub/core/migrations/graph/m028_delete_diffs.py +1 -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 +14 -11
- infrahub/core/migrations/query/attribute_rename.py +6 -11
- infrahub/core/migrations/query/delete_element_in_schema.py +19 -17
- infrahub/core/migrations/query/node_duplicate.py +19 -21
- infrahub/core/migrations/query/relationship_duplicate.py +19 -18
- infrahub/core/migrations/schema/node_attribute_remove.py +4 -8
- infrahub/core/migrations/schema/node_remove.py +19 -20
- infrahub/core/models.py +29 -2
- infrahub/core/node/__init__.py +131 -28
- infrahub/core/node/base.py +1 -1
- infrahub/core/node/create.py +211 -0
- infrahub/core/node/resource_manager/number_pool.py +31 -5
- infrahub/core/node/standard.py +6 -1
- infrahub/core/path.py +15 -1
- infrahub/core/protocols.py +57 -0
- infrahub/core/protocols_base.py +3 -0
- infrahub/core/query/__init__.py +2 -2
- infrahub/core/query/delete.py +3 -3
- infrahub/core/query/diff.py +19 -32
- infrahub/core/query/ipam.py +10 -20
- infrahub/core/query/node.py +29 -47
- infrahub/core/query/relationship.py +55 -34
- infrahub/core/query/resource_manager.py +1 -2
- infrahub/core/query/standard_node.py +19 -5
- infrahub/core/query/subquery.py +2 -4
- infrahub/core/relationship/constraints/count.py +10 -9
- infrahub/core/relationship/constraints/interface.py +2 -1
- infrahub/core/relationship/constraints/peer_kind.py +2 -1
- infrahub/core/relationship/constraints/peer_parent.py +56 -0
- infrahub/core/relationship/constraints/peer_relatives.py +72 -0
- infrahub/core/relationship/constraints/profiles_kind.py +1 -1
- infrahub/core/relationship/model.py +4 -1
- infrahub/core/schema/__init__.py +2 -1
- infrahub/core/schema/attribute_parameters.py +160 -0
- infrahub/core/schema/attribute_schema.py +130 -7
- infrahub/core/schema/basenode_schema.py +27 -3
- infrahub/core/schema/definitions/core/__init__.py +29 -1
- infrahub/core/schema/definitions/core/group.py +45 -0
- infrahub/core/schema/definitions/core/resource_pool.py +9 -0
- infrahub/core/schema/definitions/internal.py +43 -5
- infrahub/core/schema/generated/attribute_schema.py +16 -3
- infrahub/core/schema/generated/relationship_schema.py +11 -1
- infrahub/core/schema/manager.py +7 -2
- infrahub/core/schema/schema_branch.py +109 -12
- infrahub/core/validators/__init__.py +15 -2
- infrahub/core/validators/attribute/choices.py +1 -3
- infrahub/core/validators/attribute/enum.py +1 -3
- infrahub/core/validators/attribute/kind.py +1 -3
- infrahub/core/validators/attribute/length.py +13 -7
- infrahub/core/validators/attribute/min_max.py +118 -0
- infrahub/core/validators/attribute/number_pool.py +106 -0
- infrahub/core/validators/attribute/optional.py +1 -4
- infrahub/core/validators/attribute/regex.py +5 -6
- infrahub/core/validators/attribute/unique.py +1 -3
- infrahub/core/validators/determiner.py +18 -2
- infrahub/core/validators/enum.py +12 -0
- infrahub/core/validators/node/hierarchy.py +3 -6
- infrahub/core/validators/query.py +1 -3
- infrahub/core/validators/relationship/count.py +6 -12
- infrahub/core/validators/relationship/optional.py +2 -4
- infrahub/core/validators/relationship/peer.py +177 -12
- infrahub/core/validators/tasks.py +1 -1
- infrahub/core/validators/uniqueness/query.py +5 -9
- infrahub/database/__init__.py +12 -4
- infrahub/database/validation.py +100 -0
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +4 -0
- infrahub/dependencies/builder/constraint/relationship_manager/peer_parent.py +8 -0
- infrahub/dependencies/builder/constraint/relationship_manager/peer_relatives.py +8 -0
- infrahub/dependencies/builder/constraint/schema/aggregated.py +2 -0
- infrahub/dependencies/builder/constraint/schema/relationship_peer.py +8 -0
- infrahub/dependencies/builder/diff/deserializer.py +1 -1
- infrahub/dependencies/registry.py +4 -0
- infrahub/events/group_action.py +1 -0
- infrahub/events/models.py +1 -1
- infrahub/git/base.py +5 -3
- infrahub/git/integrator.py +96 -5
- infrahub/git/tasks.py +1 -0
- infrahub/graphql/analyzer.py +139 -18
- infrahub/graphql/manager.py +4 -0
- infrahub/graphql/mutations/action.py +164 -0
- infrahub/graphql/mutations/convert_object_type.py +71 -0
- infrahub/graphql/mutations/main.py +25 -176
- infrahub/graphql/mutations/proposed_change.py +20 -17
- infrahub/graphql/mutations/relationship.py +32 -0
- infrahub/graphql/mutations/resource_manager.py +63 -7
- infrahub/graphql/queries/convert_object_type_mapping.py +34 -0
- infrahub/graphql/queries/resource_manager.py +7 -1
- 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/schema.py +6 -0
- infrahub/menu/menu.py +34 -2
- infrahub/message_bus/messages/__init__.py +0 -10
- infrahub/message_bus/operations/__init__.py +0 -8
- infrahub/message_bus/operations/refresh/registry.py +4 -7
- infrahub/patch/queries/delete_duplicated_edges.py +45 -39
- infrahub/pools/models.py +14 -0
- infrahub/pools/number.py +5 -3
- infrahub/pools/registration.py +22 -0
- infrahub/pools/tasks.py +126 -0
- infrahub/prefect_server/models.py +1 -19
- infrahub/proposed_change/models.py +68 -3
- infrahub/proposed_change/tasks.py +911 -34
- infrahub/schema/__init__.py +0 -0
- infrahub/schema/tasks.py +27 -0
- infrahub/schema/triggers.py +23 -0
- infrahub/task_manager/models.py +10 -6
- infrahub/trigger/catalogue.py +6 -0
- infrahub/trigger/models.py +23 -6
- infrahub/trigger/setup.py +26 -2
- infrahub/trigger/tasks.py +4 -2
- infrahub/types.py +6 -0
- infrahub/webhook/tasks.py +6 -9
- infrahub/workflows/catalogue.py +103 -1
- infrahub_sdk/client.py +43 -10
- infrahub_sdk/ctl/generator.py +4 -4
- infrahub_sdk/ctl/repository.py +1 -1
- 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} +158 -803
- 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/pytest_plugin/items/python_transform.py +2 -1
- infrahub_sdk/query_groups.py +17 -5
- 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_sdk/utils.py +7 -20
- infrahub_sdk/yaml.py +6 -5
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/METADATA +5 -5
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/RECORD +197 -168
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/WHEEL +1 -1
- infrahub_testcontainers/container.py +239 -65
- infrahub_testcontainers/docker-compose-cluster.test.yml +321 -0
- infrahub_testcontainers/docker-compose.test.yml +2 -1
- infrahub_testcontainers/helpers.py +23 -3
- infrahub_testcontainers/plugin.py +9 -0
- infrahub/message_bus/messages/check_generator_run.py +0 -26
- infrahub/message_bus/messages/finalize_validator_execution.py +0 -15
- infrahub/message_bus/messages/proposed_change/base_with_diff.py +0 -16
- infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +0 -11
- infrahub/message_bus/messages/request_generatordefinition_check.py +0 -20
- infrahub/message_bus/messages/request_proposedchange_pipeline.py +0 -23
- infrahub/message_bus/operations/check/__init__.py +0 -3
- infrahub/message_bus/operations/check/generator.py +0 -156
- infrahub/message_bus/operations/finalize/__init__.py +0 -3
- infrahub/message_bus/operations/finalize/validator.py +0 -133
- infrahub/message_bus/operations/requests/__init__.py +0 -9
- infrahub/message_bus/operations/requests/generator_definition.py +0 -140
- infrahub/message_bus/operations/requests/proposed_change.py +0 -629
- infrahub/patch/queries/consolidate_duplicated_nodes.py +0 -109
- /infrahub/{message_bus/messages/proposed_change → actions}/__init__.py +0 -0
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.11.dist-info → infrahub_server-1.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
4
4
|
|
|
5
5
|
from infrahub.core.constants import PathType
|
|
6
6
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
7
|
+
from infrahub.core.validators.enum import ConstraintIdentifier
|
|
7
8
|
|
|
8
9
|
from ..interface import ConstraintCheckerInterface
|
|
9
10
|
from ..shared import AttributeSchemaValidatorQuery
|
|
@@ -23,13 +24,12 @@ class AttributeLengthUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
23
24
|
self.params.update(branch_params)
|
|
24
25
|
|
|
25
26
|
self.params["attr_name"] = self.attribute_schema.name
|
|
26
|
-
self.params["min_length"] = self.attribute_schema.
|
|
27
|
-
self.params["max_length"] = self.attribute_schema.
|
|
27
|
+
self.params["min_length"] = self.attribute_schema.get_min_length()
|
|
28
|
+
self.params["max_length"] = self.attribute_schema.get_max_length()
|
|
28
29
|
|
|
29
30
|
query = """
|
|
30
31
|
MATCH (n:%(node_kind)s)
|
|
31
|
-
CALL {
|
|
32
|
-
WITH n
|
|
32
|
+
CALL (n) {
|
|
33
33
|
MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue)
|
|
34
34
|
WHERE all(
|
|
35
35
|
r in relationships(path)
|
|
@@ -40,7 +40,6 @@ class AttributeLengthUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
40
40
|
LIMIT 1
|
|
41
41
|
}
|
|
42
42
|
WITH full_path, node, attribute_value, value_relationship
|
|
43
|
-
WITH full_path, node, attribute_value, value_relationship
|
|
44
43
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
45
44
|
AND (
|
|
46
45
|
(toInteger($min_length) IS NOT NULL AND size(attribute_value) < toInteger($min_length))
|
|
@@ -79,14 +78,21 @@ class AttributeLengthChecker(ConstraintCheckerInterface):
|
|
|
79
78
|
return "attribute.length.update"
|
|
80
79
|
|
|
81
80
|
def supports(self, request: SchemaConstraintValidatorRequest) -> bool:
|
|
82
|
-
return request.constraint_name in (
|
|
81
|
+
return request.constraint_name in (
|
|
82
|
+
"attribute.min_length.update",
|
|
83
|
+
"attribute.max_length.update",
|
|
84
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MIN_LENGTH_UPDATE.value,
|
|
85
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MAX_LENGTH_UPDATE.value,
|
|
86
|
+
)
|
|
83
87
|
|
|
84
88
|
async def check(self, request: SchemaConstraintValidatorRequest) -> list[GroupedDataPaths]:
|
|
85
89
|
grouped_data_paths_list: list[GroupedDataPaths] = []
|
|
86
90
|
if not request.schema_path.field_name:
|
|
87
91
|
raise ValueError("field_name is not defined")
|
|
88
92
|
attribute_schema = request.node_schema.get_attribute(name=request.schema_path.field_name)
|
|
89
|
-
|
|
93
|
+
min_length = attribute_schema.get_min_length()
|
|
94
|
+
max_length = attribute_schema.get_max_length()
|
|
95
|
+
if min_length is None and max_length is None:
|
|
90
96
|
return grouped_data_paths_list
|
|
91
97
|
|
|
92
98
|
for query_class in self.query_classes:
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from infrahub.core.constants import PathType
|
|
6
|
+
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
7
|
+
from infrahub.core.schema.attribute_parameters import NumberAttributeParameters
|
|
8
|
+
from infrahub.core.validators.enum import ConstraintIdentifier
|
|
9
|
+
|
|
10
|
+
from ..interface import ConstraintCheckerInterface
|
|
11
|
+
from ..shared import AttributeSchemaValidatorQuery
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from infrahub.core.branch import Branch
|
|
15
|
+
from infrahub.database import InfrahubDatabase
|
|
16
|
+
|
|
17
|
+
from ..model import SchemaConstraintValidatorRequest
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AttributeNumberUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
21
|
+
name: str = "attribute_constraints_number_validator"
|
|
22
|
+
|
|
23
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
24
|
+
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
|
|
25
|
+
self.params.update(branch_params)
|
|
26
|
+
|
|
27
|
+
if not isinstance(self.attribute_schema.parameters, NumberAttributeParameters):
|
|
28
|
+
raise ValueError("attribute parameters are not a NumberAttributeParameters")
|
|
29
|
+
|
|
30
|
+
self.params["attr_name"] = self.attribute_schema.name
|
|
31
|
+
self.params["min_value"] = self.attribute_schema.parameters.min_value
|
|
32
|
+
self.params["max_value"] = self.attribute_schema.parameters.max_value
|
|
33
|
+
self.params["excluded_values"] = self.attribute_schema.parameters.get_excluded_single_values()
|
|
34
|
+
self.params["excluded_ranges"] = self.attribute_schema.parameters.get_excluded_ranges()
|
|
35
|
+
|
|
36
|
+
query = """
|
|
37
|
+
MATCH (n:%(node_kind)s)
|
|
38
|
+
CALL (n) {
|
|
39
|
+
MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue)
|
|
40
|
+
WHERE all(
|
|
41
|
+
r in relationships(path)
|
|
42
|
+
WHERE %(branch_filter)s
|
|
43
|
+
)
|
|
44
|
+
RETURN path as full_path, n as node, rv as value_relationship, av.value as attribute_value
|
|
45
|
+
ORDER BY rv.branch_level DESC, ra.branch_level DESC, rr.branch_level DESC, rv.from DESC, ra.from DESC, rr.from DESC
|
|
46
|
+
LIMIT 1
|
|
47
|
+
}
|
|
48
|
+
WITH full_path, node, attribute_value, value_relationship
|
|
49
|
+
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
50
|
+
AND (
|
|
51
|
+
(toInteger($min_value) IS NOT NULL AND attribute_value < toInteger($min_value))
|
|
52
|
+
OR (toInteger($max_value) IS NOT NULL AND attribute_value > toInteger($max_value))
|
|
53
|
+
OR (size($excluded_values) > 0 AND attribute_value IN $excluded_values)
|
|
54
|
+
OR (size($excluded_ranges) > 0 AND any(range in $excluded_ranges WHERE attribute_value >= range[0] AND attribute_value <= range[1]))
|
|
55
|
+
)
|
|
56
|
+
""" % {"branch_filter": branch_filter, "node_kind": self.node_schema.kind}
|
|
57
|
+
|
|
58
|
+
self.add_to_query(query)
|
|
59
|
+
self.return_labels = ["node.uuid", "value_relationship", "attribute_value"]
|
|
60
|
+
|
|
61
|
+
async def get_paths(self) -> GroupedDataPaths:
|
|
62
|
+
grouped_data_paths = GroupedDataPaths()
|
|
63
|
+
for result in self.results:
|
|
64
|
+
grouped_data_paths.add_data_path(
|
|
65
|
+
DataPath(
|
|
66
|
+
branch=str(result.get("value_relationship").get("branch")),
|
|
67
|
+
path_type=PathType.ATTRIBUTE,
|
|
68
|
+
node_id=str(result.get("node.uuid")),
|
|
69
|
+
field_name=self.attribute_schema.name,
|
|
70
|
+
kind=self.node_schema.kind,
|
|
71
|
+
value=result.get("attribute_value"),
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return grouped_data_paths
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class AttributeNumberChecker(ConstraintCheckerInterface):
|
|
79
|
+
query_classes = [AttributeNumberUpdateValidatorQuery]
|
|
80
|
+
|
|
81
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
|
|
82
|
+
self.db = db
|
|
83
|
+
self.branch = branch
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def name(self) -> str:
|
|
87
|
+
return "attribute.number.update"
|
|
88
|
+
|
|
89
|
+
def supports(self, request: SchemaConstraintValidatorRequest) -> bool:
|
|
90
|
+
return request.constraint_name in (
|
|
91
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MIN_VALUE_UPDATE.value,
|
|
92
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MAX_VALUE_UPDATE.value,
|
|
93
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_EXCLUDED_VALUES_UPDATE.value,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
async def check(self, request: SchemaConstraintValidatorRequest) -> list[GroupedDataPaths]:
|
|
97
|
+
grouped_data_paths_list: list[GroupedDataPaths] = []
|
|
98
|
+
if not request.schema_path.field_name:
|
|
99
|
+
raise ValueError("field_name is not defined")
|
|
100
|
+
attribute_schema = request.node_schema.get_attribute(name=request.schema_path.field_name)
|
|
101
|
+
if not isinstance(attribute_schema.parameters, NumberAttributeParameters):
|
|
102
|
+
raise ValueError("attribute parameters are not a NumberAttributeParameters")
|
|
103
|
+
|
|
104
|
+
if (
|
|
105
|
+
attribute_schema.parameters.min_value is None
|
|
106
|
+
and attribute_schema.parameters.max_value is None
|
|
107
|
+
and attribute_schema.parameters.excluded_values is None
|
|
108
|
+
):
|
|
109
|
+
return grouped_data_paths_list
|
|
110
|
+
|
|
111
|
+
for query_class in self.query_classes:
|
|
112
|
+
# TODO add exception handling
|
|
113
|
+
query = await query_class.init(
|
|
114
|
+
db=self.db, branch=self.branch, node_schema=request.node_schema, schema_path=request.schema_path
|
|
115
|
+
)
|
|
116
|
+
await query.execute(db=self.db)
|
|
117
|
+
grouped_data_paths_list.append(await query.get_paths())
|
|
118
|
+
return grouped_data_paths_list
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from infrahub.core.constants import PathType
|
|
6
|
+
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
7
|
+
from infrahub.core.schema.attribute_parameters import NumberPoolParameters
|
|
8
|
+
from infrahub.core.validators.enum import ConstraintIdentifier
|
|
9
|
+
|
|
10
|
+
from ..interface import ConstraintCheckerInterface
|
|
11
|
+
from ..shared import AttributeSchemaValidatorQuery
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from infrahub.core.branch import Branch
|
|
15
|
+
from infrahub.database import InfrahubDatabase
|
|
16
|
+
|
|
17
|
+
from ..model import SchemaConstraintValidatorRequest
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AttributeNumberPoolUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
21
|
+
name: str = "attribute_constraints_numberpool_validator"
|
|
22
|
+
|
|
23
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
24
|
+
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
|
|
25
|
+
self.params.update(branch_params)
|
|
26
|
+
|
|
27
|
+
if not isinstance(self.attribute_schema.parameters, NumberPoolParameters):
|
|
28
|
+
raise ValueError("attribute parameters are not a NumberPoolParameters")
|
|
29
|
+
|
|
30
|
+
self.params["attr_name"] = self.attribute_schema.name
|
|
31
|
+
self.params["start_range"] = self.attribute_schema.parameters.start_range
|
|
32
|
+
self.params["end_range"] = self.attribute_schema.parameters.end_range
|
|
33
|
+
|
|
34
|
+
query = """
|
|
35
|
+
MATCH (n:%(node_kind)s)
|
|
36
|
+
CALL (n) {
|
|
37
|
+
MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue)
|
|
38
|
+
WHERE all(
|
|
39
|
+
r in relationships(path)
|
|
40
|
+
WHERE %(branch_filter)s
|
|
41
|
+
)
|
|
42
|
+
RETURN path as full_path, n as node, rv as value_relationship, av.value as attribute_value
|
|
43
|
+
ORDER BY rv.branch_level DESC, ra.branch_level DESC, rr.branch_level DESC, rv.from DESC, ra.from DESC, rr.from DESC
|
|
44
|
+
LIMIT 1
|
|
45
|
+
}
|
|
46
|
+
WITH full_path, node, attribute_value, value_relationship
|
|
47
|
+
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
48
|
+
AND (
|
|
49
|
+
(toInteger($start_range) IS NOT NULL AND attribute_value < toInteger($start_range))
|
|
50
|
+
OR (toInteger($end_range) IS NOT NULL AND attribute_value > toInteger($end_range))
|
|
51
|
+
)
|
|
52
|
+
""" % {"branch_filter": branch_filter, "node_kind": self.node_schema.kind}
|
|
53
|
+
|
|
54
|
+
self.add_to_query(query)
|
|
55
|
+
self.return_labels = ["node.uuid", "value_relationship", "attribute_value"]
|
|
56
|
+
|
|
57
|
+
async def get_paths(self) -> GroupedDataPaths:
|
|
58
|
+
grouped_data_paths = GroupedDataPaths()
|
|
59
|
+
for result in self.results:
|
|
60
|
+
grouped_data_paths.add_data_path(
|
|
61
|
+
DataPath(
|
|
62
|
+
branch=str(result.get("value_relationship").get("branch")),
|
|
63
|
+
path_type=PathType.ATTRIBUTE,
|
|
64
|
+
node_id=str(result.get("node.uuid")),
|
|
65
|
+
field_name=self.attribute_schema.name,
|
|
66
|
+
kind=self.node_schema.kind,
|
|
67
|
+
value=result.get("attribute_value"),
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return grouped_data_paths
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class AttributeNumberPoolChecker(ConstraintCheckerInterface):
|
|
75
|
+
query_classes = [AttributeNumberPoolUpdateValidatorQuery]
|
|
76
|
+
|
|
77
|
+
def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
|
|
78
|
+
self.db = db
|
|
79
|
+
self.branch = branch
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def name(self) -> str:
|
|
83
|
+
return "attribute.number.update"
|
|
84
|
+
|
|
85
|
+
def supports(self, request: SchemaConstraintValidatorRequest) -> bool:
|
|
86
|
+
return request.constraint_name in (
|
|
87
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_START_RANGE_UPDATE.value,
|
|
88
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_END_RANGE_UPDATE.value,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
async def check(self, request: SchemaConstraintValidatorRequest) -> list[GroupedDataPaths]:
|
|
92
|
+
grouped_data_paths_list: list[GroupedDataPaths] = []
|
|
93
|
+
if not request.schema_path.field_name:
|
|
94
|
+
raise ValueError("field_name is not defined")
|
|
95
|
+
attribute_schema = request.node_schema.get_attribute(name=request.schema_path.field_name)
|
|
96
|
+
if not isinstance(attribute_schema.parameters, NumberPoolParameters):
|
|
97
|
+
raise ValueError("attribute parameters are not a NumberPoolParameters")
|
|
98
|
+
|
|
99
|
+
for query_class in self.query_classes:
|
|
100
|
+
# TODO add exception handling
|
|
101
|
+
query = await query_class.init(
|
|
102
|
+
db=self.db, branch=self.branch, node_schema=request.node_schema, schema_path=request.schema_path
|
|
103
|
+
)
|
|
104
|
+
await query.execute(db=self.db)
|
|
105
|
+
grouped_data_paths_list.append(await query.get_paths())
|
|
106
|
+
return grouped_data_paths_list
|
|
@@ -27,8 +27,7 @@ class AttributeOptionalUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
27
27
|
|
|
28
28
|
query = """
|
|
29
29
|
MATCH (n:%(node_kind)s)
|
|
30
|
-
CALL {
|
|
31
|
-
WITH n
|
|
30
|
+
CALL (n) {
|
|
32
31
|
MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue)
|
|
33
32
|
WHERE all(
|
|
34
33
|
r in relationships(path)
|
|
@@ -39,7 +38,6 @@ class AttributeOptionalUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
39
38
|
LIMIT 1
|
|
40
39
|
}
|
|
41
40
|
WITH full_path, node, attribute_value, value_relationship
|
|
42
|
-
WITH full_path, node, attribute_value, value_relationship
|
|
43
41
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
44
42
|
AND (attribute_value IS NULL OR attribute_value = $null_value)
|
|
45
43
|
""" % {"branch_filter": branch_filter, "node_kind": self.node_schema.kind}
|
|
@@ -86,7 +84,6 @@ class AttributeOptionalChecker(ConstraintCheckerInterface):
|
|
|
86
84
|
return grouped_data_paths_list
|
|
87
85
|
|
|
88
86
|
for query_class in self.query_classes:
|
|
89
|
-
# TODO add exception handling
|
|
90
87
|
query = await query_class.init(
|
|
91
88
|
db=self.db, branch=self.branch, node_schema=request.node_schema, schema_path=request.schema_path
|
|
92
89
|
)
|
|
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
4
4
|
|
|
5
5
|
from infrahub.core.constants import NULL_VALUE, PathType
|
|
6
6
|
from infrahub.core.path import DataPath, GroupedDataPaths
|
|
7
|
+
from infrahub.core.validators.enum import ConstraintIdentifier
|
|
7
8
|
|
|
8
9
|
from ..interface import ConstraintCheckerInterface
|
|
9
10
|
from ..shared import AttributeSchemaValidatorQuery
|
|
@@ -23,12 +24,11 @@ class AttributeRegexUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
23
24
|
self.params.update(branch_params)
|
|
24
25
|
|
|
25
26
|
self.params["attr_name"] = self.attribute_schema.name
|
|
26
|
-
self.params["attr_value_regex"] = self.attribute_schema.
|
|
27
|
+
self.params["attr_value_regex"] = self.attribute_schema.get_regex()
|
|
27
28
|
self.params["null_value"] = NULL_VALUE
|
|
28
29
|
query = """
|
|
29
30
|
MATCH p = (n:%(node_kind)s)
|
|
30
|
-
CALL {
|
|
31
|
-
WITH n
|
|
31
|
+
CALL (n) {
|
|
32
32
|
MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue)
|
|
33
33
|
WHERE all(
|
|
34
34
|
r in relationships(path)
|
|
@@ -39,7 +39,6 @@ class AttributeRegexUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
39
39
|
LIMIT 1
|
|
40
40
|
}
|
|
41
41
|
WITH full_path, node, attribute_value, value_relationship
|
|
42
|
-
WITH full_path, node, attribute_value, value_relationship
|
|
43
42
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
44
43
|
AND attribute_value <> $null_value
|
|
45
44
|
AND NOT attribute_value =~ $attr_value_regex
|
|
@@ -79,14 +78,14 @@ class AttributeRegexChecker(ConstraintCheckerInterface):
|
|
|
79
78
|
return "attribute.regex.update"
|
|
80
79
|
|
|
81
80
|
def supports(self, request: SchemaConstraintValidatorRequest) -> bool:
|
|
82
|
-
return request.constraint_name
|
|
81
|
+
return request.constraint_name in (self.name, ConstraintIdentifier.ATTRIBUTE_PARAMETERS_REGEX_UPDATE.value)
|
|
83
82
|
|
|
84
83
|
async def check(self, request: SchemaConstraintValidatorRequest) -> list[GroupedDataPaths]:
|
|
85
84
|
grouped_data_paths_list: list[GroupedDataPaths] = []
|
|
86
85
|
if not request.schema_path.field_name:
|
|
87
86
|
raise ValueError("field_name is not defined")
|
|
88
87
|
attribute_schema = request.node_schema.get_attribute(name=request.schema_path.field_name)
|
|
89
|
-
if not attribute_schema.
|
|
88
|
+
if not attribute_schema.get_regex():
|
|
90
89
|
return grouped_data_paths_list
|
|
91
90
|
|
|
92
91
|
for query_class in self.query_classes:
|
|
@@ -31,12 +31,10 @@ class AttributeUniqueUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
31
31
|
query = """
|
|
32
32
|
MATCH (potential_node:Node)
|
|
33
33
|
WHERE $node_kind IN LABELS(potential_node)
|
|
34
|
-
CALL {
|
|
35
|
-
WITH potential_node
|
|
34
|
+
CALL (potential_node) {
|
|
36
35
|
MATCH potential_path = (potential_node)-[:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name })-[potential_value_relationship:HAS_VALUE]-(potential_value:AttributeValue)
|
|
37
36
|
WHERE all(r IN relationships(potential_path) WHERE (%(branch_filter)s))
|
|
38
37
|
WITH
|
|
39
|
-
potential_node,
|
|
40
38
|
potential_value,
|
|
41
39
|
potential_value_relationship,
|
|
42
40
|
potential_path,
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any
|
|
2
|
+
|
|
1
3
|
from infrahub.core.constants import RelationshipKind, SchemaPathType
|
|
2
4
|
from infrahub.core.constants.schema import UpdateSupport
|
|
3
5
|
from infrahub.core.diff.model.path import NodeDiffFieldSummary
|
|
4
6
|
from infrahub.core.models import SchemaUpdateConstraintInfo
|
|
5
7
|
from infrahub.core.path import SchemaPath
|
|
6
8
|
from infrahub.core.schema import AttributeSchema, MainSchemaTypes
|
|
9
|
+
from infrahub.core.schema.attribute_parameters import AttributeParameters
|
|
7
10
|
from infrahub.core.schema.relationship_schema import RelationshipSchema
|
|
8
11
|
from infrahub.core.schema.schema_branch import SchemaBranch
|
|
9
12
|
from infrahub.core.validators import CONSTRAINT_VALIDATOR_MAP
|
|
10
13
|
from infrahub.log import get_logger
|
|
11
14
|
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from pydantic.fields import FieldInfo
|
|
17
|
+
|
|
12
18
|
LOG = get_logger(__name__)
|
|
13
19
|
|
|
14
20
|
|
|
@@ -133,7 +139,17 @@ class ConstraintValidatorDeterminer:
|
|
|
133
139
|
self, schema: MainSchemaTypes, field: AttributeSchema | RelationshipSchema
|
|
134
140
|
) -> list[SchemaUpdateConstraintInfo]:
|
|
135
141
|
constraints: list[SchemaUpdateConstraintInfo] = []
|
|
136
|
-
|
|
142
|
+
prop_details_list: list[tuple[str, FieldInfo, Any]] = []
|
|
143
|
+
for p_name, p_info in field.model_fields.items():
|
|
144
|
+
p_value = getattr(field, p_name)
|
|
145
|
+
if isinstance(p_value, AttributeParameters):
|
|
146
|
+
for parameter_name, parameter_field_info in p_value.model_fields.items():
|
|
147
|
+
parameter_value = getattr(p_value, parameter_name)
|
|
148
|
+
prop_details_list.append((f"{p_name}.{parameter_name}", parameter_field_info, parameter_value))
|
|
149
|
+
else:
|
|
150
|
+
prop_details_list.append((p_name, p_info, p_value))
|
|
151
|
+
|
|
152
|
+
for prop_name, prop_field_info, prop_value in prop_details_list:
|
|
137
153
|
if not prop_field_info.json_schema_extra or not isinstance(prop_field_info.json_schema_extra, dict):
|
|
138
154
|
continue
|
|
139
155
|
|
|
@@ -141,7 +157,7 @@ class ConstraintValidatorDeterminer:
|
|
|
141
157
|
if prop_field_update != UpdateSupport.VALIDATE_CONSTRAINT.value:
|
|
142
158
|
continue
|
|
143
159
|
|
|
144
|
-
if
|
|
160
|
+
if prop_value is None:
|
|
145
161
|
continue
|
|
146
162
|
|
|
147
163
|
path_type = SchemaPathType.ATTRIBUTE
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ConstraintIdentifier(str, Enum):
|
|
5
|
+
ATTRIBUTE_PARAMETERS_REGEX_UPDATE = "attribute.parameters.regex.update"
|
|
6
|
+
ATTRIBUTE_PARAMETERS_MIN_LENGTH_UPDATE = "attribute.parameters.min_length.update"
|
|
7
|
+
ATTRIBUTE_PARAMETERS_MAX_LENGTH_UPDATE = "attribute.parameters.max_length.update"
|
|
8
|
+
ATTRIBUTE_PARAMETERS_MIN_VALUE_UPDATE = "attribute.parameters.min_value.update"
|
|
9
|
+
ATTRIBUTE_PARAMETERS_MAX_VALUE_UPDATE = "attribute.parameters.max_value.update"
|
|
10
|
+
ATTRIBUTE_PARAMETERS_EXCLUDED_VALUES_UPDATE = "attribute.parameters.excluded_values.update"
|
|
11
|
+
ATTRIBUTE_PARAMETERS_END_RANGE_UPDATE = "attribute.parameters.end_range.update"
|
|
12
|
+
ATTRIBUTE_PARAMETERS_START_RANGE_UPDATE = "attribute.parameters.start_range.update"
|
|
@@ -59,8 +59,7 @@ class NodeHierarchyUpdateValidatorQuery(SchemaValidatorQuery):
|
|
|
59
59
|
# ruff: noqa: E501
|
|
60
60
|
query = """
|
|
61
61
|
MATCH (n:%(node_kind)s)
|
|
62
|
-
CALL {
|
|
63
|
-
WITH n
|
|
62
|
+
CALL (n) {
|
|
64
63
|
MATCH path = (root:Root)<-[rroot:IS_PART_OF]-(n)
|
|
65
64
|
WHERE all(r in relationships(path) WHERE %(branch_filter)s)
|
|
66
65
|
RETURN path as full_path, n as active_node
|
|
@@ -70,8 +69,7 @@ class NodeHierarchyUpdateValidatorQuery(SchemaValidatorQuery):
|
|
|
70
69
|
WITH full_path, active_node
|
|
71
70
|
WITH full_path, active_node
|
|
72
71
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
73
|
-
CALL {
|
|
74
|
-
WITH active_node
|
|
72
|
+
CALL (active_node) {
|
|
75
73
|
MATCH path = (active_node)%(to_children)s-[hrel1:IS_RELATED]-%(to_parent)s(:Relationship {name: "parent__child"})%(to_children)s-[hrel2:IS_RELATED]-%(to_parent)s(peer:Node)
|
|
76
74
|
WHERE all(
|
|
77
75
|
r in relationships(path)
|
|
@@ -91,8 +89,7 @@ class NodeHierarchyUpdateValidatorQuery(SchemaValidatorQuery):
|
|
|
91
89
|
collect([branch_level_sum, from_times, active_relationship_count, hierarchy_path, deepest_branch_name]) as enriched_paths,
|
|
92
90
|
start_node,
|
|
93
91
|
peer_node
|
|
94
|
-
CALL {
|
|
95
|
-
WITH enriched_paths, peer_node
|
|
92
|
+
CALL (enriched_paths, peer_node) {
|
|
96
93
|
UNWIND enriched_paths as path_to_check
|
|
97
94
|
RETURN path_to_check[3] as current_path, path_to_check[4] as branch_name, peer_node as current_peer
|
|
98
95
|
ORDER BY
|
|
@@ -20,8 +20,7 @@ class NodeNotPresentValidatorQuery(SchemaValidatorQuery):
|
|
|
20
20
|
|
|
21
21
|
query = """
|
|
22
22
|
MATCH (n:%(node_kind)s)
|
|
23
|
-
CALL {
|
|
24
|
-
WITH n
|
|
23
|
+
CALL (n) {
|
|
25
24
|
MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)
|
|
26
25
|
WHERE all(
|
|
27
26
|
r in relationships(path)
|
|
@@ -32,7 +31,6 @@ class NodeNotPresentValidatorQuery(SchemaValidatorQuery):
|
|
|
32
31
|
LIMIT 1
|
|
33
32
|
}
|
|
34
33
|
WITH full_path, node, root_relationship
|
|
35
|
-
WITH full_path, node, root_relationship
|
|
36
34
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
37
35
|
""" % {"branch_filter": branch_filter, "node_kind": self.node_schema.kind}
|
|
38
36
|
|
|
@@ -50,8 +50,7 @@ class RelationshipCountUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
|
|
|
50
50
|
query = """
|
|
51
51
|
// get the nodes on these branches nodes
|
|
52
52
|
MATCH (n:%(node_kind)s)
|
|
53
|
-
CALL {
|
|
54
|
-
WITH n
|
|
53
|
+
CALL (n) {
|
|
55
54
|
MATCH path = (root:Root)<-[rroot:IS_PART_OF]-(n)
|
|
56
55
|
WHERE all(r in relationships(path) WHERE %(branch_filter)s)
|
|
57
56
|
RETURN path as full_path, n as active_node
|
|
@@ -60,11 +59,9 @@ class RelationshipCountUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
|
|
|
60
59
|
}
|
|
61
60
|
// filter to only the active nodes
|
|
62
61
|
WITH full_path, active_node
|
|
63
|
-
WITH full_path, active_node
|
|
64
62
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
65
63
|
// get the relationships using the given identifier for each node
|
|
66
|
-
CALL {
|
|
67
|
-
WITH active_node
|
|
64
|
+
CALL (active_node) {
|
|
68
65
|
MATCH path = (active_node)-[rrel1:IS_RELATED]-(rel:Relationship { name: $relationship_id })-[rrel2:IS_RELATED]-(peer:Node)
|
|
69
66
|
WHERE ($relationship_direction <> "outbound" OR (startNode(rrel1) = active_node AND startNode(rrel2) = rel))
|
|
70
67
|
AND ($relationship_direction <> "inbound" OR (startNode(rrel1) = rel AND startNode(rrel2) = peer))
|
|
@@ -87,8 +84,7 @@ class RelationshipCountUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
|
|
|
87
84
|
start_node,
|
|
88
85
|
peer_node
|
|
89
86
|
// make sure to only use the latest version of this particular path
|
|
90
|
-
CALL {
|
|
91
|
-
WITH enriched_paths, peer_node
|
|
87
|
+
CALL (enriched_paths, peer_node) {
|
|
92
88
|
UNWIND enriched_paths as path_to_check
|
|
93
89
|
RETURN path_to_check[3] as current_path, path_to_check[4] as branch_name, peer_node as current_peer
|
|
94
90
|
ORDER BY
|
|
@@ -100,8 +96,7 @@ class RelationshipCountUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
|
|
|
100
96
|
}
|
|
101
97
|
// filter to only the current active paths
|
|
102
98
|
WITH collect([current_peer, current_path]) as peers_and_paths, start_node, branch_name
|
|
103
|
-
CALL {
|
|
104
|
-
WITH peers_and_paths
|
|
99
|
+
CALL (peers_and_paths) {
|
|
105
100
|
UNWIND peers_and_paths AS peer_and_path
|
|
106
101
|
WITH peer_and_path
|
|
107
102
|
WHERE all(r in relationships(peer_and_path[1]) WHERE r.status = "active")
|
|
@@ -109,9 +104,8 @@ class RelationshipCountUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
|
|
|
109
104
|
}
|
|
110
105
|
// sum all the relationships across branches and identify the violators
|
|
111
106
|
WITH collect([branch_name, num_relationships_on_branch]) as branches_and_counts, start_node
|
|
112
|
-
CALL {
|
|
113
|
-
WITH
|
|
114
|
-
WITH start_node, branches_and_counts, reduce(rel_total = 0, bnc in branches_and_counts | rel_total + bnc[1]) AS total_relationships_count
|
|
107
|
+
CALL (start_node, branches_and_counts) {
|
|
108
|
+
WITH reduce(rel_total = 0, bnc in branches_and_counts | rel_total + bnc[1]) AS total_relationships_count
|
|
115
109
|
WHERE
|
|
116
110
|
(toInteger($min_count) IS NOT NULL AND total_relationships_count < toInteger($min_count))
|
|
117
111
|
OR (toInteger($max_count) IS NOT NULL AND total_relationships_count > toInteger($max_count))
|
|
@@ -30,8 +30,7 @@ class RelationshipOptionalUpdateValidatorQuery(RelationshipSchemaValidatorQuery)
|
|
|
30
30
|
// Query all Active Nodes of type
|
|
31
31
|
// and store their UUID in uuids_active_node
|
|
32
32
|
MATCH (n:%(node_kind)s)
|
|
33
|
-
CALL {
|
|
34
|
-
WITH n
|
|
33
|
+
CALL (n) {
|
|
35
34
|
MATCH (root:Root)<-[r:IS_PART_OF]-(n)
|
|
36
35
|
WHERE %(branch_filter)s
|
|
37
36
|
RETURN n as n1, r as r1
|
|
@@ -44,8 +43,7 @@ class RelationshipOptionalUpdateValidatorQuery(RelationshipSchemaValidatorQuery)
|
|
|
44
43
|
// identifier all nodes with at least one active member for this relationship
|
|
45
44
|
// and store their UUID in uuids_with_rel
|
|
46
45
|
MATCH (n:%(node_kind)s)
|
|
47
|
-
CALL {
|
|
48
|
-
WITH n, uuids_active_node
|
|
46
|
+
CALL (n, uuids_active_node) {
|
|
49
47
|
MATCH path = (n)-[r:IS_RELATED]-(:Relationship { name: $relationship_id })
|
|
50
48
|
WHERE %(branch_filter)s
|
|
51
49
|
RETURN n as n1, r as r1
|