infrahub-server 1.2.12__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/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 +28 -43
- 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/manager.py +14 -11
- 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 +30 -48
- infrahub/core/migrations/graph/m030_illegal_edges.py +1 -2
- infrahub/core/migrations/query/attribute_add.py +1 -2
- 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 +104 -9
- 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 +1 -2
- 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 +24 -175
- 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 +3 -6
- infrahub/patch/queries/delete_duplicated_edges.py +10 -15
- 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 +4 -8
- 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.12.dist-info → infrahub_server-1.3.0.dist-info}/METADATA +3 -3
- {infrahub_server-1.2.12.dist-info → infrahub_server-1.3.0.dist-info}/RECORD +192 -166
- infrahub_testcontainers/container.py +0 -1
- infrahub_testcontainers/docker-compose.test.yml +1 -1
- infrahub_testcontainers/helpers.py +8 -2
- 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.12.dist-info → infrahub_server-1.3.0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.12.dist-info → infrahub_server-1.3.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.2.12.dist-info → infrahub_server-1.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Mapping
|
|
4
|
+
|
|
5
|
+
from infrahub.core import registry
|
|
6
|
+
from infrahub.core.constants import RelationshipCardinality, RelationshipKind
|
|
7
|
+
from infrahub.core.constraint.node.runner import NodeConstraintRunner
|
|
8
|
+
from infrahub.core.manager import NodeManager
|
|
9
|
+
from infrahub.core.node import Node
|
|
10
|
+
from infrahub.core.protocols import CoreObjectTemplate
|
|
11
|
+
from infrahub.dependencies.registry import get_component_registry
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from infrahub.core.branch import Branch
|
|
15
|
+
from infrahub.core.relationship.model import RelationshipManager
|
|
16
|
+
from infrahub.core.schema import MainSchemaTypes, NonGenericSchemaTypes, RelationshipSchema
|
|
17
|
+
from infrahub.database import InfrahubDatabase
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def get_template_relationship_peers(
|
|
21
|
+
db: InfrahubDatabase, template: CoreObjectTemplate, relationship: RelationshipSchema
|
|
22
|
+
) -> Mapping[str, CoreObjectTemplate]:
|
|
23
|
+
"""For a given relationship on the template, fetch the related peers."""
|
|
24
|
+
template_relationship_manager: RelationshipManager = getattr(template, relationship.name)
|
|
25
|
+
if relationship.cardinality == RelationshipCardinality.MANY:
|
|
26
|
+
return await template_relationship_manager.get_peers(db=db, peer_type=CoreObjectTemplate)
|
|
27
|
+
|
|
28
|
+
peers: dict[str, CoreObjectTemplate] = {}
|
|
29
|
+
template_relationship_peer = await template_relationship_manager.get_peer(db=db, peer_type=CoreObjectTemplate)
|
|
30
|
+
if template_relationship_peer:
|
|
31
|
+
peers[template_relationship_peer.id] = template_relationship_peer
|
|
32
|
+
return peers
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def extract_peer_data(
|
|
36
|
+
db: InfrahubDatabase,
|
|
37
|
+
template_peer: CoreObjectTemplate,
|
|
38
|
+
obj_peer_schema: MainSchemaTypes,
|
|
39
|
+
parent_obj: Node,
|
|
40
|
+
current_template: CoreObjectTemplate,
|
|
41
|
+
) -> Mapping[str, Any]:
|
|
42
|
+
obj_peer_data: dict[str, Any] = {}
|
|
43
|
+
|
|
44
|
+
for attr in template_peer.get_schema().attribute_names:
|
|
45
|
+
if attr not in obj_peer_schema.attribute_names:
|
|
46
|
+
continue
|
|
47
|
+
obj_peer_data[attr] = {"value": getattr(template_peer, attr).value, "source": template_peer.id}
|
|
48
|
+
|
|
49
|
+
for rel in template_peer.get_schema().relationship_names:
|
|
50
|
+
rel_manager: RelationshipManager = getattr(template_peer, rel)
|
|
51
|
+
if (
|
|
52
|
+
rel_manager.schema.kind not in [RelationshipKind.COMPONENT, RelationshipKind.PARENT]
|
|
53
|
+
or rel_manager.schema.name not in obj_peer_schema.relationship_names
|
|
54
|
+
):
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
if list(await rel_manager.get_peers(db=db)) == [current_template.id]:
|
|
58
|
+
obj_peer_data[rel] = {"id": parent_obj.id}
|
|
59
|
+
|
|
60
|
+
return obj_peer_data
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
async def handle_template_relationships(
|
|
64
|
+
db: InfrahubDatabase,
|
|
65
|
+
branch: Branch,
|
|
66
|
+
obj: Node,
|
|
67
|
+
template: CoreObjectTemplate,
|
|
68
|
+
fields: list,
|
|
69
|
+
constraint_runner: NodeConstraintRunner | None = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
if constraint_runner is None:
|
|
72
|
+
component_registry = get_component_registry()
|
|
73
|
+
constraint_runner = await component_registry.get_component(NodeConstraintRunner, db=db, branch=branch)
|
|
74
|
+
|
|
75
|
+
for relationship in obj.get_relationships(kind=RelationshipKind.COMPONENT, exclude=fields):
|
|
76
|
+
template_relationship_peers = await get_template_relationship_peers(
|
|
77
|
+
db=db, template=template, relationship=relationship
|
|
78
|
+
)
|
|
79
|
+
if not template_relationship_peers:
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
for template_relationship_peer in template_relationship_peers.values():
|
|
83
|
+
# We retrieve peer schema for each peer in case we are processing a relationship which is based on a generic
|
|
84
|
+
obj_peer_schema = registry.schema.get_node_schema(
|
|
85
|
+
name=template_relationship_peer.get_schema().kind.removeprefix("Template"),
|
|
86
|
+
branch=branch,
|
|
87
|
+
duplicate=False,
|
|
88
|
+
)
|
|
89
|
+
obj_peer_data = await extract_peer_data(
|
|
90
|
+
db=db,
|
|
91
|
+
template_peer=template_relationship_peer,
|
|
92
|
+
obj_peer_schema=obj_peer_schema,
|
|
93
|
+
parent_obj=obj,
|
|
94
|
+
current_template=template,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
obj_peer = await Node.init(schema=obj_peer_schema, db=db, branch=branch)
|
|
98
|
+
await obj_peer.new(db=db, **obj_peer_data)
|
|
99
|
+
await constraint_runner.check(node=obj_peer, field_filters=list(obj_peer_data))
|
|
100
|
+
await obj_peer.save(db=db)
|
|
101
|
+
|
|
102
|
+
await handle_template_relationships(
|
|
103
|
+
db=db,
|
|
104
|
+
branch=branch,
|
|
105
|
+
constraint_runner=constraint_runner,
|
|
106
|
+
obj=obj_peer,
|
|
107
|
+
template=template_relationship_peer,
|
|
108
|
+
fields=fields,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
async def get_profile_ids(db: InfrahubDatabase, obj: Node) -> set[str]:
|
|
113
|
+
if not hasattr(obj, "profiles"):
|
|
114
|
+
return set()
|
|
115
|
+
profile_rels = await obj.profiles.get_relationships(db=db)
|
|
116
|
+
return {pr.peer_id for pr in profile_rels}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
async def refresh_for_profile_update(
|
|
120
|
+
db: InfrahubDatabase,
|
|
121
|
+
branch: Branch,
|
|
122
|
+
obj: Node,
|
|
123
|
+
schema: NonGenericSchemaTypes,
|
|
124
|
+
previous_profile_ids: set[str] | None = None,
|
|
125
|
+
) -> Node:
|
|
126
|
+
if not hasattr(obj, "profiles"):
|
|
127
|
+
return obj
|
|
128
|
+
current_profile_ids = await get_profile_ids(db=db, obj=obj)
|
|
129
|
+
if previous_profile_ids is None or previous_profile_ids != current_profile_ids:
|
|
130
|
+
refreshed_node = await NodeManager.get_one_by_id_or_default_filter(
|
|
131
|
+
db=db,
|
|
132
|
+
kind=schema.kind,
|
|
133
|
+
id=obj.get_id(),
|
|
134
|
+
branch=branch,
|
|
135
|
+
include_owner=True,
|
|
136
|
+
include_source=True,
|
|
137
|
+
)
|
|
138
|
+
refreshed_node._node_changelog = obj.node_changelog
|
|
139
|
+
return refreshed_node
|
|
140
|
+
return obj
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
async def _do_create_node(
|
|
144
|
+
node_class: type[Node],
|
|
145
|
+
db: InfrahubDatabase,
|
|
146
|
+
data: dict,
|
|
147
|
+
schema: NonGenericSchemaTypes,
|
|
148
|
+
fields_to_validate: list,
|
|
149
|
+
branch: Branch,
|
|
150
|
+
node_constraint_runner: NodeConstraintRunner,
|
|
151
|
+
) -> Node:
|
|
152
|
+
obj = await node_class.init(db=db, schema=schema, branch=branch)
|
|
153
|
+
await obj.new(db=db, **data)
|
|
154
|
+
await node_constraint_runner.check(node=obj, field_filters=fields_to_validate)
|
|
155
|
+
await obj.save(db=db)
|
|
156
|
+
|
|
157
|
+
object_template = await obj.get_object_template(db=db)
|
|
158
|
+
if object_template:
|
|
159
|
+
await handle_template_relationships(
|
|
160
|
+
db=db,
|
|
161
|
+
branch=branch,
|
|
162
|
+
template=object_template,
|
|
163
|
+
obj=obj,
|
|
164
|
+
fields=fields_to_validate,
|
|
165
|
+
)
|
|
166
|
+
return obj
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
async def create_node(
|
|
170
|
+
data: dict,
|
|
171
|
+
db: InfrahubDatabase,
|
|
172
|
+
branch: Branch,
|
|
173
|
+
schema: NonGenericSchemaTypes,
|
|
174
|
+
) -> Node:
|
|
175
|
+
"""Create a node in the database if constraint checks succeed."""
|
|
176
|
+
|
|
177
|
+
component_registry = get_component_registry()
|
|
178
|
+
node_constraint_runner = await component_registry.get_component(
|
|
179
|
+
NodeConstraintRunner, db=db.start_session() if not db.is_transaction else db, branch=branch
|
|
180
|
+
)
|
|
181
|
+
node_class = Node
|
|
182
|
+
if schema.kind in registry.node:
|
|
183
|
+
node_class = registry.node[schema.kind]
|
|
184
|
+
|
|
185
|
+
fields_to_validate = list(data)
|
|
186
|
+
if db.is_transaction:
|
|
187
|
+
obj = await _do_create_node(
|
|
188
|
+
node_class=node_class,
|
|
189
|
+
node_constraint_runner=node_constraint_runner,
|
|
190
|
+
db=db,
|
|
191
|
+
schema=schema,
|
|
192
|
+
branch=branch,
|
|
193
|
+
fields_to_validate=fields_to_validate,
|
|
194
|
+
data=data,
|
|
195
|
+
)
|
|
196
|
+
else:
|
|
197
|
+
async with db.start_transaction() as dbt:
|
|
198
|
+
obj = await _do_create_node(
|
|
199
|
+
node_class=node_class,
|
|
200
|
+
node_constraint_runner=node_constraint_runner,
|
|
201
|
+
db=dbt,
|
|
202
|
+
schema=schema,
|
|
203
|
+
branch=branch,
|
|
204
|
+
fields_to_validate=fields_to_validate,
|
|
205
|
+
data=data,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
if await get_profile_ids(db=db, obj=obj):
|
|
209
|
+
obj = await refresh_for_profile_update(db=db, branch=branch, schema=schema, obj=obj)
|
|
210
|
+
|
|
211
|
+
return obj
|
|
@@ -2,22 +2,44 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
from infrahub.core import registry
|
|
5
6
|
from infrahub.core.query.resource_manager import NumberPoolGetReserved, NumberPoolGetUsed, NumberPoolSetReserved
|
|
7
|
+
from infrahub.core.schema.attribute_parameters import NumberAttributeParameters
|
|
6
8
|
from infrahub.exceptions import PoolExhaustedError
|
|
7
9
|
|
|
8
10
|
from .. import Node
|
|
9
11
|
|
|
10
12
|
if TYPE_CHECKING:
|
|
13
|
+
from infrahub.core.attribute import BaseAttribute
|
|
11
14
|
from infrahub.core.branch import Branch
|
|
12
15
|
from infrahub.database import InfrahubDatabase
|
|
13
16
|
|
|
14
17
|
|
|
15
18
|
class CoreNumberPool(Node):
|
|
19
|
+
def get_attribute_nb_excluded_values(self) -> int:
|
|
20
|
+
"""
|
|
21
|
+
Returns the number of excluded values for the attribute of the number pool.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
pool_node = registry.schema.get(name=self.node.value) # type: ignore [attr-defined]
|
|
25
|
+
attribute = [attribute for attribute in pool_node.attributes if attribute.name == self.node_attribute.value][0] # type: ignore [attr-defined]
|
|
26
|
+
if not isinstance(attribute.parameters, NumberAttributeParameters):
|
|
27
|
+
return 0
|
|
28
|
+
|
|
29
|
+
sum_excluded_values = 0
|
|
30
|
+
excluded_ranges = attribute.parameters.get_excluded_ranges()
|
|
31
|
+
for start_range, end_range in excluded_ranges:
|
|
32
|
+
sum_excluded_values += end_range - start_range + 1
|
|
33
|
+
|
|
34
|
+
res = len(attribute.parameters.get_excluded_single_values()) + sum_excluded_values
|
|
35
|
+
return res
|
|
36
|
+
|
|
16
37
|
async def get_resource(
|
|
17
38
|
self,
|
|
18
39
|
db: InfrahubDatabase,
|
|
19
40
|
branch: Branch,
|
|
20
41
|
node: Node,
|
|
42
|
+
attribute: BaseAttribute,
|
|
21
43
|
identifier: str | None = None,
|
|
22
44
|
) -> int:
|
|
23
45
|
identifier = identifier or node.get_id()
|
|
@@ -31,23 +53,24 @@ class CoreNumberPool(Node):
|
|
|
31
53
|
return reservation
|
|
32
54
|
|
|
33
55
|
# If we have not returned a value we need to find one if avaiable
|
|
34
|
-
number = await self.get_next(db=db, branch=branch)
|
|
56
|
+
number = await self.get_next(db=db, branch=branch, attribute=attribute)
|
|
35
57
|
|
|
36
58
|
query_set = await NumberPoolSetReserved.init(
|
|
37
59
|
db=db, pool_id=self.get_id(), identifier=identifier, reserved=number
|
|
38
60
|
)
|
|
39
61
|
await query_set.execute(db=db)
|
|
40
|
-
|
|
41
62
|
return number
|
|
42
63
|
|
|
43
|
-
async def get_next(self, db: InfrahubDatabase, branch: Branch) -> int:
|
|
64
|
+
async def get_next(self, db: InfrahubDatabase, branch: Branch, attribute: BaseAttribute) -> int:
|
|
44
65
|
query = await NumberPoolGetUsed.init(db=db, branch=branch, pool=self, branch_agnostic=True)
|
|
45
66
|
await query.execute(db=db)
|
|
46
67
|
taken = [result.get_as_optional_type("av.value", return_type=int) for result in query.results]
|
|
68
|
+
parameters = attribute.schema.parameters
|
|
47
69
|
next_number = find_next_free(
|
|
48
70
|
start=self.start_range.value, # type: ignore[attr-defined]
|
|
49
71
|
end=self.end_range.value, # type: ignore[attr-defined]
|
|
50
72
|
taken=taken,
|
|
73
|
+
parameters=parameters if isinstance(parameters, NumberAttributeParameters) else None,
|
|
51
74
|
)
|
|
52
75
|
if next_number is None:
|
|
53
76
|
raise PoolExhaustedError("There are no more values available in this pool.")
|
|
@@ -55,12 +78,15 @@ class CoreNumberPool(Node):
|
|
|
55
78
|
return next_number
|
|
56
79
|
|
|
57
80
|
|
|
58
|
-
def find_next_free(
|
|
81
|
+
def find_next_free(
|
|
82
|
+
start: int, end: int, taken: list[int | None], parameters: NumberAttributeParameters | None
|
|
83
|
+
) -> int | None:
|
|
59
84
|
used_numbers = [number for number in taken if number is not None]
|
|
60
85
|
used_set = set(used_numbers)
|
|
61
86
|
|
|
62
87
|
for num in range(start, end + 1):
|
|
63
88
|
if num not in used_set:
|
|
64
|
-
|
|
89
|
+
if parameters is None or parameters.is_valid_value(num):
|
|
90
|
+
return num
|
|
65
91
|
|
|
66
92
|
return None
|
infrahub/core/node/standard.py
CHANGED
|
@@ -210,7 +210,12 @@ class StandardNode(BaseModel):
|
|
|
210
210
|
|
|
211
211
|
@classmethod
|
|
212
212
|
async def get_list(
|
|
213
|
-
cls,
|
|
213
|
+
cls,
|
|
214
|
+
db: InfrahubDatabase,
|
|
215
|
+
limit: int = 1000,
|
|
216
|
+
ids: list[str] | None = None,
|
|
217
|
+
name: str | None = None,
|
|
218
|
+
**kwargs: dict[str, Any],
|
|
214
219
|
) -> list[Self]:
|
|
215
220
|
query: Query = await StandardNodeGetListQuery.init(
|
|
216
221
|
db=db, node_class=cls, ids=ids, node_name=name, limit=limit, **kwargs
|
infrahub/core/path.py
CHANGED
|
@@ -63,6 +63,20 @@ class DataPath(InfrahubPath):
|
|
|
63
63
|
peer_id: str | None = Field(default=None, description="")
|
|
64
64
|
value: Any | None = Field(default=None, description="Optional value of the resource")
|
|
65
65
|
|
|
66
|
+
def __hash__(self) -> int:
|
|
67
|
+
return hash(
|
|
68
|
+
(
|
|
69
|
+
self.branch,
|
|
70
|
+
self.path_type,
|
|
71
|
+
self.node_id,
|
|
72
|
+
self.kind,
|
|
73
|
+
self.field_name,
|
|
74
|
+
self.property_name,
|
|
75
|
+
self.peer_id,
|
|
76
|
+
str(self.value),
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
|
|
66
80
|
@property
|
|
67
81
|
def resource_type(self) -> PathResourceType:
|
|
68
82
|
return PathResourceType.DATA
|
|
@@ -125,7 +139,7 @@ class SchemaPath(InfrahubPath):
|
|
|
125
139
|
if self.field_name:
|
|
126
140
|
identifier += f"/{self.field_name}"
|
|
127
141
|
|
|
128
|
-
if self.property_name and
|
|
142
|
+
if self.property_name and self.path_type != SchemaPathType.NODE:
|
|
129
143
|
identifier += f"/{self.property_name}"
|
|
130
144
|
|
|
131
145
|
return identifier
|
infrahub/core/protocols.py
CHANGED
|
@@ -62,6 +62,12 @@ class BuiltinIPPrefix(CoreNode):
|
|
|
62
62
|
children: RelationshipManager
|
|
63
63
|
|
|
64
64
|
|
|
65
|
+
class CoreAction(CoreNode):
|
|
66
|
+
name: String
|
|
67
|
+
description: StringOptional
|
|
68
|
+
triggers: RelationshipManager
|
|
69
|
+
|
|
70
|
+
|
|
65
71
|
class CoreArtifactTarget(CoreNode):
|
|
66
72
|
artifacts: RelationshipManager
|
|
67
73
|
|
|
@@ -148,6 +154,10 @@ class CoreMenu(CoreNode):
|
|
|
148
154
|
children: RelationshipManager
|
|
149
155
|
|
|
150
156
|
|
|
157
|
+
class CoreNodeTriggerMatch(CoreNode):
|
|
158
|
+
trigger: RelationshipManager
|
|
159
|
+
|
|
160
|
+
|
|
151
161
|
class CoreObjectComponentTemplate(CoreNode):
|
|
152
162
|
template_name: String
|
|
153
163
|
|
|
@@ -189,6 +199,14 @@ class CoreTransformation(CoreNode):
|
|
|
189
199
|
tags: RelationshipManager
|
|
190
200
|
|
|
191
201
|
|
|
202
|
+
class CoreTriggerRule(CoreNode):
|
|
203
|
+
name: String
|
|
204
|
+
description: StringOptional
|
|
205
|
+
active: Boolean
|
|
206
|
+
branch_scope: Dropdown
|
|
207
|
+
action: RelationshipManager
|
|
208
|
+
|
|
209
|
+
|
|
192
210
|
class CoreValidator(CoreNode):
|
|
193
211
|
label: StringOptional
|
|
194
212
|
state: Enum
|
|
@@ -326,6 +344,10 @@ class CoreFileThread(CoreThread):
|
|
|
326
344
|
repository: RelationshipManager
|
|
327
345
|
|
|
328
346
|
|
|
347
|
+
class CoreGeneratorAction(CoreAction):
|
|
348
|
+
generator: RelationshipManager
|
|
349
|
+
|
|
350
|
+
|
|
329
351
|
class CoreGeneratorCheck(CoreCheck):
|
|
330
352
|
instance: String
|
|
331
353
|
|
|
@@ -380,6 +402,16 @@ class CoreGraphQLQueryGroup(CoreGroup):
|
|
|
380
402
|
query: RelationshipManager
|
|
381
403
|
|
|
382
404
|
|
|
405
|
+
class CoreGroupAction(CoreAction):
|
|
406
|
+
member_action: Dropdown
|
|
407
|
+
group: RelationshipManager
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
class CoreGroupTriggerRule(CoreTriggerRule):
|
|
411
|
+
member_update: Dropdown
|
|
412
|
+
group: RelationshipManager
|
|
413
|
+
|
|
414
|
+
|
|
383
415
|
class CoreIPAddressPool(CoreResourcePool, LineageSource):
|
|
384
416
|
default_address_type: String
|
|
385
417
|
default_prefix_length: IntegerOptional
|
|
@@ -399,11 +431,31 @@ class CoreMenuItem(CoreMenu):
|
|
|
399
431
|
pass
|
|
400
432
|
|
|
401
433
|
|
|
434
|
+
class CoreNodeTriggerAttributeMatch(CoreNodeTriggerMatch):
|
|
435
|
+
attribute_name: String
|
|
436
|
+
value: StringOptional
|
|
437
|
+
value_previous: StringOptional
|
|
438
|
+
value_match: Dropdown
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
class CoreNodeTriggerRelationshipMatch(CoreNodeTriggerMatch):
|
|
442
|
+
relationship_name: String
|
|
443
|
+
modification_type: Dropdown
|
|
444
|
+
peer: StringOptional
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
class CoreNodeTriggerRule(CoreTriggerRule):
|
|
448
|
+
node_kind: String
|
|
449
|
+
mutation_action: Enum
|
|
450
|
+
matches: RelationshipManager
|
|
451
|
+
|
|
452
|
+
|
|
402
453
|
class CoreNumberPool(CoreResourcePool, LineageSource):
|
|
403
454
|
node: String
|
|
404
455
|
node_attribute: String
|
|
405
456
|
start_range: Integer
|
|
406
457
|
end_range: Integer
|
|
458
|
+
pool_type: Enum
|
|
407
459
|
|
|
408
460
|
|
|
409
461
|
class CoreObjectPermission(CoreBasePermission):
|
|
@@ -446,6 +498,11 @@ class CoreRepository(LineageOwner, LineageSource, CoreGenericRepository, CoreTas
|
|
|
446
498
|
commit: StringOptional
|
|
447
499
|
|
|
448
500
|
|
|
501
|
+
class CoreRepositoryGroup(CoreGroup):
|
|
502
|
+
content: Dropdown
|
|
503
|
+
repository: RelationshipManager
|
|
504
|
+
|
|
505
|
+
|
|
449
506
|
class CoreRepositoryValidator(CoreValidator):
|
|
450
507
|
repository: RelationshipManager
|
|
451
508
|
|
infrahub/core/protocols_base.py
CHANGED
|
@@ -7,6 +7,7 @@ from typing_extensions import Self
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
8
|
from neo4j import AsyncResult, AsyncSession, AsyncTransaction, Record
|
|
9
9
|
|
|
10
|
+
from infrahub.core.schema import NonGenericSchemaTypes
|
|
10
11
|
from infrahub.core.schema.schema_branch import SchemaBranch
|
|
11
12
|
|
|
12
13
|
|
|
@@ -70,6 +71,8 @@ class CoreNode(Protocol):
|
|
|
70
71
|
|
|
71
72
|
def get_id(self) -> str: ...
|
|
72
73
|
def get_kind(self) -> str: ...
|
|
74
|
+
def get_schema(self) -> NonGenericSchemaTypes: ...
|
|
75
|
+
|
|
73
76
|
@classmethod
|
|
74
77
|
async def init(
|
|
75
78
|
cls,
|
infrahub/core/query/__init__.py
CHANGED
|
@@ -424,8 +424,8 @@ class Query(ABC):
|
|
|
424
424
|
else:
|
|
425
425
|
self.query_lines.extend([line.strip() for line in query.split("\n") if line.strip()])
|
|
426
426
|
|
|
427
|
-
def add_subquery(self, subquery: str, with_clause: str | None = None) -> None:
|
|
428
|
-
self.add_to_query("CALL {")
|
|
427
|
+
def add_subquery(self, subquery: str, node_alias: str, with_clause: str | None = None) -> None:
|
|
428
|
+
self.add_to_query(f"CALL ({node_alias}) {{")
|
|
429
429
|
self.add_to_query(subquery)
|
|
430
430
|
self.add_to_query("}")
|
|
431
431
|
if with_clause:
|
infrahub/core/query/delete.py
CHANGED
|
@@ -21,7 +21,7 @@ class DeleteAfterTimeQuery(Query):
|
|
|
21
21
|
// ---------------------
|
|
22
22
|
// Reset edges with to time after timestamp
|
|
23
23
|
// ---------------------
|
|
24
|
-
CALL {
|
|
24
|
+
CALL () {
|
|
25
25
|
OPTIONAL MATCH (p)-[r]-(q)
|
|
26
26
|
WHERE r.to > $timestamp
|
|
27
27
|
SET r.to = NULL
|
|
@@ -33,7 +33,7 @@ class DeleteAfterTimeQuery(Query):
|
|
|
33
33
|
// ---------------------
|
|
34
34
|
// Delete edges with from time after timestamp timestamp
|
|
35
35
|
// ---------------------
|
|
36
|
-
CALL {
|
|
36
|
+
CALL () {
|
|
37
37
|
OPTIONAL MATCH (p)-[r]->(q)
|
|
38
38
|
WHERE r.from > $timestamp
|
|
39
39
|
DELETE r
|
|
@@ -49,7 +49,7 @@ class DeleteAfterTimeQuery(Query):
|
|
|
49
49
|
// ---------------------
|
|
50
50
|
// Delete edges with from time after timestamp timestamp
|
|
51
51
|
// ---------------------
|
|
52
|
-
CALL {
|
|
52
|
+
CALL () {
|
|
53
53
|
OPTIONAL MATCH (p)-[r]->(q)
|
|
54
54
|
WHERE r.from > $timestamp
|
|
55
55
|
DELETE r
|
infrahub/core/query/diff.py
CHANGED
|
@@ -121,10 +121,9 @@ class DiffCalculationQuery(DiffQuery):
|
|
|
121
121
|
|
|
122
122
|
previous_base_path_query = """
|
|
123
123
|
WITH DISTINCT diff_path AS diff_path, has_more_data
|
|
124
|
-
CALL {
|
|
125
|
-
WITH diff_path
|
|
126
|
-
WITH
|
|
127
|
-
WITH diff_path, d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop
|
|
124
|
+
CALL (diff_path) {
|
|
125
|
+
WITH nodes(diff_path) AS d_nodes, relationships(diff_path) AS d_rels
|
|
126
|
+
WITH d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop
|
|
128
127
|
// -------------------------------------
|
|
129
128
|
// add base branch paths before branched_from, if they exist
|
|
130
129
|
// -------------------------------------
|
|
@@ -158,10 +157,9 @@ CALL {
|
|
|
158
157
|
WITH diff_path, latest_base_path, has_more_data
|
|
159
158
|
UNWIND [diff_path, latest_base_path] AS penultimate_path
|
|
160
159
|
WITH DISTINCT penultimate_path, has_more_data
|
|
161
|
-
CALL {
|
|
162
|
-
WITH penultimate_path
|
|
163
|
-
WITH
|
|
164
|
-
WITH penultimate_path, d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop
|
|
160
|
+
CALL (penultimate_path) {
|
|
161
|
+
WITH nodes(penultimate_path) AS d_nodes, relationships(penultimate_path) AS d_rels
|
|
162
|
+
WITH d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop
|
|
165
163
|
// -------------------------------------
|
|
166
164
|
// Add peer-side of any relationships to get the peer's ID
|
|
167
165
|
// -------------------------------------
|
|
@@ -299,8 +297,7 @@ WITH one_result[0] AS p, one_result[1] AS q, one_result[2] AS diff_rel, one_resu
|
|
|
299
297
|
// -------------------------------------
|
|
300
298
|
// Exclude nodes added then removed on branch within timeframe
|
|
301
299
|
// -------------------------------------
|
|
302
|
-
CALL {
|
|
303
|
-
WITH p, q, row_from_time
|
|
300
|
+
CALL (p, q, row_from_time) {
|
|
304
301
|
OPTIONAL MATCH (q)<-[is_part_of:IS_PART_OF {branch: $branch_name}]-(p)
|
|
305
302
|
WHERE row_from_time <= is_part_of.from < $to_time
|
|
306
303
|
WITH DISTINCT is_part_of.status AS rel_status
|
|
@@ -312,8 +309,7 @@ WHERE intra_branch_update = FALSE
|
|
|
312
309
|
// -------------------------------------
|
|
313
310
|
// Get every path on this branch under each node
|
|
314
311
|
// -------------------------------------
|
|
315
|
-
CALL {
|
|
316
|
-
WITH p, q, diff_rel, row_from_time
|
|
312
|
+
CALL (p, q, diff_rel, row_from_time) {
|
|
317
313
|
OPTIONAL MATCH path = (
|
|
318
314
|
(q)<-[top_diff_rel:IS_PART_OF]-(p)-[r_node]-(node)-[r_prop]-(prop)
|
|
319
315
|
)
|
|
@@ -340,12 +336,11 @@ CALL {
|
|
|
340
336
|
p.uuid IS NULL OR prop.uuid IS NULL OR p.uuid <> prop.uuid
|
|
341
337
|
OR type(r_node) <> "IS_RELATED" OR type(r_prop) <> "IS_RELATED"
|
|
342
338
|
)
|
|
343
|
-
WITH path,
|
|
339
|
+
WITH path, node, prop, r_prop, r_node, type(r_node) AS rel_type, row_from_time
|
|
344
340
|
// -------------------------------------
|
|
345
341
|
// Exclude attributes/relationships added then removed on branch within timeframe
|
|
346
342
|
// -------------------------------------
|
|
347
|
-
CALL {
|
|
348
|
-
WITH p, rel_type, node, row_from_time
|
|
343
|
+
CALL (p, rel_type, node, row_from_time) {
|
|
349
344
|
OPTIONAL MATCH (p)-[rel_to_check {branch: $branch_name}]-(node)
|
|
350
345
|
WHERE row_from_time <= rel_to_check.from < $to_time
|
|
351
346
|
AND type(rel_to_check) = rel_type
|
|
@@ -484,8 +479,7 @@ END AS row_from_time
|
|
|
484
479
|
// Exclude attributes/relationship under nodes deleted on this branch in the timeframe
|
|
485
480
|
// because those were all handled above at the node level
|
|
486
481
|
// -------------------------------------
|
|
487
|
-
CALL {
|
|
488
|
-
WITH root, p, row_from_time
|
|
482
|
+
CALL (root, p, row_from_time) {
|
|
489
483
|
OPTIONAL MATCH (root)<-[r_root_deleted:IS_PART_OF {branch: $branch_name}]-(p)
|
|
490
484
|
WHERE row_from_time <= r_root_deleted.from < $to_time
|
|
491
485
|
WITH r_root_deleted
|
|
@@ -499,8 +493,7 @@ WHERE node_deleted = FALSE
|
|
|
499
493
|
// Exclude relationships added and deleted within the timeframe
|
|
500
494
|
// -------------------------------------
|
|
501
495
|
WITH root, r_root, p, diff_rel, q, has_more_data, row_from_time, type(diff_rel) AS rel_type
|
|
502
|
-
CALL {
|
|
503
|
-
WITH p, rel_type, q, row_from_time
|
|
496
|
+
CALL (p, rel_type, q, row_from_time) {
|
|
504
497
|
OPTIONAL MATCH (p)-[rel_to_check {branch: $branch_name}]-(q)
|
|
505
498
|
WHERE row_from_time <= rel_to_check.from < $to_time
|
|
506
499
|
AND type(rel_to_check) = rel_type
|
|
@@ -513,8 +506,7 @@ WHERE intra_branch_update = FALSE
|
|
|
513
506
|
// -------------------------------------
|
|
514
507
|
// Get every path on this branch under each attribute/relationship
|
|
515
508
|
// -------------------------------------
|
|
516
|
-
CALL {
|
|
517
|
-
WITH root, r_root, p, diff_rel, q
|
|
509
|
+
CALL (root, r_root, p, diff_rel, q) {
|
|
518
510
|
OPTIONAL MATCH path = (
|
|
519
511
|
(root:Root)<-[mid_r_root:IS_PART_OF]-(p)-[mid_diff_rel]-(q)-[r_prop]-(prop)
|
|
520
512
|
)
|
|
@@ -549,8 +541,7 @@ CALL {
|
|
|
549
541
|
// Exclude properties added and deleted within the timeframe
|
|
550
542
|
// -------------------------------------
|
|
551
543
|
WITH q, nodes(latest_prop_path)[3] AS prop, type(relationships(latest_prop_path)[2]) AS rel_type, latest_prop_path, has_more_data, row_from_time
|
|
552
|
-
CALL {
|
|
553
|
-
WITH q, rel_type, prop, row_from_time
|
|
544
|
+
CALL (q, rel_type, prop, row_from_time) {
|
|
554
545
|
OPTIONAL MATCH (q)-[rel_to_check {branch: $branch_name}]-(prop)
|
|
555
546
|
WHERE row_from_time <= rel_to_check.from < $to_time
|
|
556
547
|
AND type(rel_to_check) = rel_type
|
|
@@ -717,14 +708,12 @@ ORDER BY
|
|
|
717
708
|
r_node.from DESC,
|
|
718
709
|
r_root.from DESC
|
|
719
710
|
WITH n, p, row_from_time, diff_rel, diff_rel_path, has_more_data
|
|
720
|
-
CALL {
|
|
711
|
+
CALL (n, p, row_from_time){
|
|
721
712
|
// -------------------------------------
|
|
722
713
|
// Exclude properties under nodes and attributes/relationships deleted
|
|
723
714
|
// on this branch in the timeframe because those were all handled above
|
|
724
715
|
// -------------------------------------
|
|
725
|
-
|
|
726
|
-
CALL {
|
|
727
|
-
WITH n, row_from_time
|
|
716
|
+
CALL (n, row_from_time) {
|
|
728
717
|
OPTIONAL MATCH (root:Root)<-[r_root_deleted:IS_PART_OF {branch: $branch_name}]-(n)
|
|
729
718
|
WHERE r_root_deleted.from < $to_time
|
|
730
719
|
WITH r_root_deleted
|
|
@@ -732,9 +721,8 @@ CALL {
|
|
|
732
721
|
LIMIT 1
|
|
733
722
|
RETURN COALESCE(r_root_deleted.status = "deleted", FALSE) AS node_deleted
|
|
734
723
|
}
|
|
735
|
-
WITH
|
|
736
|
-
CALL {
|
|
737
|
-
WITH n, p, row_from_time
|
|
724
|
+
WITH node_deleted
|
|
725
|
+
CALL (n, p, row_from_time) {
|
|
738
726
|
OPTIONAL MATCH (n)-[r_node_deleted {branch: $branch_name}]-(p)
|
|
739
727
|
WHERE row_from_time <= r_node_deleted.from < $to_time
|
|
740
728
|
AND type(r_node_deleted) IN ["HAS_ATTRIBUTE", "IS_RELATED"]
|
|
@@ -803,8 +791,7 @@ AND (
|
|
|
803
791
|
// -------------------------------------
|
|
804
792
|
// Ignore node created and deleted on this branch
|
|
805
793
|
// -------------------------------------
|
|
806
|
-
CALL {
|
|
807
|
-
WITH n
|
|
794
|
+
CALL (n) {
|
|
808
795
|
OPTIONAL MATCH (:Root)<-[diff_rel:IS_PART_OF {branch: $branch_name}]-(n)
|
|
809
796
|
WITH diff_rel
|
|
810
797
|
ORDER BY diff_rel.from ASC
|