infrahub-server 1.2.9rc0__py3-none-any.whl → 1.3.0a0__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 +86 -0
- infrahub/actions/gather.py +114 -0
- infrahub/actions/models.py +241 -0
- infrahub/actions/parsers.py +104 -0
- infrahub/actions/schema.py +382 -0
- infrahub/actions/tasks.py +126 -0
- infrahub/actions/triggers.py +21 -0
- infrahub/cli/db.py +1 -2
- infrahub/computed_attribute/models.py +13 -0
- infrahub/computed_attribute/tasks.py +48 -26
- infrahub/config.py +9 -0
- infrahub/core/account.py +24 -47
- infrahub/core/attribute.py +53 -14
- infrahub/core/branch/models.py +8 -9
- infrahub/core/branch/tasks.py +0 -2
- infrahub/core/constants/infrahubkind.py +8 -0
- infrahub/core/constraint/node/runner.py +1 -1
- infrahub/core/convert_object_type/__init__.py +0 -0
- infrahub/core/convert_object_type/conversion.py +122 -0
- infrahub/core/convert_object_type/schema_mapping.py +56 -0
- infrahub/core/diff/calculator.py +65 -11
- infrahub/core/diff/combiner.py +38 -31
- infrahub/core/diff/coordinator.py +44 -28
- infrahub/core/diff/data_check_synchronizer.py +3 -2
- infrahub/core/diff/enricher/hierarchy.py +36 -27
- infrahub/core/diff/ipam_diff_parser.py +5 -4
- infrahub/core/diff/merger/merger.py +46 -16
- infrahub/core/diff/merger/serializer.py +1 -0
- infrahub/core/diff/model/field_specifiers_map.py +64 -0
- infrahub/core/diff/model/path.py +58 -58
- infrahub/core/diff/parent_node_adder.py +14 -16
- infrahub/core/diff/query/all_conflicts.py +1 -5
- infrahub/core/diff/query/artifact.py +10 -20
- infrahub/core/diff/query/diff_get.py +3 -6
- infrahub/core/diff/query/drop_nodes.py +42 -0
- infrahub/core/diff/query/field_specifiers.py +8 -7
- infrahub/core/diff/query/field_summary.py +2 -4
- infrahub/core/diff/query/filters.py +15 -1
- infrahub/core/diff/query/merge.py +284 -101
- infrahub/core/diff/query/save.py +26 -34
- infrahub/core/diff/query/summary_counts_enricher.py +34 -54
- infrahub/core/diff/query_parser.py +55 -65
- infrahub/core/diff/repository/deserializer.py +38 -24
- infrahub/core/diff/repository/repository.py +31 -12
- infrahub/core/diff/tasks.py +3 -3
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/manager.py +14 -11
- infrahub/core/migrations/graph/__init__.py +2 -0
- infrahub/core/migrations/graph/m003_relationship_parent_optional.py +1 -2
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +2 -4
- 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/m024_missing_hierarchy_backfill.py +1 -2
- infrahub/core/migrations/graph/m027_delete_isolated_nodes.py +50 -0
- infrahub/core/migrations/graph/m028_delete_diffs.py +38 -0
- infrahub/core/migrations/query/attribute_add.py +1 -2
- infrahub/core/migrations/query/attribute_rename.py +3 -6
- infrahub/core/migrations/query/delete_element_in_schema.py +3 -6
- infrahub/core/migrations/query/node_duplicate.py +3 -6
- infrahub/core/migrations/query/relationship_duplicate.py +3 -6
- infrahub/core/migrations/schema/node_attribute_remove.py +3 -6
- infrahub/core/migrations/schema/node_remove.py +3 -6
- infrahub/core/models.py +29 -2
- infrahub/core/node/__init__.py +18 -4
- infrahub/core/node/create.py +211 -0
- infrahub/core/protocols.py +51 -0
- infrahub/core/protocols_base.py +3 -0
- infrahub/core/query/__init__.py +2 -2
- infrahub/core/query/branch.py +27 -17
- infrahub/core/query/diff.py +186 -81
- infrahub/core/query/ipam.py +10 -20
- infrahub/core/query/node.py +65 -49
- infrahub/core/query/relationship.py +156 -58
- infrahub/core/query/resource_manager.py +1 -2
- infrahub/core/query/subquery.py +4 -6
- infrahub/core/relationship/model.py +4 -1
- infrahub/core/schema/__init__.py +2 -1
- infrahub/core/schema/attribute_parameters.py +36 -0
- infrahub/core/schema/attribute_schema.py +83 -8
- infrahub/core/schema/basenode_schema.py +25 -1
- infrahub/core/schema/definitions/core/__init__.py +21 -0
- infrahub/core/schema/definitions/internal.py +13 -3
- infrahub/core/schema/generated/attribute_schema.py +9 -3
- infrahub/core/schema/schema_branch.py +15 -7
- infrahub/core/validators/__init__.py +5 -1
- infrahub/core/validators/attribute/choices.py +1 -2
- infrahub/core/validators/attribute/enum.py +1 -2
- infrahub/core/validators/attribute/kind.py +1 -2
- infrahub/core/validators/attribute/length.py +13 -6
- infrahub/core/validators/attribute/optional.py +1 -2
- infrahub/core/validators/attribute/regex.py +5 -5
- infrahub/core/validators/attribute/unique.py +1 -3
- infrahub/core/validators/determiner.py +18 -2
- infrahub/core/validators/enum.py +7 -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 +3 -8
- infrahub/core/validators/tasks.py +1 -1
- infrahub/core/validators/uniqueness/query.py +12 -9
- infrahub/database/__init__.py +1 -3
- infrahub/events/group_action.py +1 -0
- infrahub/graphql/analyzer.py +139 -18
- infrahub/graphql/app.py +1 -1
- infrahub/graphql/loaders/node.py +1 -1
- infrahub/graphql/loaders/peers.py +1 -1
- infrahub/graphql/manager.py +4 -0
- infrahub/graphql/mutations/action.py +164 -0
- infrahub/graphql/mutations/convert_object_type.py +62 -0
- infrahub/graphql/mutations/main.py +24 -175
- infrahub/graphql/mutations/proposed_change.py +21 -18
- infrahub/graphql/queries/convert_object_type_mapping.py +36 -0
- infrahub/graphql/queries/diff/tree.py +2 -1
- infrahub/graphql/queries/relationship.py +1 -1
- infrahub/graphql/resolvers/many_relationship.py +4 -4
- infrahub/graphql/resolvers/resolver.py +4 -4
- infrahub/graphql/resolvers/single_relationship.py +2 -2
- infrahub/graphql/schema.py +6 -0
- infrahub/graphql/subscription/graphql_query.py +2 -2
- infrahub/graphql/types/branch.py +1 -1
- infrahub/menu/menu.py +31 -0
- infrahub/message_bus/messages/__init__.py +0 -10
- infrahub/message_bus/operations/__init__.py +0 -8
- infrahub/message_bus/operations/refresh/registry.py +1 -1
- infrahub/patch/queries/consolidate_duplicated_nodes.py +3 -6
- infrahub/patch/queries/delete_duplicated_edges.py +5 -10
- infrahub/prefect_server/models.py +1 -19
- infrahub/proposed_change/models.py +68 -3
- infrahub/proposed_change/tasks.py +907 -30
- infrahub/task_manager/models.py +10 -6
- infrahub/telemetry/database.py +1 -1
- infrahub/telemetry/tasks.py +1 -1
- infrahub/trigger/catalogue.py +2 -0
- infrahub/trigger/models.py +29 -3
- infrahub/trigger/setup.py +51 -15
- infrahub/trigger/tasks.py +4 -5
- infrahub/types.py +1 -1
- infrahub/webhook/models.py +2 -1
- infrahub/workflows/catalogue.py +85 -0
- infrahub/workflows/initialization.py +1 -3
- infrahub_sdk/timestamp.py +2 -2
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/METADATA +4 -4
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/RECORD +153 -146
- infrahub_testcontainers/container.py +0 -1
- infrahub_testcontainers/docker-compose.test.yml +4 -4
- infrahub_testcontainers/helpers.py +8 -2
- infrahub_testcontainers/performance_test.py +6 -3
- 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/{message_bus/messages/proposed_change → actions}/__init__.py +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.2.9rc0.dist-info → infrahub_server-1.3.0a0.dist-info}/entry_points.txt +0 -0
|
@@ -13,7 +13,7 @@ from pydantic import field_validator
|
|
|
13
13
|
from infrahub.core.constants import RelationshipCardinality, RelationshipKind
|
|
14
14
|
from infrahub.core.models import HashableModel, HashableModelDiff
|
|
15
15
|
|
|
16
|
-
from .attribute_schema import AttributeSchema
|
|
16
|
+
from .attribute_schema import AttributeSchema, get_attribute_schema_class_for_kind
|
|
17
17
|
from .generated.base_node_schema import GeneratedBaseNodeSchema
|
|
18
18
|
from .relationship_schema import RelationshipSchema
|
|
19
19
|
|
|
@@ -74,6 +74,30 @@ class BaseNodeSchema(GeneratedBaseNodeSchema):
|
|
|
74
74
|
Be careful hash generated from hash() have a salt by default and they will not be the same across run"""
|
|
75
75
|
return hash(self.get_hash())
|
|
76
76
|
|
|
77
|
+
@field_validator("attributes", mode="before")
|
|
78
|
+
@classmethod
|
|
79
|
+
def set_attribute_type(cls, raw_attributes: Any) -> Any:
|
|
80
|
+
if not isinstance(raw_attributes, list):
|
|
81
|
+
return raw_attributes
|
|
82
|
+
attribute_schemas_with_types: list[Any] = []
|
|
83
|
+
for raw_attr in raw_attributes:
|
|
84
|
+
if not isinstance(raw_attr, (dict, AttributeSchema)):
|
|
85
|
+
attribute_schemas_with_types.append(raw_attr)
|
|
86
|
+
continue
|
|
87
|
+
if isinstance(raw_attr, dict):
|
|
88
|
+
kind = raw_attr.get("kind")
|
|
89
|
+
attribute_type_class = get_attribute_schema_class_for_kind(kind=kind)
|
|
90
|
+
attribute_schemas_with_types.append(attribute_type_class(**raw_attr))
|
|
91
|
+
continue
|
|
92
|
+
|
|
93
|
+
expected_attr_schema_class = get_attribute_schema_class_for_kind(kind=raw_attr.kind)
|
|
94
|
+
if not isinstance(raw_attr, expected_attr_schema_class):
|
|
95
|
+
final_attr = expected_attr_schema_class(**raw_attr.model_dump())
|
|
96
|
+
else:
|
|
97
|
+
final_attr = raw_attr
|
|
98
|
+
attribute_schemas_with_types.append(final_attr)
|
|
99
|
+
return attribute_schemas_with_types
|
|
100
|
+
|
|
77
101
|
def to_dict(self) -> dict:
|
|
78
102
|
data = self.model_dump(
|
|
79
103
|
exclude_unset=True, exclude_none=True, exclude_defaults=True, exclude={"attributes", "relationships"}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
+
from infrahub.actions.schema import (
|
|
4
|
+
core_action,
|
|
5
|
+
core_generator_action,
|
|
6
|
+
core_group_action,
|
|
7
|
+
core_group_trigger_rule,
|
|
8
|
+
core_node_trigger_attribute_match,
|
|
9
|
+
core_node_trigger_match,
|
|
10
|
+
core_node_trigger_relationship_match,
|
|
11
|
+
core_node_trigger_rule,
|
|
12
|
+
core_trigger_rule,
|
|
13
|
+
)
|
|
14
|
+
|
|
3
15
|
from ...generic_schema import GenericSchema
|
|
4
16
|
from ...node_schema import NodeSchema
|
|
5
17
|
from .account import (
|
|
@@ -63,6 +75,9 @@ from .webhook import core_custom_webhook, core_standard_webhook, core_webhook
|
|
|
63
75
|
|
|
64
76
|
core_models_mixed: dict[str, list] = {
|
|
65
77
|
"generics": [
|
|
78
|
+
core_action,
|
|
79
|
+
core_trigger_rule,
|
|
80
|
+
core_node_trigger_match,
|
|
66
81
|
core_node,
|
|
67
82
|
lineage_owner,
|
|
68
83
|
core_profile_schema_definition,
|
|
@@ -90,12 +105,18 @@ core_models_mixed: dict[str, list] = {
|
|
|
90
105
|
],
|
|
91
106
|
"nodes": [
|
|
92
107
|
menu_item,
|
|
108
|
+
core_group_action,
|
|
93
109
|
core_standard_group,
|
|
94
110
|
core_generator_group,
|
|
95
111
|
core_graphql_query_group,
|
|
96
112
|
builtin_tag,
|
|
97
113
|
core_account,
|
|
98
114
|
core_account_token,
|
|
115
|
+
core_generator_action,
|
|
116
|
+
core_group_trigger_rule,
|
|
117
|
+
core_node_trigger_rule,
|
|
118
|
+
core_node_trigger_attribute_match,
|
|
119
|
+
core_node_trigger_relationship_match,
|
|
99
120
|
core_password_credential,
|
|
100
121
|
core_refresh_token,
|
|
101
122
|
core_proposed_change,
|
|
@@ -31,6 +31,7 @@ from infrahub.core.constants import (
|
|
|
31
31
|
RelationshipKind,
|
|
32
32
|
UpdateSupport,
|
|
33
33
|
)
|
|
34
|
+
from infrahub.core.schema.attribute_parameters import AttributeParameters
|
|
34
35
|
from infrahub.core.schema.attribute_schema import AttributeSchema
|
|
35
36
|
from infrahub.core.schema.computed_attribute import ComputedAttribute
|
|
36
37
|
from infrahub.core.schema.dropdown import DropdownChoice
|
|
@@ -506,21 +507,21 @@ attribute_schema = SchemaNode(
|
|
|
506
507
|
SchemaAttribute(
|
|
507
508
|
name="regex",
|
|
508
509
|
kind="Text",
|
|
509
|
-
description="Regex uses to limit the characters allowed in for the attributes.",
|
|
510
|
+
description="Regex uses to limit the characters allowed in for the attributes. (deprecated: please use parameters.regex instead)",
|
|
510
511
|
optional=True,
|
|
511
512
|
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
512
513
|
),
|
|
513
514
|
SchemaAttribute(
|
|
514
515
|
name="max_length",
|
|
515
516
|
kind="Number",
|
|
516
|
-
description="Set a maximum number of characters allowed for a given attribute.",
|
|
517
|
+
description="Set a maximum number of characters allowed for a given attribute. (deprecated: please use parameters.max_length instead)",
|
|
517
518
|
optional=True,
|
|
518
519
|
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
519
520
|
),
|
|
520
521
|
SchemaAttribute(
|
|
521
522
|
name="min_length",
|
|
522
523
|
kind="Number",
|
|
523
|
-
description="Set a minimum number of characters allowed for a given attribute.",
|
|
524
|
+
description="Set a minimum number of characters allowed for a given attribute. (deprecated: please use parameters.min_length instead)",
|
|
524
525
|
optional=True,
|
|
525
526
|
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
526
527
|
),
|
|
@@ -617,6 +618,15 @@ attribute_schema = SchemaNode(
|
|
|
617
618
|
optional=True,
|
|
618
619
|
extra={"update": UpdateSupport.ALLOWED},
|
|
619
620
|
),
|
|
621
|
+
SchemaAttribute(
|
|
622
|
+
name="parameters",
|
|
623
|
+
kind="JSON",
|
|
624
|
+
internal_kind=AttributeParameters,
|
|
625
|
+
optional=True,
|
|
626
|
+
description="Extra parameters specific to this kind of attribute",
|
|
627
|
+
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
628
|
+
default_factory="AttributeParameters",
|
|
629
|
+
),
|
|
620
630
|
SchemaAttribute(
|
|
621
631
|
name="deprecation",
|
|
622
632
|
kind="Text",
|
|
@@ -8,6 +8,7 @@ from pydantic import Field
|
|
|
8
8
|
|
|
9
9
|
from infrahub.core.constants import AllowOverrideType, BranchSupportType, HashableModelState
|
|
10
10
|
from infrahub.core.models import HashableModel
|
|
11
|
+
from infrahub.core.schema.attribute_parameters import AttributeParameters # noqa: TC001
|
|
11
12
|
from infrahub.core.schema.computed_attribute import ComputedAttribute # noqa: TC001
|
|
12
13
|
from infrahub.core.schema.dropdown import DropdownChoice # noqa: TC001
|
|
13
14
|
|
|
@@ -44,17 +45,17 @@ class GeneratedAttributeSchema(HashableModel):
|
|
|
44
45
|
)
|
|
45
46
|
regex: str | None = Field(
|
|
46
47
|
default=None,
|
|
47
|
-
description="Regex uses to limit the characters allowed in for the attributes.",
|
|
48
|
+
description="Regex uses to limit the characters allowed in for the attributes. (deprecated: please use parameters.regex instead)",
|
|
48
49
|
json_schema_extra={"update": "validate_constraint"},
|
|
49
50
|
)
|
|
50
51
|
max_length: int | None = Field(
|
|
51
52
|
default=None,
|
|
52
|
-
description="Set a maximum number of characters allowed for a given attribute.",
|
|
53
|
+
description="Set a maximum number of characters allowed for a given attribute. (deprecated: please use parameters.max_length instead)",
|
|
53
54
|
json_schema_extra={"update": "validate_constraint"},
|
|
54
55
|
)
|
|
55
56
|
min_length: int | None = Field(
|
|
56
57
|
default=None,
|
|
57
|
-
description="Set a minimum number of characters allowed for a given attribute.",
|
|
58
|
+
description="Set a minimum number of characters allowed for a given attribute. (deprecated: please use parameters.min_length instead)",
|
|
58
59
|
json_schema_extra={"update": "validate_constraint"},
|
|
59
60
|
)
|
|
60
61
|
label: str | None = Field(
|
|
@@ -112,6 +113,11 @@ class GeneratedAttributeSchema(HashableModel):
|
|
|
112
113
|
description="Type of allowed override for the attribute.",
|
|
113
114
|
json_schema_extra={"update": "allowed"},
|
|
114
115
|
)
|
|
116
|
+
parameters: AttributeParameters = Field(
|
|
117
|
+
default_factory=AttributeParameters,
|
|
118
|
+
description="Extra parameters specific to this kind of attribute",
|
|
119
|
+
json_schema_extra={"update": "validate_constraint"},
|
|
120
|
+
)
|
|
115
121
|
deprecation: str | None = Field(
|
|
116
122
|
default=None,
|
|
117
123
|
description="Mark attribute as deprecated and provide a user-friendly message to display",
|
|
@@ -49,6 +49,7 @@ from infrahub.core.schema import (
|
|
|
49
49
|
SchemaRoot,
|
|
50
50
|
TemplateSchema,
|
|
51
51
|
)
|
|
52
|
+
from infrahub.core.schema.attribute_schema import get_attribute_schema_class_for_kind
|
|
52
53
|
from infrahub.core.schema.definitions.core import core_profile_schema_definition
|
|
53
54
|
from infrahub.core.validators import CONSTRAINT_VALIDATOR_MAP
|
|
54
55
|
from infrahub.exceptions import SchemaNotFoundError, ValidationError
|
|
@@ -1136,7 +1137,7 @@ class SchemaBranch:
|
|
|
1136
1137
|
self.set(name=name, schema=node)
|
|
1137
1138
|
|
|
1138
1139
|
def process_labels(self) -> None:
|
|
1139
|
-
def check_if_need_to_update_label(node) -> bool:
|
|
1140
|
+
def check_if_need_to_update_label(node: MainSchemaTypes) -> bool:
|
|
1140
1141
|
if not node.label:
|
|
1141
1142
|
return True
|
|
1142
1143
|
for item in node.relationships + node.attributes:
|
|
@@ -1812,12 +1813,14 @@ class SchemaBranch:
|
|
|
1812
1813
|
def generate_profile_from_node(self, node: NodeSchema) -> ProfileSchema:
|
|
1813
1814
|
core_profile_schema = self.get(name=InfrahubKind.PROFILE, duplicate=False)
|
|
1814
1815
|
core_name_attr = core_profile_schema.get_attribute(name="profile_name")
|
|
1815
|
-
|
|
1816
|
+
name_attr_schema_class = get_attribute_schema_class_for_kind(kind=core_name_attr.kind)
|
|
1817
|
+
profile_name_attr = name_attr_schema_class(
|
|
1816
1818
|
**core_name_attr.model_dump(exclude=["id", "inherited"]),
|
|
1817
1819
|
)
|
|
1818
1820
|
profile_name_attr.branch = node.branch
|
|
1819
1821
|
core_priority_attr = core_profile_schema.get_attribute(name="profile_priority")
|
|
1820
|
-
|
|
1822
|
+
priority_attr_schema_class = get_attribute_schema_class_for_kind(kind=core_priority_attr.kind)
|
|
1823
|
+
profile_priority_attr = priority_attr_schema_class(
|
|
1821
1824
|
**core_priority_attr.model_dump(exclude=["id", "inherited"]),
|
|
1822
1825
|
)
|
|
1823
1826
|
profile_priority_attr.branch = node.branch
|
|
@@ -1848,8 +1851,8 @@ class SchemaBranch:
|
|
|
1848
1851
|
for node_attr in node.attributes:
|
|
1849
1852
|
if node_attr.read_only or node_attr.optional is False:
|
|
1850
1853
|
continue
|
|
1851
|
-
|
|
1852
|
-
attr =
|
|
1854
|
+
attr_schema_class = get_attribute_schema_class_for_kind(kind=node_attr.kind)
|
|
1855
|
+
attr = attr_schema_class(
|
|
1853
1856
|
optional=True,
|
|
1854
1857
|
**node_attr.model_dump(exclude=["id", "unique", "optional", "read_only", "default_value", "inherited"]),
|
|
1855
1858
|
)
|
|
@@ -1973,7 +1976,8 @@ class SchemaBranch:
|
|
|
1973
1976
|
else self.get(name=InfrahubKind.OBJECTTEMPLATE, duplicate=False)
|
|
1974
1977
|
)
|
|
1975
1978
|
core_name_attr = core_template_schema.get_attribute(name=OBJECT_TEMPLATE_NAME_ATTR)
|
|
1976
|
-
|
|
1979
|
+
name_attr_schema_class = get_attribute_schema_class_for_kind(kind=core_name_attr.kind)
|
|
1980
|
+
template_name_attr = name_attr_schema_class(
|
|
1977
1981
|
**core_name_attr.model_dump(exclude=["id", "inherited"]),
|
|
1978
1982
|
)
|
|
1979
1983
|
template_name_attr.branch = node.branch
|
|
@@ -2033,7 +2037,8 @@ class SchemaBranch:
|
|
|
2033
2037
|
if node_attr.unique or node_attr.read_only:
|
|
2034
2038
|
continue
|
|
2035
2039
|
|
|
2036
|
-
|
|
2040
|
+
attr_schema_class = get_attribute_schema_class_for_kind(kind=node_attr.kind)
|
|
2041
|
+
attr = attr_schema_class(
|
|
2037
2042
|
optional=node_attr.optional if is_autogenerated_subtemplate else True,
|
|
2038
2043
|
**node_attr.model_dump(exclude=["id", "unique", "optional", "read_only"]),
|
|
2039
2044
|
)
|
|
@@ -2050,6 +2055,9 @@ class SchemaBranch:
|
|
|
2050
2055
|
|
|
2051
2056
|
identified.add(node_schema)
|
|
2052
2057
|
|
|
2058
|
+
if node_schema.is_node_schema:
|
|
2059
|
+
identified.update([self.get(name=kind, duplicate=False) for kind in node_schema.inherit_from])
|
|
2060
|
+
|
|
2053
2061
|
for relationship in node_schema.relationships:
|
|
2054
2062
|
if (
|
|
2055
2063
|
relationship.peer in [InfrahubKind.GENERICGROUP, InfrahubKind.PROFILE]
|
|
@@ -5,6 +5,7 @@ from .attribute.length import AttributeLengthChecker
|
|
|
5
5
|
from .attribute.optional import AttributeOptionalChecker
|
|
6
6
|
from .attribute.regex import AttributeRegexChecker
|
|
7
7
|
from .attribute.unique import AttributeUniquenessChecker
|
|
8
|
+
from .enum import ConstraintIdentifier
|
|
8
9
|
from .interface import ConstraintCheckerInterface
|
|
9
10
|
from .node.attribute import NodeAttributeAddChecker
|
|
10
11
|
from .node.generate_profile import NodeGenerateProfileChecker
|
|
@@ -17,11 +18,14 @@ from .relationship.peer import RelationshipPeerChecker
|
|
|
17
18
|
from .uniqueness.checker import UniquenessChecker
|
|
18
19
|
|
|
19
20
|
CONSTRAINT_VALIDATOR_MAP: dict[str, type[ConstraintCheckerInterface] | None] = {
|
|
21
|
+
"attribute.kind.update": AttributeKindChecker,
|
|
20
22
|
"attribute.regex.update": AttributeRegexChecker,
|
|
23
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_REGEX_UPDATE.value: AttributeRegexChecker,
|
|
21
24
|
"attribute.enum.update": AttributeEnumChecker,
|
|
22
|
-
"attribute.kind.update": AttributeKindChecker,
|
|
23
25
|
"attribute.min_length.update": AttributeLengthChecker,
|
|
24
26
|
"attribute.max_length.update": AttributeLengthChecker,
|
|
27
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MIN_LENGTH_UPDATE.value: AttributeLengthChecker,
|
|
28
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MAX_LENGTH_UPDATE.value: AttributeLengthChecker,
|
|
25
29
|
"attribute.unique.update": AttributeUniquenessChecker,
|
|
26
30
|
"attribute.optional.update": AttributeOptionalChecker,
|
|
27
31
|
"attribute.choices.update": AttributeChoicesChecker,
|
|
@@ -31,8 +31,7 @@ class AttributeChoicesUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
31
31
|
|
|
32
32
|
query = """
|
|
33
33
|
MATCH p = (n:%(node_kind)s)
|
|
34
|
-
CALL {
|
|
35
|
-
WITH n
|
|
34
|
+
CALL (n) {
|
|
36
35
|
MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue)
|
|
37
36
|
WHERE all(
|
|
38
37
|
r in relationships(path)
|
|
@@ -30,8 +30,7 @@ class AttributeEnumUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
30
30
|
self.params["null_value"] = NULL_VALUE
|
|
31
31
|
query = """
|
|
32
32
|
MATCH (n:%(node_kind)s)
|
|
33
|
-
CALL {
|
|
34
|
-
WITH n
|
|
33
|
+
CALL (n) {
|
|
35
34
|
MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue)
|
|
36
35
|
WHERE all(
|
|
37
36
|
r in relationships(path)
|
|
@@ -37,8 +37,7 @@ class AttributeKindUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
37
37
|
|
|
38
38
|
query = """
|
|
39
39
|
MATCH p = (n:%(node_kind)s)
|
|
40
|
-
CALL {
|
|
41
|
-
WITH n
|
|
40
|
+
CALL (n) {
|
|
42
41
|
MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue)
|
|
43
42
|
WHERE all(
|
|
44
43
|
r in relationships(path)
|
|
@@ -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)
|
|
@@ -79,14 +79,21 @@ class AttributeLengthChecker(ConstraintCheckerInterface):
|
|
|
79
79
|
return "attribute.length.update"
|
|
80
80
|
|
|
81
81
|
def supports(self, request: SchemaConstraintValidatorRequest) -> bool:
|
|
82
|
-
return request.constraint_name in (
|
|
82
|
+
return request.constraint_name in (
|
|
83
|
+
"attribute.min_length.update",
|
|
84
|
+
"attribute.max_length.update",
|
|
85
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MIN_LENGTH_UPDATE.value,
|
|
86
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MAX_LENGTH_UPDATE.value,
|
|
87
|
+
)
|
|
83
88
|
|
|
84
89
|
async def check(self, request: SchemaConstraintValidatorRequest) -> list[GroupedDataPaths]:
|
|
85
90
|
grouped_data_paths_list: list[GroupedDataPaths] = []
|
|
86
91
|
if not request.schema_path.field_name:
|
|
87
92
|
raise ValueError("field_name is not defined")
|
|
88
93
|
attribute_schema = request.node_schema.get_attribute(name=request.schema_path.field_name)
|
|
89
|
-
|
|
94
|
+
min_length = attribute_schema.get_min_length()
|
|
95
|
+
max_length = attribute_schema.get_max_length()
|
|
96
|
+
if min_length is None and max_length is None:
|
|
90
97
|
return grouped_data_paths_list
|
|
91
98
|
|
|
92
99
|
for query_class in self.query_classes:
|
|
@@ -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)
|
|
@@ -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)
|
|
@@ -79,14 +79,14 @@ class AttributeRegexChecker(ConstraintCheckerInterface):
|
|
|
79
79
|
return "attribute.regex.update"
|
|
80
80
|
|
|
81
81
|
def supports(self, request: SchemaConstraintValidatorRequest) -> bool:
|
|
82
|
-
return request.constraint_name
|
|
82
|
+
return request.constraint_name in (self.name, ConstraintIdentifier.ATTRIBUTE_PARAMETERS_REGEX_UPDATE.value)
|
|
83
83
|
|
|
84
84
|
async def check(self, request: SchemaConstraintValidatorRequest) -> list[GroupedDataPaths]:
|
|
85
85
|
grouped_data_paths_list: list[GroupedDataPaths] = []
|
|
86
86
|
if not request.schema_path.field_name:
|
|
87
87
|
raise ValueError("field_name is not defined")
|
|
88
88
|
attribute_schema = request.node_schema.get_attribute(name=request.schema_path.field_name)
|
|
89
|
-
if not attribute_schema.
|
|
89
|
+
if not attribute_schema.get_regex():
|
|
90
90
|
return grouped_data_paths_list
|
|
91
91
|
|
|
92
92
|
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,7 @@
|
|
|
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"
|
|
@@ -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
|
|
@@ -36,8 +36,7 @@ class RelationshipPeerUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
|
|
|
36
36
|
# ruff: noqa: E501
|
|
37
37
|
query = """
|
|
38
38
|
MATCH (n:%(node_kind)s)
|
|
39
|
-
CALL {
|
|
40
|
-
WITH n
|
|
39
|
+
CALL (n) {
|
|
41
40
|
MATCH path = (root:Root)<-[rroot:IS_PART_OF]-(n)
|
|
42
41
|
WHERE all(r in relationships(path) WHERE %(branch_filter)s)
|
|
43
42
|
RETURN path as full_path, n as active_node
|
|
@@ -45,10 +44,8 @@ class RelationshipPeerUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
|
|
|
45
44
|
LIMIT 1
|
|
46
45
|
}
|
|
47
46
|
WITH full_path, active_node
|
|
48
|
-
WITH full_path, active_node
|
|
49
47
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
50
|
-
CALL {
|
|
51
|
-
WITH active_node
|
|
48
|
+
CALL (active_node) {
|
|
52
49
|
MATCH path = (active_node)-[rrel1:IS_RELATED]-(rel:Relationship { name: $relationship_id })-[rrel2:IS_RELATED]-(peer:Node)
|
|
53
50
|
WHERE all(
|
|
54
51
|
r in relationships(path)
|
|
@@ -68,8 +65,7 @@ class RelationshipPeerUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
|
|
|
68
65
|
collect([branch_level_sum, from_times, active_relationship_count, relationship_path, deepest_branch_name]) as enriched_paths,
|
|
69
66
|
start_node,
|
|
70
67
|
peer_node
|
|
71
|
-
CALL {
|
|
72
|
-
WITH enriched_paths, peer_node
|
|
68
|
+
CALL (enriched_paths, peer_node) {
|
|
73
69
|
UNWIND enriched_paths as path_to_check
|
|
74
70
|
RETURN path_to_check[3] as current_path, path_to_check[4] as branch_name, peer_node as current_peer
|
|
75
71
|
ORDER BY
|
|
@@ -80,7 +76,6 @@ class RelationshipPeerUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
|
|
|
80
76
|
LIMIT 1
|
|
81
77
|
}
|
|
82
78
|
WITH start_node, current_peer, branch_name, current_path
|
|
83
|
-
WITH start_node, current_peer, branch_name, current_path
|
|
84
79
|
WHERE all(r in relationships(current_path) WHERE r.status = "active")
|
|
85
80
|
AND NOT any(label IN LABELS(current_peer) WHERE label IN $allowed_peer_kinds)
|
|
86
81
|
""" % {"branch_filter": branch_filter, "node_kind": self.node_schema.kind}
|
|
@@ -71,7 +71,7 @@ async def schema_path_validate(
|
|
|
71
71
|
schema_branch: SchemaBranch,
|
|
72
72
|
service: InfrahubServices,
|
|
73
73
|
) -> SchemaValidatorPathResponseData:
|
|
74
|
-
async with service.database.start_session() as db:
|
|
74
|
+
async with service.database.start_session(read_only=True) as db:
|
|
75
75
|
constraint_request = SchemaConstraintValidatorRequest(
|
|
76
76
|
branch=branch,
|
|
77
77
|
constraint_name=constraint_name,
|