Skip to content

Commit 6ff8590

Browse files
committed
Fix node kind migration with agnostic/aware schema
1 parent 7a0b12d commit 6ff8590

File tree

7 files changed

+308
-102
lines changed

7 files changed

+308
-102
lines changed

backend/infrahub/core/migrations/query/node_duplicate.py

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,27 @@ def _render_sub_query_per_rel_type(
5656
f'WHERE type({rel_name}) = "{rel_type}"',
5757
]
5858
if rel_def.default.direction in [direction, GraphRelDirection.EITHER]:
59-
subquery.append(f"CREATE (new_node)-[:{rel_type} $rel_props_new ]->(peer_node)")
60-
subquery.append(f"CREATE (active_node)-[:{rel_type} $rel_props_prev ]->(peer_node)")
59+
subquery.append(f"""
60+
CREATE (new_node)-[new_active_edge:{rel_type} $rel_props_new ]->(peer_node)
61+
SET new_active_edge.branch = CASE WHEN {rel_name}.branch = "-global-" THEN "-global-" ELSE $branch END
62+
SET new_active_edge.branch_level = CASE WHEN {rel_name}.branch = "-global-" THEN {rel_name}.branch_level ELSE $branch_level END
63+
""")
64+
subquery.append(f"""
65+
CREATE (active_node)-[deleted_edge:{rel_type} $rel_props_prev ]->(peer_node)
66+
SET deleted_edge.branch = CASE WHEN {rel_name}.branch = "-global-" THEN "-global-" ELSE $branch END
67+
SET deleted_edge.branch_level = CASE WHEN {rel_name}.branch = "-global-" THEN {rel_name}.branch_level ELSE $branch_level END
68+
""")
6169
elif rel_def.default.direction in [direction, GraphRelDirection.EITHER]:
62-
subquery.append(f"CREATE (new_node)<-[:{rel_type} $rel_props_new ]-(peer_node)")
63-
subquery.append(f"CREATE (active_node)<-[:{rel_type} $rel_props_prev ]-(peer_node)")
70+
subquery.append(f"""
71+
CREATE (new_node)<-[new_active_edge:{rel_type} $rel_props_new ]-(peer_node)
72+
SET new_active_edge.branch = CASE WHEN {rel_name}.branch = "-global-" THEN "-global-" ELSE $branch END
73+
SET new_active_edge.branch_level = CASE WHEN {rel_name}.branch = "-global-" THEN {rel_name}.branch_level ELSE $branch_level END
74+
""")
75+
subquery.append(f"""
76+
CREATE (active_node)<-[deleted_edge:{rel_type} $rel_props_prev ]-(peer_node)
77+
SET new_active_edge.branch = CASE WHEN {rel_name}.branch = "-global-" THEN "-global-" ELSE $branch END
78+
SET new_active_edge.branch_level = CASE WHEN {rel_name}.branch = "-global-" THEN {rel_name}.branch_level ELSE $branch_level END
79+
""")
6480
subquery.append("RETURN peer_node as p2")
6581
return "\n".join(subquery)
6682

@@ -94,19 +110,16 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No
94110
self.params["previous_node"] = self.previous_node.model_dump()
95111

96112
self.params["current_time"] = self.at.to_string()
97-
self.params["branch_name"] = self.branch.name
113+
self.params["branch"] = self.branch.name
114+
self.params["branch_level"] = self.branch.hierarchy_level
98115
self.params["branch_support"] = self.new_node.branch_support
99116

100117
self.params["rel_props_new"] = {
101-
"branch": self.branch.name,
102-
"branch_level": self.branch.hierarchy_level,
103118
"status": RelationshipStatus.ACTIVE.value,
104119
"from": self.at.to_string(),
105120
}
106121

