Skip to content

Commit 966699d

Browse files
committed
Nuke generate_template for generics
1 parent 2e70ab1 commit 966699d

File tree

4 files changed

+163
-1
lines changed

4 files changed

+163
-1
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
GRAPH_VERSION = 61
1+
GRAPH_VERSION = 62

backend/infrahub/core/migrations/graph/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
from .m059_recompute_permission_display_labels import Migration059
6464
from .m060_template_number_pool_cleanup import Migration060
6565
from .m061_template_ip_pool_relationship_cleanup import Migration061
66+
from .m062_remove_generic_generate_template import Migration062
6667

6768
if TYPE_CHECKING:
6869
from ..shared import MigrationTypes
@@ -130,6 +131,7 @@
130131
Migration059,
131132
Migration060,
132133
Migration061,
134+
Migration062,
133135
]
134136

135137

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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 RemoveGenericGenerateTemplateQuery(Query):
15+
"""Remove generate_template Attribute nodes from all SchemaGeneric-labeled instances."""
16+
17+
name = "migration_062_remove_generic_generate_template"
18+
type: QueryType = QueryType.WRITE
19+
insert_return = False
20+
21+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
22+
query = """
23+
MATCH (sg:SchemaGeneric)-[:HAS_ATTRIBUTE]->(attr:Attribute {name: "generate_template"})
24+
DETACH DELETE attr
25+
"""
26+
self.add_to_query(query)
27+
28+
29+
class RemoveGenericGenerateTemplateSchemaAttributeQuery(Query):
30+
"""Remove the generate_template SchemaAttribute from the SchemaGeneric type definition."""
31+
32+
name = "migration_062_remove_generic_generate_template_schema_attribute"
33+
type: QueryType = QueryType.WRITE
34+
insert_return = False
35+
36+
async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
37+
query = """
38+
// Find the SchemaGeneric type definition (stored as SchemaNode)
39+
MATCH p1 = (sn:SchemaNode)-[:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[:HAS_VALUE]->(:AttributeValueIndexed {value: "Generic"})
40+
WHERE all(r IN relationships(p1) WHERE r.status = "active" AND r.to IS NULL)
41+
MATCH p2 = (sn)-[:HAS_ATTRIBUTE]->(:Attribute {name: "namespace"})-[:HAS_VALUE]->(:AttributeValueIndexed {value: "Schema"})
42+
WHERE all(r IN relationships(p2) WHERE r.status = "active" AND r.to IS NULL)
43+
WITH sn
44+
LIMIT 1
45+
// Find the generate_template SchemaAttribute child
46+
MATCH p3 = (sn)-[:IS_RELATED]-(rel:Relationship {name: "schema__node__attributes"})
47+
-[:IS_RELATED]-(sa:SchemaAttribute)
48+
-[:HAS_ATTRIBUTE]->(:Attribute {name: "name"})
49+
-[:HAS_VALUE]->(:AttributeValueIndexed {value: "generate_template"})
50+
WHERE all(r IN relationships(p3) WHERE r.status = "active" AND r.to IS NULL)
51+
WITH sa, rel
52+
LIMIT 1
53+
54+
// Delete the SchemaAttribute and its relationship node
55+
DETACH DELETE sa, rel
56+
"""
57+
self.add_to_query(query)
58+
59+
60+
class Migration062(GraphMigration):
61+
name: str = "062_remove_generic_generate_template"
62+
minimum_version: int = 61
63+
queries: Sequence[type[Query]] = [
64+
RemoveGenericGenerateTemplateQuery,
65+
RemoveGenericGenerateTemplateSchemaAttributeQuery,
66+
]
67+
68+
async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult: # noqa: ARG002
69+
return MigrationResult()
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import pytest
2+
3+
from infrahub.core import registry
4+
from infrahub.core.branch import Branch
5+
from infrahub.core.constants import SchemaPathType
6+
from infrahub.core.migrations.graph.m062_remove_generic_generate_template import Migration062
7+
from infrahub.core.migrations.schema.node_attribute_add import NodeAttributeAddMigration
8+
from infrahub.core.migrations.shared import InternalSchemaMigration, MigrationInput
9+
from infrahub.core.path import SchemaPath
10+
from infrahub.core.timestamp import Timestamp
11+
from infrahub.database import InfrahubDatabase
12+
13+
COUNT_GENERATE_TEMPLATE_ON_GENERICS = """
14+
MATCH (sg:SchemaGeneric)-[r:HAS_ATTRIBUTE]->(attr:Attribute {name: "generate_template"})
15+
WHERE r.status = "active" AND r.to IS NULL
16+
RETURN count(attr) AS count
17+
"""
18+
19+
COUNT_GENERATE_TEMPLATE_SCHEMA_ATTRIBUTE = """
20+
MATCH p1 = (sn:SchemaNode)-[:HAS_ATTRIBUTE]->(:Attribute {name: "name"})
21+
-[:HAS_VALUE]->(:AttributeValueIndexed {value: "Generic"})
22+
WHERE all(r IN relationships(p1) WHERE r.status = "active" AND r.to IS NULL)
23+
MATCH p2 = (sn)-[:HAS_ATTRIBUTE]->(:Attribute {name: "namespace"})
24+
-[:HAS_VALUE]->(:AttributeValueIndexed {value: "Schema"})
25+
WHERE all(r IN relationships(p2) WHERE r.status = "active" AND r.to IS NULL)
26+
WITH sn
27+
LIMIT 1
28+
MATCH p3 = (sn)-[:IS_RELATED]-(:Relationship {name: "schema__node__attributes"})
29+
-[:IS_RELATED]-(sa:SchemaAttribute)
30+
-[:HAS_ATTRIBUTE]->(:Attribute {name: "name"})
31+
-[:HAS_VALUE]->(:AttributeValueIndexed {value: "generate_template"})
32+
WHERE all(r IN relationships(p3) WHERE r.status = "active" AND r.to IS NULL)
33+
RETURN count(sa) AS count
34+
"""
35+
36+
37+
@pytest.fixture
38+
async def migration_062_data(
39+
db: InfrahubDatabase, reset_registry: None, default_branch: Branch, register_core_schema_db: None
40+
) -> None:
41+
"""Add generate_template attribute to SchemaGeneric nodes, simulating the old DB state."""
42+
internal_schema_branch = InternalSchemaMigration.get_internal_schema()
43+
schema_node = internal_schema_branch.get_node(name="SchemaNode")
44+
schema_generic = internal_schema_branch.get_node(name="SchemaGeneric")
45+
46+
# Build a SchemaGeneric definition that includes generate_template
47+
schema_generic_with_attr = internal_schema_branch.get_node(name="SchemaGeneric")
48+
generate_template_attr = schema_node.get_attribute(name="generate_template")
49+
schema_generic_with_attr.attributes.append(generate_template_attr)
50+
51+
add_migration = NodeAttributeAddMigration(
52+
new_node_schema=schema_generic_with_attr,
53+
previous_node_schema=schema_generic,
54+
schema_path=SchemaPath(
55+
schema_kind="SchemaGeneric", path_type=SchemaPathType.ATTRIBUTE, field_name="generate_template"
56+
),
57+
)
58+
await add_migration.execute(migration_input=MigrationInput(db=db), branch=default_branch)
59+
60+
# Also add generate_template SchemaAttribute to the SchemaGeneric type definition
61+
# This simulates the old DB state where update_core_schema stored the attribute definition
62+
schema_generic_def = registry.schema.get(name="SchemaGeneric", branch=default_branch, duplicate=True)
63+
gt_attr = generate_template_attr.duplicate()
64+
gt_attr.id = None
65+
schema_generic_def.attributes.append(gt_attr)
66+
await registry.schema.update_node_in_db(
67+
node=schema_generic_def, branch=default_branch, db=db, at=Timestamp(), user_id="migration-test"
68+
)
69+
70+
71+
async def test_migration_062(
72+
db: InfrahubDatabase, reset_registry: None, default_branch: Branch, migration_062_data: None
73+
) -> None:
74+
result_before = await db.execute_query(query=COUNT_GENERATE_TEMPLATE_ON_GENERICS)
75+
assert result_before[0].get("count") > 0
76+
77+
schema_attr_before = await db.execute_query(query=COUNT_GENERATE_TEMPLATE_SCHEMA_ATTRIBUTE)
78+
assert schema_attr_before[0].get("count") > 0
79+
80+
migration = Migration062.init()
81+
execution_result = await migration.execute(migration_input=MigrationInput(db=db))
82+
assert not execution_result.errors
83+
84+
validation_result = await migration.validate_migration(db=db)
85+
assert not validation_result.errors
86+
87+
result_after = await db.execute_query(query=COUNT_GENERATE_TEMPLATE_ON_GENERICS)
88+
assert result_after[0].get("count") == 0
89+
90+
schema_attr_after = await db.execute_query(query=COUNT_GENERATE_TEMPLATE_SCHEMA_ATTRIBUTE)
91+
assert schema_attr_after[0].get("count") == 0

0 commit comments

Comments
 (0)