infrahub-server 1.2.0rc0__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 +5 -3
- infrahub/artifacts/tasks.py +3 -5
- 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 +240 -12
- infrahub/computed_attribute/tasks.py +77 -441
- infrahub/computed_attribute/triggers.py +13 -47
- infrahub/config.py +43 -32
- infrahub/context.py +14 -0
- infrahub/core/account.py +4 -4
- infrahub/core/attribute.py +58 -58
- infrahub/core/branch/tasks.py +74 -22
- infrahub/core/changelog/diff.py +95 -36
- infrahub/core/changelog/models.py +217 -43
- infrahub/core/constants/__init__.py +28 -0
- infrahub/core/constants/infrahubkind.py +2 -0
- infrahub/core/constants/schema.py +2 -0
- infrahub/core/constraint/node/runner.py +9 -8
- infrahub/core/diff/branch_differ.py +10 -10
- infrahub/core/diff/enricher/cardinality_one.py +5 -0
- infrahub/core/diff/enricher/hierarchy.py +17 -4
- infrahub/core/diff/enricher/labels.py +5 -0
- infrahub/core/diff/enricher/path_identifier.py +4 -0
- infrahub/core/diff/ipam_diff_parser.py +4 -5
- infrahub/core/diff/model/diff.py +27 -27
- infrahub/core/diff/model/path.py +32 -9
- infrahub/core/diff/parent_node_adder.py +78 -0
- infrahub/core/diff/payload_builder.py +13 -2
- infrahub/core/diff/query/filters.py +2 -2
- infrahub/core/diff/query/merge.py +20 -17
- infrahub/core/diff/query/save.py +188 -182
- infrahub/core/diff/query/summary_counts_enricher.py +51 -4
- infrahub/core/diff/query_parser.py +4 -4
- infrahub/core/diff/repository/deserializer.py +8 -3
- infrahub/core/diff/repository/repository.py +156 -38
- infrahub/core/diff/tasks.py +4 -4
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/index.py +3 -0
- 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 +36 -36
- infrahub/core/merge.py +7 -7
- infrahub/core/migrations/__init__.py +2 -3
- infrahub/core/migrations/graph/__init__.py +12 -3
- 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/m019_restore_rels_to_time.py +256 -0
- 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/m022_add_generate_template_attr.py +48 -0
- 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 +43 -26
- infrahub/core/migrations/query/schema_attribute_update.py +2 -2
- infrahub/core/migrations/schema/models.py +19 -4
- infrahub/core/migrations/schema/node_remove.py +26 -12
- 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 +43 -39
- 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 +7 -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 +228 -40
- 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 +51 -59
- infrahub/core/schema/attribute_schema.py +16 -8
- infrahub/core/schema/basenode_schema.py +105 -44
- infrahub/core/schema/computed_attribute.py +3 -3
- infrahub/core/schema/definitions/core/__init__.py +147 -0
- infrahub/core/schema/definitions/core/account.py +171 -0
- infrahub/core/schema/definitions/core/artifact.py +136 -0
- infrahub/core/schema/definitions/core/builtin.py +24 -0
- infrahub/core/schema/definitions/core/check.py +68 -0
- infrahub/core/schema/definitions/core/core.py +17 -0
- infrahub/core/schema/definitions/core/generator.py +100 -0
- infrahub/core/schema/definitions/core/graphql_query.py +79 -0
- infrahub/core/schema/definitions/core/group.py +108 -0
- infrahub/core/schema/definitions/core/ipam.py +193 -0
- infrahub/core/schema/definitions/core/lineage.py +19 -0
- infrahub/core/schema/definitions/core/menu.py +48 -0
- infrahub/core/schema/definitions/core/permission.py +163 -0
- infrahub/core/schema/definitions/core/profile.py +18 -0
- infrahub/core/schema/definitions/core/propose_change.py +97 -0
- infrahub/core/schema/definitions/core/propose_change_comment.py +193 -0
- infrahub/core/schema/definitions/core/propose_change_validator.py +328 -0
- infrahub/core/schema/definitions/core/repository.py +286 -0
- infrahub/core/schema/definitions/core/resource_pool.py +170 -0
- infrahub/core/schema/definitions/core/template.py +27 -0
- infrahub/core/schema/definitions/core/transform.py +96 -0
- infrahub/core/schema/definitions/core/webhook.py +134 -0
- 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 +14 -6
- infrahub/core/schema/schema_branch.py +292 -144
- 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/timestamp.py +3 -3
- 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 +27 -22
- infrahub/database/metrics.py +7 -1
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
- infrahub/dependencies/builder/diff/deserializer.py +3 -1
- infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
- infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
- infrahub/dependencies/component/registry.py +2 -2
- infrahub/events/__init__.py +25 -2
- infrahub/events/artifact_action.py +64 -0
- infrahub/events/branch_action.py +33 -22
- infrahub/events/generator.py +71 -0
- infrahub/events/group_action.py +51 -21
- infrahub/events/models.py +18 -19
- infrahub/events/node_action.py +88 -37
- 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 +32 -24
- infrahub/generators/models.py +2 -3
- infrahub/generators/tasks.py +24 -4
- infrahub/git/base.py +7 -7
- infrahub/git/integrator.py +48 -24
- infrahub/git/models.py +101 -9
- infrahub/git/repository.py +3 -3
- infrahub/git/tasks.py +408 -6
- 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 +39 -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 +17 -19
- infrahub/graphql/mutations/artifact_definition.py +5 -5
- infrahub/graphql/mutations/branch.py +26 -1
- infrahub/graphql/mutations/computed_attribute.py +9 -5
- infrahub/graphql/mutations/diff.py +23 -11
- infrahub/graphql/mutations/diff_conflict.py +5 -0
- infrahub/graphql/mutations/generator.py +83 -0
- infrahub/graphql/mutations/graphql_query.py +5 -5
- infrahub/graphql/mutations/ipam.py +54 -74
- infrahub/graphql/mutations/main.py +195 -132
- infrahub/graphql/mutations/menu.py +7 -7
- 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 +93 -19
- infrahub/graphql/mutations/repository.py +8 -8
- infrahub/graphql/mutations/resource_manager.py +3 -3
- infrahub/graphql/mutations/schema.py +19 -4
- infrahub/graphql/mutations/webhook.py +137 -0
- infrahub/graphql/parser.py +4 -4
- infrahub/graphql/permissions.py +1 -10
- infrahub/graphql/queries/diff/tree.py +19 -14
- infrahub/graphql/queries/event.py +5 -2
- 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/schema.py +2 -0
- infrahub/graphql/subscription/graphql_query.py +2 -0
- infrahub/graphql/types/context.py +12 -0
- infrahub/graphql/types/event.py +84 -17
- 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/lock.py +20 -20
- infrahub/menu/constants.py +0 -1
- infrahub/menu/generator.py +9 -21
- infrahub/menu/menu.py +17 -38
- infrahub/menu/models.py +117 -16
- infrahub/menu/repository.py +111 -0
- infrahub/menu/utils.py +5 -8
- infrahub/message_bus/__init__.py +11 -13
- infrahub/message_bus/messages/__init__.py +1 -21
- infrahub/message_bus/messages/check_generator_run.py +3 -3
- infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
- infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
- infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
- infrahub/message_bus/messages/send_echo_request.py +1 -1
- infrahub/message_bus/operations/__init__.py +1 -10
- infrahub/message_bus/operations/check/__init__.py +2 -2
- infrahub/message_bus/operations/check/generator.py +1 -0
- infrahub/message_bus/operations/event/__init__.py +2 -2
- infrahub/message_bus/operations/event/worker.py +0 -3
- infrahub/message_bus/operations/finalize/validator.py +51 -1
- infrahub/message_bus/operations/requests/__init__.py +0 -2
- infrahub/message_bus/operations/requests/generator_definition.py +21 -23
- infrahub/message_bus/operations/requests/proposed_change.py +14 -10
- infrahub/permissions/globals.py +15 -0
- infrahub/pools/number.py +2 -4
- infrahub/proposed_change/models.py +3 -0
- infrahub/proposed_change/tasks.py +58 -45
- infrahub/pytest_plugin.py +13 -10
- infrahub/server.py +2 -3
- infrahub/services/__init__.py +2 -2
- infrahub/services/adapters/cache/__init__.py +4 -6
- infrahub/services/adapters/cache/nats.py +4 -5
- infrahub/services/adapters/cache/redis.py +3 -7
- infrahub/services/adapters/event/__init__.py +1 -1
- infrahub/services/adapters/message_bus/__init__.py +3 -3
- infrahub/services/adapters/message_bus/local.py +2 -2
- infrahub/services/adapters/message_bus/nats.py +4 -4
- infrahub/services/adapters/message_bus/rabbitmq.py +4 -4
- infrahub/services/adapters/workflow/local.py +2 -2
- infrahub/services/component.py +5 -5
- infrahub/services/protocols.py +7 -7
- infrahub/services/scheduler.py +1 -3
- infrahub/task_manager/event.py +102 -9
- infrahub/task_manager/models.py +27 -7
- infrahub/tasks/artifact.py +7 -6
- 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 +4 -6
- infrahub/trigger/constants.py +0 -8
- infrahub/trigger/models.py +54 -5
- infrahub/trigger/setup.py +90 -0
- infrahub/trigger/tasks.py +35 -84
- 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 +176 -44
- infrahub/webhook/tasks.py +154 -155
- infrahub/webhook/triggers.py +31 -7
- infrahub/workers/infrahub_async.py +2 -2
- infrahub/workers/utils.py +2 -2
- infrahub/workflows/catalogue.py +86 -35
- infrahub/workflows/initialization.py +8 -2
- infrahub/workflows/models.py +27 -1
- infrahub/workflows/utils.py +10 -1
- infrahub_sdk/client.py +35 -8
- infrahub_sdk/config.py +3 -0
- infrahub_sdk/context.py +13 -0
- infrahub_sdk/ctl/branch.py +3 -2
- infrahub_sdk/ctl/cli_commands.py +5 -1
- infrahub_sdk/ctl/utils.py +0 -16
- infrahub_sdk/exceptions.py +12 -0
- infrahub_sdk/generator.py +4 -1
- infrahub_sdk/graphql.py +45 -13
- infrahub_sdk/node.py +71 -22
- infrahub_sdk/protocols.py +21 -8
- 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 +11 -0
- infrahub_sdk/task/constants.py +3 -0
- infrahub_sdk/task/exceptions.py +25 -0
- infrahub_sdk/task/manager.py +551 -0
- infrahub_sdk/task/models.py +74 -0
- infrahub_sdk/testing/schemas/animal.py +9 -0
- infrahub_sdk/timestamp.py +142 -33
- infrahub_sdk/utils.py +29 -1
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +8 -6
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +349 -293
- {infrahub_server-1.2.0rc0.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/core/schema/definitions/core.py +0 -2286
- infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
- infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
- infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
- 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/messages/request_repository_checks.py +0 -12
- infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
- infrahub/message_bus/operations/check/repository.py +0 -293
- infrahub/message_bus/operations/event/node.py +0 -20
- infrahub/message_bus/operations/event/schema.py +0 -17
- infrahub/message_bus/operations/requests/repository.py +0 -133
- infrahub/webhook/constants.py +0 -1
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Self, cast
|
|
5
|
+
|
|
6
|
+
from graphene import InputObjectType, Mutation
|
|
7
|
+
|
|
8
|
+
from infrahub.core.manager import NodeManager
|
|
9
|
+
from infrahub.core.protocols import CoreWebhook
|
|
10
|
+
from infrahub.core.schema import NodeSchema
|
|
11
|
+
from infrahub.database import retry_db_transaction
|
|
12
|
+
from infrahub.events.utils import get_all_infrahub_node_kind_events
|
|
13
|
+
from infrahub.exceptions import ValidationError
|
|
14
|
+
from infrahub.log import get_logger
|
|
15
|
+
|
|
16
|
+
from .main import InfrahubMutationMixin, InfrahubMutationOptions
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from graphql import GraphQLResolveInfo
|
|
20
|
+
|
|
21
|
+
from infrahub.core.branch import Branch
|
|
22
|
+
from infrahub.core.node import Node
|
|
23
|
+
from infrahub.database import InfrahubDatabase
|
|
24
|
+
from infrahub.graphql.initialization import GraphqlContext
|
|
25
|
+
|
|
26
|
+
log = get_logger()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class StringValue:
|
|
31
|
+
value: str
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class WebhookCreate:
|
|
36
|
+
event_type: StringValue | None = field(default=None)
|
|
37
|
+
node_kind: StringValue | None = field(default=None)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class WebhookUpdate(WebhookCreate):
|
|
41
|
+
id: str | None = field(default=None)
|
|
42
|
+
hfid: list[str] | None = field(default=None)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class InfrahubWebhookMutation(InfrahubMutationMixin, Mutation):
|
|
46
|
+
_meta: InfrahubMutationOptions
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def __init_subclass_with_meta__(
|
|
50
|
+
cls, schema: NodeSchema | None = None, _meta: InfrahubMutationOptions | None = None, **options: dict[str, Any]
|
|
51
|
+
) -> None:
|
|
52
|
+
# Make sure schema is a valid NodeSchema Node Class
|
|
53
|
+
if not isinstance(schema, NodeSchema):
|
|
54
|
+
raise ValueError(f"You need to pass a valid NodeSchema in '{cls.__name__}.Meta', received '{schema}'")
|
|
55
|
+
|
|
56
|
+
if not _meta:
|
|
57
|
+
_meta = InfrahubMutationOptions(cls)
|
|
58
|
+
|
|
59
|
+
_meta.schema = schema
|
|
60
|
+
|
|
61
|
+
super().__init_subclass_with_meta__(_meta=_meta, **options)
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
async def mutate_create(
|
|
65
|
+
cls,
|
|
66
|
+
info: GraphQLResolveInfo,
|
|
67
|
+
data: InputObjectType,
|
|
68
|
+
branch: Branch,
|
|
69
|
+
database: InfrahubDatabase | None = None,
|
|
70
|
+
) -> tuple[Node, Self]:
|
|
71
|
+
graphql_context: GraphqlContext = info.context
|
|
72
|
+
|
|
73
|
+
input_data = cast("WebhookCreate", data)
|
|
74
|
+
|
|
75
|
+
_validate_input(graphql_context=graphql_context, branch=branch, input_data=input_data)
|
|
76
|
+
|
|
77
|
+
obj, result = await super().mutate_create(info=info, data=data, branch=branch, database=database)
|
|
78
|
+
|
|
79
|
+
return obj, result
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
@retry_db_transaction(name="object_update")
|
|
83
|
+
async def mutate_update(
|
|
84
|
+
cls,
|
|
85
|
+
info: GraphQLResolveInfo,
|
|
86
|
+
data: InputObjectType,
|
|
87
|
+
branch: Branch,
|
|
88
|
+
database: InfrahubDatabase | None = None,
|
|
89
|
+
node: Node | None = None,
|
|
90
|
+
) -> tuple[Node, Self]:
|
|
91
|
+
graphql_context: GraphqlContext = info.context
|
|
92
|
+
|
|
93
|
+
db = database or graphql_context.db
|
|
94
|
+
|
|
95
|
+
input_data = cast("WebhookUpdate", data)
|
|
96
|
+
|
|
97
|
+
_validate_input(graphql_context=graphql_context, branch=branch, input_data=input_data)
|
|
98
|
+
|
|
99
|
+
obj = node or await NodeManager.find_object(
|
|
100
|
+
db=db,
|
|
101
|
+
kind=cls._meta.active_schema.kind,
|
|
102
|
+
id=input_data.id,
|
|
103
|
+
hfid=input_data.hfid,
|
|
104
|
+
branch=branch,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
webhook = cast(CoreWebhook, obj)
|
|
108
|
+
|
|
109
|
+
event_type = input_data.event_type.value if input_data.event_type else webhook.event_type.value.value
|
|
110
|
+
node_kind = input_data.node_kind.value if input_data.node_kind else webhook.node_kind.value
|
|
111
|
+
|
|
112
|
+
if event_type and node_kind:
|
|
113
|
+
updated_data = WebhookUpdate(
|
|
114
|
+
event_type=StringValue(value=event_type), node_kind=StringValue(value=node_kind)
|
|
115
|
+
)
|
|
116
|
+
_validate_input(graphql_context=graphql_context, branch=branch, input_data=updated_data)
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
obj, result = await cls._call_mutate_update(info=info, data=data, db=db, branch=branch, obj=obj)
|
|
120
|
+
except ValidationError as exc:
|
|
121
|
+
raise ValueError(str(exc)) from exc
|
|
122
|
+
|
|
123
|
+
return obj, result
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _validate_input(graphql_context: GraphqlContext, branch: Branch, input_data: WebhookCreate) -> None:
|
|
127
|
+
if input_data.node_kind:
|
|
128
|
+
# Validate that the requested node_kind exists, will raise an error if not
|
|
129
|
+
graphql_context.db.schema.get(name=input_data.node_kind.value, branch=branch, duplicate=False)
|
|
130
|
+
|
|
131
|
+
if input_data.event_type:
|
|
132
|
+
# If the event type is not set then all events are applicable, this will mean that some events
|
|
133
|
+
# would be filtered out, as they won't match the node.
|
|
134
|
+
if input_data.event_type.value not in get_all_infrahub_node_kind_events():
|
|
135
|
+
raise ValidationError(
|
|
136
|
+
input_value=f"Defining a node_kind is not valid for {input_data.event_type.value} events"
|
|
137
|
+
)
|
infrahub/graphql/parser.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from graphql.language import (
|
|
7
7
|
DirectiveNode,
|
|
@@ -172,13 +172,13 @@ class GraphQLExtractor:
|
|
|
172
172
|
return fields
|
|
173
173
|
|
|
174
174
|
async def extract_fields(
|
|
175
|
-
self, selection_set:
|
|
176
|
-
) ->
|
|
175
|
+
self, selection_set: SelectionSetNode | None, path: str = "/"
|
|
176
|
+
) -> dict[str, dict | None] | None:
|
|
177
177
|
"""Extract fields and apply Directives"""
|
|
178
178
|
if not selection_set:
|
|
179
179
|
return None
|
|
180
180
|
|
|
181
|
-
fields: dict[str,
|
|
181
|
+
fields: dict[str, dict | None] = {}
|
|
182
182
|
for node in selection_set.selections:
|
|
183
183
|
sub_selection_set = getattr(node, "selection_set", None)
|
|
184
184
|
if isinstance(node, FieldNode):
|
infrahub/graphql/permissions.py
CHANGED
|
@@ -15,16 +15,7 @@ async def get_permissions(schema: MainSchemaTypes, graphql_context: GraphqlConte
|
|
|
15
15
|
schema_objects = [schema]
|
|
16
16
|
if isinstance(schema, GenericSchema):
|
|
17
17
|
for node_name in schema.used_by:
|
|
18
|
-
|
|
19
|
-
try:
|
|
20
|
-
schema_object = registry.schema.get_node_schema(
|
|
21
|
-
name=node_name, branch=graphql_context.branch, duplicate=False
|
|
22
|
-
)
|
|
23
|
-
except ValueError:
|
|
24
|
-
schema_object = registry.schema.get_profile_schema(
|
|
25
|
-
name=node_name, branch=graphql_context.branch, duplicate=False
|
|
26
|
-
)
|
|
27
|
-
schema_objects.append(schema_object)
|
|
18
|
+
schema_objects.append(registry.schema.get(name=node_name, branch=graphql_context.branch, duplicate=False))
|
|
28
19
|
|
|
29
20
|
response: dict[str, Any] = {"count": len(schema_objects), "edges": []}
|
|
30
21
|
|
|
@@ -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 graphene import Argument, Boolean, DateTime, Field, InputObjectType, Int, List, NonNull, ObjectType, String
|
|
6
6
|
from graphene import Enum as GrapheneEnum
|
|
@@ -193,7 +193,7 @@ class DiffTreeResolver:
|
|
|
193
193
|
label=enriched_node.label,
|
|
194
194
|
status=enriched_node.action,
|
|
195
195
|
parent=parent,
|
|
196
|
-
last_changed_at=enriched_node.changed_at.
|
|
196
|
+
last_changed_at=enriched_node.changed_at.to_datetime() if enriched_node.changed_at else None,
|
|
197
197
|
path_identifier=enriched_node.path_identifier,
|
|
198
198
|
attributes=diff_attributes,
|
|
199
199
|
relationships=diff_relationships,
|
|
@@ -219,7 +219,7 @@ class DiffTreeResolver:
|
|
|
219
219
|
diff_prop.conflict = None
|
|
220
220
|
return DiffAttribute(
|
|
221
221
|
name=enriched_attribute.name,
|
|
222
|
-
last_changed_at=enriched_attribute.changed_at.
|
|
222
|
+
last_changed_at=enriched_attribute.changed_at.to_datetime(),
|
|
223
223
|
status=enriched_attribute.action,
|
|
224
224
|
path_identifier=enriched_attribute.path_identifier,
|
|
225
225
|
properties=diff_properties,
|
|
@@ -241,7 +241,9 @@ class DiffTreeResolver:
|
|
|
241
241
|
return DiffRelationship(
|
|
242
242
|
name=enriched_relationship.name,
|
|
243
243
|
label=enriched_relationship.label,
|
|
244
|
-
last_changed_at=enriched_relationship.changed_at.
|
|
244
|
+
last_changed_at=enriched_relationship.changed_at.to_datetime()
|
|
245
|
+
if enriched_relationship.changed_at
|
|
246
|
+
else None,
|
|
245
247
|
status=enriched_relationship.action,
|
|
246
248
|
cardinality=enriched_relationship.cardinality,
|
|
247
249
|
path_identifier=enriched_relationship.path_identifier,
|
|
@@ -263,7 +265,7 @@ class DiffTreeResolver:
|
|
|
263
265
|
enriched_conflict=enriched_element.conflict, graphql_context=graphql_context
|
|
264
266
|
)
|
|
265
267
|
return DiffSingleRelationship(
|
|
266
|
-
last_changed_at=enriched_element.changed_at.
|
|
268
|
+
last_changed_at=enriched_element.changed_at.to_datetime(),
|
|
267
269
|
status=enriched_element.action,
|
|
268
270
|
peer_id=enriched_element.peer_id,
|
|
269
271
|
peer_label=enriched_element.peer_label,
|
|
@@ -287,7 +289,7 @@ class DiffTreeResolver:
|
|
|
287
289
|
)
|
|
288
290
|
return DiffProperty(
|
|
289
291
|
property_type=enriched_property.property_type.value,
|
|
290
|
-
last_changed_at=enriched_property.changed_at.
|
|
292
|
+
last_changed_at=enriched_property.changed_at.to_datetime(),
|
|
291
293
|
previous_value=enriched_property.previous_value,
|
|
292
294
|
new_value=enriched_property.new_value,
|
|
293
295
|
previous_label=enriched_property.previous_label,
|
|
@@ -306,13 +308,13 @@ class DiffTreeResolver:
|
|
|
306
308
|
uuid=enriched_conflict.uuid,
|
|
307
309
|
base_branch_action=enriched_conflict.base_branch_action,
|
|
308
310
|
base_branch_value=enriched_conflict.base_branch_value,
|
|
309
|
-
base_branch_changed_at=enriched_conflict.base_branch_changed_at.
|
|
311
|
+
base_branch_changed_at=enriched_conflict.base_branch_changed_at.to_datetime()
|
|
310
312
|
if enriched_conflict.base_branch_changed_at
|
|
311
313
|
else None,
|
|
312
314
|
base_branch_label=enriched_conflict.base_branch_label,
|
|
313
315
|
diff_branch_action=enriched_conflict.diff_branch_action,
|
|
314
316
|
diff_branch_value=enriched_conflict.diff_branch_value,
|
|
315
|
-
diff_branch_changed_at=enriched_conflict.diff_branch_changed_at.
|
|
317
|
+
diff_branch_changed_at=enriched_conflict.diff_branch_changed_at.to_datetime()
|
|
316
318
|
if enriched_conflict.diff_branch_changed_at
|
|
317
319
|
else None,
|
|
318
320
|
diff_branch_label=enriched_conflict.diff_branch_label,
|
|
@@ -322,7 +324,7 @@ class DiffTreeResolver:
|
|
|
322
324
|
|
|
323
325
|
async def to_graphql(
|
|
324
326
|
self, fields: dict[str, dict], diff_object: Any | None
|
|
325
|
-
) ->
|
|
327
|
+
) -> list[dict[str, Any]] | dict[str, Any] | None:
|
|
326
328
|
if diff_object is None:
|
|
327
329
|
return None
|
|
328
330
|
if isinstance(diff_object, list):
|
|
@@ -385,7 +387,7 @@ class DiffTreeResolver:
|
|
|
385
387
|
root_node_uuids: list[str] | None = None,
|
|
386
388
|
limit: int | None = None,
|
|
387
389
|
offset: int | None = None,
|
|
388
|
-
) ->
|
|
390
|
+
) -> list[dict[str, Any]] | dict[str, Any] | None:
|
|
389
391
|
component_registry = get_component_registry()
|
|
390
392
|
graphql_context: GraphqlContext = info.context
|
|
391
393
|
base_branch = await registry.get_branch(db=graphql_context.db, branch=registry.default_branch)
|
|
@@ -426,7 +428,10 @@ class DiffTreeResolver:
|
|
|
426
428
|
# take the one with the longest duration that covers multiple branches
|
|
427
429
|
enriched_diff = sorted(
|
|
428
430
|
enriched_diffs,
|
|
429
|
-
key=lambda d: (
|
|
431
|
+
key=lambda d: (
|
|
432
|
+
d.base_branch_name != d.diff_branch_name,
|
|
433
|
+
d.to_time.to_datetime() - d.from_time.to_datetime(),
|
|
434
|
+
),
|
|
430
435
|
reverse=True,
|
|
431
436
|
)[0]
|
|
432
437
|
else:
|
|
@@ -454,7 +459,7 @@ class DiffTreeResolver:
|
|
|
454
459
|
from_time: datetime | None = None,
|
|
455
460
|
to_time: datetime | None = None,
|
|
456
461
|
filters: dict | None = None,
|
|
457
|
-
) ->
|
|
462
|
+
) -> list[dict[str, Any]] | dict[str, Any] | None:
|
|
458
463
|
component_registry = get_component_registry()
|
|
459
464
|
graphql_context: GraphqlContext = info.context
|
|
460
465
|
base_branch = await registry.get_branch(db=graphql_context.db, branch=registry.default_branch)
|
|
@@ -485,8 +490,8 @@ class DiffTreeResolver:
|
|
|
485
490
|
diff_tree_summary = DiffTreeSummary(
|
|
486
491
|
base_branch=base_branch.name,
|
|
487
492
|
diff_branch=diff_branch.name,
|
|
488
|
-
from_time=summary.from_time.
|
|
489
|
-
to_time=summary.to_time.
|
|
493
|
+
from_time=summary.from_time.to_datetime(),
|
|
494
|
+
to_time=summary.to_time.to_datetime(),
|
|
490
495
|
**summary.model_dump(exclude={"from_time", "to_time"}),
|
|
491
496
|
)
|
|
492
497
|
full_fields = await extract_fields(info.field_nodes[0].selection_set)
|
|
@@ -2,11 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
|
-
from graphene import Boolean, DateTime, Field, Int, List, NonNull, ObjectType, String
|
|
5
|
+
from graphene import Argument, Boolean, DateTime, Field, Int, List, NonNull, ObjectType, String
|
|
6
6
|
from infrahub_sdk.utils import extract_fields_first_node
|
|
7
7
|
|
|
8
8
|
from infrahub.exceptions import ValidationError
|
|
9
|
-
from infrahub.graphql.types.event import EventNodes
|
|
9
|
+
from infrahub.graphql.types.event import EventNodes, EventTypeFilter
|
|
10
10
|
from infrahub.task_manager.event import PrefectEvent
|
|
11
11
|
from infrahub.task_manager.models import InfrahubEventFilter
|
|
12
12
|
|
|
@@ -32,6 +32,7 @@ class Events(ObjectType):
|
|
|
32
32
|
ids: list[str] | None = None,
|
|
33
33
|
branches: list[str] | None = None,
|
|
34
34
|
event_type: list[str] | None = None,
|
|
35
|
+
event_type_filter: dict[str, Any] | None = None,
|
|
35
36
|
related_node__ids: list[str] | None = None,
|
|
36
37
|
primary_node__ids: list[str] | None = None,
|
|
37
38
|
parent__ids: list[str] | None = None,
|
|
@@ -49,6 +50,7 @@ class Events(ObjectType):
|
|
|
49
50
|
account__ids=account__ids,
|
|
50
51
|
has_children=has_children,
|
|
51
52
|
event_type=event_type,
|
|
53
|
+
event_type_filter=event_type_filter,
|
|
52
54
|
related_node__ids=related_node__ids,
|
|
53
55
|
primary_node__ids=primary_node__ids,
|
|
54
56
|
parent__ids=parent__ids,
|
|
@@ -93,6 +95,7 @@ Event = Field(
|
|
|
93
95
|
level=Int(required=False),
|
|
94
96
|
has_children=Boolean(required=False, description="Filter events based on if they can have children or not"),
|
|
95
97
|
event_type=List(NonNull(String), description="Filter events that match a specific type"),
|
|
98
|
+
event_type_filter=Argument(EventTypeFilter, required=False, description="Filters specific to a given event_type"),
|
|
96
99
|
primary_node__ids=List(
|
|
97
100
|
NonNull(String), description="Filter events where the primary node id is within indicated node ids"
|
|
98
101
|
),
|
infrahub/graphql/queries/ipam.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import ipaddress
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from graphene import Field, Int, ObjectType, String
|
|
7
7
|
from netaddr import IPSet
|
|
@@ -27,7 +27,7 @@ class IPAddressGetNextAvailable(ObjectType):
|
|
|
27
27
|
root: dict, # noqa: ARG004
|
|
28
28
|
info: GraphQLResolveInfo,
|
|
29
29
|
prefix_id: str,
|
|
30
|
-
prefix_length:
|
|
30
|
+
prefix_length: int | None = None,
|
|
31
31
|
) -> dict[str, str]:
|
|
32
32
|
graphql_context: GraphqlContext = info.context
|
|
33
33
|
|
|
@@ -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 graphene import Field, Int, List, NonNull, ObjectType, String
|
|
6
6
|
from infrahub_sdk.utils import extract_fields_first_node
|
|
@@ -25,7 +25,7 @@ class Relationships(ObjectType):
|
|
|
25
25
|
ids: list[str],
|
|
26
26
|
limit: int = 10,
|
|
27
27
|
offset: int = 0,
|
|
28
|
-
excluded_namespaces:
|
|
28
|
+
excluded_namespaces: list[str] | None = None,
|
|
29
29
|
) -> dict[str, Any]:
|
|
30
30
|
graphql_context: GraphqlContext = info.context
|
|
31
31
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import ipaddress
|
|
4
|
-
from typing import TYPE_CHECKING, Any
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
5
|
|
|
6
6
|
from graphene import Boolean, Field, Int, List, NonNull, ObjectType, String
|
|
7
7
|
from infrahub_sdk.utils import extract_fields_first_node, is_valid_uuid
|
|
@@ -110,7 +110,7 @@ async def search_resolver(
|
|
|
110
110
|
fields = await extract_fields_first_node(info)
|
|
111
111
|
|
|
112
112
|
if is_valid_uuid(q):
|
|
113
|
-
matching:
|
|
113
|
+
matching: CoreNode | None = await NodeManager.get_one(
|
|
114
114
|
db=graphql_context.db, branch=graphql_context.branch, at=graphql_context.at, id=q
|
|
115
115
|
)
|
|
116
116
|
if matching:
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any
|
|
2
|
+
|
|
3
|
+
from graphql import GraphQLResolveInfo
|
|
4
|
+
from infrahub_sdk.utils import deep_merge_dict, extract_fields
|
|
5
|
+
|
|
6
|
+
from infrahub.core.branch.models import Branch
|
|
7
|
+
from infrahub.core.constants import BranchSupportType, RelationshipHierarchyDirection
|
|
8
|
+
from infrahub.core.manager import NodeManager
|
|
9
|
+
from infrahub.core.query.node import NodeGetHierarchyQuery
|
|
10
|
+
from infrahub.core.schema.node_schema import NodeSchema
|
|
11
|
+
from infrahub.core.schema.relationship_schema import RelationshipSchema
|
|
12
|
+
from infrahub.core.timestamp import Timestamp
|
|
13
|
+
from infrahub.database import InfrahubDatabase
|
|
14
|
+
|
|
15
|
+
from ..loaders.peers import PeerRelationshipsDataLoader, QueryPeerParams
|
|
16
|
+
from ..types import RELATIONS_PROPERTY_MAP, RELATIONS_PROPERTY_MAP_REVERSED
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from infrahub.core.schema import MainSchemaTypes
|
|
20
|
+
|
|
21
|
+
from ..initialization import GraphqlContext
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ManyRelationshipResolver:
|
|
25
|
+
def __init__(self) -> None:
|
|
26
|
+
self._data_loader_instances: dict[QueryPeerParams, PeerRelationshipsDataLoader] = {}
|
|
27
|
+
|
|
28
|
+
async def get_descendant_ids(
|
|
29
|
+
self,
|
|
30
|
+
db: InfrahubDatabase,
|
|
31
|
+
branch: Branch,
|
|
32
|
+
at: Timestamp | None,
|
|
33
|
+
parent_id: str,
|
|
34
|
+
node_schema: NodeSchema,
|
|
35
|
+
) -> list[str]:
|
|
36
|
+
async with db.start_session() as dbs:
|
|
37
|
+
query = await NodeGetHierarchyQuery.init(
|
|
38
|
+
db=dbs,
|
|
39
|
+
direction=RelationshipHierarchyDirection.DESCENDANTS,
|
|
40
|
+
node_id=parent_id,
|
|
41
|
+
node_schema=node_schema,
|
|
42
|
+
at=at,
|
|
43
|
+
branch=branch,
|
|
44
|
+
)
|
|
45
|
+
await query.execute(db=dbs)
|
|
46
|
+
return list(query.get_peer_ids())
|
|
47
|
+
|
|
48
|
+
async def get_peer_count(
|
|
49
|
+
self,
|
|
50
|
+
db: InfrahubDatabase,
|
|
51
|
+
branch: Branch,
|
|
52
|
+
at: Timestamp | None,
|
|
53
|
+
ids: list[str],
|
|
54
|
+
source_kind: str,
|
|
55
|
+
rel_schema: RelationshipSchema,
|
|
56
|
+
filters: dict[str, Any],
|
|
57
|
+
) -> int:
|
|
58
|
+
async with db.start_session() as dbs:
|
|
59
|
+
return await NodeManager.count_peers(
|
|
60
|
+
db=dbs,
|
|
61
|
+
ids=ids,
|
|
62
|
+
source_kind=source_kind,
|
|
63
|
+
schema=rel_schema,
|
|
64
|
+
filters=filters,
|
|
65
|
+
at=at,
|
|
66
|
+
branch=branch,
|
|
67
|
+
branch_agnostic=rel_schema.branch is BranchSupportType.AGNOSTIC,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
async def resolve(
|
|
71
|
+
self,
|
|
72
|
+
parent: dict,
|
|
73
|
+
info: GraphQLResolveInfo,
|
|
74
|
+
include_descendants: bool = False,
|
|
75
|
+
offset: int | None = None,
|
|
76
|
+
limit: int | None = None,
|
|
77
|
+
**kwargs: Any,
|
|
78
|
+
) -> dict[str, Any]:
|
|
79
|
+
"""Resolver for relationships of cardinality=one for Edged responses
|
|
80
|
+
|
|
81
|
+
This resolver is used for paginated responses and as such we redefined the requested
|
|
82
|
+
fields by only reusing information below the 'node' key.
|
|
83
|
+
"""
|
|
84
|
+
# Extract the InfraHub schema by inspecting the GQL Schema
|
|
85
|
+
|
|
86
|
+
node_schema: MainSchemaTypes = info.parent_type.graphene_type._meta.schema # type: ignore[attr-defined]
|
|
87
|
+
|
|
88
|
+
graphql_context: GraphqlContext = info.context
|
|
89
|
+
|
|
90
|
+
# Extract the name of the fields in the GQL query
|
|
91
|
+
fields = await extract_fields(info.field_nodes[0].selection_set)
|
|
92
|
+
edges = fields.get("edges", {})
|
|
93
|
+
node_fields = edges.get("node", {})
|
|
94
|
+
property_fields = edges.get("properties", {})
|
|
95
|
+
for key, value in property_fields.items():
|
|
96
|
+
mapped_name = RELATIONS_PROPERTY_MAP[key]
|
|
97
|
+
node_fields[mapped_name] = value
|
|
98
|
+
|
|
99
|
+
filters = {
|
|
100
|
+
f"{info.field_name}__{key}": value
|
|
101
|
+
for key, value in kwargs.items()
|
|
102
|
+
if "__" in key and value or key in ["id", "ids"]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
response: dict[str, Any] = {"edges": [], "count": None}
|
|
106
|
+
|
|
107
|
+
# Extract the schema of the node on the other end of the relationship from the GQL Schema
|
|
108
|
+
node_rel = node_schema.get_relationship(info.field_name)
|
|
109
|
+
source_kind = node_schema.kind
|
|
110
|
+
ids = [parent["id"]]
|
|
111
|
+
if isinstance(node_schema, NodeSchema):
|
|
112
|
+
if node_schema.hierarchy:
|
|
113
|
+
source_kind = node_schema.hierarchy
|
|
114
|
+
|
|
115
|
+
if include_descendants:
|
|
116
|
+
descendant_ids = await self.get_descendant_ids(
|
|
117
|
+
db=graphql_context.db,
|
|
118
|
+
branch=graphql_context.branch,
|
|
119
|
+
at=graphql_context.at,
|
|
120
|
+
parent_id=ids[0],
|
|
121
|
+
node_schema=node_schema,
|
|
122
|
+
)
|
|
123
|
+
ids.extend(descendant_ids)
|
|
124
|
+
|
|
125
|
+
if "count" in fields:
|
|
126
|
+
peer_count = await self.get_peer_count(
|
|
127
|
+
db=graphql_context.db,
|
|
128
|
+
branch=graphql_context.branch,
|
|
129
|
+
at=graphql_context.at,
|
|
130
|
+
ids=ids,
|
|
131
|
+
source_kind=source_kind,
|
|
132
|
+
rel_schema=node_rel,
|
|
133
|
+
filters=filters,
|
|
134
|
+
)
|
|
135
|
+
response["count"] = peer_count
|
|
136
|
+
|
|
137
|
+
if not node_fields:
|
|
138
|
+
return response
|
|
139
|
+
|
|
140
|
+
if offset or limit:
|
|
141
|
+
node_graph = await self._get_entities_simple(
|
|
142
|
+
db=graphql_context.db,
|
|
143
|
+
branch=graphql_context.branch,
|
|
144
|
+
ids=ids,
|
|
145
|
+
at=graphql_context.at,
|
|
146
|
+
related_node_ids=graphql_context.related_node_ids,
|
|
147
|
+
source_kind=source_kind,
|
|
148
|
+
rel_schema=node_rel,
|
|
149
|
+
filters=filters,
|
|
150
|
+
node_fields=node_fields,
|
|
151
|
+
offset=offset,
|
|
152
|
+
limit=limit,
|
|
153
|
+
)
|
|
154
|
+
else:
|
|
155
|
+
node_graph = await self._get_entities_with_data_loader(
|
|
156
|
+
db=graphql_context.db,
|
|
157
|
+
branch=graphql_context.branch,
|
|
158
|
+
ids=ids,
|
|
159
|
+
at=graphql_context.at,
|
|
160
|
+
related_node_ids=graphql_context.related_node_ids,
|
|
161
|
+
source_kind=source_kind,
|
|
162
|
+
rel_schema=node_rel,
|
|
163
|
+
filters=filters,
|
|
164
|
+
node_fields=node_fields,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if not node_graph:
|
|
168
|
+
return response
|
|
169
|
+
|
|
170
|
+
entries = []
|
|
171
|
+
for node in node_graph:
|
|
172
|
+
entry: dict[str, dict[str, Any]] = {"node": {}, "properties": {}}
|
|
173
|
+
for key, mapped in RELATIONS_PROPERTY_MAP_REVERSED.items():
|
|
174
|
+
value = node.pop(key, None)
|
|
175
|
+
if value:
|
|
176
|
+
entry["properties"][mapped] = value
|
|
177
|
+
entry["node"] = node
|
|
178
|
+
entries.append(entry)
|
|
179
|
+
|
|
180
|
+
response["edges"] = entries
|
|
181
|
+
return response
|
|
182
|
+
|
|
183
|
+
async def _get_entities_simple(
|
|
184
|
+
self,
|
|
185
|
+
db: InfrahubDatabase,
|
|
186
|
+
branch: Branch,
|
|
187
|
+
ids: list[str],
|
|
188
|
+
at: Timestamp | None,
|
|
189
|
+
related_node_ids: set[str] | None,
|
|
190
|
+
source_kind: str,
|
|
191
|
+
rel_schema: RelationshipSchema,
|
|
192
|
+
filters: dict[str, Any],
|
|
193
|
+
node_fields: dict[str, Any],
|
|
194
|
+
offset: int | None = None,
|
|
195
|
+
limit: int | None = None,
|
|
196
|
+
) -> list[dict[str, Any]] | None:
|
|
197
|
+
async with db.start_session() as dbs:
|
|
198
|
+
objs = await NodeManager.query_peers(
|
|
199
|
+
db=dbs,
|
|
200
|
+
ids=ids,
|
|
201
|
+
source_kind=source_kind,
|
|
202
|
+
schema=rel_schema,
|
|
203
|
+
filters=filters,
|
|
204
|
+
fields=node_fields,
|
|
205
|
+
offset=offset,
|
|
206
|
+
limit=limit,
|
|
207
|
+
at=at,
|
|
208
|
+
branch=branch,
|
|
209
|
+
branch_agnostic=rel_schema.branch is BranchSupportType.AGNOSTIC,
|
|
210
|
+
fetch_peers=True,
|
|
211
|
+
)
|
|
212
|
+
if not objs:
|
|
213
|
+
return None
|
|
214
|
+
return [await obj.to_graphql(db=dbs, fields=node_fields, related_node_ids=related_node_ids) for obj in objs]
|
|
215
|
+
|
|
216
|
+
async def _get_entities_with_data_loader(
|
|
217
|
+
self,
|
|
218
|
+
db: InfrahubDatabase,
|
|
219
|
+
branch: Branch,
|
|
220
|
+
ids: list[str],
|
|
221
|
+
at: Timestamp | None,
|
|
222
|
+
related_node_ids: set[str] | None,
|
|
223
|
+
source_kind: str,
|
|
224
|
+
rel_schema: RelationshipSchema,
|
|
225
|
+
filters: dict[str, Any],
|
|
226
|
+
node_fields: dict[str, Any],
|
|
227
|
+
) -> list[dict[str, Any]] | None:
|
|
228
|
+
if node_fields and "display_label" in node_fields:
|
|
229
|
+
schema_branch = db.schema.get_schema_branch(name=branch.name)
|
|
230
|
+
display_label_fields = schema_branch.generate_fields_for_display_label(name=rel_schema.peer)
|
|
231
|
+
if display_label_fields:
|
|
232
|
+
node_fields = deep_merge_dict(dicta=node_fields, dictb=display_label_fields)
|
|
233
|
+
|
|
234
|
+
if node_fields and "hfid" in node_fields:
|
|
235
|
+
peer_schema = db.schema.get(name=rel_schema.peer, branch=branch, duplicate=False)
|
|
236
|
+
hfid_fields = peer_schema.generate_fields_for_hfid()
|
|
237
|
+
if hfid_fields:
|
|
238
|
+
node_fields = deep_merge_dict(dicta=node_fields, dictb=hfid_fields)
|
|
239
|
+
|
|
240
|
+
query_params = QueryPeerParams(
|
|
241
|
+
branch=branch,
|
|
242
|
+
source_kind=source_kind,
|
|
243
|
+
schema=rel_schema,
|
|
244
|
+
filters=filters,
|
|
245
|
+
fields=node_fields,
|
|
246
|
+
at=at,
|
|
247
|
+
branch_agnostic=rel_schema.branch is BranchSupportType.AGNOSTIC,
|
|
248
|
+
)
|
|
249
|
+
if query_params in self._data_loader_instances:
|
|
250
|
+
loader = self._data_loader_instances[query_params]
|
|
251
|
+
else:
|
|
252
|
+
loader = PeerRelationshipsDataLoader(db=db, query_params=query_params)
|
|
253
|
+
self._data_loader_instances[query_params] = loader
|
|
254
|
+
all_peer_rels = []
|
|
255
|
+
for node_id in ids:
|
|
256
|
+
node_peer_rels = await loader.load(key=node_id)
|
|
257
|
+
all_peer_rels.extend(node_peer_rels)
|
|
258
|
+
if not all_peer_rels:
|
|
259
|
+
return None
|
|
260
|
+
async with db.start_session() as dbs:
|
|
261
|
+
return [
|
|
262
|
+
await obj.to_graphql(db=dbs, fields=node_fields, related_node_ids=related_node_ids)
|
|
263
|
+
for obj in all_peer_rels
|
|
264
|
+
]
|