107122
self.params["rel_props_prev"] = {
108-
"branch": self.branch.name,
109-
"branch_level": self.branch.hierarchy_level,
110123
"status": RelationshipStatus.DELETED.value,
111124
"from": self.at.to_string(),
112125
}
@@ -127,7 +140,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No
127140
LIMIT 1
128141
}
129142
WITH n1 as active_node, r1 as rb
130-
WHERE rb.status = "active"
143+
WHERE rb.status = "active" AND rb.to IS NULL
131144
CREATE (new_node:Node:%(labels)s { uuid: active_node.uuid, kind: $new_node.kind, namespace: $new_node.namespace, branch_support: $new_node.branch_support })
132145
WITH active_node, new_node
133146
// Process Outbound Relationship
@@ -141,15 +154,15 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No
141154
LIMIT 1
142155
}
143156
WITH n1 as active_node, rel_outband1 as rel_outband, p1 as peer_node, new_node
144-
WHERE rel_outband.status = "active"
157+
WHERE rel_outband.status = "active" AND rel_outband.to IS NULL
145158
CALL {
146159
%(sub_query_out)s
147160
}
148161
WITH p2 as peer_node, rel_outband, active_node, new_node
149-
FOREACH (i in CASE WHEN rel_outband.branch = $branch_name THEN [1] ELSE [] END |
162+
FOREACH (i in CASE WHEN rel_outband.branch = "-global-" or rel_outband.branch = $branch THEN [1] ELSE [] END |
150163
SET rel_outband.to = $current_time
151164
)
152-
WITH active_node, new_node
165+
WITH peer_node, rel_outband, active_node, new_node
153166
MATCH (active_node)<-[]-(peer)
154167
CALL {
155168
WITH active_node, peer
@@ -160,14 +173,16 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No
160173
LIMIT 1
161174
}
162175
WITH n1 as active_node, rel_inband1 as rel_inband, p1 as peer_node, new_node
163-
WHERE rel_inband.status = "active"
176+
WHERE rel_inband.status = "active" AND rel_inband.to IS NULL
164177
CALL {
165178
%(sub_query_in)s
166179
}
167180
WITH p2 as peer_node, rel_inband, active_node, new_node
168-
FOREACH (i in CASE WHEN rel_inband.branch = $branch_name THEN [1] ELSE [] END |
181+
FOREACH (i in CASE WHEN rel_inband.branch = "-global-" or rel_inband.branch = $branch THEN [1] ELSE [] END |
169182
SET rel_inband.to = $current_time
170183
)
184+
185+
WITH peer_node, rel_inband, active_node, new_node
171186
RETURN DISTINCT new_node
172187
""" % {
173188
"branch_filter": branch_filter,

backend/infrahub/core/migrations/schema/node_remove.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,17 @@ def render_sub_query_per_rel_type(
2323
f'WHERE type({rel_name}) = "{rel_type}"',
2424
]
2525
if rel_def.default.direction in [direction, GraphRelDirection.EITHER]:
26-
subquery.append(f"CREATE (active_node)-[:{rel_type} $rel_props ]->(peer_node)")
26+
subquery.append(f"""
27+
CREATE (active_node)-[edge:{rel_type} $rel_props ]->(peer_node)
28+
SET edge.branch = CASE WHEN {rel_name}.branch = "-global-" THEN "-global-" ELSE $branch END
29+
SET edge.branch_level = CASE WHEN {rel_name}.branch = "-global-" THEN {rel_name}.branch_level ELSE $branch_level END
30+
""")
2731
elif rel_def.default.direction in [direction, GraphRelDirection.EITHER]:
28-
subquery.append(f"CREATE (active_node)<-[:{rel_type} $rel_props ]-(peer_node)")
32+
subquery.append(f"""
33+
CREATE (active_node)<-[edge:{rel_type} $rel_props ]-(peer_node)
34+
SET edge.branch = CASE WHEN {rel_name}.branch = "-global-" THEN "-global-" ELSE $branch END
35+
SET edge.branch_level = CASE WHEN {rel_name}.branch = "-global-" THEN {rel_name}.branch_level ELSE $branch_level END
36+
""")
2937
subquery.append("RETURN peer_node as p2")
3038
return "\n".join(subquery)
3139

@@ -38,10 +46,10 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No
3846

3947
self.params["current_time"] = self.at.to_string()
4048
self.params["branch_name"] = self.branch.name
49+
self.params["branch"] = self.branch.name
50+
self.params["branch_level"] = self.branch.hierarchy_level
4151

4252
self.params["rel_props"] = {
43-
"branch": self.branch.name,
44-
"branch_level": self.branch.hierarchy_level,
4553
"status": RelationshipStatus.DELETED.value,
4654
"from": self.at.to_string(),
4755
}
@@ -94,12 +102,12 @@ def render_node_remove_query(self, branch_filter: str) -> str:
94102
LIMIT 1
95103
}
96104
WITH n1 as active_node, rel_inband1 as rel_inband, p1 as peer_node
97-
WHERE rel_inband.status = "active"
105+
WHERE rel_inband.status = "active" AND rel_inband.to IS NULL
98106
CALL {
99107
%(sub_query)s
100108
}
101109
WITH p2 as peer_node, rel_inband, active_node
102-
FOREACH (i in CASE WHEN rel_inband.branch = $branch_name THEN [1] ELSE [] END |
110+
FOREACH (i in CASE WHEN rel_inband.branch = "-global-" or rel_inband.branch = $branch THEN [1] ELSE [] END |
103111
SET rel_inband.to = $current_time
104112
)
105113
""" % {"sub_query": sub_query, "branch_filter": branch_filter}
@@ -138,12 +146,11 @@ def render_node_remove_query(self, branch_filter: str) -> str:
138146
LIMIT 1
139147
}
140148
WITH n1 as active_node, rel_outband1 as rel_outband, p1 as peer_node
141-
WHERE rel_outband.status = "active"
149+
WHERE rel_outband.status = "active" AND rel_outband.to IS NULL
142150
CALL {
143151
%(sub_query)s
144152
}
145-
WITH p2 as peer_node, rel_outband, active_node
146-
FOREACH (i in CASE WHEN rel_outband.branch = $branch_name THEN [1] ELSE [] END |
153+
FOREACH (i in CASE WHEN rel_outband.branch = "-global-" or rel_outband.branch = $branch THEN [1] ELSE [] END |
147154
SET rel_outband.to = $current_time
148155
)
149156
""" % {"sub_query": sub_query, "branch_filter": branch_filter}

backend/tests/conftest.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,3 +951,75 @@ def patch_services(helper):
951951
yield bus
952952
services.service.message_bus = original
953953
services.prepare(service=services.service)
954+
955+
956+
@pytest.fixture(scope="class")
957+
def car_person_branch_agnostic_schema() -> dict[str, Any]:
958+
schema: dict[str, Any] = {
959+
"version": "1.0",
960+
"nodes": [
961+
{
962+
"name": "Car",
963+
"namespace": "Test",
964+
"default_filter": "name__value",
965+
"uniqueness_constraints": [["name__value"]],
966+
"branch": BranchSupportType.AGNOSTIC.value,
967+
"attributes": [
968+
{"name": "name", "kind": "Text", "unique": True},
969+
],
970+
"relationships": [
971+
{
972+
"name": "owner",
973+
"label": "Commander of Car",
974+
"peer": "TestPerson",
975+
"optional": False,
976+
"kind": "Parent",
977+
"cardinality": "one",
978+
"direction": "outbound",
979+
"branch": BranchSupportType.AGNOSTIC.value,
980+
},
981+
],
982+
},
983+
{
984+
"name": "Person",
985+
"namespace": "Test",
986+
"default_filter": "name__value",
987+
"display_labels": ["name__value"],
988+
"branch": BranchSupportType.AWARE.value,
989+
"uniqueness_constraints": [["name__value"]],
990+
"attributes": [
991+
{"name": "name", "kind": "Text", "unique": True},
992+
],
993+
"relationships": [
994+
{
995+
"name": "cars",
996+
"peer": "TestCar",
997+
"cardinality": "many",
998+
"direction": "inbound",
999+
"branch": BranchSupportType.AGNOSTIC.value,
1000+
}
1001+
],
1002+
},
1003+
{
1004+
"name": "Roofrack",
1005+
"namespace": "Test",
1006+
"branch": BranchSupportType.AWARE.value,
1007+
"attributes": [
1008+
{"name": "size", "kind": "Text", "unique": True},
1009+
],
1010+
"relationships": [
1011+
{
1012+
"name": "car",
1013+
"label": "Commander of Car",
1014+
"peer": "TestCar",
1015+
"optional": False,
1016+
"kind": "Parent",
1017+
"cardinality": "one",
1018+
"direction": "outbound",
1019+
"branch": BranchSupportType.AGNOSTIC.value,
1020+
},
1021+
],
1022+
},
1023+
],
1024+
}
1025+
return schema

backend/tests/functional/branch/conftest.py

Lines changed: 0 additions & 76 deletions
This file was deleted.

0 commit comments

Comments
 (0)