infrahub-server 1.6.3__py3-none-any.whl → 1.7.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/tasks.py +4 -2
- infrahub/api/exceptions.py +2 -2
- infrahub/api/schema.py +3 -1
- infrahub/artifacts/tasks.py +1 -0
- infrahub/auth.py +2 -2
- infrahub/cli/db.py +54 -28
- infrahub/computed_attribute/gather.py +3 -4
- infrahub/computed_attribute/tasks.py +23 -6
- infrahub/config.py +8 -0
- infrahub/constants/enums.py +12 -0
- infrahub/core/account.py +4 -4
- infrahub/core/attribute.py +106 -108
- infrahub/core/branch/models.py +44 -71
- infrahub/core/branch/tasks.py +5 -3
- infrahub/core/changelog/diff.py +1 -20
- infrahub/core/changelog/models.py +0 -7
- infrahub/core/constants/__init__.py +17 -0
- infrahub/core/constants/database.py +0 -1
- infrahub/core/constants/schema.py +0 -1
- infrahub/core/convert_object_type/repository_conversion.py +3 -4
- infrahub/core/diff/branch_differ.py +1 -1
- infrahub/core/diff/conflict_transferer.py +1 -1
- infrahub/core/diff/data_check_synchronizer.py +4 -3
- infrahub/core/diff/enricher/cardinality_one.py +2 -2
- infrahub/core/diff/enricher/hierarchy.py +1 -1
- infrahub/core/diff/enricher/labels.py +1 -1
- infrahub/core/diff/merger/merger.py +28 -2
- infrahub/core/diff/merger/serializer.py +3 -10
- infrahub/core/diff/model/diff.py +1 -1
- infrahub/core/diff/query/merge.py +376 -135
- infrahub/core/diff/repository/repository.py +3 -1
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/graph/constraints.py +3 -3
- infrahub/core/graph/schema.py +2 -12
- infrahub/core/ipam/reconciler.py +8 -6
- infrahub/core/ipam/utilization.py +8 -15
- infrahub/core/manager.py +133 -152
- infrahub/core/merge.py +1 -1
- infrahub/core/metadata/__init__.py +0 -0
- infrahub/core/metadata/interface.py +37 -0
- infrahub/core/metadata/model.py +31 -0
- infrahub/core/metadata/query/__init__.py +0 -0
- infrahub/core/metadata/query/node_metadata.py +301 -0
- infrahub/core/migrations/graph/__init__.py +4 -0
- infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -12
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -12
- infrahub/core/migrations/graph/m017_add_core_profile.py +5 -2
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -1
- infrahub/core/migrations/graph/m019_restore_rels_to_time.py +0 -10
- infrahub/core/migrations/graph/m020_duplicate_edges.py +0 -8
- infrahub/core/migrations/graph/m025_uniqueness_nulls.py +2 -1
- infrahub/core/migrations/graph/m026_0000_prefix_fix.py +2 -1
- infrahub/core/migrations/graph/m029_duplicates_cleanup.py +0 -1
- infrahub/core/migrations/graph/m031_check_number_attributes.py +2 -2
- infrahub/core/migrations/graph/m038_redo_0000_prefix_fix.py +2 -1
- infrahub/core/migrations/graph/m041_deleted_dup_edges.py +1 -1
- infrahub/core/migrations/graph/m049_remove_is_visible_relationship.py +53 -0
- infrahub/core/migrations/graph/m050_backfill_vertex_metadata.py +168 -0
- infrahub/core/migrations/query/__init__.py +2 -2
- infrahub/core/migrations/query/attribute_add.py +17 -6
- infrahub/core/migrations/query/attribute_remove.py +19 -5
- infrahub/core/migrations/query/attribute_rename.py +21 -5
- infrahub/core/migrations/query/node_duplicate.py +19 -4
- infrahub/core/migrations/query/schema_attribute_update.py +1 -1
- infrahub/core/migrations/schema/attribute_kind_update.py +21 -2
- infrahub/core/migrations/schema/attribute_name_update.py +1 -1
- infrahub/core/migrations/schema/attribute_supports_profile.py +5 -3
- infrahub/core/migrations/schema/models.py +3 -0
- infrahub/core/migrations/schema/node_attribute_add.py +5 -2
- infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
- infrahub/core/migrations/schema/node_kind_update.py +1 -1
- infrahub/core/migrations/schema/node_remove.py +24 -2
- infrahub/core/migrations/schema/tasks.py +4 -1
- infrahub/core/migrations/shared.py +13 -6
- infrahub/core/models.py +6 -6
- infrahub/core/node/__init__.py +157 -58
- infrahub/core/node/base.py +9 -5
- infrahub/core/node/create.py +7 -3
- infrahub/core/node/delete_validator.py +1 -1
- infrahub/core/node/standard.py +100 -14
- infrahub/core/order.py +30 -0
- infrahub/core/property.py +0 -1
- infrahub/core/protocols.py +1 -0
- infrahub/core/protocols_base.py +10 -2
- infrahub/core/query/__init__.py +5 -3
- infrahub/core/query/attribute.py +164 -49
- infrahub/core/query/branch.py +58 -70
- infrahub/core/query/delete.py +1 -1
- infrahub/core/query/diff.py +7 -7
- infrahub/core/query/ipam.py +104 -43
- infrahub/core/query/node.py +1072 -281
- infrahub/core/query/relationship.py +531 -325
- infrahub/core/query/resource_manager.py +107 -18
- infrahub/core/query/standard_node.py +25 -5
- infrahub/core/query/utils.py +2 -4
- infrahub/core/relationship/constraints/count.py +1 -1
- infrahub/core/relationship/constraints/peer_kind.py +1 -1
- infrahub/core/relationship/constraints/peer_parent.py +1 -1
- infrahub/core/relationship/constraints/peer_relatives.py +1 -1
- infrahub/core/relationship/constraints/profiles_kind.py +1 -1
- infrahub/core/relationship/constraints/profiles_removal.py +168 -0
- infrahub/core/relationship/model.py +293 -139
- infrahub/core/schema/attribute_schema.py +2 -2
- infrahub/core/schema/basenode_schema.py +3 -0
- infrahub/core/schema/definitions/core/__init__.py +8 -2
- infrahub/core/schema/definitions/core/account.py +10 -10
- infrahub/core/schema/definitions/core/artifact.py +14 -8
- infrahub/core/schema/definitions/core/check.py +10 -4
- infrahub/core/schema/definitions/core/generator.py +26 -6
- infrahub/core/schema/definitions/core/graphql_query.py +1 -1
- infrahub/core/schema/definitions/core/group.py +9 -2
- infrahub/core/schema/definitions/core/ipam.py +80 -10
- infrahub/core/schema/definitions/core/menu.py +41 -7
- infrahub/core/schema/definitions/core/permission.py +16 -2
- infrahub/core/schema/definitions/core/profile.py +16 -2
- infrahub/core/schema/definitions/core/propose_change.py +24 -4
- infrahub/core/schema/definitions/core/propose_change_comment.py +23 -11
- infrahub/core/schema/definitions/core/propose_change_validator.py +50 -21
- infrahub/core/schema/definitions/core/repository.py +10 -0
- infrahub/core/schema/definitions/core/resource_pool.py +8 -1
- infrahub/core/schema/definitions/core/template.py +19 -2
- infrahub/core/schema/definitions/core/transform.py +11 -5
- infrahub/core/schema/definitions/core/webhook.py +27 -9
- infrahub/core/schema/manager.py +63 -43
- infrahub/core/schema/relationship_schema.py +6 -2
- infrahub/core/schema/schema_branch.py +48 -10
- infrahub/core/task/task.py +4 -2
- infrahub/core/utils.py +3 -25
- infrahub/core/validators/aggregated_checker.py +1 -1
- infrahub/core/validators/attribute/choices.py +1 -1
- infrahub/core/validators/attribute/enum.py +1 -1
- infrahub/core/validators/attribute/kind.py +1 -1
- infrahub/core/validators/attribute/length.py +1 -1
- infrahub/core/validators/attribute/min_max.py +1 -1
- infrahub/core/validators/attribute/number_pool.py +1 -1
- infrahub/core/validators/attribute/optional.py +1 -1
- infrahub/core/validators/attribute/regex.py +1 -1
- infrahub/core/validators/determiner.py +3 -3
- infrahub/core/validators/node/attribute.py +1 -1
- infrahub/core/validators/node/relationship.py +1 -1
- infrahub/core/validators/relationship/peer.py +1 -1
- infrahub/database/__init__.py +4 -4
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +2 -0
- infrahub/dependencies/builder/constraint/relationship_manager/profiles_removal.py +8 -0
- infrahub/dependencies/registry.py +2 -0
- infrahub/display_labels/tasks.py +12 -3
- infrahub/git/integrator.py +18 -18
- infrahub/git/tasks.py +1 -1
- infrahub/git/utils.py +1 -1
- infrahub/graphql/constants.py +3 -0
- infrahub/graphql/context.py +1 -1
- infrahub/graphql/field_extractor.py +1 -1
- infrahub/graphql/initialization.py +11 -0
- infrahub/graphql/loaders/account.py +134 -0
- infrahub/graphql/loaders/node.py +5 -12
- infrahub/graphql/loaders/peers.py +5 -7
- infrahub/graphql/manager.py +175 -21
- infrahub/graphql/metadata.py +91 -0
- infrahub/graphql/mutations/account.py +6 -6
- infrahub/graphql/mutations/attribute.py +0 -2
- infrahub/graphql/mutations/branch.py +9 -5
- infrahub/graphql/mutations/computed_attribute.py +1 -1
- infrahub/graphql/mutations/display_label.py +1 -1
- infrahub/graphql/mutations/hfid.py +1 -1
- infrahub/graphql/mutations/ipam.py +4 -6
- infrahub/graphql/mutations/main.py +9 -4
- infrahub/graphql/mutations/profile.py +16 -22
- infrahub/graphql/mutations/proposed_change.py +4 -4
- infrahub/graphql/mutations/relationship.py +40 -10
- infrahub/graphql/mutations/repository.py +14 -12
- infrahub/graphql/mutations/schema.py +2 -2
- infrahub/graphql/order.py +14 -0
- infrahub/graphql/queries/branch.py +62 -6
- infrahub/graphql/queries/resource_manager.py +25 -24
- infrahub/graphql/resolvers/account_metadata.py +84 -0
- infrahub/graphql/resolvers/ipam.py +6 -8
- infrahub/graphql/resolvers/many_relationship.py +77 -35
- infrahub/graphql/resolvers/resolver.py +59 -14
- infrahub/graphql/resolvers/single_relationship.py +87 -23
- infrahub/graphql/subscription/graphql_query.py +2 -0
- infrahub/graphql/types/__init__.py +0 -1
- infrahub/graphql/types/attribute.py +10 -5
- infrahub/graphql/types/branch.py +40 -53
- infrahub/graphql/types/enums.py +3 -0
- infrahub/graphql/types/metadata.py +28 -0
- infrahub/graphql/types/node.py +22 -2
- infrahub/graphql/types/relationship.py +10 -2
- infrahub/graphql/types/standard_node.py +12 -7
- infrahub/hfid/tasks.py +12 -3
- infrahub/lock.py +7 -0
- infrahub/menu/repository.py +1 -1
- infrahub/patch/queries/base.py +1 -1
- infrahub/pools/number.py +1 -8
- infrahub/profiles/gather.py +56 -0
- infrahub/profiles/mandatory_fields_checker.py +116 -0
- infrahub/profiles/models.py +66 -0
- infrahub/profiles/node_applier.py +154 -13
- infrahub/profiles/queries/get_profile_data.py +143 -31
- infrahub/profiles/tasks.py +79 -27
- infrahub/profiles/triggers.py +22 -0
- infrahub/proposed_change/action_checker.py +1 -1
- infrahub/proposed_change/tasks.py +4 -1
- infrahub/services/__init__.py +1 -1
- infrahub/services/adapters/cache/nats.py +1 -1
- infrahub/services/adapters/cache/redis.py +7 -0
- infrahub/tasks/artifact.py +1 -0
- infrahub/transformations/tasks.py +2 -2
- infrahub/trigger/catalogue.py +2 -0
- infrahub/trigger/models.py +1 -0
- infrahub/trigger/setup.py +3 -3
- infrahub/trigger/tasks.py +3 -0
- infrahub/validators/tasks.py +1 -0
- infrahub/webhook/gather.py +1 -1
- infrahub/webhook/models.py +1 -1
- infrahub/webhook/tasks.py +23 -7
- infrahub/workers/dependencies.py +9 -3
- infrahub/workers/infrahub_async.py +13 -4
- infrahub/workflows/catalogue.py +19 -0
- infrahub_sdk/analyzer.py +2 -2
- infrahub_sdk/branch.py +12 -39
- infrahub_sdk/checks.py +4 -4
- infrahub_sdk/client.py +36 -0
- infrahub_sdk/ctl/cli_commands.py +2 -1
- infrahub_sdk/ctl/graphql.py +15 -4
- infrahub_sdk/ctl/utils.py +2 -2
- infrahub_sdk/enums.py +6 -0
- infrahub_sdk/graphql/renderers.py +21 -0
- infrahub_sdk/graphql/utils.py +85 -0
- infrahub_sdk/node/attribute.py +12 -2
- infrahub_sdk/node/constants.py +12 -0
- infrahub_sdk/node/metadata.py +69 -0
- infrahub_sdk/node/node.py +65 -14
- infrahub_sdk/node/property.py +3 -0
- infrahub_sdk/node/related_node.py +37 -5
- infrahub_sdk/node/relationship.py +18 -1
- infrahub_sdk/operation.py +2 -2
- infrahub_sdk/schema/repository.py +1 -2
- infrahub_sdk/transforms.py +2 -2
- infrahub_sdk/types.py +18 -2
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/METADATA +17 -16
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/RECORD +249 -228
- infrahub_testcontainers/container.py +3 -3
- infrahub_testcontainers/docker-compose-cluster.test.yml +7 -7
- infrahub_testcontainers/docker-compose.test.yml +13 -5
- infrahub_testcontainers/models.py +3 -3
- infrahub_testcontainers/performance_test.py +1 -1
- infrahub/graphql/models.py +0 -6
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/entry_points.txt +0 -0
- {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING, Sequence
|
|
4
4
|
|
|
5
|
+
from infrahub.core.constants import SYSTEM_USER_ID
|
|
5
6
|
from infrahub.core.migrations.shared import MigrationResult
|
|
6
7
|
from infrahub.log import get_logger
|
|
7
8
|
|
|
@@ -22,5 +23,5 @@ class Migration025(InternalSchemaMigration):
|
|
|
22
23
|
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
23
24
|
return MigrationResult()
|
|
24
25
|
|
|
25
|
-
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
26
|
+
async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult: # noqa: ARG002
|
|
26
27
|
return await validate_nulls_in_uniqueness_constraints(db=db)
|
|
@@ -4,6 +4,7 @@ import ipaddress
|
|
|
4
4
|
from typing import TYPE_CHECKING, Sequence
|
|
5
5
|
|
|
6
6
|
from infrahub.core.branch.models import Branch
|
|
7
|
+
from infrahub.core.constants import SYSTEM_USER_ID
|
|
7
8
|
from infrahub.core.initialization import initialization
|
|
8
9
|
from infrahub.core.ipam.reconciler import IpamReconciler
|
|
9
10
|
from infrahub.core.manager import NodeManager
|
|
@@ -28,7 +29,7 @@ class Migration026(InternalSchemaMigration):
|
|
|
28
29
|
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
29
30
|
return MigrationResult()
|
|
30
31
|
|
|
31
|
-
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
32
|
+
async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult: # noqa: ARG002
|
|
32
33
|
# load schemas from database into registry
|
|
33
34
|
initialize_lock()
|
|
34
35
|
await initialization(db=db)
|
|
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Sequence
|
|
|
5
5
|
from infrahub import config
|
|
6
6
|
from infrahub.core import registry
|
|
7
7
|
from infrahub.core.branch import Branch
|
|
8
|
-
from infrahub.core.constants import SchemaPathType
|
|
8
|
+
from infrahub.core.constants import SYSTEM_USER_ID, SchemaPathType
|
|
9
9
|
from infrahub.core.initialization import initialization
|
|
10
10
|
from infrahub.core.migrations.shared import InternalSchemaMigration, MigrationResult, SchemaMigration
|
|
11
11
|
from infrahub.core.path import SchemaPath
|
|
@@ -35,7 +35,7 @@ class Migration031(InternalSchemaMigration):
|
|
|
35
35
|
minimum_version: int = 30
|
|
36
36
|
migrations: Sequence[SchemaMigration] = []
|
|
37
37
|
|
|
38
|
-
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
38
|
+
async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult: # noqa: ARG002
|
|
39
39
|
"""Retrieve all number attributes that have a min/max/excluded_values
|
|
40
40
|
For any of these attributes, check if corresponding existing nodes are valid."""
|
|
41
41
|
|
|
@@ -4,6 +4,7 @@ import ipaddress
|
|
|
4
4
|
from typing import TYPE_CHECKING, Sequence
|
|
5
5
|
|
|
6
6
|
from infrahub.core.branch.models import Branch
|
|
7
|
+
from infrahub.core.constants import SYSTEM_USER_ID
|
|
7
8
|
from infrahub.core.initialization import initialization
|
|
8
9
|
from infrahub.core.ipam.reconciler import IpamReconciler
|
|
9
10
|
from infrahub.core.manager import NodeManager
|
|
@@ -37,7 +38,7 @@ class Migration038(InternalSchemaMigration):
|
|
|
37
38
|
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
38
39
|
return MigrationResult()
|
|
39
40
|
|
|
40
|
-
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
41
|
+
async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult: # noqa: ARG002
|
|
41
42
|
# load schemas from database into registry
|
|
42
43
|
initialize_lock()
|
|
43
44
|
await initialization(db=db)
|
|
@@ -73,7 +73,7 @@ class DeleteDuplicatedRelationshipEdges(Query):
|
|
|
73
73
|
type = QueryType.WRITE
|
|
74
74
|
insert_return = False
|
|
75
75
|
|
|
76
|
-
def __init__(self, migrated_kind_nodes_only: bool = True, **kwargs: Any):
|
|
76
|
+
def __init__(self, migrated_kind_nodes_only: bool = True, **kwargs: Any) -> None:
|
|
77
77
|
self.migrated_kind_nodes_only = migrated_kind_nodes_only
|
|
78
78
|
super().__init__(**kwargs)
|
|
79
79
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Sequence
|
|
4
|
+
|
|
5
|
+
from infrahub.core.migrations.shared import MigrationResult
|
|
6
|
+
from infrahub.core.query import Query, QueryType
|
|
7
|
+
|
|
8
|
+
from ..shared import GraphMigration
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from infrahub.database import InfrahubDatabase
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RemoveIsVisibleRelationshipQuery(Query):
|
|
15
|
+
name = "remove_is_visible_relationship"
|
|
16
|
+
type: QueryType = QueryType.WRITE
|
|
17
|
+
insert_return = False
|
|
18
|
+
|
|
19
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
20
|
+
query = """
|
|
21
|
+
MATCH ()-[rel:IS_VISIBLE]->()
|
|
22
|
+
CALL (rel) {
|
|
23
|
+
DELETE rel
|
|
24
|
+
} IN TRANSACTIONS
|
|
25
|
+
"""
|
|
26
|
+
self.add_to_query(query)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class RemoveIsVisibleFromDiffsQuery(Query):
|
|
30
|
+
name = "remove_is_visible_from_diffs"
|
|
31
|
+
type = QueryType.WRITE
|
|
32
|
+
insert_return = False
|
|
33
|
+
|
|
34
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
|
|
35
|
+
query = """
|
|
36
|
+
MATCH (diff_prop:DiffProperty {property_type: "IS_VISIBLE"})
|
|
37
|
+
CALL (diff_prop) {
|
|
38
|
+
DETACH DELETE diff_prop
|
|
39
|
+
} IN TRANSACTIONS
|
|
40
|
+
"""
|
|
41
|
+
self.add_to_query(query)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Migration049(GraphMigration):
|
|
45
|
+
name: str = "049_remove_is_visible_relationship"
|
|
46
|
+
minimum_version: int = 48
|
|
47
|
+
queries: Sequence[type[Query]] = [RemoveIsVisibleRelationshipQuery, RemoveIsVisibleFromDiffsQuery]
|
|
48
|
+
|
|
49
|
+
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
50
|
+
return MigrationResult()
|
|
51
|
+
|
|
52
|
+
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
53
|
+
return await self.do_execute(db=db)
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Sequence
|
|
4
|
+
|
|
5
|
+
from infrahub.core.migrations.shared import MigrationResult
|
|
6
|
+
from infrahub.core.query import Query, QueryType
|
|
7
|
+
|
|
8
|
+
from ..shared import GraphMigration
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from infrahub.database import InfrahubDatabase
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BackfillAttributeMetadataQuery(Query):
|
|
15
|
+
"""Backfill created_at and updated_at for Attribute vertices on default/global branches.
|
|
16
|
+
|
|
17
|
+
- created_at = from time of HAS_ATTRIBUTE edge
|
|
18
|
+
- updated_at = latest from or to time of any non-HAS_ATTRIBUTE edge
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
name = "backfill_attribute_metadata"
|
|
22
|
+
type: QueryType = QueryType.WRITE
|
|
23
|
+
insert_return = False
|
|
24
|
+
|
|
25
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
26
|
+
query = """
|
|
27
|
+
// Find all Attribute vertices on default/global branch without created_at
|
|
28
|
+
MATCH (:Node)-[ha:HAS_ATTRIBUTE {status: "active"}]->(attr:Attribute)
|
|
29
|
+
WHERE ha.branch_level = 1
|
|
30
|
+
AND attr.created_at IS NULL
|
|
31
|
+
|
|
32
|
+
// created_at = from time of HAS_ATTRIBUTE edge
|
|
33
|
+
WITH DISTINCT attr, ha.from AS created_at
|
|
34
|
+
|
|
35
|
+
// Find latest change time from all non-HAS_ATTRIBUTE edges (both from and to)
|
|
36
|
+
CALL (attr) {
|
|
37
|
+
MATCH (attr)-[e]->()
|
|
38
|
+
WHERE e.branch_level = 1
|
|
39
|
+
WITH e.from AS change_time
|
|
40
|
+
WHERE change_time IS NOT NULL
|
|
41
|
+
RETURN change_time
|
|
42
|
+
UNION ALL
|
|
43
|
+
MATCH (attr)-[e]->()
|
|
44
|
+
WHERE e.branch_level = 1
|
|
45
|
+
AND e.to IS NOT NULL
|
|
46
|
+
RETURN e.to AS change_time
|
|
47
|
+
}
|
|
48
|
+
WITH attr, created_at, max(change_time) AS updated_at
|
|
49
|
+
|
|
50
|
+
// Set metadata (use coalesce to fall back to created_at if no changes found)
|
|
51
|
+
CALL (attr, created_at, updated_at) {
|
|
52
|
+
SET attr.created_at = created_at
|
|
53
|
+
SET attr.updated_at = coalesce(updated_at, created_at)
|
|
54
|
+
} IN TRANSACTIONS
|
|
55
|
+
"""
|
|
56
|
+
self.add_to_query(query)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class BackfillRelationshipMetadataQuery(Query):
|
|
60
|
+
"""Backfill created_at and updated_at for Relationship vertices on default/global branches.
|
|
61
|
+
|
|
62
|
+
- created_at = earliest from time of any IS_RELATED edge
|
|
63
|
+
- updated_at = latest from or to time of any non-IS_RELATED edge
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
name = "backfill_relationship_metadata"
|
|
67
|
+
type: QueryType = QueryType.WRITE
|
|
68
|
+
insert_return = False
|
|
69
|
+
|
|
70
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
71
|
+
query = """
|
|
72
|
+
// Find all Relationship vertices on default/global branch without created_at
|
|
73
|
+
MATCH (:Node)-[ir:IS_RELATED]-(rel:Relationship)
|
|
74
|
+
WHERE ir.branch_level = 1
|
|
75
|
+
AND rel.created_at IS NULL
|
|
76
|
+
WITH DISTINCT rel
|
|
77
|
+
|
|
78
|
+
// created_at = earliest IS_RELATED edge from time
|
|
79
|
+
CALL (rel) {
|
|
80
|
+
MATCH ()-[ir:IS_RELATED]-(rel)
|
|
81
|
+
WHERE ir.branch_level = 1
|
|
82
|
+
RETURN min(ir.from) AS created_at
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Find latest change time from all non-IS_RELATED edges (both from and to)
|
|
86
|
+
CALL (rel) {
|
|
87
|
+
MATCH (rel)-[e:!IS_RELATED]-()
|
|
88
|
+
WHERE e.branch_level = 1
|
|
89
|
+
WITH e.from AS change_time
|
|
90
|
+
WHERE change_time IS NOT NULL
|
|
91
|
+
RETURN change_time
|
|
92
|
+
UNION ALL
|
|
93
|
+
MATCH (rel)-[e:!IS_RELATED]-()
|
|
94
|
+
WHERE e.branch_level = 1
|
|
95
|
+
AND e.to IS NOT NULL
|
|
96
|
+
RETURN e.to AS change_time
|
|
97
|
+
}
|
|
98
|
+
WITH rel, created_at, max(change_time) AS updated_at
|
|
99
|
+
|
|
100
|
+
// Set metadata (use coalesce to fall back to created_at if no changes found)
|
|
101
|
+
CALL (rel, created_at, updated_at) {
|
|
102
|
+
SET rel.created_at = created_at
|
|
103
|
+
SET rel.updated_at = coalesce(updated_at, created_at)
|
|
104
|
+
} IN TRANSACTIONS
|
|
105
|
+
"""
|
|
106
|
+
self.add_to_query(query)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class BackfillNodeMetadataQuery(Query):
|
|
110
|
+
"""Backfill created_at and updated_at for Node vertices on default/global branches.
|
|
111
|
+
|
|
112
|
+
- created_at = earliest from time of any IS_PART_OF edge for Nodes with this UUID
|
|
113
|
+
- updated_at = latest updated_at from any linked Attribute or Relationship
|
|
114
|
+
|
|
115
|
+
Must run after BackfillAttributeMetadataQuery and BackfillRelationshipMetadataQuery
|
|
116
|
+
since Node.updated_at depends on field updated_at values.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
name = "backfill_node_metadata"
|
|
120
|
+
type: QueryType = QueryType.WRITE
|
|
121
|
+
insert_return = False
|
|
122
|
+
|
|
123
|
+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
|
|
124
|
+
query = """
|
|
125
|
+
// Find all Node vertices on default/global branch without created_at
|
|
126
|
+
MATCH (n:Node)-[e:IS_PART_OF]->(:Root)
|
|
127
|
+
WHERE e.branch_level = 1
|
|
128
|
+
AND n.created_at IS NULL
|
|
129
|
+
WITH DISTINCT n
|
|
130
|
+
|
|
131
|
+
// created_at = earliest IS_PART_OF edge from time for this UUID
|
|
132
|
+
// (handles migrated kind/namespace where multiple Node vertices share same UUID)
|
|
133
|
+
CALL (n) {
|
|
134
|
+
MATCH (:Node {uuid: n.uuid})-[ip:IS_PART_OF]->(:Root)
|
|
135
|
+
WHERE ip.branch_level = 1
|
|
136
|
+
RETURN min(ip.from) AS created_at
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// updated_at = latest updated_at from any linked Attribute or Relationship
|
|
140
|
+
CALL (n) {
|
|
141
|
+
MATCH (n)-[:HAS_ATTRIBUTE|IS_RELATED]-(field:Attribute|Relationship)
|
|
142
|
+
WHERE field.updated_at IS NOT NULL
|
|
143
|
+
RETURN max(field.updated_at) AS latest_field_update
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Set metadata (use coalesce to fall back to created_at if no field updates found)
|
|
147
|
+
CALL (n, created_at, latest_field_update) {
|
|
148
|
+
SET n.created_at = created_at
|
|
149
|
+
SET n.updated_at = coalesce(latest_field_update, created_at)
|
|
150
|
+
} IN TRANSACTIONS
|
|
151
|
+
"""
|
|
152
|
+
self.add_to_query(query)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class Migration050(GraphMigration):
|
|
156
|
+
name: str = "050_backfill_vertex_metadata"
|
|
157
|
+
minimum_version: int = 49
|
|
158
|
+
queries: Sequence[type[Query]] = [
|
|
159
|
+
BackfillAttributeMetadataQuery, # Run first
|
|
160
|
+
BackfillRelationshipMetadataQuery, # Run second
|
|
161
|
+
BackfillNodeMetadataQuery, # Run last (depends on Attr/Rel updated_at)
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
|
|
165
|
+
return MigrationResult()
|
|
166
|
+
|
|
167
|
+
async def execute(self, db: InfrahubDatabase) -> MigrationResult:
|
|
168
|
+
return await self.do_execute(db=db)
|
|
@@ -20,7 +20,7 @@ class MigrationQuery(MigrationBaseQuery):
|
|
|
20
20
|
self,
|
|
21
21
|
migration: SchemaMigration,
|
|
22
22
|
**kwargs: Any,
|
|
23
|
-
):
|
|
23
|
+
) -> None:
|
|
24
24
|
self.migration = migration
|
|
25
25
|
super().__init__(**kwargs)
|
|
26
26
|
|
|
@@ -32,6 +32,6 @@ class AttributeMigrationQuery(MigrationBaseQuery):
|
|
|
32
32
|
self,
|
|
33
33
|
migration: AttributeSchemaMigration,
|
|
34
34
|
**kwargs: Any,
|
|
35
|
-
):
|
|
35
|
+
) -> None:
|
|
36
36
|
self.migration = migration
|
|
37
37
|
super().__init__(**kwargs)
|
|
@@ -47,15 +47,20 @@ class AttributeAddQuery(Query):
|
|
|
47
47
|
else:
|
|
48
48
|
self.params["attr_value"] = NULL_VALUE
|
|
49
49
|
|
|
50
|
+
self.params["user_id"] = self.user_id
|
|
51
|
+
|
|
50
52
|
self.params["rel_props"] = {
|
|
51
53
|
"branch": self.branch.name,
|
|
52
54
|
"branch_level": self.branch.hierarchy_level,
|
|
53
55
|
"status": RelationshipStatus.ACTIVE.value,
|
|
54
56
|
"from": self.at.to_string(),
|
|
57
|
+
"from_user_id": self.user_id,
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
self.params["is_protected_default"] = False
|
|
58
|
-
|
|
61
|
+
|
|
62
|
+
# Set metadata for vertex properties on default/global branch
|
|
63
|
+
self.params["set_metadata"] = self.branch.is_default or self.branch.is_global
|
|
59
64
|
|
|
60
65
|
attr_value_label = GraphAttributeValueNode.get_default_label()
|
|
61
66
|
if not is_large_attribute_type(self.attribute_kind):
|
|
@@ -84,8 +89,7 @@ class AttributeAddQuery(Query):
|
|
|
84
89
|
query = """
|
|
85
90
|
%(match_query)s
|
|
86
91
|
MERGE (is_protected_value:Boolean { value: $is_protected_default })
|
|
87
|
-
|
|
88
|
-
WITH av, is_protected_value, is_visible_value
|
|
92
|
+
WITH av, is_protected_value
|
|
89
93
|
MATCH (n:%(node_kinds_str)s)
|
|
90
94
|
CALL (n) {
|
|
91
95
|
MATCH (:Root)<-[r:IS_PART_OF]-(n)
|
|
@@ -98,16 +102,23 @@ class AttributeAddQuery(Query):
|
|
|
98
102
|
ORDER BY has_attr_e.branch_level DESC, has_attr_e.from ASC, is_part_of_e.branch_level DESC, is_part_of_e.from ASC
|
|
99
103
|
LIMIT 1
|
|
100
104
|
}
|
|
101
|
-
WITH n, is_part_of_e, has_attr_e, av, is_protected_value
|
|
105
|
+
WITH n, is_part_of_e, has_attr_e, av, is_protected_value
|
|
102
106
|
WHERE is_part_of_e.status = "active" AND (has_attr_e IS NULL OR has_attr_e.status = "deleted")
|
|
103
107
|
CREATE (a:Attribute { name: $attr_name, branch_support: $branch_support })
|
|
104
108
|
CREATE (n)-[:HAS_ATTRIBUTE $rel_props ]->(a)
|
|
105
109
|
CREATE (a)-[:HAS_VALUE $rel_props ]->(av)
|
|
106
110
|
CREATE (a)-[:IS_PROTECTED $rel_props]->(is_protected_value)
|
|
107
|
-
CREATE (a)-[:IS_VISIBLE $rel_props]->(is_visible_value)
|
|
108
111
|
%(uuid_generation)s
|
|
112
|
+
// Set metadata on Attribute and Node vertices if on default/global branch
|
|
113
|
+
WITH a, n, has_attr_e
|
|
114
|
+
CALL (a, n) {
|
|
115
|
+
WITH a, n
|
|
116
|
+
WHERE $set_metadata
|
|
117
|
+
SET a.created_at = $current_time, a.created_by = $user_id, a.updated_at = $current_time, a.updated_by = $user_id
|
|
118
|
+
SET n.updated_at = $current_time, n.updated_by = $user_id
|
|
119
|
+
}
|
|
109
120
|
FOREACH (i in CASE WHEN has_attr_e.status = "deleted" THEN [1] ELSE [] END |
|
|
110
|
-
SET has_attr_e.to = $current_time
|
|
121
|
+
SET has_attr_e.to = $current_time, has_attr_e.to_user_id = $user_id
|
|
111
122
|
)
|
|
112
123
|
""" % {
|
|
113
124
|
"match_query": match_query,
|
|
@@ -53,13 +53,19 @@ class AttributeRemoveQuery(Query):
|
|
|
53
53
|
self.params["current_time"] = self.at.to_string()
|
|
54
54
|
self.params["branch_name"] = self.branch.name
|
|
55
55
|
|
|
56
|
+
self.params["user_id"] = self.user_id
|
|
57
|
+
|
|
56
58
|
self.params["rel_props"] = {
|
|
57
59
|
"branch": self.branch.name,
|
|
58
60
|
"branch_level": self.branch.hierarchy_level,
|
|
59
61
|
"status": RelationshipStatus.DELETED.value,
|
|
60
62
|
"from": self.at.to_string(),
|
|
63
|
+
"from_user_id": self.user_id,
|
|
61
64
|
}
|
|
62
65
|
|
|
66
|
+
# Set metadata for vertex properties on default/global branch
|
|
67
|
+
self.params["set_metadata"] = self.branch.is_default or self.branch.is_global
|
|
68
|
+
|
|
63
69
|
def render_sub_query_per_rel_type(rel_type: str, rel_def: FieldInfo) -> str:
|
|
64
70
|
subquery = [
|
|
65
71
|
"WITH peer_node, rb, active_attr",
|
|
@@ -106,9 +112,9 @@ class AttributeRemoveQuery(Query):
|
|
|
106
112
|
}
|
|
107
113
|
WITH n1 as active_node, r1 as rb, attr1 as active_attr
|
|
108
114
|
WHERE rb.status = "active"
|
|
109
|
-
WITH active_attr
|
|
115
|
+
WITH active_node, active_attr
|
|
110
116
|
MATCH (active_attr)-[]-(peer)
|
|
111
|
-
WITH DISTINCT active_attr, peer
|
|
117
|
+
WITH DISTINCT active_node, active_attr, peer
|
|
112
118
|
CALL (active_attr, peer) {
|
|
113
119
|
MATCH (active_attr)-[r]-(peer)
|
|
114
120
|
WHERE %(branch_filter)s
|
|
@@ -116,15 +122,23 @@ class AttributeRemoveQuery(Query):
|
|
|
116
122
|
ORDER BY r.branch_level DESC, r.from DESC
|
|
117
123
|
LIMIT 1
|
|
118
124
|
}
|
|
119
|
-
WITH a1 as active_attr, r1 as rb, p1 as peer_node
|
|
125
|
+
WITH active_node, a1 as active_attr, r1 as rb, p1 as peer_node
|
|
120
126
|
WHERE rb.status = "active"
|
|
121
127
|
CALL (peer_node, rb, active_attr) {
|
|
122
128
|
%(sub_query_all)s
|
|
123
129
|
}
|
|
124
|
-
WITH p2 as peer_node, rb, active_attr
|
|
130
|
+
WITH p2 as peer_node, rb, active_node, active_attr
|
|
125
131
|
FOREACH (i in CASE WHEN rb.branch = $branch_name THEN [1] ELSE [] END |
|
|
126
|
-
SET rb.to = $current_time
|
|
132
|
+
SET rb.to = $current_time, rb.to_user_id = $user_id
|
|
127
133
|
)
|
|
134
|
+
// Set metadata on Attribute and Node vertices if on default/global branch
|
|
135
|
+
WITH active_attr, active_node
|
|
136
|
+
CALL (active_attr, active_node) {
|
|
137
|
+
WITH active_attr, active_node
|
|
138
|
+
WHERE $set_metadata
|
|
139
|
+
SET active_attr.updated_at = $current_time, active_attr.updated_by = $user_id
|
|
140
|
+
SET active_node.updated_at = $current_time, active_node.updated_by = $user_id
|
|
141
|
+
}
|
|
128
142
|
RETURN DISTINCT active_attr
|
|
129
143
|
""" % {
|
|
130
144
|
"branch_filter": branch_filter,
|
|
@@ -32,7 +32,6 @@ class AttributeRenameQuery(Query):
|
|
|
32
32
|
) -> None:
|
|
33
33
|
self.previous_attr = previous_attr
|
|
34
34
|
self.new_attr = new_attr
|
|
35
|
-
|
|
36
35
|
super().__init__(**kwargs)
|
|
37
36
|
|
|
38
37
|
def render_match(self) -> str:
|
|
@@ -94,11 +93,14 @@ class AttributeRenameQuery(Query):
|
|
|
94
93
|
self.params["current_time"] = self.at.to_string()
|
|
95
94
|
self.params["branch_name"] = self.branch.name
|
|
96
95
|
|
|
96
|
+
self.params["user_id"] = self.user_id
|
|
97
|
+
|
|
97
98
|
self.params["rel_props_create"] = {
|
|
98
99
|
"branch": self.branch.name,
|
|
99
100
|
"branch_level": self.branch.hierarchy_level,
|
|
100
101
|
"status": RelationshipStatus.ACTIVE.value,
|
|
101
102
|
"from": self.at.to_string(),
|
|
103
|
+
"from_user_id": self.user_id,
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
self.params["rel_props_delete"] = {
|
|
@@ -106,8 +108,12 @@ class AttributeRenameQuery(Query):
|
|
|
106
108
|
"branch_level": self.branch.hierarchy_level,
|
|
107
109
|
"status": RelationshipStatus.DELETED.value,
|
|
108
110
|
"from": self.at.to_string(),
|
|
111
|
+
"from_user_id": self.user_id,
|
|
109
112
|
}
|
|
110
113
|
|
|
114
|
+
# Set metadata for vertex properties on default/global branch
|
|
115
|
+
self.params["set_metadata"] = self.branch.is_default or self.branch.is_global
|
|
116
|
+
|
|
111
117
|
sub_queries_create = [
|
|
112
118
|
self._render_sub_query_per_rel_type_create_new(rel_type, rel_def)
|
|
113
119
|
for rel_type, rel_def in GraphAttributeRelationships.model_fields.items()
|
|
@@ -145,8 +151,9 @@ class AttributeRenameQuery(Query):
|
|
|
145
151
|
WHERE rb.status = "active"
|
|
146
152
|
CREATE (new_attr:Attribute { name: $new_attr.name, branch_support: $new_attr.branch_support })
|
|
147
153
|
%(add_uuid)s
|
|
148
|
-
WITH active_attr, new_attr
|
|
154
|
+
WITH active_node, active_attr, new_attr
|
|
149
155
|
MATCH (active_attr)-[]-(peer)
|
|
156
|
+
WITH DISTINCT active_node, active_attr, new_attr, peer
|
|
150
157
|
CALL (active_attr, peer) {
|
|
151
158
|
MATCH (active_attr)-[r]-(peer)
|
|
152
159
|
WHERE %(branch_filter)s
|
|
@@ -154,12 +161,12 @@ class AttributeRenameQuery(Query):
|
|
|
154
161
|
ORDER BY r.branch_level DESC, r.from DESC
|
|
155
162
|
LIMIT 1
|
|
156
163
|
}
|
|
157
|
-
WITH a1 as active_attr, r1 as rb, p1 as peer_node, new_attr
|
|
164
|
+
WITH active_node, a1 as active_attr, r1 as rb, p1 as peer_node, new_attr
|
|
158
165
|
WHERE rb.status = "active"
|
|
159
166
|
CALL (peer_node, rb, active_attr, new_attr){
|
|
160
167
|
%(sub_query_create_all)s
|
|
161
168
|
}
|
|
162
|
-
WITH p2 as peer_node, rb, new_attr, active_attr
|
|
169
|
+
WITH p2 as peer_node, rb, new_attr, active_attr, active_node
|
|
163
170
|
""" % {"branch_filter": branch_filter, "add_uuid": add_uuid, "sub_query_create_all": sub_query_create_all}
|
|
164
171
|
self.add_to_query(query)
|
|
165
172
|
|
|
@@ -175,8 +182,17 @@ class AttributeRenameQuery(Query):
|
|
|
175
182
|
else:
|
|
176
183
|
query = """
|
|
177
184
|
FOREACH (i in CASE WHEN rb.branch = $branch_name THEN [1] ELSE [] END |
|
|
178
|
-
SET rb.to = $current_time
|
|
185
|
+
SET rb.to = $current_time, rb.to_user_id = $user_id
|
|
179
186
|
)
|
|
187
|
+
WITH new_attr, active_node
|
|
188
|
+
// Set metadata on new Attribute and Node vertices if on default/global branch
|
|
189
|
+
CALL (new_attr, active_node) {
|
|
190
|
+
WITH new_attr, active_node
|
|
191
|
+
WHERE $set_metadata
|
|
192
|
+
SET new_attr.created_at = $current_time, new_attr.created_by = $user_id
|
|
193
|
+
SET new_attr.updated_at = $current_time, new_attr.updated_by = $user_id
|
|
194
|
+
SET active_node.updated_at = $current_time, active_node.updated_by = $user_id
|
|
195
|
+
}
|
|
180
196
|
RETURN DISTINCT new_attr
|
|
181
197
|
"""
|
|
182
198
|
self.add_to_query(query)
|
|
@@ -40,7 +40,6 @@ class NodeDuplicateQuery(Query):
|
|
|
40
40
|
) -> None:
|
|
41
41
|
self.previous_node = previous_node
|
|
42
42
|
self.new_node = new_node
|
|
43
|
-
|
|
44
43
|
super().__init__(**kwargs)
|
|
45
44
|
|
|
46
45
|
def render_match(self) -> str:
|
|
@@ -140,16 +139,23 @@ class NodeDuplicateQuery(Query):
|
|
|
140
139
|
self.params["branch_level"] = self.branch.hierarchy_level
|
|
141
140
|
self.params["branch_support"] = self.new_node.branch_support
|
|
142
141
|
|
|
142
|
+
self.params["user_id"] = self.user_id
|
|
143
|
+
|
|
143
144
|
self.params["rel_props_new"] = {
|
|
144
145
|
"status": RelationshipStatus.ACTIVE.value,
|
|
145
146
|
"from": self.at.to_string(),
|
|
147
|
+
"from_user_id": self.user_id,
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
self.params["rel_props_prev"] = {
|
|
149
151
|
"status": RelationshipStatus.DELETED.value,
|
|
150
152
|
"from": self.at.to_string(),
|
|
153
|
+
"from_user_id": self.user_id,
|
|
151
154
|
}
|
|
152
155
|
|
|
156
|
+
# Set metadata for vertex properties on default/global branch
|
|
157
|
+
self.params["set_metadata"] = self.branch.is_default or self.branch.is_global
|
|
158
|
+
|
|
153
159
|
sub_query_out, sub_query_out_args = self._render_sub_query_out()
|
|
154
160
|
sub_query_in, sub_query_in_args = self._render_sub_query_in()
|
|
155
161
|
|
|
@@ -168,6 +174,16 @@ class NodeDuplicateQuery(Query):
|
|
|
168
174
|
WHERE rb.status = "active"
|
|
169
175
|
CREATE (new_node:Node:%(labels)s { uuid: active_node.uuid, kind: $new_node.kind, namespace: $new_node.namespace, branch_support: $new_node.branch_support })
|
|
170
176
|
WITH active_node, new_node
|
|
177
|
+
// Set metadata on new Node vertex
|
|
178
|
+
CALL (active_node, new_node) {
|
|
179
|
+
// always pass created_by/at from active node
|
|
180
|
+
SET new_node.created_at = active_node.created_at, new_node.created_by = active_node.created_by
|
|
181
|
+
WITH new_node
|
|
182
|
+
// set updated_by/at if we're on the default/global branch
|
|
183
|
+
WHERE $set_metadata
|
|
184
|
+
SET new_node.updated_at = $current_time, new_node.updated_by = $user_id
|
|
185
|
+
}
|
|
186
|
+
|
|
171
187
|
// Process Outbound Relationship
|
|
172
188
|
MATCH (active_node)-[]->(peer)
|
|
173
189
|
WITH DISTINCT active_node, new_node, peer
|
|
@@ -185,7 +201,7 @@ class NodeDuplicateQuery(Query):
|
|
|
185
201
|
}
|
|
186
202
|
WITH p2 as peer_node, rel_outband, active_node, new_node
|
|
187
203
|
FOREACH (i in CASE WHEN rel_outband.branch IN ["-global-", $branch] THEN [1] ELSE [] END |
|
|
188
|
-
SET rel_outband.to = $current_time
|
|
204
|
+
SET rel_outband.to = $current_time, rel_outband.to_user_id = $user_id
|
|
189
205
|
)
|
|
190
206
|
WITH DISTINCT active_node, new_node
|
|
191
207
|
// Process Inbound Relationship
|
|
@@ -205,9 +221,8 @@ class NodeDuplicateQuery(Query):
|
|
|
205
221
|
}
|
|
206
222
|
WITH p2 as peer_node, rel_inband, active_node, new_node
|
|
207
223
|
FOREACH (i in CASE WHEN rel_inband.branch IN ["-global-", $branch] THEN [1] ELSE [] END |
|
|
208
|
-
SET rel_inband.to = $current_time
|
|
224
|
+
SET rel_inband.to = $current_time, rel_inband.to_user_id = $user_id
|
|
209
225
|
)
|
|
210
|
-
|
|
211
226
|
RETURN DISTINCT new_node
|
|
212
227
|
""" % {
|
|
213
228
|
"branch_filter": branch_filter,
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING, Any, Sequence
|
|
4
4
|
|
|
5
|
+
from infrahub.core.constants import SYSTEM_USER_ID
|
|
5
6
|
from infrahub.types import is_large_attribute_type
|
|
6
7
|
|
|
7
8
|
from ..query import AttributeMigrationQuery, MigrationBaseQuery
|
|
@@ -26,6 +27,11 @@ class AttributeKindUpdateMigrationQuery(AttributeMigrationQuery):
|
|
|
26
27
|
self.params["branch_level"] = self.branch.hierarchy_level
|
|
27
28
|
self.params["at"] = self.at.to_string()
|
|
28
29
|
self.params["attr_name"] = self.migration.previous_attribute_schema.name
|
|
30
|
+
self.params["user_id"] = self.user_id
|
|
31
|
+
|
|
32
|
+
# Set metadata for vertex properties on default/global branch
|
|
33
|
+
self.params["set_metadata"] = self.branch.is_default or self.branch.is_global
|
|
34
|
+
|
|
29
35
|
new_attr_value_labels = "AttributeValue"
|
|
30
36
|
if needs_index:
|
|
31
37
|
new_attr_value_labels += ":AttributeValueIndexed"
|
|
@@ -108,6 +114,7 @@ CALL (attr, has_value_e, av) {
|
|
|
108
114
|
SET new_has_value_e.branch = $branch
|
|
109
115
|
SET new_has_value_e.branch_level = $branch_level
|
|
110
116
|
SET new_has_value_e.from = $at
|
|
117
|
+
SET new_has_value_e.from_user_id = $user_id
|
|
111
118
|
SET new_has_value_e.to = NULL
|
|
112
119
|
|
|
113
120
|
// ------------
|
|
@@ -122,6 +129,7 @@ CALL (attr, has_value_e, av) {
|
|
|
122
129
|
SET deleted_has_value_e.branch = $branch
|
|
123
130
|
SET deleted_has_value_e.branch_level = $branch_level
|
|
124
131
|
SET deleted_has_value_e.from = $at
|
|
132
|
+
SET deleted_has_value_e.from_user_id = $user_id
|
|
125
133
|
SET deleted_has_value_e.to = NULL
|
|
126
134
|
}
|
|
127
135
|
|
|
@@ -132,7 +140,17 @@ CALL (attr, has_value_e, av) {
|
|
|
132
140
|
CALL (has_value_e) {
|
|
133
141
|
WITH has_value_e
|
|
134
142
|
WHERE has_value_e.branch = $branch
|
|
135
|
-
SET has_value_e.to = $at
|
|
143
|
+
SET has_value_e.to = $at, has_value_e.to_user_id = $user_id
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ------------
|
|
147
|
+
// Set metadata on Attribute and Node vertices if on default/global branch
|
|
148
|
+
// ------------
|
|
149
|
+
CALL (attr, n) {
|
|
150
|
+
WITH attr, n
|
|
151
|
+
WHERE $set_metadata
|
|
152
|
+
SET attr.updated_at = $at, attr.updated_by = $user_id
|
|
153
|
+
SET n.updated_at = $at, n.updated_by = $user_id
|
|
136
154
|
}
|
|
137
155
|
""" % {
|
|
138
156
|
"schema_kinds": (
|
|
@@ -154,10 +172,11 @@ class AttributeKindUpdateMigration(AttributeSchemaMigration):
|
|
|
154
172
|
branch: Branch,
|
|
155
173
|
at: Timestamp | str | None = None,
|
|
156
174
|
queries: Sequence[type[MigrationBaseQuery]] | None = None,
|
|
175
|
+
user_id: str = SYSTEM_USER_ID,
|
|
157
176
|
) -> MigrationResult:
|
|
158
177
|
is_indexed_previous = is_large_attribute_type(self.previous_attribute_schema.kind)
|
|
159
178
|
is_indexed_new = is_large_attribute_type(self.new_attribute_schema.kind)
|
|
160
179
|
if is_indexed_previous is is_indexed_new:
|
|
161
180
|
return MigrationResult()
|
|
162
181
|
|
|
163
|
-
return await super().execute(db=db, branch=branch, at=at, queries=queries)
|
|
182
|
+
return await super().execute(db=db, branch=branch, at=at, queries=queries, user_id=user_id)
|