infrahub-server 1.2.0b1__py3-none-any.whl → 1.2.1__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/api/dependencies.py +6 -6
- infrahub/api/diff/validation_models.py +7 -7
- infrahub/api/schema.py +1 -1
- infrahub/artifacts/models.py +1 -3
- infrahub/artifacts/tasks.py +1 -3
- infrahub/cli/__init__.py +13 -9
- infrahub/cli/constants.py +3 -0
- infrahub/cli/db.py +165 -183
- infrahub/cli/upgrade.py +146 -0
- infrahub/computed_attribute/gather.py +185 -0
- infrahub/computed_attribute/models.py +239 -11
- infrahub/computed_attribute/tasks.py +77 -442
- infrahub/computed_attribute/triggers.py +11 -45
- infrahub/config.py +43 -32
- infrahub/context.py +14 -0
- infrahub/core/account.py +4 -4
- infrahub/core/attribute.py +57 -57
- infrahub/core/branch/tasks.py +12 -9
- infrahub/core/changelog/diff.py +16 -8
- infrahub/core/changelog/models.py +189 -26
- infrahub/core/constants/__init__.py +5 -1
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/constraint/node/runner.py +9 -8
- infrahub/core/diff/branch_differ.py +10 -10
- infrahub/core/diff/ipam_diff_parser.py +4 -5
- infrahub/core/diff/model/diff.py +27 -27
- infrahub/core/diff/model/path.py +3 -3
- infrahub/core/diff/query/merge.py +20 -17
- infrahub/core/diff/query_parser.py +4 -4
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/initialization.py +1 -10
- infrahub/core/ipam/constants.py +3 -4
- infrahub/core/ipam/reconciler.py +12 -12
- infrahub/core/ipam/utilization.py +10 -13
- infrahub/core/manager.py +34 -34
- infrahub/core/merge.py +7 -7
- infrahub/core/migrations/__init__.py +2 -3
- infrahub/core/migrations/graph/__init__.py +9 -4
- infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
- infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
- infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
- infrahub/core/migrations/graph/{m020_add_generate_template_attr.py → m022_add_generate_template_attr.py} +3 -3
- infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
- infrahub/core/migrations/query/attribute_add.py +2 -2
- infrahub/core/migrations/query/node_duplicate.py +18 -21
- infrahub/core/migrations/query/schema_attribute_update.py +2 -2
- infrahub/core/migrations/schema/models.py +19 -4
- infrahub/core/migrations/schema/tasks.py +2 -2
- infrahub/core/migrations/shared.py +16 -16
- infrahub/core/models.py +15 -6
- infrahub/core/node/__init__.py +29 -28
- infrahub/core/node/base.py +2 -4
- infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
- infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
- infrahub/core/node/constraints/interface.py +1 -2
- infrahub/core/node/delete_validator.py +3 -5
- infrahub/core/node/ipam.py +4 -4
- infrahub/core/node/permissions.py +7 -7
- infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
- infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
- infrahub/core/node/resource_manager/number_pool.py +3 -3
- infrahub/core/path.py +12 -12
- infrahub/core/property.py +11 -11
- infrahub/core/protocols.py +5 -0
- infrahub/core/protocols_base.py +21 -21
- infrahub/core/query/__init__.py +33 -33
- infrahub/core/query/attribute.py +6 -4
- infrahub/core/query/diff.py +3 -3
- infrahub/core/query/node.py +82 -32
- infrahub/core/query/relationship.py +24 -24
- infrahub/core/query/resource_manager.py +2 -0
- infrahub/core/query/standard_node.py +3 -3
- infrahub/core/query/subquery.py +9 -9
- infrahub/core/registry.py +13 -15
- infrahub/core/relationship/constraints/count.py +3 -4
- infrahub/core/relationship/constraints/peer_kind.py +3 -4
- infrahub/core/relationship/constraints/profiles_kind.py +2 -2
- infrahub/core/relationship/model.py +40 -46
- infrahub/core/schema/attribute_schema.py +9 -9
- infrahub/core/schema/basenode_schema.py +93 -44
- infrahub/core/schema/computed_attribute.py +3 -3
- infrahub/core/schema/definitions/core/__init__.py +13 -19
- infrahub/core/schema/definitions/core/account.py +151 -148
- infrahub/core/schema/definitions/core/artifact.py +122 -113
- infrahub/core/schema/definitions/core/builtin.py +19 -16
- infrahub/core/schema/definitions/core/check.py +61 -53
- infrahub/core/schema/definitions/core/core.py +17 -0
- infrahub/core/schema/definitions/core/generator.py +89 -85
- infrahub/core/schema/definitions/core/graphql_query.py +72 -70
- infrahub/core/schema/definitions/core/group.py +96 -93
- infrahub/core/schema/definitions/core/ipam.py +176 -235
- infrahub/core/schema/definitions/core/lineage.py +18 -16
- infrahub/core/schema/definitions/core/menu.py +42 -40
- infrahub/core/schema/definitions/core/permission.py +144 -142
- infrahub/core/schema/definitions/core/profile.py +16 -27
- infrahub/core/schema/definitions/core/propose_change.py +88 -79
- infrahub/core/schema/definitions/core/propose_change_comment.py +170 -165
- infrahub/core/schema/definitions/core/propose_change_validator.py +290 -288
- infrahub/core/schema/definitions/core/repository.py +231 -225
- infrahub/core/schema/definitions/core/resource_pool.py +156 -166
- infrahub/core/schema/definitions/core/template.py +27 -12
- infrahub/core/schema/definitions/core/transform.py +85 -76
- infrahub/core/schema/definitions/core/webhook.py +127 -101
- infrahub/core/schema/definitions/internal.py +16 -16
- infrahub/core/schema/dropdown.py +3 -4
- infrahub/core/schema/generated/attribute_schema.py +15 -18
- infrahub/core/schema/generated/base_node_schema.py +12 -14
- infrahub/core/schema/generated/node_schema.py +3 -5
- infrahub/core/schema/generated/relationship_schema.py +9 -11
- infrahub/core/schema/generic_schema.py +2 -2
- infrahub/core/schema/manager.py +20 -9
- infrahub/core/schema/node_schema.py +4 -2
- infrahub/core/schema/relationship_schema.py +7 -7
- infrahub/core/schema/schema_branch.py +276 -138
- infrahub/core/schema/schema_branch_computed.py +41 -4
- infrahub/core/task/task.py +3 -3
- infrahub/core/task/user_task.py +15 -15
- infrahub/core/utils.py +20 -18
- infrahub/core/validators/__init__.py +1 -3
- infrahub/core/validators/aggregated_checker.py +2 -2
- infrahub/core/validators/attribute/choices.py +2 -2
- infrahub/core/validators/attribute/enum.py +2 -2
- infrahub/core/validators/attribute/kind.py +2 -2
- infrahub/core/validators/attribute/length.py +2 -2
- infrahub/core/validators/attribute/optional.py +2 -2
- infrahub/core/validators/attribute/regex.py +2 -2
- infrahub/core/validators/attribute/unique.py +2 -2
- infrahub/core/validators/checks_runner.py +25 -2
- infrahub/core/validators/determiner.py +1 -3
- infrahub/core/validators/interface.py +6 -2
- infrahub/core/validators/model.py +22 -3
- infrahub/core/validators/models/validate_migration.py +17 -4
- infrahub/core/validators/node/attribute.py +2 -2
- infrahub/core/validators/node/generate_profile.py +2 -2
- infrahub/core/validators/node/hierarchy.py +3 -5
- infrahub/core/validators/node/inherit_from.py +27 -5
- infrahub/core/validators/node/relationship.py +2 -2
- infrahub/core/validators/relationship/count.py +4 -4
- infrahub/core/validators/relationship/optional.py +2 -2
- infrahub/core/validators/relationship/peer.py +2 -2
- infrahub/core/validators/shared.py +2 -2
- infrahub/core/validators/tasks.py +8 -0
- infrahub/core/validators/uniqueness/checker.py +22 -21
- infrahub/core/validators/uniqueness/index.py +2 -2
- infrahub/core/validators/uniqueness/model.py +11 -11
- infrahub/database/__init__.py +26 -22
- infrahub/database/metrics.py +7 -1
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
- infrahub/dependencies/component/registry.py +2 -2
- infrahub/events/__init__.py +25 -2
- infrahub/events/artifact_action.py +13 -25
- infrahub/events/branch_action.py +26 -18
- infrahub/events/generator.py +71 -0
- infrahub/events/group_action.py +10 -24
- infrahub/events/models.py +10 -16
- infrahub/events/node_action.py +87 -32
- infrahub/events/repository_action.py +5 -18
- infrahub/events/schema_action.py +4 -9
- infrahub/events/utils.py +16 -0
- infrahub/events/validator_action.py +55 -0
- infrahub/exceptions.py +23 -24
- infrahub/generators/models.py +1 -3
- infrahub/git/base.py +7 -7
- infrahub/git/integrator.py +26 -25
- infrahub/git/models.py +22 -9
- infrahub/git/repository.py +3 -3
- infrahub/git/tasks.py +67 -49
- infrahub/git/utils.py +48 -0
- infrahub/git/worktree.py +1 -2
- infrahub/git_credential/askpass.py +1 -2
- infrahub/graphql/analyzer.py +12 -0
- infrahub/graphql/app.py +13 -15
- infrahub/graphql/context.py +6 -0
- infrahub/graphql/initialization.py +3 -0
- infrahub/graphql/loaders/node.py +2 -12
- infrahub/graphql/loaders/peers.py +77 -0
- infrahub/graphql/loaders/shared.py +13 -0
- infrahub/graphql/manager.py +13 -10
- infrahub/graphql/mutations/artifact_definition.py +5 -5
- infrahub/graphql/mutations/computed_attribute.py +4 -5
- infrahub/graphql/mutations/graphql_query.py +5 -5
- infrahub/graphql/mutations/ipam.py +50 -70
- infrahub/graphql/mutations/main.py +164 -141
- infrahub/graphql/mutations/menu.py +5 -5
- infrahub/graphql/mutations/models.py +2 -4
- infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
- infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
- infrahub/graphql/mutations/node_getter/by_id.py +1 -3
- infrahub/graphql/mutations/node_getter/interface.py +1 -2
- infrahub/graphql/mutations/proposed_change.py +7 -7
- infrahub/graphql/mutations/relationship.py +67 -35
- infrahub/graphql/mutations/repository.py +8 -8
- infrahub/graphql/mutations/resource_manager.py +3 -3
- infrahub/graphql/mutations/schema.py +4 -4
- infrahub/graphql/mutations/webhook.py +137 -0
- infrahub/graphql/parser.py +4 -4
- infrahub/graphql/queries/diff/tree.py +4 -4
- infrahub/graphql/queries/ipam.py +2 -2
- infrahub/graphql/queries/relationship.py +2 -2
- infrahub/graphql/queries/search.py +2 -2
- infrahub/graphql/resolvers/many_relationship.py +264 -0
- infrahub/graphql/resolvers/resolver.py +13 -110
- infrahub/graphql/subscription/graphql_query.py +2 -0
- infrahub/graphql/types/event.py +20 -11
- infrahub/graphql/types/node.py +2 -2
- infrahub/graphql/utils.py +2 -2
- infrahub/groups/ancestors.py +29 -0
- infrahub/groups/parsers.py +107 -0
- infrahub/menu/generator.py +7 -7
- infrahub/menu/menu.py +0 -10
- infrahub/menu/models.py +117 -16
- infrahub/menu/repository.py +111 -0
- infrahub/menu/utils.py +5 -8
- infrahub/message_bus/messages/__init__.py +1 -11
- infrahub/message_bus/messages/check_generator_run.py +2 -0
- infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
- infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
- infrahub/message_bus/operations/__init__.py +0 -2
- infrahub/message_bus/operations/check/generator.py +1 -0
- infrahub/message_bus/operations/event/__init__.py +2 -2
- infrahub/message_bus/operations/finalize/validator.py +51 -1
- infrahub/message_bus/operations/requests/generator_definition.py +19 -19
- infrahub/message_bus/operations/requests/proposed_change.py +3 -1
- infrahub/pools/number.py +2 -4
- infrahub/proposed_change/tasks.py +37 -28
- infrahub/pytest_plugin.py +13 -10
- infrahub/server.py +1 -2
- infrahub/services/adapters/event/__init__.py +1 -1
- infrahub/task_manager/event.py +23 -9
- infrahub/tasks/artifact.py +2 -4
- infrahub/telemetry/__init__.py +0 -0
- infrahub/telemetry/constants.py +9 -0
- infrahub/telemetry/database.py +86 -0
- infrahub/telemetry/models.py +65 -0
- infrahub/telemetry/task_manager.py +77 -0
- infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
- infrahub/telemetry/utils.py +11 -0
- infrahub/trace.py +4 -4
- infrahub/transformations/tasks.py +2 -2
- infrahub/trigger/catalogue.py +2 -5
- infrahub/trigger/constants.py +0 -8
- infrahub/trigger/models.py +14 -1
- infrahub/trigger/setup.py +90 -0
- infrahub/trigger/tasks.py +35 -90
- infrahub/utils.py +11 -1
- infrahub/validators/__init__.py +0 -0
- infrahub/validators/events.py +42 -0
- infrahub/validators/tasks.py +41 -0
- infrahub/webhook/gather.py +17 -0
- infrahub/webhook/models.py +22 -5
- infrahub/webhook/tasks.py +44 -19
- infrahub/webhook/triggers.py +22 -5
- infrahub/workers/infrahub_async.py +2 -2
- infrahub/workers/utils.py +2 -2
- infrahub/workflows/catalogue.py +28 -20
- infrahub/workflows/initialization.py +1 -3
- infrahub/workflows/models.py +1 -1
- infrahub/workflows/utils.py +10 -1
- infrahub_sdk/client.py +27 -8
- infrahub_sdk/config.py +3 -0
- infrahub_sdk/context.py +13 -0
- infrahub_sdk/exceptions.py +6 -0
- infrahub_sdk/generator.py +4 -1
- infrahub_sdk/graphql.py +45 -13
- infrahub_sdk/node.py +69 -20
- infrahub_sdk/protocols_base.py +32 -11
- infrahub_sdk/query_groups.py +6 -35
- infrahub_sdk/schema/__init__.py +55 -26
- infrahub_sdk/schema/main.py +8 -0
- infrahub_sdk/task/__init__.py +10 -0
- infrahub_sdk/task/manager.py +12 -6
- infrahub_sdk/testing/schemas/animal.py +9 -0
- infrahub_sdk/timestamp.py +12 -4
- {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +3 -2
- {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +289 -260
- {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/entry_points.txt +1 -0
- infrahub_testcontainers/constants.py +2 -0
- infrahub_testcontainers/container.py +157 -12
- infrahub_testcontainers/docker-compose.test.yml +31 -6
- infrahub_testcontainers/helpers.py +18 -73
- infrahub_testcontainers/host.py +41 -0
- infrahub_testcontainers/measurements.py +93 -0
- infrahub_testcontainers/models.py +38 -0
- infrahub_testcontainers/performance_test.py +166 -0
- infrahub_testcontainers/plugin.py +136 -0
- infrahub_testcontainers/prometheus.yml +30 -0
- infrahub/message_bus/messages/event_branch_create.py +0 -11
- infrahub/message_bus/messages/event_branch_delete.py +0 -11
- infrahub/message_bus/messages/event_branch_rebased.py +0 -9
- infrahub/message_bus/messages/event_node_mutated.py +0 -15
- infrahub/message_bus/messages/event_schema_update.py +0 -9
- infrahub/message_bus/operations/event/node.py +0 -20
- infrahub/message_bus/operations/event/schema.py +0 -17
- infrahub/webhook/constants.py +0 -1
- {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
infrahub/core/property.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
from uuid import UUID
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel
|
|
@@ -32,7 +32,7 @@ class FlagPropertyMixin:
|
|
|
32
32
|
is_visible = True
|
|
33
33
|
is_protected = False
|
|
34
34
|
|
|
35
|
-
def _init_flag_property_mixin(self, kwargs:
|
|
35
|
+
def _init_flag_property_mixin(self, kwargs: dict | None = None) -> None:
|
|
36
36
|
if not kwargs:
|
|
37
37
|
return
|
|
38
38
|
|
|
@@ -47,7 +47,7 @@ class NodePropertyMixin:
|
|
|
47
47
|
branch: Branch
|
|
48
48
|
at: Timestamp
|
|
49
49
|
|
|
50
|
-
def _init_node_property_mixin(self, kwargs:
|
|
50
|
+
def _init_node_property_mixin(self, kwargs: dict | None = None) -> None:
|
|
51
51
|
for node in self._node_properties:
|
|
52
52
|
setattr(self, f"_{node}", None)
|
|
53
53
|
setattr(self, f"{node}_id", None)
|
|
@@ -66,7 +66,7 @@ class NodePropertyMixin:
|
|
|
66
66
|
return self._get_node_property_from_cache(name="source")
|
|
67
67
|
|
|
68
68
|
@source.setter
|
|
69
|
-
def source(self, value:
|
|
69
|
+
def source(self, value: str | Node | UUID) -> None:
|
|
70
70
|
self._set_node_property(name="source", value=value)
|
|
71
71
|
|
|
72
72
|
@property
|
|
@@ -74,25 +74,25 @@ class NodePropertyMixin:
|
|
|
74
74
|
return self._get_node_property_from_cache(name="owner")
|
|
75
75
|
|
|
76
76
|
@owner.setter
|
|
77
|
-
def owner(self, value:
|
|
77
|
+
def owner(self, value: str | Node | UUID | None) -> None:
|
|
78
78
|
self._set_node_property(name="owner", value=value)
|
|
79
79
|
|
|
80
80
|
def clear_owner(self) -> None:
|
|
81
81
|
self._set_node_property(name="owner", value=None)
|
|
82
82
|
|
|
83
|
-
async def get_source(self, db: InfrahubDatabase) ->
|
|
83
|
+
async def get_source(self, db: InfrahubDatabase) -> Node | None:
|
|
84
84
|
return await self._get_node_property(name="source", db=db)
|
|
85
85
|
|
|
86
86
|
def clear_source(self) -> None:
|
|
87
87
|
self._set_node_property(name="source", value=None)
|
|
88
88
|
|
|
89
|
-
def set_source(self, value:
|
|
89
|
+
def set_source(self, value: str | Node | UUID) -> None:
|
|
90
90
|
self._set_node_property(name="source", value=value)
|
|
91
91
|
|
|
92
|
-
async def get_owner(self, db: InfrahubDatabase) ->
|
|
92
|
+
async def get_owner(self, db: InfrahubDatabase) -> Node | None:
|
|
93
93
|
return await self._get_node_property(name="owner", db=db)
|
|
94
94
|
|
|
95
|
-
def set_owner(self, value:
|
|
95
|
+
def set_owner(self, value: str | Node | UUID) -> None:
|
|
96
96
|
self._set_node_property(name="owner", value=value)
|
|
97
97
|
|
|
98
98
|
def _get_node_property_from_cache(self, name: str) -> Node:
|
|
@@ -107,7 +107,7 @@ class NodePropertyMixin:
|
|
|
107
107
|
|
|
108
108
|
return item
|
|
109
109
|
|
|
110
|
-
async def _get_node_property(self, db: InfrahubDatabase, name: str) ->
|
|
110
|
+
async def _get_node_property(self, db: InfrahubDatabase, name: str) -> Node | None:
|
|
111
111
|
"""Return the node attribute.
|
|
112
112
|
If the node is already present in cache, serve from the cache
|
|
113
113
|
If the node is not present, query it on the fly using the node_id
|
|
@@ -117,7 +117,7 @@ class NodePropertyMixin:
|
|
|
117
117
|
|
|
118
118
|
return getattr(self, f"_{name}", None)
|
|
119
119
|
|
|
120
|
-
def _set_node_property(self, name: str, value:
|
|
120
|
+
def _set_node_property(self, name: str, value: str | Node | UUID | None) -> None:
|
|
121
121
|
"""Set the value of the node_property.
|
|
122
122
|
If the value is a string, we assume it's an ID and we'll save it to query it later (if needed)
|
|
123
123
|
If the value is a Node, we save the node and we extract the ID
|
infrahub/core/protocols.py
CHANGED
|
@@ -148,6 +148,10 @@ class CoreMenu(CoreNode):
|
|
|
148
148
|
children: RelationshipManager
|
|
149
149
|
|
|
150
150
|
|
|
151
|
+
class CoreObjectComponentTemplate(CoreNode):
|
|
152
|
+
template_name: String
|
|
153
|
+
|
|
154
|
+
|
|
151
155
|
class CoreObjectTemplate(CoreNode):
|
|
152
156
|
template_name: String
|
|
153
157
|
|
|
@@ -199,6 +203,7 @@ class CoreWebhook(CoreNode):
|
|
|
199
203
|
name: String
|
|
200
204
|
event_type: Enum
|
|
201
205
|
branch_scope: Dropdown
|
|
206
|
+
node_kind: StringOptional
|
|
202
207
|
description: StringOptional
|
|
203
208
|
url: URL
|
|
204
209
|
validate_certificates: BooleanOptional
|
infrahub/core/protocols_base.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any,
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
|
|
4
4
|
|
|
5
5
|
from typing_extensions import Self
|
|
6
6
|
|
|
@@ -38,23 +38,23 @@ class InfrahubDatabase(Protocol):
|
|
|
38
38
|
@property
|
|
39
39
|
def is_transaction(self) -> bool: ...
|
|
40
40
|
|
|
41
|
-
def add_schema(self, schema: SchemaBranch, name:
|
|
42
|
-
def start_session(self, read_only: bool = False, schemas:
|
|
43
|
-
def start_transaction(self, schemas:
|
|
41
|
+
def add_schema(self, schema: SchemaBranch, name: str | None = None) -> None: ...
|
|
42
|
+
def start_session(self, read_only: bool = False, schemas: list[SchemaBranch] | None = None) -> Self: ...
|
|
43
|
+
def start_transaction(self, schemas: list[SchemaBranch] | None = None) -> Self: ...
|
|
44
44
|
async def session(self) -> AsyncSession: ...
|
|
45
|
-
async def transaction(self, name:
|
|
45
|
+
async def transaction(self, name: str | None) -> AsyncTransaction: ...
|
|
46
46
|
async def close(self) -> None: ...
|
|
47
47
|
|
|
48
48
|
async def execute_query(
|
|
49
|
-
self, query: str, params:
|
|
49
|
+
self, query: str, params: dict[str, Any] | None = None, name: str = "undefined"
|
|
50
50
|
) -> list[Record]: ...
|
|
51
51
|
|
|
52
52
|
async def execute_query_with_metadata(
|
|
53
|
-
self, query: str, params:
|
|
53
|
+
self, query: str, params: dict[str, Any] | None = None, name: str = "undefined"
|
|
54
54
|
) -> tuple[list[Record], dict[str, Any]]: ...
|
|
55
55
|
|
|
56
56
|
async def run_query(
|
|
57
|
-
self, query: str, params:
|
|
57
|
+
self, query: str, params: dict[str, Any] | None = None, name: str = "undefined"
|
|
58
58
|
) -> AsyncResult: ...
|
|
59
59
|
|
|
60
60
|
def render_list_comprehension(self, items: str, item_name: str) -> str: ...
|
|
@@ -73,29 +73,29 @@ class CoreNode(Protocol):
|
|
|
73
73
|
@classmethod
|
|
74
74
|
async def init(
|
|
75
75
|
cls,
|
|
76
|
-
schema:
|
|
76
|
+
schema: NodeSchema | ProfileSchema | str,
|
|
77
77
|
db: InfrahubDatabase,
|
|
78
|
-
branch:
|
|
79
|
-
at:
|
|
78
|
+
branch: Branch | str | None = None,
|
|
79
|
+
at: Timestamp | str | None = None,
|
|
80
80
|
) -> Self: ...
|
|
81
|
-
async def new(self, db: InfrahubDatabase, id:
|
|
82
|
-
async def save(self, db: InfrahubDatabase, at:
|
|
83
|
-
async def delete(self, db: InfrahubDatabase, at:
|
|
81
|
+
async def new(self, db: InfrahubDatabase, id: str | None = None, **kwargs: Any) -> Self: ...
|
|
82
|
+
async def save(self, db: InfrahubDatabase, at: Timestamp | None = None) -> Self: ...
|
|
83
|
+
async def delete(self, db: InfrahubDatabase, at: Timestamp | None = None) -> None: ...
|
|
84
84
|
async def load(
|
|
85
85
|
self,
|
|
86
86
|
db: InfrahubDatabase,
|
|
87
|
-
id:
|
|
88
|
-
db_id:
|
|
89
|
-
updated_at:
|
|
87
|
+
id: str | None = None,
|
|
88
|
+
db_id: str | None = None,
|
|
89
|
+
updated_at: Timestamp | str | None = None,
|
|
90
90
|
**kwargs: Any,
|
|
91
91
|
) -> Self: ...
|
|
92
92
|
async def to_graphql(
|
|
93
93
|
self,
|
|
94
94
|
db: InfrahubDatabase,
|
|
95
|
-
fields:
|
|
96
|
-
related_node_ids:
|
|
95
|
+
fields: dict | None = None,
|
|
96
|
+
related_node_ids: set | None = None,
|
|
97
97
|
filter_sensitive: bool = False,
|
|
98
|
-
permissions:
|
|
98
|
+
permissions: dict | None = None,
|
|
99
99
|
) -> dict: ...
|
|
100
|
-
async def render_display_label(self, db:
|
|
100
|
+
async def render_display_label(self, db: InfrahubDatabase | None = None) -> str: ...
|
|
101
101
|
async def from_graphql(self, data: dict, db: InfrahubDatabase) -> bool: ...
|
infrahub/core/query/__init__.py
CHANGED
|
@@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
|
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
from dataclasses import dataclass, field
|
|
6
6
|
from enum import Enum
|
|
7
|
-
from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator,
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator, TypeVar
|
|
8
8
|
|
|
9
9
|
import ujson
|
|
10
10
|
from neo4j.graph import Node as Neo4jNode
|
|
@@ -68,9 +68,9 @@ class QueryRelDirection(Enum):
|
|
|
68
68
|
@dataclass
|
|
69
69
|
class QueryElement:
|
|
70
70
|
type: QueryElementType
|
|
71
|
-
name:
|
|
72
|
-
labels:
|
|
73
|
-
params:
|
|
71
|
+
name: str | None = None
|
|
72
|
+
labels: list[str] | None = None
|
|
73
|
+
params: dict | None = None
|
|
74
74
|
|
|
75
75
|
def __str__(self) -> str:
|
|
76
76
|
main_str = "%s%s%s" % (self.name or "", self.labels_as_str, self.params_as_str)
|
|
@@ -112,7 +112,7 @@ class QueryRel(QueryElement):
|
|
|
112
112
|
type: QueryElementType = QueryElementType.RELATIONSHIP
|
|
113
113
|
direction: QueryRelDirection = QueryRelDirection.BIDIR
|
|
114
114
|
length_min: int = 1
|
|
115
|
-
length_max:
|
|
115
|
+
length_max: int | None = None
|
|
116
116
|
|
|
117
117
|
def __str__(self) -> str:
|
|
118
118
|
length_str = ""
|
|
@@ -160,7 +160,7 @@ def cleanup_return_labels(labels: list[str]) -> list[str]:
|
|
|
160
160
|
|
|
161
161
|
|
|
162
162
|
class QueryResult:
|
|
163
|
-
def __init__(self, data: list[
|
|
163
|
+
def __init__(self, data: list[Neo4jNode | Neo4jRelationship | list[Neo4jNode]], labels: list[str]):
|
|
164
164
|
self.data = data
|
|
165
165
|
self.labels = labels
|
|
166
166
|
self.branch_score: int = 0
|
|
@@ -212,23 +212,23 @@ class QueryResult:
|
|
|
212
212
|
self.has_deleted_rels = True
|
|
213
213
|
return
|
|
214
214
|
|
|
215
|
-
def _get(self, label: str) ->
|
|
215
|
+
def _get(self, label: str) -> Neo4jNode | Neo4jRelationship | list[Neo4jNode]:
|
|
216
216
|
if label not in self.labels:
|
|
217
217
|
raise ValueError(f"{label} is not a valid value for this query, must be one of {self.labels}")
|
|
218
218
|
|
|
219
219
|
return_id = self.labels.index(label)
|
|
220
220
|
return self.data[return_id]
|
|
221
221
|
|
|
222
|
-
def get(self, label: str) ->
|
|
222
|
+
def get(self, label: str) -> Neo4jNode | Neo4jRelationship:
|
|
223
223
|
return self._get(label=label)
|
|
224
224
|
|
|
225
|
-
def get_as_str(self, label: str) ->
|
|
225
|
+
def get_as_str(self, label: str) -> str | None:
|
|
226
226
|
item = self._get(label=label)
|
|
227
227
|
if item:
|
|
228
228
|
return str(item)
|
|
229
229
|
return None
|
|
230
230
|
|
|
231
|
-
def get_as_optional_type(self, label: str, return_type: Callable[..., RETURN_TYPE]) ->
|
|
231
|
+
def get_as_optional_type(self, label: str, return_type: Callable[..., RETURN_TYPE]) -> RETURN_TYPE | None:
|
|
232
232
|
"""Return a label as a given type.
|
|
233
233
|
|
|
234
234
|
For example if an integer is needed the caller would use:
|
|
@@ -305,7 +305,7 @@ class QueryResult:
|
|
|
305
305
|
class QueryStats:
|
|
306
306
|
stats: list[QueryStat] = field(default_factory=list)
|
|
307
307
|
|
|
308
|
-
def add(self, data:
|
|
308
|
+
def add(self, data: dict[str, Any] | None) -> None:
|
|
309
309
|
if data:
|
|
310
310
|
self.stats.append(QueryStat.from_metadata(data))
|
|
311
311
|
|
|
@@ -322,13 +322,13 @@ class QueryStats:
|
|
|
322
322
|
@dataclass
|
|
323
323
|
class QueryStat:
|
|
324
324
|
contains_updates: bool = False
|
|
325
|
-
labels_added:
|
|
326
|
-
labels_removed:
|
|
327
|
-
nodes_created:
|
|
328
|
-
nodes_deleted:
|
|
329
|
-
properties_set:
|
|
330
|
-
relationships_created:
|
|
331
|
-
relationships_deleted:
|
|
325
|
+
labels_added: int | None = None
|
|
326
|
+
labels_removed: int | None = None
|
|
327
|
+
nodes_created: int | None = None
|
|
328
|
+
nodes_deleted: int | None = None
|
|
329
|
+
properties_set: int | None = None
|
|
330
|
+
relationships_created: int | None = None
|
|
331
|
+
relationships_deleted: int | None = None
|
|
332
332
|
|
|
333
333
|
@classmethod
|
|
334
334
|
def from_metadata(cls, data: dict[str, Any]) -> Self:
|
|
@@ -346,11 +346,11 @@ class Query(ABC):
|
|
|
346
346
|
|
|
347
347
|
def __init__(
|
|
348
348
|
self,
|
|
349
|
-
branch:
|
|
350
|
-
at:
|
|
351
|
-
limit:
|
|
352
|
-
offset:
|
|
353
|
-
order_by:
|
|
349
|
+
branch: Branch | None = None,
|
|
350
|
+
at: Timestamp | str | None = None,
|
|
351
|
+
limit: int | None = None,
|
|
352
|
+
offset: int | None = None,
|
|
353
|
+
order_by: list[str] | None = None,
|
|
354
354
|
branch_agnostic: bool = False,
|
|
355
355
|
):
|
|
356
356
|
if branch:
|
|
@@ -379,7 +379,7 @@ class Query(ABC):
|
|
|
379
379
|
|
|
380
380
|
self.stats: QueryStats = QueryStats()
|
|
381
381
|
|
|
382
|
-
def update_return_labels(self, value:
|
|
382
|
+
def update_return_labels(self, value: str | list[str]) -> None:
|
|
383
383
|
if isinstance(value, str) and value not in self.return_labels:
|
|
384
384
|
self.return_labels.append(value)
|
|
385
385
|
return
|
|
@@ -391,10 +391,10 @@ class Query(ABC):
|
|
|
391
391
|
async def init(
|
|
392
392
|
cls,
|
|
393
393
|
db: InfrahubDatabase,
|
|
394
|
-
branch:
|
|
395
|
-
at:
|
|
396
|
-
limit:
|
|
397
|
-
offset:
|
|
394
|
+
branch: Branch | None = None,
|
|
395
|
+
at: Timestamp | str | None = None,
|
|
396
|
+
limit: int | None = None,
|
|
397
|
+
offset: int | None = None,
|
|
398
398
|
**kwargs: Any,
|
|
399
399
|
) -> Self:
|
|
400
400
|
query = cls(branch=branch, at=at, limit=limit, offset=offset, **kwargs)
|
|
@@ -412,7 +412,7 @@ class Query(ABC):
|
|
|
412
412
|
Right now it's mainly used to add more labels to the metrics."""
|
|
413
413
|
return {}
|
|
414
414
|
|
|
415
|
-
def add_to_query(self, query:
|
|
415
|
+
def add_to_query(self, query: str | list[str]) -> None:
|
|
416
416
|
"""Add a new section at the end of the query.
|
|
417
417
|
|
|
418
418
|
A string with multiple lines will be broken down into multiple entries in self.query_lines
|
|
@@ -424,7 +424,7 @@ 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:
|
|
427
|
+
def add_subquery(self, subquery: str, with_clause: str | None = None) -> None:
|
|
428
428
|
self.add_to_query("CALL {")
|
|
429
429
|
self.add_to_query(subquery)
|
|
430
430
|
self.add_to_query("}")
|
|
@@ -435,8 +435,8 @@ class Query(ABC):
|
|
|
435
435
|
self,
|
|
436
436
|
var: bool = False,
|
|
437
437
|
inline: bool = False,
|
|
438
|
-
limit:
|
|
439
|
-
offset:
|
|
438
|
+
limit: int | None = None,
|
|
439
|
+
offset: int | None = None,
|
|
440
440
|
) -> str:
|
|
441
441
|
# Make a local copy of the _query_lines
|
|
442
442
|
limit = limit or self.limit
|
|
@@ -602,7 +602,7 @@ class Query(ABC):
|
|
|
602
602
|
|
|
603
603
|
return results[0][0]
|
|
604
604
|
|
|
605
|
-
def get_result(self) ->
|
|
605
|
+
def get_result(self) -> QueryResult | None:
|
|
606
606
|
"""Return a single Result."""
|
|
607
607
|
|
|
608
608
|
if not self.has_been_executed:
|
infrahub/core/query/attribute.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from infrahub.core.constants import AttributeDBNodeType
|
|
6
6
|
from infrahub.core.constants.relationship_label import RELATIONSHIP_TO_NODE_LABEL, RELATIONSHIP_TO_VALUE_LABEL
|
|
@@ -20,9 +20,9 @@ class AttributeQuery(Query):
|
|
|
20
20
|
def __init__(
|
|
21
21
|
self,
|
|
22
22
|
attr: BaseAttribute,
|
|
23
|
-
attr_id:
|
|
24
|
-
at:
|
|
25
|
-
branch:
|
|
23
|
+
attr_id: str | None = None,
|
|
24
|
+
at: Timestamp | str | None = None,
|
|
25
|
+
branch: Branch | None = None,
|
|
26
26
|
**kwargs: Any,
|
|
27
27
|
):
|
|
28
28
|
self.attr = attr
|
|
@@ -66,6 +66,8 @@ class AttributeUpdateValueQuery(AttributeQuery):
|
|
|
66
66
|
query = """
|
|
67
67
|
MATCH (a:Attribute { uuid: $attr_uuid })
|
|
68
68
|
MERGE (av:%(labels)s { %(props)s } )
|
|
69
|
+
WITH av, a
|
|
70
|
+
LIMIT 1
|
|
69
71
|
CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "active", from: $at }]->(av)
|
|
70
72
|
""" % {"rel_label": self.attr._rel_to_value_label, "labels": ":".join(labels), "props": ", ".join(prop_list)}
|
|
71
73
|
|
infrahub/core/query/diff.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from infrahub import config
|
|
6
6
|
from infrahub.core.constants import GLOBAL_BRANCH_NAME, BranchSupportType
|
|
@@ -21,8 +21,8 @@ class DiffQuery(Query):
|
|
|
21
21
|
def __init__(
|
|
22
22
|
self,
|
|
23
23
|
branch: Branch,
|
|
24
|
-
diff_from:
|
|
25
|
-
diff_to:
|
|
24
|
+
diff_from: Timestamp | str = None,
|
|
25
|
+
diff_to: Timestamp | str = None,
|
|
26
26
|
**kwargs,
|
|
27
27
|
):
|
|
28
28
|
"""A diff is always in the context of a branch"""
|
infrahub/core/query/node.py
CHANGED
|
@@ -5,7 +5,7 @@ from copy import copy
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from dataclasses import field as dataclass_field
|
|
7
7
|
from enum import Enum
|
|
8
|
-
from typing import TYPE_CHECKING, Any, AsyncIterator, Generator
|
|
8
|
+
from typing import TYPE_CHECKING, Any, AsyncIterator, Generator
|
|
9
9
|
|
|
10
10
|
from infrahub import config
|
|
11
11
|
from infrahub.core.constants import (
|
|
@@ -37,7 +37,7 @@ if TYPE_CHECKING:
|
|
|
37
37
|
|
|
38
38
|
@dataclass
|
|
39
39
|
class NodeToProcess:
|
|
40
|
-
schema:
|
|
40
|
+
schema: NodeSchema | ProfileSchema | TemplateSchema | None
|
|
41
41
|
|
|
42
42
|
node_id: str
|
|
43
43
|
node_uuid: str
|
|
@@ -65,7 +65,7 @@ class AttributeFromDB:
|
|
|
65
65
|
attr_uuid: str
|
|
66
66
|
|
|
67
67
|
attr_value_id: str
|
|
68
|
-
attr_value_uuid:
|
|
68
|
+
attr_value_uuid: str | None
|
|
69
69
|
|
|
70
70
|
value: Any
|
|
71
71
|
content: Any
|
|
@@ -96,11 +96,11 @@ class PeerInfo:
|
|
|
96
96
|
class NodeQuery(Query):
|
|
97
97
|
def __init__(
|
|
98
98
|
self,
|
|
99
|
-
node:
|
|
100
|
-
node_id:
|
|
101
|
-
node_db_id:
|
|
102
|
-
id:
|
|
103
|
-
branch:
|
|
99
|
+
node: Node | None = None,
|
|
100
|
+
node_id: str | None = None,
|
|
101
|
+
node_db_id: int | None = None,
|
|
102
|
+
id: str | None = None,
|
|
103
|
+
branch: Branch | None = None,
|
|
104
104
|
**kwargs,
|
|
105
105
|
) -> None:
|
|
106
106
|
# TODO Validate that Node is a valid node
|
|
@@ -202,15 +202,16 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
202
202
|
}
|
|
203
203
|
ipnetwork_prop_list = [f"{key}: {value}" for key, value in ipnetwork_prop.items()]
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
MATCH (root:Root)
|
|
207
|
-
CREATE (n:Node:%(labels)s $node_prop )
|
|
208
|
-
CREATE (n)-[r:IS_PART_OF $node_branch_prop ]->(root)
|
|
205
|
+
attrs_query = """
|
|
209
206
|
WITH distinct n
|
|
210
|
-
|
|
207
|
+
UNWIND $attrs AS attr
|
|
208
|
+
CALL {
|
|
209
|
+
WITH n, attr
|
|
211
210
|
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
212
211
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
213
212
|
MERGE (av:AttributeValue { value: attr.content.value, is_default: attr.content.is_default })
|
|
213
|
+
WITH n, attr, av, a
|
|
214
|
+
LIMIT 1
|
|
214
215
|
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
215
216
|
MERGE (ip:Boolean { value: attr.is_protected })
|
|
216
217
|
MERGE (iv:Boolean { value: attr.is_visible })
|
|
@@ -224,11 +225,19 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
224
225
|
MERGE (peer:Node { uuid: prop.peer_id })
|
|
225
226
|
CREATE (a)-[:HAS_OWNER { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
|
|
226
227
|
)
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
}"""
|
|
229
|
+
|
|
230
|
+
attrs_iphost_query = """
|
|
231
|
+
WITH distinct n
|
|
232
|
+
UNWIND $attrs_iphost AS attr_iphost
|
|
233
|
+
CALL {
|
|
234
|
+
WITH n, attr_iphost
|
|
235
|
+
WITH n, attr_iphost AS attr
|
|
229
236
|
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
230
237
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
231
238
|
MERGE (av:AttributeValue:AttributeIPHost { %(iphost_prop)s })
|
|
239
|
+
WITH n, attr, av, a
|
|
240
|
+
LIMIT 1
|
|
232
241
|
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
233
242
|
MERGE (ip:Boolean { value: attr.is_protected })
|
|
234
243
|
MERGE (iv:Boolean { value: attr.is_visible })
|
|
@@ -242,11 +251,20 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
242
251
|
MERGE (peer:Node { uuid: prop.peer_id })
|
|
243
252
|
CREATE (a)-[:HAS_OWNER { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
|
|
244
253
|
)
|
|
245
|
-
|
|
246
|
-
|
|
254
|
+
}
|
|
255
|
+
""" % {"iphost_prop": ", ".join(iphost_prop_list)}
|
|
256
|
+
|
|
257
|
+
attrs_ipnetwork_query = """
|
|
258
|
+
WITH distinct n
|
|
259
|
+
UNWIND $attrs_ipnetwork AS attr_ipnetwork
|
|
260
|
+
CALL {
|
|
261
|
+
WITH n, attr_ipnetwork
|
|
262
|
+
WITH n, attr_ipnetwork AS attr
|
|
247
263
|
CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
|
|
248
264
|
CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
|
|
249
265
|
MERGE (av:AttributeValue:AttributeIPNetwork { %(ipnetwork_prop)s })
|
|
266
|
+
WITH n, attr, av, a
|
|
267
|
+
LIMIT 1
|
|
250
268
|
CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
|
|
251
269
|
MERGE (ip:Boolean { value: attr.is_protected })
|
|
252
270
|
MERGE (iv:Boolean { value: attr.is_visible })
|
|
@@ -260,8 +278,14 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
260
278
|
MERGE (peer:Node { uuid: prop.peer_id })
|
|
261
279
|
CREATE (a)-[:HAS_OWNER { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
|
|
262
280
|
)
|
|
263
|
-
|
|
264
|
-
|
|
281
|
+
}
|
|
282
|
+
""" % {"ipnetwork_prop": ", ".join(ipnetwork_prop_list)}
|
|
283
|
+
|
|
284
|
+
rels_bidir_query = """
|
|
285
|
+
WITH distinct n
|
|
286
|
+
UNWIND $rels_bidir AS rel
|
|
287
|
+
CALL {
|
|
288
|
+
WITH n, rel
|
|
265
289
|
MERGE (d:Node { uuid: rel.destination_id })
|
|
266
290
|
CREATE (rl:Relationship { uuid: rel.uuid, name: rel.name, branch_support: rel.branch_support })
|
|
267
291
|
CREATE (n)-[:IS_RELATED %(rel_prop)s ]->(rl)
|
|
@@ -278,8 +302,15 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
278
302
|
MERGE (peer:Node { uuid: prop.peer_id })
|
|
279
303
|
CREATE (rl)-[:HAS_OWNER { branch: rel.branch, branch_level: rel.branch_level, status: rel.status, from: $at }]->(peer)
|
|
280
304
|
)
|
|
281
|
-
|
|
282
|
-
|
|
305
|
+
}
|
|
306
|
+
""" % {"rel_prop": rel_prop_str}
|
|
307
|
+
|
|
308
|
+
rels_out_query = """
|
|
309
|
+
WITH distinct n
|
|
310
|
+
UNWIND $rels_out AS rel_out
|
|
311
|
+
CALL {
|
|
312
|
+
WITH n, rel_out
|
|
313
|
+
WITH n, rel_out as rel
|
|
283
314
|
MERGE (d:Node { uuid: rel.destination_id })
|
|
284
315
|
CREATE (rl:Relationship { uuid: rel.uuid, name: rel.name, branch_support: rel.branch_support })
|
|
285
316
|
CREATE (n)-[:IS_RELATED %(rel_prop)s ]->(rl)
|
|
@@ -296,8 +327,15 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
296
327
|
MERGE (peer:Node { uuid: prop.peer_id })
|
|
297
328
|
CREATE (rl)-[:HAS_OWNER { branch: rel.branch, branch_level: rel.branch_level, status: rel.status, from: $at }]->(peer)
|
|
298
329
|
)
|
|
299
|
-
|
|
300
|
-
|
|
330
|
+
}
|
|
331
|
+
""" % {"rel_prop": rel_prop_str}
|
|
332
|
+
|
|
333
|
+
rels_in_query = """
|
|
334
|
+
WITH distinct n
|
|
335
|
+
UNWIND $rels_in AS rel_in
|
|
336
|
+
CALL {
|
|
337
|
+
WITH n, rel_in
|
|
338
|
+
WITH n, rel_in AS rel
|
|
301
339
|
MERGE (d:Node { uuid: rel.destination_id })
|
|
302
340
|
CREATE (rl:Relationship { uuid: rel.uuid, name: rel.name, branch_support: rel.branch_support })
|
|
303
341
|
CREATE (n)<-[:IS_RELATED %(rel_prop)s ]-(rl)
|
|
@@ -314,14 +352,23 @@ class NodeCreateAllQuery(NodeQuery):
|
|
|
314
352
|
MERGE (peer:Node { uuid: prop.peer_id })
|
|
315
353
|
CREATE (rl)-[:HAS_OWNER { branch: rel.branch, branch_level: rel.branch_level, status: rel.status, from: $at }]->(peer)
|
|
316
354
|
)
|
|
317
|
-
|
|
355
|
+
}
|
|
356
|
+
""" % {"rel_prop": rel_prop_str}
|
|
357
|
+
|
|
358
|
+
query = f"""
|
|
359
|
+
MATCH (root:Root)
|
|
360
|
+
CREATE (n:Node:%(labels)s $node_prop )
|
|
361
|
+
CREATE (n)-[r:IS_PART_OF $node_branch_prop ]->(root)
|
|
362
|
+
{attrs_query if self.params["attrs"] else ""}
|
|
363
|
+
{attrs_iphost_query if self.params["attrs_iphost"] else ""}
|
|
364
|
+
{attrs_ipnetwork_query if self.params["attrs_ipnetwork"] else ""}
|
|
365
|
+
{rels_bidir_query if self.params["rels_bidir"] else ""}
|
|
366
|
+
{rels_out_query if self.params["rels_out"] else ""}
|
|
367
|
+
{rels_in_query if self.params["rels_in"] else ""}
|
|
318
368
|
WITH distinct n
|
|
319
369
|
MATCH (n)-[:HAS_ATTRIBUTE|IS_RELATED]-(rn)-[:HAS_VALUE|IS_RELATED]-(rv)
|
|
320
370
|
""" % {
|
|
321
371
|
"labels": ":".join(self.node.get_labels()),
|
|
322
|
-
"rel_prop": rel_prop_str,
|
|
323
|
-
"iphost_prop": ", ".join(iphost_prop_list),
|
|
324
|
-
"ipnetwork_prop": ", ".join(ipnetwork_prop_list),
|
|
325
372
|
}
|
|
326
373
|
|
|
327
374
|
self.params["at"] = at.to_string()
|
|
@@ -415,7 +462,7 @@ class NodeListGetAttributeQuery(Query):
|
|
|
415
462
|
def __init__(
|
|
416
463
|
self,
|
|
417
464
|
ids: list[str],
|
|
418
|
-
fields:
|
|
465
|
+
fields: dict | None = None,
|
|
419
466
|
include_source: bool = False,
|
|
420
467
|
include_owner: bool = False,
|
|
421
468
|
account=None,
|
|
@@ -618,18 +665,21 @@ class NodeListGetRelationshipsQuery(Query):
|
|
|
618
665
|
MATCH paths_in = ((n)<-[r1:IS_RELATED]-(rel:Relationship)<-[r2:IS_RELATED]-(peer))
|
|
619
666
|
WHERE ($relationship_identifiers IS NULL OR rel.name in $relationship_identifiers)
|
|
620
667
|
AND all(r IN relationships(paths_in) WHERE (%(filters)s))
|
|
668
|
+
AND n.uuid <> peer.uuid
|
|
621
669
|
RETURN n, rel, peer, r1, r2, "inbound" as direction
|
|
622
670
|
UNION
|
|
623
671
|
MATCH (n:Node) WHERE n.uuid IN $ids
|
|
624
672
|
MATCH paths_out = ((n)-[r1:IS_RELATED]->(rel:Relationship)-[r2:IS_RELATED]->(peer))
|
|
625
673
|
WHERE ($relationship_identifiers IS NULL OR rel.name in $relationship_identifiers)
|
|
626
674
|
AND all(r IN relationships(paths_out) WHERE (%(filters)s))
|
|
675
|
+
AND n.uuid <> peer.uuid
|
|
627
676
|
RETURN n, rel, peer, r1, r2, "outbound" as direction
|
|
628
677
|
UNION
|
|
629
678
|
MATCH (n:Node) WHERE n.uuid IN $ids
|
|
630
679
|
MATCH paths_bidir = ((n)-[r1:IS_RELATED]->(rel:Relationship)<-[r2:IS_RELATED]-(peer))
|
|
631
680
|
WHERE ($relationship_identifiers IS NULL OR rel.name in $relationship_identifiers)
|
|
632
681
|
AND all(r IN relationships(paths_bidir) WHERE (%(filters)s))
|
|
682
|
+
AND n.uuid <> peer.uuid
|
|
633
683
|
RETURN n, rel, peer, r1, r2, "bidirectional" as direction
|
|
634
684
|
""" % {"filters": rels_filter}
|
|
635
685
|
|
|
@@ -757,7 +807,7 @@ class FieldAttributeRequirementType(Enum):
|
|
|
757
807
|
@dataclass
|
|
758
808
|
class FieldAttributeRequirement:
|
|
759
809
|
field_name: str
|
|
760
|
-
field:
|
|
810
|
+
field: AttributeSchema | RelationshipSchema | None
|
|
761
811
|
field_attr_name: str
|
|
762
812
|
field_attr_value: Any
|
|
763
813
|
index: int
|
|
@@ -817,7 +867,7 @@ class NodeGetListQuery(Query):
|
|
|
817
867
|
def __init__(
|
|
818
868
|
self,
|
|
819
869
|
schema: NodeSchema,
|
|
820
|
-
filters:
|
|
870
|
+
filters: dict | None = None,
|
|
821
871
|
partial_match: bool = False,
|
|
822
872
|
order: OrderModel | None = None,
|
|
823
873
|
**kwargs: Any,
|
|
@@ -1264,8 +1314,8 @@ class NodeGetHierarchyQuery(Query):
|
|
|
1264
1314
|
self,
|
|
1265
1315
|
node_id: str,
|
|
1266
1316
|
direction: RelationshipHierarchyDirection,
|
|
1267
|
-
node_schema:
|
|
1268
|
-
filters:
|
|
1317
|
+
node_schema: NodeSchema | GenericSchema,
|
|
1318
|
+
filters: dict | None = None,
|
|
1269
1319
|
hierarchical_ordering: bool = False,
|
|
1270
1320
|
**kwargs: Any,
|
|
1271
1321
|
) -> None:
|