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
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from infrahub.core.constants import (
|
|
2
2
|
BranchSupportType,
|
|
3
3
|
InfrahubKind,
|
|
4
|
+
RepositoryObjects,
|
|
4
5
|
)
|
|
5
6
|
from infrahub.core.constants import RelationshipCardinality as Cardinality
|
|
6
7
|
from infrahub.core.constants import RelationshipKind as RelKind
|
|
8
|
+
from infrahub.core.schema.dropdown import DropdownChoice
|
|
7
9
|
|
|
8
10
|
from ...attribute_schema import AttributeSchema as Attr
|
|
9
11
|
from ...generic_schema import GenericSchema
|
|
@@ -80,6 +82,7 @@ core_generator_group = NodeSchema(
|
|
|
80
82
|
generate_profile=False,
|
|
81
83
|
)
|
|
82
84
|
|
|
85
|
+
|
|
83
86
|
core_graphql_query_group = NodeSchema(
|
|
84
87
|
name="GraphQLQueryGroup",
|
|
85
88
|
namespace="Core",
|
|
@@ -106,3 +109,45 @@ core_graphql_query_group = NodeSchema(
|
|
|
106
109
|
),
|
|
107
110
|
],
|
|
108
111
|
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
core_repository_group = NodeSchema(
|
|
115
|
+
name="RepositoryGroup",
|
|
116
|
+
namespace="Core",
|
|
117
|
+
description="Group of nodes associated with a given repository.",
|
|
118
|
+
include_in_menu=False,
|
|
119
|
+
icon="mdi:account-group",
|
|
120
|
+
label="Repository Group",
|
|
121
|
+
default_filter="name__value",
|
|
122
|
+
order_by=["name__value"],
|
|
123
|
+
display_labels=["name__value"],
|
|
124
|
+
branch=BranchSupportType.LOCAL,
|
|
125
|
+
inherit_from=[InfrahubKind.GENERICGROUP],
|
|
126
|
+
generate_profile=False,
|
|
127
|
+
attributes=[
|
|
128
|
+
Attr(
|
|
129
|
+
name="content",
|
|
130
|
+
kind="Dropdown",
|
|
131
|
+
description="Type of data to load, can be either `object` or `menu`",
|
|
132
|
+
choices=[
|
|
133
|
+
DropdownChoice(
|
|
134
|
+
name=RepositoryObjects.OBJECT.value,
|
|
135
|
+
label="Objects",
|
|
136
|
+
),
|
|
137
|
+
DropdownChoice(
|
|
138
|
+
name=RepositoryObjects.MENU.value,
|
|
139
|
+
label="Menus",
|
|
140
|
+
),
|
|
141
|
+
],
|
|
142
|
+
optional=False,
|
|
143
|
+
),
|
|
144
|
+
],
|
|
145
|
+
relationships=[
|
|
146
|
+
Rel(
|
|
147
|
+
name="repository",
|
|
148
|
+
peer=InfrahubKind.GENERICREPOSITORY,
|
|
149
|
+
optional=False,
|
|
150
|
+
cardinality=Cardinality.ONE,
|
|
151
|
+
),
|
|
152
|
+
],
|
|
153
|
+
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from infrahub.core.constants import (
|
|
2
2
|
BranchSupportType,
|
|
3
3
|
InfrahubKind,
|
|
4
|
+
NumberPoolType,
|
|
4
5
|
)
|
|
5
6
|
from infrahub.core.constants import RelationshipCardinality as Cardinality
|
|
6
7
|
from infrahub.core.constants import RelationshipKind as RelKind
|
|
@@ -186,5 +187,13 @@ core_number_pool = NodeSchema(
|
|
|
186
187
|
Attr(
|
|
187
188
|
name="end_range", kind="Number", optional=False, description="The end range for the pool", order_weight=6000
|
|
188
189
|
),
|
|
190
|
+
Attr(
|
|
191
|
+
name="pool_type",
|
|
192
|
+
kind="Text",
|
|
193
|
+
description="Defines how this number pool was created",
|
|
194
|
+
default_value=NumberPoolType.USER.value,
|
|
195
|
+
enum=NumberPoolType.available_types(),
|
|
196
|
+
read_only=True,
|
|
197
|
+
),
|
|
189
198
|
],
|
|
190
199
|
)
|
|
@@ -31,6 +31,12 @@ from infrahub.core.constants import (
|
|
|
31
31
|
RelationshipKind,
|
|
32
32
|
UpdateSupport,
|
|
33
33
|
)
|
|
34
|
+
from infrahub.core.schema.attribute_parameters import (
|
|
35
|
+
AttributeParameters,
|
|
36
|
+
NumberAttributeParameters,
|
|
37
|
+
NumberPoolParameters,
|
|
38
|
+
TextAttributeParameters,
|
|
39
|
+
)
|
|
34
40
|
from infrahub.core.schema.attribute_schema import AttributeSchema
|
|
35
41
|
from infrahub.core.schema.computed_attribute import ComputedAttribute
|
|
36
42
|
from infrahub.core.schema.dropdown import DropdownChoice
|
|
@@ -47,7 +53,7 @@ class SchemaAttribute(BaseModel):
|
|
|
47
53
|
kind: str
|
|
48
54
|
description: str
|
|
49
55
|
extra: ExtraField
|
|
50
|
-
internal_kind: type[Any] | GenericAlias | None = None
|
|
56
|
+
internal_kind: type[Any] | GenericAlias | list[type[Any]] | None = None
|
|
51
57
|
regex: str | None = None
|
|
52
58
|
unique: bool | None = None
|
|
53
59
|
optional: bool | None = None
|
|
@@ -76,7 +82,7 @@ class SchemaAttribute(BaseModel):
|
|
|
76
82
|
|
|
77
83
|
@property
|
|
78
84
|
def optional_in_model(self) -> bool:
|
|
79
|
-
if self.optional and self.default_value is None and self.default_factory is None or self.default_to_none:
|
|
85
|
+
if (self.optional and self.default_value is None and self.default_factory is None) or self.default_to_none:
|
|
80
86
|
return True
|
|
81
87
|
|
|
82
88
|
return False
|
|
@@ -93,6 +99,9 @@ class SchemaAttribute(BaseModel):
|
|
|
93
99
|
if isinstance(self.internal_kind, GenericAlias):
|
|
94
100
|
return str(self.internal_kind)
|
|
95
101
|
|
|
102
|
+
if isinstance(self.internal_kind, list):
|
|
103
|
+
return " | ".join([internal_kind.__name__ for internal_kind in self.internal_kind])
|
|
104
|
+
|
|
96
105
|
if self.internal_kind and self.kind == "List":
|
|
97
106
|
return f"list[{self.internal_kind.__name__}]"
|
|
98
107
|
|
|
@@ -506,21 +515,21 @@ attribute_schema = SchemaNode(
|
|
|
506
515
|
SchemaAttribute(
|
|
507
516
|
name="regex",
|
|
508
517
|
kind="Text",
|
|
509
|
-
description="Regex uses to limit the characters allowed in for the attributes.",
|
|
518
|
+
description="Regex uses to limit the characters allowed in for the attributes. (deprecated: please use parameters.regex instead)",
|
|
510
519
|
optional=True,
|
|
511
520
|
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
512
521
|
),
|
|
513
522
|
SchemaAttribute(
|
|
514
523
|
name="max_length",
|
|
515
524
|
kind="Number",
|
|
516
|
-
description="Set a maximum number of characters allowed for a given attribute.",
|
|
525
|
+
description="Set a maximum number of characters allowed for a given attribute. (deprecated: please use parameters.max_length instead)",
|
|
517
526
|
optional=True,
|
|
518
527
|
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
519
528
|
),
|
|
520
529
|
SchemaAttribute(
|
|
521
530
|
name="min_length",
|
|
522
531
|
kind="Number",
|
|
523
|
-
description="Set a minimum number of characters allowed for a given attribute.",
|
|
532
|
+
description="Set a minimum number of characters allowed for a given attribute. (deprecated: please use parameters.min_length instead)",
|
|
524
533
|
optional=True,
|
|
525
534
|
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
526
535
|
),
|
|
@@ -617,6 +626,20 @@ attribute_schema = SchemaNode(
|
|
|
617
626
|
optional=True,
|
|
618
627
|
extra={"update": UpdateSupport.ALLOWED},
|
|
619
628
|
),
|
|
629
|
+
SchemaAttribute(
|
|
630
|
+
name="parameters",
|
|
631
|
+
kind="JSON",
|
|
632
|
+
internal_kind=[
|
|
633
|
+
AttributeParameters,
|
|
634
|
+
TextAttributeParameters,
|
|
635
|
+
NumberAttributeParameters,
|
|
636
|
+
NumberPoolParameters,
|
|
637
|
+
],
|
|
638
|
+
optional=True,
|
|
639
|
+
description="Extra parameters specific to this kind of attribute",
|
|
640
|
+
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
641
|
+
default_factory="AttributeParameters",
|
|
642
|
+
),
|
|
620
643
|
SchemaAttribute(
|
|
621
644
|
name="deprecation",
|
|
622
645
|
kind="Text",
|
|
@@ -731,6 +754,21 @@ relationship_schema = SchemaNode(
|
|
|
731
754
|
optional=True,
|
|
732
755
|
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
733
756
|
),
|
|
757
|
+
SchemaAttribute(
|
|
758
|
+
name="common_parent",
|
|
759
|
+
kind="Text",
|
|
760
|
+
optional=True,
|
|
761
|
+
description="Name of a parent relationship on the peer schema that must share the same related object with the object's parent.",
|
|
762
|
+
extra={"update": UpdateSupport.VALIDATE_CONSTRAINT},
|
|
763
|
+
),
|
|
764
|
+
SchemaAttribute(
|
|
765
|
+
name="common_relatives",
|
|
766
|
+
kind="List",
|
|
767
|
+
internal_kind=str,
|
|
768
|
+
optional=True,
|
|
769
|
+
description="List of relationship names on the peer schema for which all objects must share the same set of peers.",
|
|
770
|
+
extra={"update": UpdateSupport.ALLOWED},
|
|
771
|
+
),
|
|
734
772
|
SchemaAttribute(
|
|
735
773
|
name="order_weight",
|
|
736
774
|
kind="Number",
|
|
@@ -8,6 +8,12 @@ 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 (
|
|
12
|
+
AttributeParameters,
|
|
13
|
+
NumberAttributeParameters,
|
|
14
|
+
NumberPoolParameters,
|
|
15
|
+
TextAttributeParameters,
|
|
16
|
+
)
|
|
11
17
|
from infrahub.core.schema.computed_attribute import ComputedAttribute # noqa: TC001
|
|
12
18
|
from infrahub.core.schema.dropdown import DropdownChoice # noqa: TC001
|
|
13
19
|
|
|
@@ -44,17 +50,17 @@ class GeneratedAttributeSchema(HashableModel):
|
|
|
44
50
|
)
|
|
45
51
|
regex: str | None = Field(
|
|
46
52
|
default=None,
|
|
47
|
-
description="Regex uses to limit the characters allowed in for the attributes.",
|
|
53
|
+
description="Regex uses to limit the characters allowed in for the attributes. (deprecated: please use parameters.regex instead)",
|
|
48
54
|
json_schema_extra={"update": "validate_constraint"},
|
|
49
55
|
)
|
|
50
56
|
max_length: int | None = Field(
|
|
51
57
|
default=None,
|
|
52
|
-
description="Set a maximum number of characters allowed for a given attribute.",
|
|
58
|
+
description="Set a maximum number of characters allowed for a given attribute. (deprecated: please use parameters.max_length instead)",
|
|
53
59
|
json_schema_extra={"update": "validate_constraint"},
|
|
54
60
|
)
|
|
55
61
|
min_length: int | None = Field(
|
|
56
62
|
default=None,
|
|
57
|
-
description="Set a minimum number of characters allowed for a given attribute.",
|
|
63
|
+
description="Set a minimum number of characters allowed for a given attribute. (deprecated: please use parameters.min_length instead)",
|
|
58
64
|
json_schema_extra={"update": "validate_constraint"},
|
|
59
65
|
)
|
|
60
66
|
label: str | None = Field(
|
|
@@ -112,6 +118,13 @@ class GeneratedAttributeSchema(HashableModel):
|
|
|
112
118
|
description="Type of allowed override for the attribute.",
|
|
113
119
|
json_schema_extra={"update": "allowed"},
|
|
114
120
|
)
|
|
121
|
+
parameters: AttributeParameters | TextAttributeParameters | NumberAttributeParameters | NumberPoolParameters = (
|
|
122
|
+
Field(
|
|
123
|
+
default_factory=AttributeParameters,
|
|
124
|
+
description="Extra parameters specific to this kind of attribute",
|
|
125
|
+
json_schema_extra={"update": "validate_constraint"},
|
|
126
|
+
)
|
|
127
|
+
)
|
|
115
128
|
deprecation: str | None = Field(
|
|
116
129
|
default=None,
|
|
117
130
|
description="Mark attribute as deprecated and provide a user-friendly message to display",
|
|
@@ -12,7 +12,7 @@ from infrahub.core.constants import (
|
|
|
12
12
|
RelationshipDeleteBehavior,
|
|
13
13
|
RelationshipDirection,
|
|
14
14
|
RelationshipKind,
|
|
15
|
-
)
|
|
15
|
+
)
|
|
16
16
|
from infrahub.core.models import HashableModel
|
|
17
17
|
|
|
18
18
|
|
|
@@ -73,6 +73,16 @@ class GeneratedRelationshipSchema(HashableModel):
|
|
|
73
73
|
description="Defines the maximum objects allowed on the other side of the relationship.",
|
|
74
74
|
json_schema_extra={"update": "validate_constraint"},
|
|
75
75
|
)
|
|
76
|
+
common_parent: str | None = Field(
|
|
77
|
+
default=None,
|
|
78
|
+
description="Name of a parent relationship on the peer schema that must share the same related object with the object's parent.",
|
|
79
|
+
json_schema_extra={"update": "validate_constraint"},
|
|
80
|
+
)
|
|
81
|
+
common_relatives: list[str] | None = Field(
|
|
82
|
+
default=None,
|
|
83
|
+
description="List of relationship names on the peer schema for which all objects must share the same set of peers.",
|
|
84
|
+
json_schema_extra={"update": "allowed"},
|
|
85
|
+
)
|
|
76
86
|
order_weight: int | None = Field(
|
|
77
87
|
default=None,
|
|
78
88
|
description="Number used to order the relationship in the frontend (table and view). Lowest value will be ordered first.",
|
infrahub/core/schema/manager.py
CHANGED
|
@@ -471,7 +471,7 @@ class SchemaManager(NodeManager):
|
|
|
471
471
|
if diff_attributes:
|
|
472
472
|
for item in node.local_attributes:
|
|
473
473
|
# if item is in changed and has no ID, then it is being overridden from a generic and must be added
|
|
474
|
-
if item.name in diff_attributes.added or item.name in diff_attributes.changed and item.id is None:
|
|
474
|
+
if item.name in diff_attributes.added or (item.name in diff_attributes.changed and item.id is None):
|
|
475
475
|
created_item = await self.create_attribute_in_db(
|
|
476
476
|
schema=attribute_schema, item=item, branch=branch, db=db, parent=obj
|
|
477
477
|
)
|
|
@@ -491,7 +491,9 @@ class SchemaManager(NodeManager):
|
|
|
491
491
|
if diff_relationships:
|
|
492
492
|
for item in node.local_relationships:
|
|
493
493
|
# if item is in changed and has no ID, then it is being overridden from a generic and must be added
|
|
494
|
-
if item.name in diff_relationships.added or
|
|
494
|
+
if item.name in diff_relationships.added or (
|
|
495
|
+
item.name in diff_relationships.changed and item.id is None
|
|
496
|
+
):
|
|
495
497
|
created_rel = await self.create_relationship_in_db(
|
|
496
498
|
schema=relationship_schema, item=item, branch=branch, db=db, parent=obj
|
|
497
499
|
)
|
|
@@ -764,3 +766,6 @@ class SchemaManager(NodeManager):
|
|
|
764
766
|
del self._cache[hash_key]
|
|
765
767
|
|
|
766
768
|
return removed_branches
|
|
769
|
+
|
|
770
|
+
def get_branches(self) -> list[str]:
|
|
771
|
+
return list(self._branches.keys())
|
|
@@ -5,6 +5,7 @@ import hashlib
|
|
|
5
5
|
from collections import defaultdict
|
|
6
6
|
from itertools import chain, combinations
|
|
7
7
|
from typing import Any
|
|
8
|
+
from uuid import uuid4
|
|
8
9
|
|
|
9
10
|
from infrahub_sdk.template import Jinja2Template
|
|
10
11
|
from infrahub_sdk.template.exceptions import JinjaTemplateError, JinjaTemplateOperationViolationError
|
|
@@ -49,6 +50,8 @@ from infrahub.core.schema import (
|
|
|
49
50
|
SchemaRoot,
|
|
50
51
|
TemplateSchema,
|
|
51
52
|
)
|
|
53
|
+
from infrahub.core.schema.attribute_parameters import NumberPoolParameters
|
|
54
|
+
from infrahub.core.schema.attribute_schema import get_attribute_schema_class_for_kind
|
|
52
55
|
from infrahub.core.schema.definitions.core import core_profile_schema_definition
|
|
53
56
|
from infrahub.core.validators import CONSTRAINT_VALIDATOR_MAP
|
|
54
57
|
from infrahub.exceptions import SchemaNotFoundError, ValidationError
|
|
@@ -88,7 +91,7 @@ class SchemaBranch:
|
|
|
88
91
|
self.templates = data.get("templates", {})
|
|
89
92
|
|
|
90
93
|
@classmethod
|
|
91
|
-
def validate(cls, data: Any) -> Self:
|
|
94
|
+
def validate(cls, data: Any) -> Self:
|
|
92
95
|
if isinstance(data, cls):
|
|
93
96
|
return data
|
|
94
97
|
if isinstance(data, dict):
|
|
@@ -450,7 +453,7 @@ class SchemaBranch:
|
|
|
450
453
|
if isinstance(node, NodeSchema | ProfileSchema | TemplateSchema):
|
|
451
454
|
return node.generate_fields_for_display_label()
|
|
452
455
|
|
|
453
|
-
fields: dict[str, str |
|
|
456
|
+
fields: dict[str, str | dict[str, None] | None] = {}
|
|
454
457
|
if isinstance(node, GenericSchema):
|
|
455
458
|
for child_node_name in node.used_by:
|
|
456
459
|
child_node = self.get(name=child_node_name, duplicate=False)
|
|
@@ -517,6 +520,7 @@ class SchemaBranch:
|
|
|
517
520
|
self.validate_names()
|
|
518
521
|
self.validate_kinds()
|
|
519
522
|
self.validate_computed_attributes()
|
|
523
|
+
self.validate_attribute_parameters()
|
|
520
524
|
self.validate_default_values()
|
|
521
525
|
self.validate_count_against_cardinality()
|
|
522
526
|
self.validate_identifiers()
|
|
@@ -971,6 +975,28 @@ class SchemaBranch:
|
|
|
971
975
|
):
|
|
972
976
|
raise ValueError(f"{node.kind}: {rel.name} isn't allowed as a relationship name.")
|
|
973
977
|
|
|
978
|
+
def _validate_common_parent(self, node: NodeSchema, rel: RelationshipSchema) -> None:
|
|
979
|
+
if not rel.common_parent:
|
|
980
|
+
return
|
|
981
|
+
|
|
982
|
+
peer_schema = self.get(name=rel.peer, duplicate=False)
|
|
983
|
+
if not node.has_parent_relationship:
|
|
984
|
+
raise ValueError(
|
|
985
|
+
f"{node.kind}: Relationship {rel.name!r} defines 'common_parent' but node does not have a parent relationship"
|
|
986
|
+
)
|
|
987
|
+
|
|
988
|
+
try:
|
|
989
|
+
parent_rel = peer_schema.get_relationship(name=rel.common_parent)
|
|
990
|
+
except ValueError as exc:
|
|
991
|
+
raise ValueError(
|
|
992
|
+
f"{node.kind}: Relationship {rel.name!r} defines 'common_parent' but '{rel.peer}.{rel.common_parent}' does not exist"
|
|
993
|
+
) from exc
|
|
994
|
+
|
|
995
|
+
if parent_rel.kind != RelationshipKind.PARENT:
|
|
996
|
+
raise ValueError(
|
|
997
|
+
f"{node.kind}: Relationship {rel.name!r} defines 'common_parent' but '{rel.peer}.{rel.common_parent} is not of kind 'parent'"
|
|
998
|
+
)
|
|
999
|
+
|
|
974
1000
|
def validate_kinds(self) -> None:
|
|
975
1001
|
for name in list(self.nodes.keys()):
|
|
976
1002
|
node = self.get_node(name=name, duplicate=False)
|
|
@@ -994,6 +1020,71 @@ class SchemaBranch:
|
|
|
994
1020
|
f"{node.kind}: Relationship {rel.name!r} is referring an invalid peer {rel.peer!r}"
|
|
995
1021
|
) from None
|
|
996
1022
|
|
|
1023
|
+
self._validate_common_parent(node=node, rel=rel)
|
|
1024
|
+
|
|
1025
|
+
if rel.common_relatives:
|
|
1026
|
+
peer_schema = self.get(name=rel.peer, duplicate=False)
|
|
1027
|
+
for common_relatives_rel_name in rel.common_relatives:
|
|
1028
|
+
if common_relatives_rel_name not in peer_schema.relationship_names:
|
|
1029
|
+
raise ValueError(
|
|
1030
|
+
f"{node.kind}: Relationship {rel.name!r} set 'common_relatives' with invalid relationship from '{rel.peer}'"
|
|
1031
|
+
) from None
|
|
1032
|
+
|
|
1033
|
+
def validate_attribute_parameters(self) -> None:
|
|
1034
|
+
for name in self.generics.keys():
|
|
1035
|
+
generic_schema = self.get_generic(name=name, duplicate=False)
|
|
1036
|
+
for attribute in generic_schema.attributes:
|
|
1037
|
+
if (
|
|
1038
|
+
attribute.kind == "NumberPool"
|
|
1039
|
+
and isinstance(attribute.parameters, NumberPoolParameters)
|
|
1040
|
+
and not attribute.parameters.number_pool_id
|
|
1041
|
+
):
|
|
1042
|
+
attribute.parameters.number_pool_id = str(uuid4())
|
|
1043
|
+
|
|
1044
|
+
for name in self.nodes.keys():
|
|
1045
|
+
node_schema = self.get_node(name=name, duplicate=False)
|
|
1046
|
+
for attribute in node_schema.attributes:
|
|
1047
|
+
if attribute.kind == "NumberPool" and isinstance(attribute.parameters, NumberPoolParameters):
|
|
1048
|
+
self._validate_number_pool_parameters(
|
|
1049
|
+
node_schema=node_schema, attribute=attribute, number_pool_parameters=attribute.parameters
|
|
1050
|
+
)
|
|
1051
|
+
|
|
1052
|
+
def _validate_number_pool_parameters(
|
|
1053
|
+
self, node_schema: NodeSchema, attribute: AttributeSchema, number_pool_parameters: NumberPoolParameters
|
|
1054
|
+
) -> None:
|
|
1055
|
+
if attribute.optional:
|
|
1056
|
+
raise ValidationError(f"{node_schema.kind}.{attribute.name} is a NumberPool it can't be optional")
|
|
1057
|
+
|
|
1058
|
+
if not attribute.read_only:
|
|
1059
|
+
raise ValidationError(
|
|
1060
|
+
f"{node_schema.kind}.{attribute.name} is a NumberPool it has to be a read_only attribute"
|
|
1061
|
+
)
|
|
1062
|
+
|
|
1063
|
+
if attribute.inherited and not number_pool_parameters.number_pool_id:
|
|
1064
|
+
generics_with_attribute = []
|
|
1065
|
+
for generic_name in node_schema.inherit_from:
|
|
1066
|
+
generic_schema = self.get_generic(name=generic_name, duplicate=False)
|
|
1067
|
+
if attribute.name in generic_schema.attribute_names:
|
|
1068
|
+
generic_attribute = generic_schema.get_attribute(name=attribute.name)
|
|
1069
|
+
generics_with_attribute.append(generic_schema)
|
|
1070
|
+
if isinstance(generic_attribute.parameters, NumberPoolParameters):
|
|
1071
|
+
number_pool_parameters.number_pool_id = generic_attribute.parameters.number_pool_id
|
|
1072
|
+
|
|
1073
|
+
if len(generics_with_attribute) > 1:
|
|
1074
|
+
raise ValidationError(
|
|
1075
|
+
f"{node_schema.kind}.{attribute.name} is a NumberPool inherited from more than one generic"
|
|
1076
|
+
)
|
|
1077
|
+
elif not attribute.inherited:
|
|
1078
|
+
for generic_name in node_schema.inherit_from:
|
|
1079
|
+
generic_schema = self.get_generic(name=generic_name, duplicate=False)
|
|
1080
|
+
if attribute.name in generic_schema.attribute_names:
|
|
1081
|
+
raise ValidationError(
|
|
1082
|
+
f"Overriding '{node_schema.kind}.{attribute.name}' NumberPool attribute from generic '{generic_name}' is not supported"
|
|
1083
|
+
)
|
|
1084
|
+
|
|
1085
|
+
if not number_pool_parameters.number_pool_id:
|
|
1086
|
+
number_pool_parameters.number_pool_id = str(uuid4())
|
|
1087
|
+
|
|
997
1088
|
def validate_computed_attributes(self) -> None:
|
|
998
1089
|
self.computed_attributes = ComputedAttributes()
|
|
999
1090
|
for name in self.nodes.keys():
|
|
@@ -1136,7 +1227,7 @@ class SchemaBranch:
|
|
|
1136
1227
|
self.set(name=name, schema=node)
|
|
1137
1228
|
|
|
1138
1229
|
def process_labels(self) -> None:
|
|
1139
|
-
def check_if_need_to_update_label(node) -> bool:
|
|
1230
|
+
def check_if_need_to_update_label(node: MainSchemaTypes) -> bool:
|
|
1140
1231
|
if not node.label:
|
|
1141
1232
|
return True
|
|
1142
1233
|
for item in node.relationships + node.attributes:
|
|
@@ -1812,12 +1903,14 @@ class SchemaBranch:
|
|
|
1812
1903
|
def generate_profile_from_node(self, node: NodeSchema) -> ProfileSchema:
|
|
1813
1904
|
core_profile_schema = self.get(name=InfrahubKind.PROFILE, duplicate=False)
|
|
1814
1905
|
core_name_attr = core_profile_schema.get_attribute(name="profile_name")
|
|
1815
|
-
|
|
1906
|
+
name_attr_schema_class = get_attribute_schema_class_for_kind(kind=core_name_attr.kind)
|
|
1907
|
+
profile_name_attr = name_attr_schema_class(
|
|
1816
1908
|
**core_name_attr.model_dump(exclude=["id", "inherited"]),
|
|
1817
1909
|
)
|
|
1818
1910
|
profile_name_attr.branch = node.branch
|
|
1819
1911
|
core_priority_attr = core_profile_schema.get_attribute(name="profile_priority")
|
|
1820
|
-
|
|
1912
|
+
priority_attr_schema_class = get_attribute_schema_class_for_kind(kind=core_priority_attr.kind)
|
|
1913
|
+
profile_priority_attr = priority_attr_schema_class(
|
|
1821
1914
|
**core_priority_attr.model_dump(exclude=["id", "inherited"]),
|
|
1822
1915
|
)
|
|
1823
1916
|
profile_priority_attr.branch = node.branch
|
|
@@ -1848,8 +1941,8 @@ class SchemaBranch:
|
|
|
1848
1941
|
for node_attr in node.attributes:
|
|
1849
1942
|
if node_attr.read_only or node_attr.optional is False:
|
|
1850
1943
|
continue
|
|
1851
|
-
|
|
1852
|
-
attr =
|
|
1944
|
+
attr_schema_class = get_attribute_schema_class_for_kind(kind=node_attr.kind)
|
|
1945
|
+
attr = attr_schema_class(
|
|
1853
1946
|
optional=True,
|
|
1854
1947
|
**node_attr.model_dump(exclude=["id", "unique", "optional", "read_only", "default_value", "inherited"]),
|
|
1855
1948
|
)
|
|
@@ -1957,7 +2050,11 @@ class SchemaBranch:
|
|
|
1957
2050
|
)
|
|
1958
2051
|
|
|
1959
2052
|
parent_hfid = f"{relationship.name}__template_name__value"
|
|
1960
|
-
if
|
|
2053
|
+
if (
|
|
2054
|
+
not isinstance(template_schema, GenericSchema)
|
|
2055
|
+
and relationship.kind == RelationshipKind.PARENT
|
|
2056
|
+
and parent_hfid not in template_schema.human_friendly_id
|
|
2057
|
+
):
|
|
1961
2058
|
template_schema.human_friendly_id = [parent_hfid] + template_schema.human_friendly_id
|
|
1962
2059
|
template_schema.uniqueness_constraints[0].append(relationship.name)
|
|
1963
2060
|
|
|
@@ -1973,7 +2070,8 @@ class SchemaBranch:
|
|
|
1973
2070
|
else self.get(name=InfrahubKind.OBJECTTEMPLATE, duplicate=False)
|
|
1974
2071
|
)
|
|
1975
2072
|
core_name_attr = core_template_schema.get_attribute(name=OBJECT_TEMPLATE_NAME_ATTR)
|
|
1976
|
-
|
|
2073
|
+
name_attr_schema_class = get_attribute_schema_class_for_kind(kind=core_name_attr.kind)
|
|
2074
|
+
template_name_attr = name_attr_schema_class(
|
|
1977
2075
|
**core_name_attr.model_dump(exclude=["id", "inherited"]),
|
|
1978
2076
|
)
|
|
1979
2077
|
template_name_attr.branch = node.branch
|
|
@@ -1992,7 +2090,6 @@ class SchemaBranch:
|
|
|
1992
2090
|
include_in_menu=False,
|
|
1993
2091
|
display_labels=["template_name__value"],
|
|
1994
2092
|
human_friendly_id=["template_name__value"],
|
|
1995
|
-
uniqueness_constraints=[["template_name__value"]],
|
|
1996
2093
|
attributes=[template_name_attr],
|
|
1997
2094
|
)
|
|
1998
2095
|
|
|
@@ -2011,7 +2108,6 @@ class SchemaBranch:
|
|
|
2011
2108
|
human_friendly_id=["template_name__value"],
|
|
2012
2109
|
uniqueness_constraints=[["template_name__value"]],
|
|
2013
2110
|
inherit_from=[InfrahubKind.LINEAGESOURCE, InfrahubKind.NODE, core_template_schema.kind],
|
|
2014
|
-
default_filter="template_name__value",
|
|
2015
2111
|
attributes=[template_name_attr],
|
|
2016
2112
|
relationships=[
|
|
2017
2113
|
RelationshipSchema(
|
|
@@ -2033,7 +2129,8 @@ class SchemaBranch:
|
|
|
2033
2129
|
if node_attr.unique or node_attr.read_only:
|
|
2034
2130
|
continue
|
|
2035
2131
|
|
|
2036
|
-
|
|
2132
|
+
attr_schema_class = get_attribute_schema_class_for_kind(kind=node_attr.kind)
|
|
2133
|
+
attr = attr_schema_class(
|
|
2037
2134
|
optional=node_attr.optional if is_autogenerated_subtemplate else True,
|
|
2038
2135
|
**node_attr.model_dump(exclude=["id", "unique", "optional", "read_only"]),
|
|
2039
2136
|
)
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
from infrahub.core.validators.attribute.min_max import AttributeNumberChecker
|
|
2
|
+
|
|
1
3
|
from .attribute.choices import AttributeChoicesChecker
|
|
2
4
|
from .attribute.enum import AttributeEnumChecker
|
|
3
5
|
from .attribute.kind import AttributeKindChecker
|
|
4
6
|
from .attribute.length import AttributeLengthChecker
|
|
7
|
+
from .attribute.number_pool import AttributeNumberPoolChecker
|
|
5
8
|
from .attribute.optional import AttributeOptionalChecker
|
|
6
9
|
from .attribute.regex import AttributeRegexChecker
|
|
7
10
|
from .attribute.unique import AttributeUniquenessChecker
|
|
11
|
+
from .enum import ConstraintIdentifier
|
|
8
12
|
from .interface import ConstraintCheckerInterface
|
|
9
13
|
from .node.attribute import NodeAttributeAddChecker
|
|
10
14
|
from .node.generate_profile import NodeGenerateProfileChecker
|
|
@@ -13,15 +17,23 @@ from .node.inherit_from import NodeInheritFromChecker
|
|
|
13
17
|
from .node.relationship import NodeRelationshipAddChecker
|
|
14
18
|
from .relationship.count import RelationshipCountChecker
|
|
15
19
|
from .relationship.optional import RelationshipOptionalChecker
|
|
16
|
-
from .relationship.peer import RelationshipPeerChecker
|
|
20
|
+
from .relationship.peer import RelationshipPeerChecker, RelationshipPeerParentChecker
|
|
17
21
|
from .uniqueness.checker import UniquenessChecker
|
|
18
22
|
|
|
19
23
|
CONSTRAINT_VALIDATOR_MAP: dict[str, type[ConstraintCheckerInterface] | None] = {
|
|
24
|
+
"attribute.kind.update": AttributeKindChecker,
|
|
20
25
|
"attribute.regex.update": AttributeRegexChecker,
|
|
26
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_REGEX_UPDATE.value: AttributeRegexChecker,
|
|
21
27
|
"attribute.enum.update": AttributeEnumChecker,
|
|
22
|
-
"attribute.kind.update": AttributeKindChecker,
|
|
23
28
|
"attribute.min_length.update": AttributeLengthChecker,
|
|
24
29
|
"attribute.max_length.update": AttributeLengthChecker,
|
|
30
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MIN_LENGTH_UPDATE.value: AttributeLengthChecker,
|
|
31
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MAX_LENGTH_UPDATE.value: AttributeLengthChecker,
|
|
32
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MIN_VALUE_UPDATE.value: AttributeNumberChecker,
|
|
33
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_MAX_VALUE_UPDATE.value: AttributeNumberChecker,
|
|
34
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_EXCLUDED_VALUES_UPDATE.value: AttributeNumberChecker,
|
|
35
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_START_RANGE_UPDATE: AttributeNumberPoolChecker,
|
|
36
|
+
ConstraintIdentifier.ATTRIBUTE_PARAMETERS_END_RANGE_UPDATE: AttributeNumberPoolChecker,
|
|
25
37
|
"attribute.unique.update": AttributeUniquenessChecker,
|
|
26
38
|
"attribute.optional.update": AttributeOptionalChecker,
|
|
27
39
|
"attribute.choices.update": AttributeChoicesChecker,
|
|
@@ -30,6 +42,7 @@ CONSTRAINT_VALIDATOR_MAP: dict[str, type[ConstraintCheckerInterface] | None] = {
|
|
|
30
42
|
"relationship.optional.update": RelationshipOptionalChecker,
|
|
31
43
|
"relationship.min_count.update": RelationshipCountChecker,
|
|
32
44
|
"relationship.max_count.update": RelationshipCountChecker,
|
|
45
|
+
"relationship.common_parent.update": RelationshipPeerParentChecker,
|
|
33
46
|
"node.inherit_from.update": NodeInheritFromChecker,
|
|
34
47
|
"node.uniqueness_constraints.update": UniquenessChecker,
|
|
35
48
|
"node.parent.update": NodeHierarchyChecker,
|
|
@@ -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)
|
|
@@ -43,7 +42,6 @@ class AttributeChoicesUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
43
42
|
LIMIT 1
|
|
44
43
|
}
|
|
45
44
|
WITH full_path, node, attribute_value, value_relationship
|
|
46
|
-
WITH full_path, node, attribute_value, value_relationship
|
|
47
45
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
48
46
|
AND attribute_value IS NOT NULL
|
|
49
47
|
AND attribute_value <> $null_value
|
|
@@ -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)
|
|
@@ -42,7 +41,6 @@ class AttributeEnumUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
42
41
|
LIMIT 1
|
|
43
42
|
}
|
|
44
43
|
WITH full_path, node, attribute_value, value_relationship
|
|
45
|
-
WITH full_path, node, attribute_value, value_relationship
|
|
46
44
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
47
45
|
AND attribute_value IS NOT NULL
|
|
48
46
|
AND attribute_value <> $null_value
|
|
@@ -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)
|
|
@@ -49,7 +48,6 @@ class AttributeKindUpdateValidatorQuery(AttributeSchemaValidatorQuery):
|
|
|
49
48
|
LIMIT 1
|
|
50
49
|
}
|
|
51
50
|
WITH full_path, node, attribute_value, value_relationship
|
|
52
|
-
WITH full_path, node, attribute_value, value_relationship
|
|
53
51
|
WHERE all(r in relationships(full_path) WHERE r.status = "active")
|
|
54
52
|
AND attribute_value IS NOT NULL
|
|
55
53
|
AND attribute_value <> $null_value
|