diff --git a/.github/workflows/version-upgrade.yml b/.github/workflows/version-upgrade.yml index df8ba91ee4..9b22414550 100644 --- a/.github/workflows/version-upgrade.yml +++ b/.github/workflows/version-upgrade.yml @@ -34,6 +34,7 @@ jobs: include: - name: From 1.1.0 source_version: 1.1.0 + neo4j_image: "neo4j:5.20.0-enterprise" name: ${{ matrix.name }} runs-on: group: huge-runners @@ -68,21 +69,28 @@ jobs: # Initialize the demo environment with the Source Version - name: Pull External Docker Images run: invoke demo.pull + env: + NEO4J_DOCKER_IMAGE: ${{ matrix.neo4j_image }} - name: Initialize Demo id: init-demo run: invoke demo.start demo.load-infra-schema env: PREFECT_SERVER_COMMAND: "prefect server start --host 0.0.0.0 --ui" + NEO4J_DOCKER_IMAGE: ${{ matrix.neo4j_image }} - name: Check Demo Status run: invoke demo.status + env: + NEO4J_DOCKER_IMAGE: ${{ matrix.neo4j_image }} - name: Load Infra Data run: invoke demo.load-infra-data env: PREFECT_SERVER_COMMAND: "prefect server start --host 0.0.0.0 --ui" + NEO4J_DOCKER_IMAGE: ${{ matrix.neo4j_image }} - name: Run infra data patch scripts run: invoke demo.run-infra-patch-scripts env: PREFECT_SERVER_COMMAND: "prefect server start --host 0.0.0.0 --ui" + NEO4J_DOCKER_IMAGE: ${{ matrix.neo4j_image }} - name: Stop Demo run: invoke demo.stop diff --git a/backend/infrahub/cli/db.py b/backend/infrahub/cli/db.py index 0cd7c11f82..b4dbe5376d 100644 --- a/backend/infrahub/cli/db.py +++ b/backend/infrahub/cli/db.py @@ -478,11 +478,10 @@ async def selected_export( ORDER BY %(id_func)s(n) SKIP toInteger($offset) LIMIT toInteger($limit) -CALL { +CALL (n) { // -------------- // get all the nodes and edges linked to this node up to 2 steps away, excluding IS_PART_OF // -------------- - WITH n MATCH (n)-[r1]-(v1)-[r2]-(v2) WHERE type(r1) <> "IS_PART_OF" WITH collect([v1, v2]) AS vertex_pairs, collect([r1, r2]) AS edge_pairs diff --git a/backend/infrahub/core/account.py b/backend/infrahub/core/account.py index eba03864f0..52b369c829 100644 --- a/backend/infrahub/core/account.py +++ b/backend/infrahub/core/account.py @@ -69,8 +69,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa query = """ MATCH (account:%(generic_account_node)s) WHERE account.uuid = $account_id - CALL { - WITH account + CALL (account) { MATCH (account)-[r:IS_PART_OF]-(root:Root) WHERE %(branch_filter)s RETURN account as account1, r as r1 @@ -80,8 +79,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa WITH account, r1 as r WHERE r.status = "active" WITH account - CALL { - WITH account + CALL (account) { MATCH (account)-[r1:IS_RELATED]->(:Relationship {name: "group_member"})<-[r2:IS_RELATED]-(account_group:%(account_group_node)s) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) WITH account_group, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active @@ -92,8 +90,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH account_group - CALL { - WITH account_group + CALL (account_group) { MATCH (account_group)-[r1:IS_RELATED]->(:Relationship {name: "role__accountgroups"})<-[r2:IS_RELATED]-(account_role:%(account_role_node)s) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) WITH account_role, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active @@ -104,8 +101,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH account_role - CALL { - WITH account_role + CALL (account_role) { MATCH (account_role)-[r1:IS_RELATED]->(:Relationship {name: "role__permissions"})<-[r2:IS_RELATED]-(global_permission:%(global_permission_node)s) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) WITH global_permission, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active @@ -116,7 +112,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH global_permission - CALL { + CALL (global_permission) { WITH global_permission MATCH (global_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[r2:HAS_VALUE]->(global_permission_action:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) @@ -127,8 +123,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa WITH global_permission, global_permission_action, is_active AS gpa_is_active WHERE gpa_is_active = TRUE - CALL { - WITH global_permission + CALL (global_permission) { MATCH (global_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[r2:HAS_VALUE]->(global_permission_decision:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN global_permission_decision, (r1.status = "active" AND r2.status = "active") AS is_active @@ -183,8 +178,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa query = """ MATCH (account:%(generic_account_node)s) WHERE account.uuid = $account_id - CALL { - WITH account + CALL (account) { MATCH (account)-[r:IS_PART_OF]-(root:Root) WHERE %(branch_filter)s RETURN account as account1, r as r1 @@ -194,8 +188,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa WITH account, r1 as r WHERE r.status = "active" WITH account - CALL { - WITH account + CALL (account) { MATCH (account)-[r1:IS_RELATED]->(:Relationship {name: "group_member"})<-[r2:IS_RELATED]-(account_group:%(account_group_node)s) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) WITH account_group, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active @@ -206,8 +199,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH account_group - CALL { - WITH account_group + CALL (account_group) { MATCH (account_group)-[r1:IS_RELATED]->(:Relationship {name: "role__accountgroups"})<-[r2:IS_RELATED]-(account_role:%(account_role_node)s) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) WITH account_role, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active @@ -218,8 +210,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH account_role - CALL { - WITH account_role + CALL (account_role) { MATCH (account_role)-[r1:IS_RELATED]->(:Relationship {name: "role__permissions"})<-[r2:IS_RELATED]-(object_permission:%(object_permission_node)s) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) WITH object_permission, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active @@ -230,8 +221,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH object_permission - CALL { - WITH object_permission + CALL (object_permission) { MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "namespace"})-[r2:HAS_VALUE]->(object_permission_namespace:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN object_permission_namespace, (r1.status = "active" AND r2.status = "active") AS is_active @@ -240,8 +230,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH object_permission, object_permission_namespace, is_active AS opn_is_active WHERE opn_is_active = TRUE - CALL { - WITH object_permission + CALL (object_permission) { MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[r2:HAS_VALUE]->(object_permission_name:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN object_permission_name, (r1.status = "active" AND r2.status = "active") AS is_active @@ -250,8 +239,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH object_permission, object_permission_namespace, object_permission_name, is_active AS opn_is_active WHERE opn_is_active = TRUE - CALL { - WITH object_permission + CALL (object_permission) { MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[r2:HAS_VALUE]->(object_permission_action:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN object_permission_action, (r1.status = "active" AND r2.status = "active") AS is_active @@ -260,8 +248,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH object_permission, object_permission_namespace, object_permission_name, object_permission_action, is_active AS opa_is_active WHERE opa_is_active = TRUE - CALL { - WITH object_permission + CALL (object_permission) { MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[r2:HAS_VALUE]->(object_permission_decision:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN object_permission_decision, (r1.status = "active" AND r2.status = "active") AS is_active @@ -336,8 +323,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa query = """ MATCH (account_role:%(account_role_node)s) WHERE account_role.uuid = $role_id - CALL { - WITH account_role + CALL (account_role) { MATCH (account_role)-[r:IS_PART_OF]-(root:Root) WHERE %(branch_filter)s RETURN account_role as account_role1, r as r1 @@ -348,8 +334,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa WHERE r.status = "active" WITH account_role - CALL { - WITH account_role + CALL (account_role) { MATCH (account_role)-[r1:IS_RELATED]->(:Relationship {name: "role__permissions"})<-[r2:IS_RELATED]-(global_permission:%(global_permission_node)s) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) WITH global_permission, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active @@ -360,8 +345,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH global_permission - CALL { - WITH global_permission + CALL (global_permission) { MATCH (global_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[r2:HAS_VALUE]->(global_permission_action:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN global_permission_action, (r1.status = "active" AND r2.status = "active") AS is_active @@ -371,8 +355,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa WITH global_permission, global_permission_action, is_active AS gpa_is_active WHERE gpa_is_active = TRUE - CALL { - WITH global_permission + CALL (global_permission) { MATCH (global_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[r2:HAS_VALUE]->(global_permission_decision:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN global_permission_decision, (r1.status = "active" AND r2.status = "active") AS is_active @@ -425,8 +408,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa query = """ MATCH (account_role:%(account_role_node)s) WHERE account_role.uuid = $role_id - CALL { - WITH account_role + CALL (account_role) { MATCH (account_role)-[r:IS_PART_OF]-(root:Root) WHERE %(branch_filter)s RETURN account_role as account_role1, r as r1 @@ -437,8 +419,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa WHERE r.status = "active" WITH account_role - CALL { - WITH account_role + CALL (account_role) { MATCH (account_role)-[r1:IS_RELATED]->(:Relationship {name: "role__permissions"})<-[r2:IS_RELATED]-(object_permission:%(object_permission_node)s) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) WITH object_permission, r1, r2, (r1.status = "active" AND r2.status = "active") AS is_active @@ -449,8 +430,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH object_permission - CALL { - WITH object_permission + CALL (object_permission) { MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "namespace"})-[r2:HAS_VALUE]->(object_permission_namespace:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN object_permission_namespace, (r1.status = "active" AND r2.status = "active") AS is_active @@ -459,8 +439,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH object_permission, object_permission_namespace, is_active AS opn_is_active WHERE opn_is_active = TRUE - CALL { - WITH object_permission + CALL (object_permission) { MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[r2:HAS_VALUE]->(object_permission_name:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN object_permission_name, (r1.status = "active" AND r2.status = "active") AS is_active @@ -469,8 +448,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH object_permission, object_permission_namespace, object_permission_name, is_active AS opn_is_active WHERE opn_is_active = TRUE - CALL { - WITH object_permission + CALL (object_permission) { MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[r2:HAS_VALUE]->(object_permission_action:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN object_permission_action, (r1.status = "active" AND r2.status = "active") AS is_active @@ -479,8 +457,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH object_permission, object_permission_namespace, object_permission_name, object_permission_action, is_active AS opa_is_active WHERE opa_is_active = TRUE - CALL { - WITH object_permission + CALL (object_permission) { MATCH (object_permission)-[r1:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[r2:HAS_VALUE]->(object_permission_decision:AttributeValue) WHERE all(r IN [r1, r2] WHERE (%(branch_filter)s)) RETURN object_permission_decision, (r1.status = "active" AND r2.status = "active") AS is_active diff --git a/backend/infrahub/core/diff/query/all_conflicts.py b/backend/infrahub/core/diff/query/all_conflicts.py index d933c1af6f..aa09a2b53f 100644 --- a/backend/infrahub/core/diff/query/all_conflicts.py +++ b/backend/infrahub/core/diff/query/all_conflicts.py @@ -37,22 +37,18 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa ($diff_id IS NOT NULL AND root.uuid = $diff_id) OR ($tracking_id IS NOT NULL AND root.tracking_id = $tracking_id AND root.diff_branch = $diff_branch_name) ) -CALL { - WITH root +CALL (root) { MATCH (root)-[:DIFF_HAS_NODE]->(node:DiffNode)-[:DIFF_HAS_CONFLICT]->(node_conflict:DiffConflict) RETURN node.path_identifier AS path_identifier, node_conflict AS conflict UNION - WITH root MATCH (root)-[:DIFF_HAS_NODE]->(node:DiffNode)-[:DIFF_HAS_ATTRIBUTE]->(:DiffAttribute) -[:DIFF_HAS_PROPERTY]->(property:DiffProperty)-[:DIFF_HAS_CONFLICT]->(attr_property_conflict:DiffConflict) RETURN property.path_identifier AS path_identifier, attr_property_conflict AS conflict UNION - WITH root MATCH (root)-[:DIFF_HAS_NODE]->(node:DiffNode)-[:DIFF_HAS_RELATIONSHIP]->(:DiffRelationship) -[:DIFF_HAS_ELEMENT]->(element:DiffRelationshipElement)-[:DIFF_HAS_CONFLICT]->(rel_element_conflict:DiffConflict) RETURN element.path_identifier AS path_identifier, rel_element_conflict AS conflict UNION - WITH root MATCH (root)-[:DIFF_HAS_NODE]->(node:DiffNode)-[:DIFF_HAS_RELATIONSHIP]->(:DiffRelationship) -[:DIFF_HAS_ELEMENT]->(:DiffRelationshipElement)-[:DIFF_HAS_PROPERTY]->(property:DiffProperty) -[:DIFF_HAS_CONFLICT]->(rel_property_conflict:DiffConflict) diff --git a/backend/infrahub/core/diff/query/artifact.py b/backend/infrahub/core/diff/query/artifact.py index bf006e3570..50816f7ff1 100644 --- a/backend/infrahub/core/diff/query/artifact.py +++ b/backend/infrahub/core/diff/query/artifact.py @@ -40,8 +40,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ----------------------- MATCH (source_artifact:%(artifact_kind)s)-[r:IS_PART_OF]->(:Root) WHERE r.branch IN [$source_branch_name, $target_branch_name] -CALL { - WITH source_artifact +CALL (source_artifact) { MATCH (source_artifact)-[r:IS_PART_OF]->(:Root) WHERE %(source_branch_filter)s RETURN r AS root_rel @@ -50,13 +49,11 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } WITH source_artifact, root_rel WHERE root_rel.status = "active" -CALL { - WITH source_artifact +CALL (source_artifact) { // ----------------------- // get the artifact's target node // ----------------------- - CALL { - WITH source_artifact + CALL (source_artifact) { OPTIONAL MATCH (source_artifact)-[rrel1:IS_RELATED]-(rel_node:Relationship)-[rrel2:IS_RELATED]-(target_node:Node) WHERE rel_node.name = $target_rel_identifier AND all(r IN [rrel1, rrel2] WHERE ( %(source_branch_filter)s )) @@ -70,8 +67,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ----------------------- // get the artifact's definition node // ----------------------- - CALL { - WITH source_artifact + CALL (source_artifact) { OPTIONAL MATCH (source_artifact)-[rrel1:IS_RELATED]-(rel_node:Relationship)-[rrel2:IS_RELATED]-(definition_node:Node) WHERE rel_node.name = $definition_rel_identifier AND all(r IN [rrel1, rrel2] WHERE ( %(source_branch_filter)s )) @@ -85,8 +81,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ----------------------- // get the artifact's checksum // ----------------------- - CALL { - WITH source_artifact + CALL (source_artifact) { OPTIONAL MATCH (source_artifact)-[attr_rel:HAS_ATTRIBUTE]->(attr:Attribute)-[value_rel:HAS_VALUE]->(attr_val:AttributeValue) WHERE attr.name = "checksum" AND all(r IN [attr_rel, value_rel] WHERE ( %(source_branch_filter)s )) @@ -100,8 +95,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ----------------------- // get the artifact's storage_id // ----------------------- - CALL { - WITH source_artifact + CALL (source_artifact) { OPTIONAL MATCH (source_artifact)-[attr_rel:HAS_ATTRIBUTE]->(attr:Attribute)-[value_rel:HAS_VALUE]->(attr_val:AttributeValue) WHERE attr.name = "storage_id" AND all(r IN [attr_rel, value_rel] WHERE ( %(source_branch_filter)s )) @@ -137,13 +131,11 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa ELSE NULL END AS source_storage_id } -CALL { +CALL (target_node, definition_node){ // ----------------------- // get the corresponding artifact on the target branch, if it exists // ----------------------- - WITH target_node, definition_node - CALL { - WITH target_node, definition_node + CALL (target_node, definition_node) { OPTIONAL MATCH path = (target_node)-[trel1:IS_RELATED]-(trel_node:Relationship)-[trel2:IS_RELATED]- (target_artifact:%(artifact_kind)s)-[drel1:IS_RELATED]-(drel_node:Relationship)-[drel2:IS_RELATED]-(definition_node) WHERE trel_node.name = $target_rel_identifier @@ -165,8 +157,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ----------------------- // get the artifact's checksum on target branch // ----------------------- - CALL { - WITH target_artifact + CALL (target_artifact) { OPTIONAL MATCH (target_artifact)-[attr_rel:HAS_ATTRIBUTE]->(attr:Attribute)-[value_rel:HAS_VALUE]->(attr_val:AttributeValue) WHERE attr.name = "checksum" AND attr_rel.branch = $target_branch_name @@ -178,8 +169,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ----------------------- // get the artifact's storage_id on target branch // ----------------------- - CALL { - WITH target_artifact + CALL (target_artifact) { OPTIONAL MATCH (target_artifact)-[attr_rel:HAS_ATTRIBUTE]->(attr:Attribute)-[value_rel:HAS_VALUE]->(attr_val:AttributeValue) WHERE attr.name = "storage_id" AND attr_rel.branch = $target_branch_name diff --git a/backend/infrahub/core/diff/query/diff_get.py b/backend/infrahub/core/diff/query/diff_get.py index fd8fd76cba..9fb343cb22 100644 --- a/backend/infrahub/core/diff/query/diff_get.py +++ b/backend/infrahub/core/diff/query/diff_get.py @@ -96,8 +96,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------------- // Retrieve Parents // ------------------------------------- - CALL { - WITH diff_node + CALL (diff_node) { OPTIONAL MATCH parents_path = (diff_node)-[:DIFF_HAS_RELATIONSHIP|DIFF_HAS_NODE*1..%(max_depth)s]->(:DiffNode) RETURN parents_path ORDER BY size(nodes(parents_path)) DESC @@ -112,8 +111,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------------- // Retrieve Attributes // ------------------------------------- - CALL { - WITH diff_node + CALL (diff_node) { OPTIONAL MATCH (diff_node)-[:DIFF_HAS_ATTRIBUTE]->(diff_attribute:DiffAttribute) WITH diff_attribute OPTIONAL MATCH (diff_attribute)-[:DIFF_HAS_PROPERTY]->(diff_attr_property:DiffProperty) @@ -126,8 +124,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------------- // Retrieve Relationships // ------------------------------------- - CALL { - WITH diff_node + CALL (diff_node) { OPTIONAL MATCH (diff_node)-[:DIFF_HAS_RELATIONSHIP]->(diff_relationship:DiffRelationship) WITH diff_relationship OPTIONAL MATCH (diff_relationship)-[:DIFF_HAS_ELEMENT]->(diff_rel_element:DiffRelationshipElement) diff --git a/backend/infrahub/core/diff/query/field_summary.py b/backend/infrahub/core/diff/query/field_summary.py index 667d730fb2..833b657232 100644 --- a/backend/infrahub/core/diff/query/field_summary.py +++ b/backend/infrahub/core/diff/query/field_summary.py @@ -45,8 +45,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa OPTIONAL MATCH (diff_root)-[:DIFF_HAS_NODE]->(n:DiffNode) WHERE n.action <> $unchanged_str WITH DISTINCT n.kind AS kind - CALL { - WITH kind + CALL (kind) { OPTIONAL MATCH (n:DiffNode {kind: kind})-[:DIFF_HAS_ATTRIBUTE]->(a:DiffAttribute) WHERE n.action <> $unchanged_str AND a.action <> $unchanged_str @@ -54,8 +53,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa RETURN collect(attr_name) AS attr_names } WITH kind, attr_names - CALL { - WITH kind + CALL (kind) { OPTIONAL MATCH (n:DiffNode {kind: kind})-[:DIFF_HAS_RELATIONSHIP]->(r:DiffRelationship) WHERE n.action <> $unchanged_str AND r.action <> $unchanged_str diff --git a/backend/infrahub/core/diff/query/merge.py b/backend/infrahub/core/diff/query/merge.py index 1593d99399..cbfa15d42d 100644 --- a/backend/infrahub/core/diff/query/merge.py +++ b/backend/infrahub/core/diff/query/merge.py @@ -39,33 +39,29 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa # ruff: noqa: E501 query = """ UNWIND $node_diff_dicts AS node_diff_map -CALL { - WITH node_diff_map +CALL (node_diff_map) { MATCH (n:Node {uuid: node_diff_map.uuid}) RETURN n } WITH n, node_diff_map -CALL { - WITH n, node_diff_map - WITH n, node_diff_map, CASE +CALL (n, node_diff_map) { + WITH CASE WHEN node_diff_map.action = "ADDED" THEN "active" WHEN node_diff_map.action = "REMOVED" THEN "deleted" ELSE NULL END AS node_rel_status - CALL { + CALL (n, node_diff_map, node_rel_status) { // ------------------------------ // only make IS_PART_OF updates if node is ADDED or REMOVED // ------------------------------ WITH n, node_diff_map, node_rel_status - WITH n, node_diff_map, node_rel_status WHERE node_rel_status IS NOT NULL MATCH (root:Root) // ------------------------------ // set IS_PART_OF.to, optionally, target branch // ------------------------------ WITH root, n, node_rel_status - CALL { - WITH root, n, node_rel_status + CALL (root, n, node_rel_status) { OPTIONAL MATCH (root)<-[target_r_root:IS_PART_OF {branch: $target_branch, status: "active"}]-(n) WHERE node_rel_status = "deleted" AND target_r_root.from <= $at AND target_r_root.to IS NULL @@ -75,13 +71,12 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // create new IS_PART_OF relationship on target_branch // ------------------------------ WITH root, n, node_rel_status - CALL { - WITH root, n, node_rel_status + CALL (root, n, node_rel_status) { OPTIONAL MATCH (root)<-[r_root:IS_PART_OF {branch: $target_branch}]-(n) WHERE r_root.status = node_rel_status AND r_root.from <= $at AND (r_root.to >= $at OR r_root.to IS NULL) - WITH root, r_root, n, node_rel_status + WITH r_root WHERE r_root IS NULL CREATE (root) <-[:IS_PART_OF { branch: $target_branch, branch_level: $branch_level, from: $at, status: node_rel_status }] @@ -90,12 +85,10 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------ // shortcut to delete all attributes and relationships for this node if the node is deleted // ------------------------------ - CALL { - WITH n, node_rel_status + CALL (n, node_rel_status) { WITH n, node_rel_status WHERE node_rel_status = "deleted" - CALL { - WITH n + CALL (n) { OPTIONAL MATCH (n)-[rel1:IS_RELATED]-(:Relationship)-[rel2]-(p) WHERE (p.uuid IS NULL OR n.uuid <> p.uuid) AND rel1.branch = $target_branch @@ -104,7 +97,6 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa AND rel2.status = "active" RETURN rel1, rel2 UNION - WITH n OPTIONAL MATCH (n)-[rel1:HAS_ATTRIBUTE]->(:Attribute)-[rel2]->() WHERE type(rel2) <> "HAS_ATTRIBUTE" AND rel1.branch = $target_branch @@ -113,7 +105,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa AND rel2.status = "active" RETURN rel1, rel2 } - WITH n, rel1, rel2 + WITH rel1, rel2 WHERE rel1.to IS NULL AND rel2.to IS NULL AND rel1.from <= $at @@ -124,10 +116,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // and delete HAS_OWNER and HAS_SOURCE edges to this node if the node is deleted // ------------------------------ WITH n - CALL { - WITH n - CALL { - WITH n + CALL (n) { + CALL (n) { MATCH (n)<-[rel:HAS_OWNER]-() WHERE rel.branch = $target_branch AND rel.status = "active" @@ -147,9 +137,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } } WITH n, node_diff_map - CALL { - WITH n, node_diff_map - WITH n, CASE + CALL (n, node_diff_map) { + WITH CASE WHEN node_diff_map.attributes IS NULL OR node_diff_map.attributes = [] THEN [NULL] ELSE node_diff_map.attributes END AS attribute_maps @@ -157,15 +146,13 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------ // handle updates for attributes under this node // ------------------------------ - CALL { - WITH n, attribute_diff_map - WITH n, attribute_diff_map.name AS attr_name, CASE + CALL (n, attribute_diff_map) { + WITH attribute_diff_map.name AS attr_name, CASE WHEN attribute_diff_map.action = "ADDED" THEN "active" WHEN attribute_diff_map.action = "REMOVED" THEN "deleted" ELSE NULL END AS attr_rel_status - CALL { - WITH n, attr_name + CALL (n, attr_name) { OPTIONAL MATCH (n)-[has_attr:HAS_ATTRIBUTE]->(a:Attribute {name: attr_name}) WHERE has_attr.branch IN [$source_branch, $target_branch] RETURN a @@ -176,8 +163,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------ // set HAS_ATTRIBUTE.to on target branch if necessary // ------------------------------ - CALL { - WITH n, attr_rel_status, a + CALL (n, attr_rel_status, a) { OPTIONAL MATCH (n) -[target_r_attr:HAS_ATTRIBUTE {branch: $target_branch, status: "active"}] ->(a) @@ -189,15 +175,14 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------ // conditionally create new HAS_ATTRIBUTE relationship on target_branch, if necessary // ------------------------------ - CALL { - WITH n, attr_rel_status, a + CALL (n, attr_rel_status, a) { WITH n, attr_rel_status, a WHERE a IS NOT NULL OPTIONAL MATCH (n)-[r_attr:HAS_ATTRIBUTE {branch: $target_branch}]->(a) WHERE r_attr.status = attr_rel_status AND r_attr.from <= $at AND (r_attr.to >= $at OR r_attr.to IS NULL) - WITH n, r_attr, attr_rel_status, a + WITH r_attr WHERE r_attr IS NULL CREATE (n)-[:HAS_ATTRIBUTE { branch: $target_branch, branch_level: $branch_level, from: $at, status: attr_rel_status }]->(a) } @@ -206,15 +191,13 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa RETURN 1 AS done } WITH n, node_diff_map - CALL { - WITH n,node_diff_map + CALL (n, node_diff_map) { UNWIND node_diff_map.relationships AS relationship_diff_map // ------------------------------ // handle updates for relationships under this node // ------------------------------ - CALL { - WITH n, relationship_diff_map - WITH n, relationship_diff_map.peer_id AS rel_peer_id, relationship_diff_map.name AS rel_name, CASE + CALL (n, relationship_diff_map) { + WITH relationship_diff_map.peer_id AS rel_peer_id, relationship_diff_map.name AS rel_name, CASE WHEN relationship_diff_map.action = "ADDED" THEN "active" WHEN relationship_diff_map.action = "REMOVED" THEN "deleted" ELSE NULL @@ -222,8 +205,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------ // determine the directions of each IS_RELATED // ------------------------------ - CALL { - WITH n, rel_name, rel_peer_id, related_rel_status + CALL (n, rel_name, rel_peer_id, related_rel_status) { MATCH (n) -[source_r_rel_1:IS_RELATED] -(r:Relationship {name: rel_name}) @@ -233,7 +215,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa AND source_r_rel_2.branch IN [$source_branch, $target_branch] AND source_r_rel_1.from <= $at AND source_r_rel_1.to IS NULL AND source_r_rel_2.from <= $at AND source_r_rel_2.to IS NULL - WITH n, rel_name, rel_peer_id, related_rel_status, r, source_r_rel_1, source_r_rel_2 + WITH r, source_r_rel_1, source_r_rel_2 ORDER BY source_r_rel_1.branch_level DESC, source_r_rel_2.branch_level DESC, source_r_rel_1.from DESC, source_r_rel_2.from DESC LIMIT 1 RETURN r, CASE @@ -248,8 +230,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa source_r_rel_2.hierarchy AS r2_hierarchy } WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status - CALL { - WITH n, rel_name, rel_peer_id, related_rel_status + CALL (n, rel_name, rel_peer_id, related_rel_status) { OPTIONAL MATCH (n) -[target_r_rel_1:IS_RELATED {branch: $target_branch, status: "active"}] -(:Relationship {name: rel_name}) @@ -265,8 +246,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------ // conditionally create new IS_RELATED relationships on target_branch, if necessary // ------------------------------ - CALL { - WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status + CALL (n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status) { MATCH (p:Node {uuid: rel_peer_id}) OPTIONAL MATCH (n) -[r_rel_1:IS_RELATED {branch: $target_branch, status: related_rel_status}] @@ -277,38 +257,34 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa AND (r_rel_1.to >= $at OR r_rel_1.to IS NULL) AND r_rel_2.from <= $at AND (r_rel_2.to >= $at OR r_rel_2.to IS NULL) - WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, p, related_rel_status, r_rel_1, r_rel_2 + WITH p, r_rel_1, r_rel_2 WHERE r_rel_1 IS NULL AND r_rel_2 IS NULL // ------------------------------ // create IS_RELATED relationships with directions maintained from source // ------------------------------ - CALL { - WITH n, r, r1_dir, r1_hierarchy, related_rel_status + CALL (n, r, r1_dir, r1_hierarchy, related_rel_status) { WITH n, r, r1_dir, r1_hierarchy, related_rel_status WHERE r1_dir = "r" CREATE (n) -[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r1_hierarchy}] ->(r) } - CALL { - WITH n, r, r1_dir, r1_hierarchy, related_rel_status + CALL (n, r, r1_dir, r1_hierarchy, related_rel_status) { WITH n, r, r1_dir, r1_hierarchy, related_rel_status WHERE r1_dir = "l" CREATE (n) <-[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r1_hierarchy}] -(r) } - CALL { - WITH r, p, r2_dir, r2_hierarchy, related_rel_status + CALL (r, p, r2_dir, r2_hierarchy, related_rel_status) { WITH r, p, r2_dir, r2_hierarchy, related_rel_status WHERE r2_dir = "r" CREATE (r) -[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r2_hierarchy}] ->(p) } - CALL { - WITH r, p, r2_dir, r2_hierarchy, related_rel_status + CALL (r, p, r2_dir, r2_hierarchy, related_rel_status) { WITH r, p, r2_dir, r2_hierarchy, related_rel_status WHERE r2_dir = "l" CREATE (r) @@ -352,13 +328,11 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } query = """ UNWIND $property_diff_dicts AS attr_rel_prop_diff -CALL { +CALL (attr_rel_prop_diff) { // ------------------------------ // find the Attribute node // ------------------------------ - WITH attr_rel_prop_diff - CALL { - WITH attr_rel_prop_diff + CALL (attr_rel_prop_diff) { OPTIONAL MATCH (n:Node {uuid: attr_rel_prop_diff.node_uuid}) -[has_attr:HAS_ATTRIBUTE] ->(attr:Attribute {name: attr_rel_prop_diff.attribute_name}) @@ -368,8 +342,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa ORDER BY has_attr.from DESC LIMIT 1 } - CALL { - WITH attr_rel_prop_diff + CALL (attr_rel_prop_diff) { OPTIONAL MATCH (n:Node {uuid: attr_rel_prop_diff.node_uuid}) -[r1:IS_RELATED] -(rel:Relationship {name: attr_rel_prop_diff.relationship_id}) @@ -382,26 +355,23 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa ORDER BY r1.branch_level DESC, r2.branch_level DESC, r1.from DESC, r2.from DESC LIMIT 1 } - WITH attr_rel_prop_diff, COALESCE(attr, rel) AS attr_rel + WITH COALESCE(attr, rel) AS attr_rel UNWIND attr_rel_prop_diff.properties AS property_diff // ------------------------------ // handle updates for properties under this attribute/relationship // ------------------------------ - CALL { - WITH attr_rel, property_diff + CALL (attr_rel, property_diff) { // ------------------------------ // identify the correct property node to link // ------------------------------ - CALL { - WITH attr_rel, property_diff + CALL (attr_rel, property_diff) { OPTIONAL MATCH (peer:Node {uuid: property_diff.value}) WHERE property_diff.property_type IN ["HAS_SOURCE", "HAS_OWNER"] // ------------------------------ // the serialized diff might not include the values for IS_VISIBLE and IS_PROTECTED in // some cases, so we need to figure them out here // ------------------------------ - CALL { - WITH attr_rel, property_diff + CALL (attr_rel, property_diff) { OPTIONAL MATCH (attr_rel)-[r_vis_pro]->(bool:Boolean) WHERE property_diff.property_type IN ["IS_VISIBLE", "IS_PROTECTED"] AND r_vis_pro.branch IN [$source_branch, $target_branch] @@ -411,12 +381,11 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa ORDER BY r_vis_pro.from DESC LIMIT 1 } - CALL { + CALL (attr_rel, property_diff) { // ------------------------------ // get the latest linked AttributeValue on the source b/c there could be multiple // with different is_default values // ------------------------------ - WITH attr_rel, property_diff OPTIONAL MATCH (attr_rel)-[r_attr_val:HAS_VALUE]->(av:AttributeValue) WHERE property_diff.property_type = "HAS_VALUE" AND ( @@ -430,7 +399,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa } RETURN COALESCE (peer, bool, av) AS prop_node } - WITH attr_rel, property_diff.property_type AS prop_type, prop_node, CASE + WITH attr_rel,property_diff.property_type AS prop_type, prop_node, CASE WHEN property_diff.action = "ADDED" THEN "active" WHEN property_diff.action = "REMOVED" THEN "deleted" ELSE NULL @@ -438,8 +407,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------ // set property edge.to, optionally, on target branch // ------------------------------ - CALL { - WITH attr_rel, prop_rel_status, prop_type + CALL (attr_rel, prop_rel_status, prop_type) { OPTIONAL MATCH (attr_rel) -[target_r_prop {branch: $target_branch}] ->() @@ -450,8 +418,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------ // check for existing edge on target_branch // ------------------------------ - CALL { - WITH attr_rel, prop_rel_status, prop_type, prop_node + CALL (attr_rel, prop_rel_status, prop_type, prop_node) { OPTIONAL MATCH (attr_rel)-[r_prop {branch: $target_branch}]->(prop_node) WHERE type(r_prop) = prop_type AND r_prop.status = prop_rel_status @@ -459,38 +426,33 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa AND (r_prop.to > $at OR r_prop.to IS NULL) RETURN r_prop } - WITH attr_rel, prop_rel_status, prop_type, prop_node, r_prop + WITH attr_rel,prop_rel_status, prop_type, prop_node, r_prop WHERE r_prop IS NULL // ------------------------------ // create new edge to prop_node on target_branch, if necessary // one subquery per possible edge type b/c edge type cannot be a variable // ------------------------------ - CALL { - WITH attr_rel, prop_rel_status, prop_type, prop_node + CALL (attr_rel, prop_rel_status, prop_type, prop_node) { WITH attr_rel, prop_rel_status, prop_type, prop_node WHERE prop_type = "HAS_VALUE" CREATE (attr_rel)-[:HAS_VALUE { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node) } - CALL { - WITH attr_rel, prop_rel_status, prop_type, prop_node + CALL (attr_rel, prop_rel_status, prop_type, prop_node) { WITH attr_rel, prop_rel_status, prop_type, prop_node WHERE prop_type = "HAS_SOURCE" CREATE (attr_rel)-[:HAS_SOURCE { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node) } - CALL { - WITH attr_rel, prop_rel_status, prop_type, prop_node + CALL (attr_rel, prop_rel_status, prop_type, prop_node) { WITH attr_rel, prop_rel_status, prop_type, prop_node WHERE prop_type = "HAS_OWNER" CREATE (attr_rel)-[:HAS_OWNER { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node) } - CALL { - WITH attr_rel, prop_rel_status, prop_type, prop_node + CALL (attr_rel, prop_rel_status, prop_type, prop_node) { WITH attr_rel, prop_rel_status, prop_type, prop_node WHERE prop_type = "IS_VISIBLE" CREATE (attr_rel)-[:IS_VISIBLE { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node) } - CALL { - WITH attr_rel, prop_rel_status, prop_type, prop_node + CALL (attr_rel, prop_rel_status, prop_type, prop_node) { WITH attr_rel, prop_rel_status, prop_type, prop_node WHERE prop_type = "IS_PROTECTED" CREATE (attr_rel)-[:IS_PROTECTED { branch: $target_branch, branch_level: $branch_level, from: $at, status: prop_rel_status }]->(prop_node) diff --git a/backend/infrahub/core/diff/query/save.py b/backend/infrahub/core/diff/query/save.py index c03048763a..2cf1dbd12b 100644 --- a/backend/infrahub/core/diff/query/save.py +++ b/backend/infrahub/core/diff/query/save.py @@ -30,8 +30,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa query = """ UNWIND $diff_root_list AS diff_root_map WITH diff_root_map -CALL { - WITH diff_root_map +CALL (diff_root_map) { MERGE (diff_root:DiffRoot {uuid: diff_root_map.uuid}) SET diff_root.base_branch = diff_root_map.base_branch SET diff_root.diff_branch = diff_root_map.diff_branch @@ -43,8 +42,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa WITH DISTINCT diff_root AS diff_root WITH collect(diff_root) AS diff_roots WHERE SIZE(diff_roots) = 2 -CALL { - WITH diff_roots +CALL (diff_roots) { WITH diff_roots[0] AS base_diff_node, diff_roots[1] AS branch_diff_node MERGE (base_diff_node)-[:DIFF_HAS_PARTNER]-(branch_diff_node) SET (base_diff_node).partner_uuid = (branch_diff_node).uuid @@ -96,7 +94,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa diff_node.action = node_map.node_properties.action, diff_node.path_identifier = node_map.node_properties.path_identifier WITH root_uuid, node_map, diff_node, has_node_conflict -CALL { +CALL (diff_node) { // ------------------------- // delete parent-child relationships for included nodes, they will be added in EnrichedNodesLinkQuery // ------------------------- @@ -105,43 +103,38 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa DELETE parent_rel } OPTIONAL MATCH (diff_node)-[:DIFF_HAS_CONFLICT]->(current_node_conflict:DiffConflict) -CALL { +CALL (diff_node, current_node_conflict, has_node_conflict) { // ------------------------- // create a node-level conflict, if necessary // ------------------------- WITH diff_node, current_node_conflict, has_node_conflict - WITH diff_node, current_node_conflict, has_node_conflict WHERE current_node_conflict IS NULL AND has_node_conflict = TRUE CREATE (diff_node)-[:DIFF_HAS_CONFLICT]->(:DiffConflict) } -CALL { +CALL (current_node_conflict, has_node_conflict) { // ------------------------- // delete a node-level conflict, if necessary // ------------------------- WITH current_node_conflict, has_node_conflict - WITH current_node_conflict, has_node_conflict WHERE current_node_conflict IS NOT NULL AND has_node_conflict = FALSE DETACH DELETE current_node_conflict } WITH root_uuid, node_map, diff_node, has_node_conflict, node_map.conflict_params AS node_conflict_params -CALL { +CALL (diff_node, has_node_conflict, node_conflict_params) { // ------------------------- // set the properties of the node-level conflict, if necessary // ------------------------- WITH diff_node, has_node_conflict, node_conflict_params - WITH diff_node, has_node_conflict, node_conflict_params WHERE has_node_conflict = TRUE OPTIONAL MATCH (diff_node)-[:DIFF_HAS_CONFLICT]->(node_conflict:DiffConflict) SET node_conflict = node_conflict_params } -CALL { +CALL (diff_node, node_map) { // ------------------------- // remove stale attributes for this node // ------------------------- - WITH diff_node, node_map - CALL { - WITH diff_node, node_map - WITH diff_node, %(attr_name_list_comp)s AS attr_names + CALL (diff_node, node_map) { + WITH %(attr_name_list_comp)s AS attr_names OPTIONAL MATCH (diff_node)-[:DIFF_HAS_ATTRIBUTE]->(attr_to_delete:DiffAttribute) WHERE NOT (attr_to_delete.name IN attr_names) OPTIONAL MATCH (attr_to_delete)-[*..6]->(next_to_delete) @@ -161,9 +154,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------- // remove stale properties for this attribute // ------------------------- - CALL { - WITH diff_attribute, node_attribute - WITH diff_attribute, %(attr_props_list_comp)s AS prop_types + CALL (diff_attribute, node_attribute) { + WITH %(attr_props_list_comp)s AS prop_types OPTIONAL MATCH (diff_attribute)-[:DIFF_HAS_PROPERTY]->(prop_to_delete:DiffProperty) WHERE NOT (prop_to_delete.property_type IN prop_types) OPTIONAL MATCH (prop_to_delete)-[*..4]->(next_to_delete) @@ -190,9 +182,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------- // remove stale relationships for this node // ------------------------- -CALL { - WITH diff_node, node_map - WITH diff_node, %(rel_name_list_comp)s AS rel_names +CALL (diff_node, node_map) { + WITH %(rel_name_list_comp)s AS rel_names OPTIONAL MATCH (diff_node)-[:DIFF_HAS_RELATIONSHIP]->(rel_to_delete:DiffRelationship) WHERE NOT (rel_to_delete.name IN rel_names) OPTIONAL MATCH (rel_to_delete)-[*..8]->(next_to_delete) @@ -210,9 +201,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // remove stale elements for this relationship group // ------------------------- WITH diff_relationship, node_relationship -CALL { - WITH diff_relationship, node_relationship - WITH diff_relationship, %(rel_peers_list_comp)s AS rel_peers +CALL (diff_relationship, node_relationship) { + WITH %(rel_peers_list_comp)s AS rel_peers OPTIONAL MATCH (diff_relationship)-[:DIFF_HAS_ELEMENT]->(element_to_delete:DiffRelationshipElement) WHERE NOT (element_to_delete.peer_id IN rel_peers) OPTIONAL MATCH (element_to_delete)-[*..6]->(next_to_delete) @@ -245,9 +235,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // remove stale properties for this relationship element // ------------------------- WITH diff_relationship_element, node_single_relationship -CALL { - WITH diff_relationship_element, node_single_relationship - WITH diff_relationship_element, %(element_props_list_comp)s AS element_props +CALL (diff_relationship_element, node_single_relationship) { + WITH %(element_props_list_comp)s AS element_props OPTIONAL MATCH (diff_relationship_element)-[:DIFF_HAS_PROPERTY]->(property_to_delete:DiffProperty) WHERE NOT (property_to_delete.property_type IN element_props) OPTIONAL MATCH (property_to_delete)-[*..4]->(next_to_delete) @@ -447,10 +436,9 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa MATCH (diff_root:DiffRoot {uuid: $root_uuid}) MATCH (diff_root)-[:DIFF_HAS_NODE]->(child_node:DiffNode) WHERE child_node.uuid IN child_node_uuids -CALL { - WITH diff_root, child_node - WITH diff_root, child_node, $parent_node_map[child_node.uuid] AS sub_map - WITH diff_root, child_node, sub_map, keys(sub_map) AS relationship_names +CALL (diff_root, child_node) { + WITH $parent_node_map[child_node.uuid] AS sub_map + WITH sub_map, keys(sub_map) AS relationship_names MATCH (child_node)-[:DIFF_HAS_RELATIONSHIP]->(diff_rel_group:DiffRelationship) WHERE diff_rel_group.name IN relationship_names WITH diff_root, diff_rel_group, toString(sub_map[diff_rel_group.name]) AS parent_uuid diff --git a/backend/infrahub/core/diff/query/summary_counts_enricher.py b/backend/infrahub/core/diff/query/summary_counts_enricher.py index 69863e18fe..6d77182a38 100644 --- a/backend/infrahub/core/diff/query/summary_counts_enricher.py +++ b/backend/infrahub/core/diff/query/summary_counts_enricher.py @@ -46,70 +46,59 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa OR ($tracking_id IS NOT NULL AND root.tracking_id = $tracking_id AND root.diff_branch = $diff_branch_name) MATCH (root)-[:DIFF_HAS_NODE]->(dn:DiffNode) WHERE $node_uuids IS NULL OR dn.uuid IN $node_uuids -CALL { +CALL (dn) { // ---------------------- // handle attribute count updates // ---------------------- - WITH dn MATCH (dn)-[:DIFF_HAS_ATTRIBUTE]->(da:DiffAttribute) - CALL { - WITH da + CALL (da) { OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty)-[:DIFF_HAS_CONFLICT]->(dc:DiffConflict) - WITH da, count(dc) AS num_conflicts + WITH count(dc) AS num_conflicts SET da.num_conflicts = num_conflicts SET da.contains_conflict = (num_conflicts > 0) } - CALL { - WITH da + CALL (da) { OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "added"}) - WITH da, count(dp.action) AS num_added + WITH count(dp.action) AS num_added SET da.num_added = num_added } - CALL { - WITH da + CALL (da) { OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "updated"}) - WITH da, count(dp.action) AS num_updated + WITH count(dp.action) AS num_updated SET da.num_updated = num_updated } - CALL { - WITH da + CALL (da) { OPTIONAL MATCH (da)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "removed"}) - WITH da, count(dp.action) AS num_removed + WITH count(dp.action) AS num_removed SET da.num_removed = num_removed } } -CALL { - WITH dn +CALL (dn) { MATCH (dn)-[:DIFF_HAS_RELATIONSHIP]->(dr:DiffRelationship) - CALL { + CALL (dr) { // ---------------------- // handle relationship element count updates // ---------------------- - WITH dr MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement) - CALL { - WITH dre + CALL (dre) { OPTIONAL MATCH (dre)-[*..4]->(dc:DiffConflict) - WITH dre, count(dc) AS num_conflicts + WITH count(dc) AS num_conflicts SET dre.num_conflicts = num_conflicts SET dre.contains_conflict = (num_conflicts > 0) } - CALL { - WITH dre + CALL (dre) { OPTIONAL MATCH (dre)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "added"}) - WITH dre, count(dp.action) AS num_added + WITH count(dp.action) AS num_added SET dre.num_added = num_added } - CALL { - WITH dre + CALL (dre) { OPTIONAL MATCH (dre)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "updated"}) - WITH dre, count(dp.action) AS num_updated + WITH count(dp.action) AS num_updated SET dre.num_updated = num_updated } - CALL { - WITH dre + CALL (dre) { OPTIONAL MATCH (dre)-[:DIFF_HAS_PROPERTY]->(dp:DiffProperty {action: "removed"}) - WITH dre, count(dp.action) AS num_removed + WITH count(dp.action) AS num_removed SET dre.num_removed = num_removed } } @@ -121,22 +110,19 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa SET dr.num_conflicts = num_conflicts SET dr.contains_conflict = (num_conflicts > 0) WITH dr - CALL { - WITH dr + CALL (dr) { OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement {action: "added"}) - WITH dr, count(dre.action) AS num_added + WITH count(dre.action) AS num_added SET dr.num_added = num_added } - CALL { - WITH dr + CALL (dr) { OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement {action: "updated"}) - WITH dr, count(dre.action) AS num_updated + WITH count(dre.action) AS num_updated SET dr.num_updated = num_updated } - CALL { - WITH dr + CALL (dr) { OPTIONAL MATCH (dr)-[:DIFF_HAS_ELEMENT]->(dre:DiffRelationshipElement {action: "removed"}) - WITH dr, count(dre.action) AS num_removed + WITH count(dre.action) AS num_removed SET dr.num_removed = num_removed } } @@ -189,19 +175,16 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // handle node count updates // ---------------------- WITH root, dn, coalesce(dn.num_conflicts, 0) AS previous_num_conflicts -CALL { +CALL (dn) { // ---------------------- // handle node num_conflicts update // ---------------------- - WITH dn OPTIONAL MATCH (dn)-[:DIFF_HAS_ATTRIBUTE]->(da:DiffAttribute {contains_conflict: TRUE}) RETURN sum(da.num_conflicts) AS num_conflicts UNION ALL - WITH dn OPTIONAL MATCH (dn)-[:DIFF_HAS_RELATIONSHIP]->(dr:DiffRelationship {contains_conflict: TRUE}) RETURN sum(dr.num_conflicts) AS num_conflicts UNION ALL - WITH dn OPTIONAL MATCH (dn)-[:DIFF_HAS_CONFLICT]->(dc:DiffConflict) RETURN count(dc) AS num_conflicts } @@ -209,17 +192,16 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa SET dn.num_conflicts = updated_num_conflicts SET dn.contains_conflict = (updated_num_conflicts > 0) WITH root, dn, updated_num_conflicts - previous_num_conflicts AS num_conflicts_delta -CALL { +CALL (dn) { // ---------------------- // handle node added/updated/removed updates // ---------------------- - WITH dn OPTIONAL MATCH (dn)-[:DIFF_HAS_ATTRIBUTE]->(da:DiffAttribute) - WITH dn, collect(da.action) AS attr_actions + WITH collect(da.action) AS attr_actions OPTIONAL MATCH (dn)-[:DIFF_HAS_RELATIONSHIP]->(dr:DiffRelationship) - WITH dn, attr_actions, collect(dr.action) AS rel_actions - WITH dn, attr_actions + rel_actions AS actions - WITH dn, reduce(counts = [0,0,0], a IN actions | + WITH attr_actions, collect(dr.action) AS rel_actions + WITH attr_actions + rel_actions AS actions + WITH reduce(counts = [0,0,0], a IN actions | CASE WHEN a = "added" THEN [counts[0] + 1, counts[1], counts[2]] WHEN a = "updated" THEN [counts[0], counts[1] + 1, counts[2]] @@ -227,7 +209,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa ELSE counts END ) AS action_counts - WITH dn, action_counts[0] AS num_added, action_counts[1] AS num_updated, action_counts[2] AS num_removed + WITH action_counts[0] AS num_added, action_counts[1] AS num_updated, action_counts[2] AS num_removed SET dn.num_added = num_added SET dn.num_updated = num_updated SET dn.num_removed = num_removed @@ -236,8 +218,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // handle conflict updates for parent nodes // ---------------------- WITH root, dn, num_conflicts_delta -CALL { - WITH dn, num_conflicts_delta +CALL (dn, num_conflicts_delta) { OPTIONAL MATCH (dn)-[:DIFF_HAS_RELATIONSHIP|DIFF_HAS_NODE*1..]->(parent_node:DiffNode) SET parent_node.num_conflicts = parent_node.num_conflicts + num_conflicts_delta SET parent_node.contains_conflict = (parent_node.num_conflicts > 0) @@ -246,8 +227,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // handle root count updates // ---------------------- WITH root, sum(num_conflicts_delta) AS total_conflicts_delta -CALL { - WITH root, total_conflicts_delta +CALL (root, total_conflicts_delta) { SET root.num_conflicts = coalesce(root.num_conflicts, 0) + total_conflicts_delta SET root.contains_conflict = root.num_conflicts > 0 WITH root diff --git a/backend/infrahub/core/migrations/graph/m003_relationship_parent_optional.py b/backend/infrahub/core/migrations/graph/m003_relationship_parent_optional.py index fef6e3e4dd..02638150ee 100644 --- a/backend/infrahub/core/migrations/graph/m003_relationship_parent_optional.py +++ b/backend/infrahub/core/migrations/graph/m003_relationship_parent_optional.py @@ -26,8 +26,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ MATCH path = (av2:AttributeValue)-[:HAS_VALUE]-(:Attribute {name: "optional"})-[:HAS_ATTRIBUTE]-(n:SchemaRelationship)-[:HAS_ATTRIBUTE]-(:Attribute {name: "kind"})-[:HAS_VALUE]-(av1:AttributeValue) WHERE av1.value = "Parent" AND av2.value = true AND all(r IN relationships(path) WHERE ( %(filters)s )) - CALL { - WITH n + CALL (n) { MATCH path22 = (av22:AttributeValue)-[r22:HAS_VALUE]-(a2:Attribute {name: "optional"})-[:HAS_ATTRIBUTE]-(n:SchemaRelationship)-[:HAS_ATTRIBUTE]-(:Attribute {name:"kind"})-[:HAS_VALUE]-(av11:AttributeValue) WHERE av11.value = "Parent" AND av22.value = true AND all(r IN relationships(path22) WHERE ( %(filters)s )) RETURN av22 as av2_sub, r22, a2, path22 as path2 diff --git a/backend/infrahub/core/migrations/graph/m013_convert_git_password_credential.py b/backend/infrahub/core/migrations/graph/m013_convert_git_password_credential.py index 783e88dbba..753d8dc267 100644 --- a/backend/infrahub/core/migrations/graph/m013_convert_git_password_credential.py +++ b/backend/infrahub/core/migrations/graph/m013_convert_git_password_credential.py @@ -98,8 +98,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No // -------------------------------- MATCH (git_repo)-[:HAS_ATTRIBUTE]-(git_attr_name:Attribute)-[:HAS_VALUE]->(git_name_value:AttributeValue) WHERE git_attr_name.name = "name" - CALL { - WITH git_repo + CALL (git_repo) { MATCH path1 = (git_repo)-[r1:HAS_ATTRIBUTE]-(git_attr_name2:Attribute)-[r2:HAS_VALUE]->(git_name_value2:AttributeValue) WHERE git_attr_name2.name = "name" AND all(r IN relationships(path1) WHERE %(filters)s) @@ -204,8 +203,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No WHERE a.name in ["username", "password"] AND av.value = "NULL" AND all(r IN relationships(path) WHERE %(filters)s AND r.status = "active") - CALL { - WITH node + CALL (node) { MATCH (root:Root)<-[r:IS_PART_OF]-(node) WHERE %(filters)s RETURN node as n1, r as r1 diff --git a/backend/infrahub/core/migrations/graph/m019_restore_rels_to_time.py b/backend/infrahub/core/migrations/graph/m019_restore_rels_to_time.py index 7266008c58..307a77193f 100644 --- a/backend/infrahub/core/migrations/graph/m019_restore_rels_to_time.py +++ b/backend/infrahub/core/migrations/graph/m019_restore_rels_to_time.py @@ -97,8 +97,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No // - on deleted edge branch // - or on any branch and deleted node is agnostic // - or deleted node is aware and rel is agnostic - CALL { - WITH rel, deleted_edge + CALL (rel, deleted_edge) { OPTIONAL MATCH (rel)-[peer_active_edge {status: "active"}]-(peer_1) WHERE (peer_active_edge.branch = deleted_edge.branch OR (rel.branch_support <> $branch_agnostic AND deleted_edge.branch = $global_branch)) AND peer_active_edge.to IS NULL @@ -160,62 +159,52 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No // Below CALL subqueries are called once for each rel-peer_2 pair for which we want to create a deleted edge. // Note that with current infrahub relationships edges design, only one of this CALL should be matched per pair. - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)-[:IS_RELATED]->(peer_2) MERGE (rel)-[:IS_RELATED {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]->(peer_2) } - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)-[:IS_PROTECTED]->(peer_2) MERGE (rel)-[:IS_PROTECTED {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]->(peer_2) } - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)-[:IS_VISIBLE]->(peer_2) MERGE (rel)-[:IS_VISIBLE {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]->(peer_2) } - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)-[:HAS_OWNER]->(peer_2) MERGE (rel)-[:HAS_OWNER {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]->(peer_2) } - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)-[:HAS_SOURCE]->(peer_2) MERGE (rel)-[:HAS_SOURCE {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]->(peer_2) } - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)<-[:IS_RELATED]-(peer_2) MERGE (rel)<-[:IS_RELATED {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]-(peer_2) } - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)<-[:IS_PROTECTED]-(peer_2) MERGE (rel)<-[:IS_PROTECTED {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]-(peer_2) } - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)<-[:IS_VISIBLE]-(peer_2) MERGE (rel)<-[:IS_VISIBLE {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]-(peer_2) } - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)<-[:HAS_OWNER]-(peer_2) MERGE (rel)<-[:HAS_OWNER {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]-(peer_2) } - CALL { - WITH rel, peer_2, branch, branch_level, deleted_time + CALL (rel, peer_2, branch, branch_level, deleted_time) { MATCH (rel)<-[:HAS_SOURCE]-(peer_2) MERGE (rel)<-[:HAS_SOURCE {status: "deleted", branch: branch, branch_level: branch_level, from: deleted_time}]-(peer_2) } diff --git a/backend/infrahub/core/migrations/graph/m020_duplicate_edges.py b/backend/infrahub/core/migrations/graph/m020_duplicate_edges.py index 2d89d28f95..57dc11d7ad 100644 --- a/backend/infrahub/core/migrations/graph/m020_duplicate_edges.py +++ b/backend/infrahub/core/migrations/graph/m020_duplicate_edges.py @@ -33,8 +33,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No // ------------------- WITH DISTINCT a, branch, branch_level, status, from, to, attr_val, attr_default WITH attr_val, attr_default, collect([a, branch, branch_level, status, from, to]) AS details_list -CALL { - WITH attr_val, attr_default +CALL (attr_val, attr_default) { MATCH (av:AttributeValue {value: attr_val, is_default: attr_default}) RETURN av AS the_one_av ORDER by %(id_func)s(av) ASC @@ -53,11 +52,10 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No // ------------------- // get the identical edges for a given set of Attribute node, edge properties, AttributeValue.value // ------------------- -CALL { +CALL (a, branch, status, from, to, attr_val, attr_default, e_id_to_keep) { // ------------------- // delete the duplicate edges a given set of Attribute node, edge properties, AttributeValue.value // ------------------- - WITH a, branch, status, from, to, attr_val, attr_default, e_id_to_keep MATCH (a)-[e:HAS_VALUE]->(av:AttributeValue {value: attr_val, is_default: attr_default}) WHERE %(id_func)s(e) <> e_id_to_keep AND e.branch = branch AND e.status = status AND e.from = from @@ -99,8 +97,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No CREATE (a)-[fresh_e:%(edge_type)s {branch: branch, branch_level: branch_level, status: status, from: from}]->(b) SET fresh_e.to = to WITH a, branch, status, from, to, b, %(id_func)s(fresh_e) AS e_id_to_keep -CALL { - WITH a, branch, status, from, to, b, e_id_to_keep +CALL (a, branch, status, from, to, b, e_id_to_keep) { MATCH (a)-[e:%(edge_type)s]->(b) WHERE %(id_func)s(e) <> e_id_to_keep AND e.branch = branch AND e.status = status AND e.from = from diff --git a/backend/infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py b/backend/infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py index e817a9af16..3df08ea117 100644 --- a/backend/infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +++ b/backend/infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py @@ -24,8 +24,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No WITH r.default_branch AS default_branch MATCH (n:Node)-[main_e:IS_RELATED {branch: default_branch}]-(rel:Relationship) WHERE main_e.hierarchy IS NULL - CALL { - WITH n, main_e, rel + CALL (n, main_e, rel) { MATCH (n)-[branch_e:IS_RELATED]-(rel) WHERE branch_e.hierarchy IS NOT NULL AND branch_e.branch <> main_e.branch diff --git a/backend/infrahub/core/migrations/graph/m024_missing_hierarchy_backfill.py b/backend/infrahub/core/migrations/graph/m024_missing_hierarchy_backfill.py index 337cc1bfe6..2ab816a8a9 100644 --- a/backend/infrahub/core/migrations/graph/m024_missing_hierarchy_backfill.py +++ b/backend/infrahub/core/migrations/graph/m024_missing_hierarchy_backfill.py @@ -39,8 +39,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No MATCH (rel:Relationship {name: "parent__child"})-[e:IS_RELATED]-(n:Node) WHERE e.hierarchy IS NULL WITH DISTINCT rel, n, default_branch - CALL { - WITH rel, n, default_branch + CALL (rel, n, default_branch) { MATCH (rel)-[e:IS_RELATED {branch: default_branch}]-(n) RETURN e ORDER BY e.from DESC diff --git a/backend/infrahub/core/migrations/query/attribute_add.py b/backend/infrahub/core/migrations/query/attribute_add.py index 69e1a59bac..1adfe1d580 100644 --- a/backend/infrahub/core/migrations/query/attribute_add.py +++ b/backend/infrahub/core/migrations/query/attribute_add.py @@ -61,8 +61,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No MERGE (is_visible_value:Boolean { value: $is_visible_default }) WITH av, is_protected_value, is_visible_value MATCH p = (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH (root:Root)<-[r1:IS_PART_OF]-(n) OPTIONAL MATCH (n)-[r2:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name }) WHERE all(r in [r1, r2] WHERE (%(branch_filter)s)) diff --git a/backend/infrahub/core/migrations/query/attribute_rename.py b/backend/infrahub/core/migrations/query/attribute_rename.py index 410f12553d..7c326f39f8 100644 --- a/backend/infrahub/core/migrations/query/attribute_rename.py +++ b/backend/infrahub/core/migrations/query/attribute_rename.py @@ -126,8 +126,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No add_uuid = db.render_uuid_generation(node_label="new_attr", node_attr="uuid") query = """ - CALL { - WITH node + CALL (node) { MATCH (root:Root)<-[r:IS_PART_OF]-(node) WHERE %(branch_filter)s RETURN node as n1, r as r1 @@ -137,8 +136,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No WITH n1 as active_node, r1 as rb WHERE rb.status = "active" // Find all the attributes that need to be updated - CALL { - WITH active_node + CALL (active_node) { MATCH (active_node)-[r:HAS_ATTRIBUTE]-(attr:Attribute { name: $prev_attr.name }) WHERE %(branch_filter)s RETURN active_node as n1, r as r1, attr as attr1 @@ -151,8 +149,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No %(add_uuid)s WITH active_attr, new_attr MATCH (active_attr)-[]-(peer) - CALL { - WITH active_attr, peer + CALL (active_attr, peer) { MATCH (active_attr)-[r]-(peer) WHERE %(branch_filter)s RETURN active_attr as a1, r as r1, peer as p1 diff --git a/backend/infrahub/core/migrations/query/delete_element_in_schema.py b/backend/infrahub/core/migrations/query/delete_element_in_schema.py index 7d6d4ea684..089396554d 100644 --- a/backend/infrahub/core/migrations/query/delete_element_in_schema.py +++ b/backend/infrahub/core/migrations/query/delete_element_in_schema.py @@ -116,8 +116,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No # ruff: noqa: E501 query = """ - CALL { - WITH attr_node + CALL (attr_node) { MATCH (root:Root)<-[r:IS_PART_OF]-(attr_node) WHERE %(branch_filter)s RETURN attr_node as n1, r as r1 @@ -130,8 +129,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No // Process Outbound Relationship MATCH (element_to_delete)-[]->(peer) - CALL { - WITH element_to_delete, peer + CALL (element_to_delete, peer) { MATCH (element_to_delete)-[r]->(peer) WHERE %(branch_filter)s RETURN element_to_delete as n1, r as rel_outband1, peer as p1 @@ -150,8 +148,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No WITH DISTINCT(element_to_delete) AS element_to_delete // Process Inbound Relationship MATCH (element_to_delete)<-[]-(peer) - CALL { - WITH element_to_delete, peer + CALL (element_to_delete, peer) { MATCH (element_to_delete)<-[r]-(peer) WHERE %(branch_filter)s RETURN element_to_delete as n1, r as rel_inband1, peer as p1 diff --git a/backend/infrahub/core/migrations/query/node_duplicate.py b/backend/infrahub/core/migrations/query/node_duplicate.py index 8a29abc79e..f192f4c359 100644 --- a/backend/infrahub/core/migrations/query/node_duplicate.py +++ b/backend/infrahub/core/migrations/query/node_duplicate.py @@ -133,8 +133,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No # ruff: noqa: E501 query = """ - CALL { - WITH node + CALL (node) { MATCH (root:Root)<-[r:IS_PART_OF]-(node) WHERE %(branch_filter)s RETURN node as n1, r as r1 @@ -147,8 +146,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No WITH active_node, new_node // Process Outbound Relationship MATCH (active_node)-[]->(peer) - CALL { - WITH active_node, peer + CALL (active_node, peer) { MATCH (active_node)-[r]->(peer) WHERE %(branch_filter)s RETURN active_node as n1, r as rel_outband1, peer as p1 @@ -167,8 +165,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No WITH DISTINCT active_node, new_node // Process Inbound Relationship MATCH (active_node)<-[]-(peer) - CALL { - WITH active_node, peer + CALL (active_node, peer) { MATCH (active_node)<-[r]-(peer) WHERE %(branch_filter)s RETURN active_node as n1, r as rel_inband1, peer as p1 diff --git a/backend/infrahub/core/migrations/query/relationship_duplicate.py b/backend/infrahub/core/migrations/query/relationship_duplicate.py index fa55b9b15e..1c5e686839 100644 --- a/backend/infrahub/core/migrations/query/relationship_duplicate.py +++ b/backend/infrahub/core/migrations/query/relationship_duplicate.py @@ -116,8 +116,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No # ruff: noqa: E501 query = """ - CALL { - WITH source, rel, destination + CALL (source, rel, destination) { MATCH path = (source)-[r1:IS_RELATED]-(rel)-[r2:IS_RELATED]-(destination) WHERE all(r IN relationships(path) WHERE %(branch_filter)s) RETURN rel as rel1, r1 as r11, r2 as r12 @@ -130,8 +129,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No WITH DISTINCT(active_rel) as active_rel, new_rel // Process Inbound Relationship MATCH (active_rel)<-[]-(peer) - CALL { - WITH active_rel, peer + CALL (active_rel, peer) { MATCH (active_rel)<-[r]-(peer) WHERE %(branch_filter)s RETURN active_rel as n1, r as rel_inband1, peer as p1 @@ -150,8 +148,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No WITH DISTINCT(active_rel) as active_rel, new_rel // Process Outbound Relationship MATCH (active_rel)-[]->(peer) - CALL { - WITH active_rel, peer + CALL (active_rel, peer) { MATCH (active_rel)-[r]->(peer) WHERE %(branch_filter)s RETURN active_rel as n1, r as rel_outband1, peer as p1 diff --git a/backend/infrahub/core/migrations/schema/node_attribute_remove.py b/backend/infrahub/core/migrations/schema/node_attribute_remove.py index 206bb9b13a..e320af5e46 100644 --- a/backend/infrahub/core/migrations/schema/node_attribute_remove.py +++ b/backend/infrahub/core/migrations/schema/node_attribute_remove.py @@ -75,8 +75,7 @@ def render_sub_query_per_rel_type(rel_type: str, rel_def: FieldInfo) -> str: MATCH (node:%(node_kind)s) WHERE (size($kinds_to_ignore) = 0 OR NOT any(l IN labels(node) WHERE l IN $kinds_to_ignore)) AND exists((node)-[:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name })) - CALL { - WITH node + CALL (node) { MATCH (root:Root)<-[r:IS_PART_OF]-(node) WHERE %(branch_filter)s RETURN node as n1, r as r1 @@ -86,8 +85,7 @@ def render_sub_query_per_rel_type(rel_type: str, rel_def: FieldInfo) -> str: WITH n1 as active_node, r1 as rb WHERE rb.status = "active" // Find all the attributes that need to be updated - CALL { - WITH active_node + CALL (active_node) { MATCH (active_node)-[r:HAS_ATTRIBUTE]-(attr:Attribute { name: $attr_name }) WHERE %(branch_filter)s RETURN active_node as n1, r as r1, attr as attr1 @@ -98,8 +96,7 @@ def render_sub_query_per_rel_type(rel_type: str, rel_def: FieldInfo) -> str: WHERE rb.status = "active" WITH active_attr MATCH (active_attr)-[]-(peer) - CALL { - WITH active_attr, peer + CALL (active_attr, peer) { MATCH (active_attr)-[r]-(peer) WHERE %(branch_filter)s RETURN active_attr as a1, r as r1, peer as p1 diff --git a/backend/infrahub/core/migrations/schema/node_remove.py b/backend/infrahub/core/migrations/schema/node_remove.py index 9e3ea29ba8..08049b9f12 100644 --- a/backend/infrahub/core/migrations/schema/node_remove.py +++ b/backend/infrahub/core/migrations/schema/node_remove.py @@ -63,8 +63,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ // Find all the active nodes MATCH (node:%(node_kind)s) - CALL { - WITH node + CALL (node) { MATCH (root:Root)<-[r:IS_PART_OF]-(node) WHERE %(branch_filter)s RETURN node as n1, r as r1 @@ -96,8 +95,7 @@ def render_node_remove_query(self, branch_filter: str) -> str: // Process Inbound Relationship WITH active_node MATCH (active_node)<-[]-(peer) - CALL { - WITH active_node, peer + CALL (active_node, peer) { MATCH (active_node)-[r]->(peer) WHERE %(branch_filter)s RETURN active_node as n1, r as rel_inband1, peer as p1 @@ -142,8 +140,7 @@ def render_node_remove_query(self, branch_filter: str) -> str: // Process Outbound Relationship WITH active_node MATCH (active_node)-[]->(peer) - CALL { - WITH active_node, peer + CALL (active_node, peer) { MATCH (active_node)-[r]->(peer) WHERE %(branch_filter)s RETURN active_node as n1, r as rel_outband1, peer as p1 diff --git a/backend/infrahub/core/query/__init__.py b/backend/infrahub/core/query/__init__.py index e606d3db05..f98797a8f6 100644 --- a/backend/infrahub/core/query/__init__.py +++ b/backend/infrahub/core/query/__init__.py @@ -424,8 +424,8 @@ def add_to_query(self, query: str | list[str]) -> None: else: self.query_lines.extend([line.strip() for line in query.split("\n") if line.strip()]) - def add_subquery(self, subquery: str, with_clause: str | None = None) -> None: - self.add_to_query("CALL {") + def add_subquery(self, subquery: str, node_alias: str, with_clause: str | None = None) -> None: + self.add_to_query(f"CALL ({node_alias}) {{") self.add_to_query(subquery) self.add_to_query("}") if with_clause: diff --git a/backend/infrahub/core/query/diff.py b/backend/infrahub/core/query/diff.py index d77d11bf48..1bfe00326b 100644 --- a/backend/infrahub/core/query/diff.py +++ b/backend/infrahub/core/query/diff.py @@ -119,10 +119,9 @@ def __init__( previous_base_path_query = """ WITH DISTINCT diff_path AS diff_path, has_more_data -CALL { - WITH diff_path - WITH diff_path, nodes(diff_path) AS d_nodes, relationships(diff_path) AS d_rels - WITH diff_path, d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop +CALL (diff_path) { + WITH nodes(diff_path) AS d_nodes, relationships(diff_path) AS d_rels + WITH d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop // ------------------------------------- // add base branch paths before branched_from, if they exist // ------------------------------------- @@ -155,10 +154,9 @@ def __init__( WITH diff_path, latest_base_path, has_more_data UNWIND [diff_path, latest_base_path] AS penultimate_path WITH DISTINCT penultimate_path, has_more_data -CALL { - WITH penultimate_path - WITH penultimate_path, nodes(penultimate_path) AS d_nodes, relationships(penultimate_path) AS d_rels - WITH penultimate_path, d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop +CALL (penultimate_path) { + WITH nodes(penultimate_path) AS d_nodes, relationships(penultimate_path) AS d_rels + WITH d_rels[0] AS r_root, d_nodes[1] AS n, d_rels[1] AS r_node, d_nodes[2] AS attr_rel, d_rels[2] AS r_prop // ------------------------------------- // Add peer-side of any relationships to get the peer's ID // ------------------------------------- @@ -289,8 +287,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------------- // Exclude nodes added then removed on branch within timeframe // ------------------------------------- -CALL { - WITH p, q, row_from_time +CALL (p, q, row_from_time) { OPTIONAL MATCH (q)<-[is_part_of:IS_PART_OF {branch: $branch_name}]-(p) WHERE row_from_time <= is_part_of.from < $to_time WITH DISTINCT is_part_of.status AS rel_status @@ -302,8 +299,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------------- // Get every path on this branch under each node // ------------------------------------- -CALL { - WITH p, q, diff_rel, row_from_time +CALL (p, q, diff_rel, row_from_time) { OPTIONAL MATCH path = ( (q)<-[top_diff_rel:IS_PART_OF]-(p)-[r_node]-(node)-[r_prop]-(prop) ) @@ -330,12 +326,11 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa p.uuid IS NULL OR prop.uuid IS NULL OR p.uuid <> prop.uuid OR type(r_node) <> "IS_RELATED" OR type(r_prop) <> "IS_RELATED" ) - WITH path, p, node, prop, r_prop, r_node, type(r_node) AS rel_type, row_from_time + WITH path, node, prop, r_prop, r_node, type(r_node) AS rel_type, row_from_time // ------------------------------------- // Exclude attributes/relationships added then removed on branch within timeframe // ------------------------------------- - CALL { - WITH p, rel_type, node, row_from_time + CALL (p, rel_type, node, row_from_time) { OPTIONAL MATCH (p)-[rel_to_check {branch: $branch_name}]-(node) WHERE row_from_time <= rel_to_check.from < $to_time AND type(rel_to_check) = rel_type @@ -461,8 +456,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // Exclude attributes/relationship under nodes deleted on this branch in the timeframe // because those were all handled above at the node level // ------------------------------------- -CALL { - WITH root, p, row_from_time +CALL (root, p, row_from_time) { OPTIONAL MATCH (root)<-[r_root_deleted:IS_PART_OF {branch: $branch_name}]-(p) WHERE row_from_time <= r_root_deleted.from < $to_time WITH r_root_deleted @@ -476,8 +470,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // Exclude relationships added and deleted within the timeframe // ------------------------------------- WITH root, r_root, p, diff_rel, q, has_more_data, row_from_time, type(diff_rel) AS rel_type -CALL { - WITH p, rel_type, q, row_from_time +CALL (p, rel_type, q, row_from_time) { OPTIONAL MATCH (p)-[rel_to_check {branch: $branch_name}]-(q) WHERE row_from_time <= rel_to_check.from < $to_time AND type(rel_to_check) = rel_type @@ -490,8 +483,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // ------------------------------------- // Get every path on this branch under each attribute/relationship // ------------------------------------- -CALL { - WITH root, r_root, p, diff_rel, q +CALL (root, r_root, p, diff_rel, q) { OPTIONAL MATCH path = ( (root:Root)<-[mid_r_root:IS_PART_OF]-(p)-[mid_diff_rel]-(q)-[r_prop]-(prop) ) @@ -526,8 +518,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa // Exclude properties added and deleted within the timeframe // ------------------------------------- WITH q, nodes(latest_prop_path)[3] AS prop, type(relationships(latest_prop_path)[2]) AS rel_type, latest_prop_path, has_more_data, row_from_time -CALL { - WITH q, rel_type, prop, row_from_time +CALL (q, rel_type, prop, row_from_time) { OPTIONAL MATCH (q)-[rel_to_check {branch: $branch_name}]-(prop) WHERE row_from_time <= rel_to_check.from < $to_time AND type(rel_to_check) = rel_type @@ -681,14 +672,12 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa r_node.from DESC, r_root.from DESC WITH n, p, row_from_time, diff_rel, diff_rel_path, has_more_data -CALL { +CALL (n, p, row_from_time){ // ------------------------------------- // Exclude properties under nodes and attributes/relationships deleted // on this branch in the timeframe because those were all handled above // ------------------------------------- - WITH n, p, row_from_time - CALL { - WITH n, row_from_time + CALL (n, row_from_time) { OPTIONAL MATCH (root:Root)<-[r_root_deleted:IS_PART_OF {branch: $branch_name}]-(n) WHERE row_from_time <= r_root_deleted.from < $to_time WITH r_root_deleted @@ -696,9 +685,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa LIMIT 1 RETURN COALESCE(r_root_deleted.status = "deleted", FALSE) AS node_deleted } - WITH n, p, row_from_time, node_deleted - CALL { - WITH n, p, row_from_time + WITH node_deleted + CALL (n, p, row_from_time) { OPTIONAL MATCH (n)-[r_node_deleted {branch: $branch_name}]-(p) WHERE row_from_time <= r_node_deleted.from < $to_time AND type(r_node_deleted) IN ["HAS_ATTRIBUTE", "IS_RELATED"] diff --git a/backend/infrahub/core/query/ipam.py b/backend/infrahub/core/query/ipam.py index 79f246dfc7..b092f57f66 100644 --- a/backend/infrahub/core/query/ipam.py +++ b/backend/infrahub/core/query/ipam.py @@ -80,8 +80,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG // First match on IPNAMESPACE MATCH (ns:%(ns_label)s) WHERE ns.uuid = $ns_id - CALL { - WITH ns + CALL (ns) { MATCH (ns)-[r:IS_PART_OF]-(root:Root) WHERE %(branch_filter)s RETURN ns as ns1, r as r1 @@ -104,8 +103,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG // --- // FIND ALL CHILDREN OF THESE PREFIXES // --- - CALL { - WITH all_prefixes + CALL (all_prefixes) { UNWIND all_prefixes as prefix OPTIONAL MATCH (prefix)<-[:IS_RELATED]-(ch_rel:Relationship)<-[:IS_RELATED]-(children:BuiltinIPPrefix) WHERE ch_rel.name = "parent__child" @@ -171,8 +169,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG // First match on IPNAMESPACE MATCH (ns:%(ns_label)s) WHERE ns.uuid = $ns_id - CALL { - WITH ns + CALL (ns) { MATCH (ns)-[r:IS_PART_OF]-(root:Root) WHERE %(branch_filter)s RETURN ns as ns1, r as r1 @@ -271,8 +268,7 @@ def rel_filter(rel_name: str) -> str: query = f""" MATCH (pfx:Node) WHERE pfx.uuid IN $ids - CALL {{ - WITH pfx + CALL (pfx) {{ MATCH (pfx)-[r_rel1:IS_RELATED]-(rl:Relationship)<-[r_rel2:IS_RELATED]-(child:Node) WHERE rl.name IN [{", ".join(self.allocated_kinds_rel)}] AND any(l IN labels(child) WHERE l IN [{", ".join(self.allocated_kinds)}]) @@ -424,8 +420,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG // ------------------ // Get prefix node's current parent, if it exists // ------------------ - CALL { - WITH ip_node + CALL (ip_node) { OPTIONAL MATCH parent_prefix_path = (ip_node)-[r1:IS_RELATED]->(:Relationship {name: "parent__child"})-[r2:IS_RELATED]->(current_parent:%(ip_prefix_kind)s) WHERE all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s)) RETURN current_parent, (r1.status = "active" AND r2.status = "active") AS parent_is_active @@ -443,8 +438,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG // ------------------ // Get prefix node's current prefix children, if any exist // ------------------ - CALL { - WITH ip_node + CALL (ip_node) { OPTIONAL MATCH child_prefix_path = (ip_node)<-[r1:IS_RELATED]-(:Relationship {name: "parent__child"})<-[r2:IS_RELATED]-(current_prefix_child:%(ip_prefix_kind)s) WHERE all(r IN relationships(child_prefix_path) WHERE (%(branch_filter)s)) WITH current_prefix_child, (r1.status = "active" AND r2.status = "active") AS is_active @@ -456,8 +450,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG // ------------------ // Get prefix node's current address children, if any exist // ------------------ - CALL { - WITH ip_node + CALL (ip_node) { OPTIONAL MATCH child_address_path = (ip_node)-[r1:IS_RELATED]-(:Relationship {name: "ip_prefix__ip_address"})-[r2:IS_RELATED]-(current_address_child:%(ip_address_kind)s) WHERE all(r IN relationships(child_address_path) WHERE (%(branch_filter)s)) WITH current_address_child, (r1.status = "active" AND r2.status = "active") AS is_active @@ -479,8 +472,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG // ------------------ // Identify the correct parent, if any, for the prefix node // ------------------ - CALL { - WITH ip_namespace + CALL (ip_namespace) { OPTIONAL MATCH parent_path = (ip_namespace)-[pr1:IS_RELATED {status: "active"}]-(ns_rel:Relationship {name: "ip_namespace__ip_prefix"}) -[pr2:IS_RELATED {status: "active"}]-(maybe_new_parent:%(ip_prefix_kind)s) -[har:HAS_ATTRIBUTE]->(:Attribute {name: "prefix"}) @@ -515,9 +507,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG // ------------------ // Identify the correct children, if any, for the prefix node // ------------------ - CALL { + CALL (ip_namespace, ip_node) { // Get ALL possible children for the prefix node - WITH ip_namespace, ip_node OPTIONAL MATCH child_path = ( (ip_namespace)-[r1:IS_RELATED] -(ns_rel:Relationship)-[r2:IS_RELATED] @@ -556,12 +547,11 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG WITH ip_namespace, ip_node, current_parent, current_children, new_parent, collect([maybe_new_child, latest_mnc_attribute]) AS maybe_children_ips WITH ip_namespace, ip_node, current_parent, current_children, new_parent, maybe_children_ips, range(0, size(maybe_children_ips) - 1) AS child_indices UNWIND child_indices as ind - CALL { + CALL (ind, maybe_children_ips) { // ------------------ // Filter all possible children to remove those that have a more-specific parent // among the list of all possible children // ------------------ - WITH ind, maybe_children_ips WITH ind, maybe_children_ips AS ips RETURN REDUCE( has_more_specific_parent = FALSE, potential_parent IN ips | diff --git a/backend/infrahub/core/query/node.py b/backend/infrahub/core/query/node.py index fabcc06a3a..4de7a28598 100644 --- a/backend/infrahub/core/query/node.py +++ b/backend/infrahub/core/query/node.py @@ -206,12 +206,11 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG attrs_query = """ WITH distinct n UNWIND $attrs AS attr - CALL { - WITH n, attr + CALL (n, attr) { CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support }) CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a) MERGE (av:AttributeValue { value: attr.content.value, is_default: attr.content.is_default }) - WITH n, attr, av, a + WITH av, a LIMIT 1 CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av) MERGE (ip:Boolean { value: attr.is_protected }) @@ -231,13 +230,12 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG attrs_iphost_query = """ WITH distinct n UNWIND $attrs_iphost AS attr_iphost - CALL { - WITH n, attr_iphost + CALL (n, attr_iphost) { WITH n, attr_iphost AS attr CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support }) CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a) MERGE (av:AttributeValue:AttributeIPHost { %(iphost_prop)s }) - WITH n, attr, av, a + WITH attr, av, a LIMIT 1 CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av) MERGE (ip:Boolean { value: attr.is_protected }) @@ -258,13 +256,12 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG attrs_ipnetwork_query = """ WITH distinct n UNWIND $attrs_ipnetwork AS attr_ipnetwork - CALL { - WITH n, attr_ipnetwork + CALL (n, attr_ipnetwork) { WITH n, attr_ipnetwork AS attr CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support }) CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a) MERGE (av:AttributeValue:AttributeIPNetwork { %(ipnetwork_prop)s }) - WITH n, attr, av, a + WITH attr, av, a LIMIT 1 CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av) MERGE (ip:Boolean { value: attr.is_protected }) @@ -285,8 +282,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG rels_bidir_query = """ WITH distinct n UNWIND $rels_bidir AS rel - CALL { - WITH n, rel + CALL (n, rel) { MERGE (d:Node { uuid: rel.destination_id }) CREATE (rl:Relationship { uuid: rel.uuid, name: rel.name, branch_support: rel.branch_support }) CREATE (n)-[:IS_RELATED %(rel_prop)s ]->(rl) @@ -309,8 +305,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG rels_out_query = """ WITH distinct n UNWIND $rels_out AS rel_out - CALL { - WITH n, rel_out + CALL (n, rel_out) { WITH n, rel_out as rel MERGE (d:Node { uuid: rel.destination_id }) CREATE (rl:Relationship { uuid: rel.uuid, name: rel.name, branch_support: rel.branch_support }) @@ -334,8 +329,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG rels_in_query = """ WITH distinct n UNWIND $rels_in AS rel_in - CALL { - WITH n, rel_in + CALL (n, rel_in) { WITH n, rel_in AS rel MERGE (d:Node { uuid: rel.destination_id }) CREATE (rl:Relationship { uuid: rel.uuid, name: rel.name, branch_support: rel.branch_support }) @@ -496,8 +490,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG self.add_to_query(query) query = """ - CALL { - WITH n, a + CALL (n, a) { MATCH (n)-[r:HAS_ATTRIBUTE]-(a:Attribute) WHERE %(branch_filter)s RETURN n as n1, r as r1, a as a1 @@ -509,8 +502,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG WITH n, r1, a MATCH (a)-[r:HAS_VALUE]-(av:AttributeValue) WHERE %(branch_filter)s - CALL { - WITH a, av + CALL (a, av) { MATCH (a)-[r:HAS_VALUE]-(av:AttributeValue) WHERE %(branch_filter)s RETURN a as a1, r as r2, av as av1 @@ -758,8 +750,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa query = """ MATCH p = (root:Root)<-[:IS_PART_OF]-(n:Node) WHERE n.uuid IN $ids - CALL { - WITH root, n + CALL (root, n) { MATCH (root:Root)<-[r:IS_PART_OF]-(n:Node) WHERE %(branch_filter)s RETURN n as n1, r as r1 @@ -955,8 +946,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa if not self.branch.is_default: topquery = """ MATCH (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH (root:Root)<-[r:IS_PART_OF]-(n) WHERE %(branch_filter)s RETURN r @@ -1061,7 +1051,7 @@ async def _add_node_filter_attributes( ) filter_params.update(subquery_params) - filter_query.append("CALL {") + filter_query.append("CALL (n) {") filter_query.append(subquery) filter_query.append("}") filter_query.append(f"WITH {with_str}") @@ -1110,7 +1100,7 @@ async def _add_node_order_attributes( with_str = ", ".join(self._get_tracked_variables()) sort_params.update(subquery_params) - sort_query.append("CALL {") + sort_query.append("CALL (n) {") sort_query.append(subquery) sort_query.append("}") sort_query.append(f"WITH {with_str}") @@ -1124,8 +1114,7 @@ async def _add_profiles_per_node_query(self, db: InfrahubDatabase, branch_filter froms_str = db.render_list_comprehension(items="relationships(profile_path)", item_name="from") profiles_per_node_query = ( """ - CALL { - WITH n + CALL (n) { OPTIONAL MATCH profile_path = (n)-[:IS_RELATED]->(profile_r:Relationship)<-[:IS_RELATED]-(maybe_profile_n:Node)-[:IS_PART_OF]->(:Root) WHERE profile_r.name = "node__profile" AND all(r in relationships(profile_path) WHERE %(branch_filter)s) @@ -1143,8 +1132,7 @@ async def _add_profiles_per_node_query(self, db: InfrahubDatabase, branch_filter WITH %(with_str)s, CASE WHEN ordered_is_actives[0] = True THEN maybe_profile_n ELSE NULL END AS profile_n - CALL { - WITH profile_n + CALL (profile_n) { OPTIONAL MATCH profile_priority_path = (profile_n)-[pr1:HAS_ATTRIBUTE]->(a:Attribute)-[pr2:HAS_VALUE]->(av:AttributeValue) WHERE a.name = "profile_priority" AND all(r in relationships(profile_priority_path) WHERE %(branch_filter)s and r.status = "active") @@ -1185,7 +1173,7 @@ async def _add_profile_attributes( self._track_variable(profile_attr.profile_value_query_variable) with_str = ", ".join(self._get_tracked_variables()) - attributes_queries.append("CALL {") + attributes_queries.append("CALL (profile_n) {") attributes_queries.append(subquery) attributes_queries.append("}") attributes_queries.append(f"WITH {with_str}") @@ -1366,13 +1354,11 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa MATCH path = (n:Node { uuid: $uuid } )%(filter)s(peer:Node) WHERE $hierarchy IN LABELS(peer) and all(r IN relationships(path) WHERE (%(branch_filter)s)) WITH n, collect(last(nodes(path))) AS peers_with_duplicates - CALL { - WITH peers_with_duplicates + CALL (peers_with_duplicates) { UNWIND peers_with_duplicates AS pwd RETURN DISTINCT pwd AS peer } - CALL { - WITH n, peer + CALL (n, peer) { MATCH path = (n)%(filter)s(peer) WHERE all(r IN relationships(path) WHERE (%(branch_filter)s)) WITH %(with_clause)s @@ -1432,7 +1418,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa [f"{subquery_result_name} as {label}" if label == "peer" else label for label in self.return_labels] ) - self.add_subquery(subquery=subquery, with_clause=with_str) + self.add_subquery(subquery=subquery, node_alias="peer", with_clause=with_str) # ---------------------------------------------------------------------------- # ORDER Results @@ -1460,7 +1446,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa self.order_by.append(subquery_result_name) self.params.update(subquery_params) - self.add_subquery(subquery=subquery) + self.add_subquery(subquery=subquery, node_alias="peer") order_cnt += 1 else: diff --git a/backend/infrahub/core/query/relationship.py b/backend/infrahub/core/query/relationship.py index f3a26c8a88..61ac4c6862 100644 --- a/backend/infrahub/core/query/relationship.py +++ b/backend/infrahub/core/query/relationship.py @@ -461,8 +461,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG CREATE (s)%(r1)s(rl) CREATE (rl)%(r2)s(d) WITH rl - CALL { - WITH rl + CALL (rl) { MATCH (rl)-[edge:IS_VISIBLE]->(visible) WHERE %(rel_filter)s AND edge.status = "active" WITH rl, edge, visible @@ -473,8 +472,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG WHERE edge.branch = $branch SET edge.to = $at } - CALL { - WITH rl + CALL (rl) { MATCH (rl)-[edge:IS_PROTECTED]->(protected) WHERE %(rel_filter)s AND edge.status = "active" WITH rl, edge, protected @@ -485,8 +483,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG WHERE edge.branch = $branch SET edge.to = $at } - CALL { - WITH rl + CALL (rl) { MATCH (rl)-[edge:HAS_OWNER]->(owner_node) WHERE %(rel_filter)s AND edge.status = "active" WITH rl, edge, owner_node @@ -497,8 +494,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG WHERE edge.branch = $branch SET edge.to = $at } - CALL { - WITH rl + CALL (rl) { MATCH (rl)-[edge:HAS_SOURCE]->(source_node) WHERE %(rel_filter)s AND edge.status = "active" WITH rl, edge, source_node @@ -593,8 +589,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG MATCH (source_node:Node)%(arrow_left_start)s[:IS_RELATED]%(arrow_left_end)s(rl:Relationship { name: $rel_identifier }) WHERE source_node.uuid IN $source_ids WITH DISTINCT source_node, rl - CALL { - WITH rl, source_node + CALL (rl, source_node) { MATCH path = (source_node)%(path)s(peer:Node) WHERE $source_kind IN LABELS(source_node) AND @@ -663,22 +658,19 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG with_str = ", ".join( [f"{subquery_result_name} as {label}" if label == "peer" else label for label in self.return_labels] ) - self.add_subquery(subquery=subquery, with_clause=with_str) - + self.add_subquery(subquery=subquery, node_alias="peer", with_clause=with_str) # ---------------------------------------------------------------------------- # QUERY Properties # ---------------------------------------------------------------------------- query = """ - CALL { - WITH rl + CALL (rl) { MATCH (rl)-[r:IS_VISIBLE]-(is_visible) WHERE %(branch_filter)s RETURN r AS rel_is_visible, is_visible ORDER BY r.branch_level DESC, r.from DESC, r.status ASC LIMIT 1 } - CALL { - WITH rl + CALL (rl) { MATCH (rl)-[r:IS_PROTECTED]-(is_protected) WHERE %(branch_filter)s RETURN r AS rel_is_protected, is_protected @@ -695,8 +687,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG # We must query them one by one otherwise the second one won't return for node_prop in ["source", "owner"]: query = """ - CALL { - WITH rl + CALL (rl) { OPTIONAL MATCH (rl)-[r:HAS_%(node_prop_type)s]-(%(node_prop)s) WHERE %(branch_filter)s RETURN r AS rel_%(node_prop)s, %(node_prop)s @@ -737,7 +728,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG self.order_by.append(subquery_result_name) self.params.update(subquery_params) - self.add_subquery(subquery=subquery) + self.add_subquery(subquery=subquery, node_alias="peer") order_cnt += 1 @@ -870,8 +861,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG query = """ MATCH (rl:Relationship) WHERE rl.name IN $identifiers - CALL { - WITH rl + CALL (rl) { MATCH (src:Node)-[r1:IS_RELATED]-(rl:Relationship)-[r2:IS_RELATED]-(dst:Node) WHERE (size($full_identifiers) = 0 OR [src.kind, rl.name, dst.kind] in $full_identifiers) AND NOT src.namespace IN $excluded_namespaces @@ -934,8 +924,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG query = """ MATCH (peer_node:Node)%(path)s(rl:Relationship { name: $rel_identifier }) WHERE peer_node.uuid IN $peer_ids AND %(branch_filter)s - CALL { - WITH rl + CALL (rl) { MATCH path = (peer_node:Node)%(path)s(rl) WHERE peer_node.uuid IN $peer_ids AND %(branch_filter)s RETURN peer_node as peer, r as r1 @@ -1013,8 +1002,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG for arrow_left, arrow_right in (("<-", "-"), ("-", "->")): for edge_type in edge_types: sub_query = """ - CALL { - WITH rl + CALL (rl) { MATCH (rl)%(arrow_left)s[active_edge:%(edge_type)s]%(arrow_right)s(n) WHERE %(active_rel_filter)s AND active_edge.status ="active" CREATE (rl)%(arrow_left)s[deleted_edge:%(edge_type)s $rel_prop]%(arrow_right)s(n) @@ -1034,8 +1022,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG # We only want to return uuid/kind of `Node` connected through `IS_RELATED` edges. query += """ - CALL { - WITH rl + CALL (rl) { MATCH (rl)-[active_edge:IS_RELATED]->(n) WHERE %(active_rel_filter)s AND active_edge.status ="active" CREATE (rl)-[deleted_edge:IS_RELATED $rel_prop]->(n) @@ -1050,7 +1037,6 @@ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG "outbound" as rel_direction UNION - WITH rl MATCH (rl)<-[active_edge:IS_RELATED]-(n) WHERE %(active_rel_filter)s AND active_edge.status ="active" diff --git a/backend/infrahub/core/query/resource_manager.py b/backend/infrahub/core/query/resource_manager.py index 88d6da77c0..b42297ffd6 100644 --- a/backend/infrahub/core/query/resource_manager.py +++ b/backend/infrahub/core/query/resource_manager.py @@ -220,8 +220,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ MATCH (pool:%(number_pool)s { uuid: $pool_id }) - CALL { - WITH pool + CALL (pool) { MATCH (pool)-[res:IS_RESERVED]->(av:AttributeValue)<-[hv:HAS_VALUE]-(attr:Attribute) WHERE attr.name = $attribute_name diff --git a/backend/infrahub/core/query/subquery.py b/backend/infrahub/core/query/subquery.py index e01268876b..9ea7c9f449 100644 --- a/backend/infrahub/core/query/subquery.py +++ b/backend/infrahub/core/query/subquery.py @@ -61,7 +61,7 @@ async def build_subquery_filter( where_str = " AND ".join(field_where) branch_level_str = "reduce(br_lvl = 0, r in relationships(path) | br_lvl + r.branch_level)" froms_str = db.render_list_comprehension(items="relationships(path)", item_name="from") - to_return = f"{node_alias} AS {prefix}" + to_return = f"{prefix}" with_extra = "" final_with_extra = "" is_isnull = filter_name == "isnull" @@ -82,7 +82,6 @@ async def build_subquery_filter( elif field is not None and field.is_attribute: is_active_filter = "(latest_node_details[2]).value = 'NULL'" query = f""" - WITH {node_alias} {match} path = {filter_str} WHERE {where_str} WITH @@ -94,7 +93,7 @@ async def build_subquery_filter( ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC WITH head(collect([is_active, {node_alias}{with_extra}])) AS latest_node_details WHERE {is_active_filter} - WITH latest_node_details[1] AS {node_alias}{final_with_extra} + WITH latest_node_details[1] AS {prefix}{final_with_extra} RETURN {to_return} """ return query, params, prefix @@ -174,7 +173,6 @@ async def build_subquery_order( to_return_str_parts.append(f"CASE WHEN is_active = TRUE THEN {expression} ELSE NULL END AS {alias}") to_return_str = ", ".join(to_return_str_parts) query = f""" - WITH {node_alias} OPTIONAL MATCH path = {filter_str} WHERE {where_str} WITH {with_str_to_alias} diff --git a/backend/infrahub/core/validators/attribute/choices.py b/backend/infrahub/core/validators/attribute/choices.py index 33291f9005..488b16fe8c 100644 --- a/backend/infrahub/core/validators/attribute/choices.py +++ b/backend/infrahub/core/validators/attribute/choices.py @@ -31,8 +31,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ MATCH p = (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue) WHERE all( r in relationships(path) diff --git a/backend/infrahub/core/validators/attribute/enum.py b/backend/infrahub/core/validators/attribute/enum.py index 61a06a1f49..cc95df5489 100644 --- a/backend/infrahub/core/validators/attribute/enum.py +++ b/backend/infrahub/core/validators/attribute/enum.py @@ -30,8 +30,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No self.params["null_value"] = NULL_VALUE query = """ MATCH (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue) WHERE all( r in relationships(path) diff --git a/backend/infrahub/core/validators/attribute/kind.py b/backend/infrahub/core/validators/attribute/kind.py index 78080d6897..b450b3c4d3 100644 --- a/backend/infrahub/core/validators/attribute/kind.py +++ b/backend/infrahub/core/validators/attribute/kind.py @@ -37,8 +37,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ MATCH p = (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue) WHERE all( r in relationships(path) diff --git a/backend/infrahub/core/validators/attribute/length.py b/backend/infrahub/core/validators/attribute/length.py index 999ad417cb..9765cb36d3 100644 --- a/backend/infrahub/core/validators/attribute/length.py +++ b/backend/infrahub/core/validators/attribute/length.py @@ -28,8 +28,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ MATCH (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue) WHERE all( r in relationships(path) diff --git a/backend/infrahub/core/validators/attribute/optional.py b/backend/infrahub/core/validators/attribute/optional.py index 9ec6685375..5f00425b44 100644 --- a/backend/infrahub/core/validators/attribute/optional.py +++ b/backend/infrahub/core/validators/attribute/optional.py @@ -27,8 +27,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ MATCH (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue) WHERE all( r in relationships(path) diff --git a/backend/infrahub/core/validators/attribute/regex.py b/backend/infrahub/core/validators/attribute/regex.py index 53d762d5b1..8ba760a656 100644 --- a/backend/infrahub/core/validators/attribute/regex.py +++ b/backend/infrahub/core/validators/attribute/regex.py @@ -27,8 +27,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No self.params["null_value"] = NULL_VALUE query = """ MATCH p = (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n)-[ra:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name } )-[rv:HAS_VALUE]-(av:AttributeValue) WHERE all( r in relationships(path) diff --git a/backend/infrahub/core/validators/attribute/unique.py b/backend/infrahub/core/validators/attribute/unique.py index 18a673b372..d43df91a39 100644 --- a/backend/infrahub/core/validators/attribute/unique.py +++ b/backend/infrahub/core/validators/attribute/unique.py @@ -31,12 +31,10 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ MATCH (potential_node:Node) WHERE $node_kind IN LABELS(potential_node) - CALL { - WITH potential_node + CALL (potential_node) { MATCH potential_path = (potential_node)-[:HAS_ATTRIBUTE]-(:Attribute { name: $attr_name })-[potential_value_relationship:HAS_VALUE]-(potential_value:AttributeValue) WHERE all(r IN relationships(potential_path) WHERE (%(branch_filter)s)) WITH - potential_node, potential_value, potential_value_relationship, potential_path, diff --git a/backend/infrahub/core/validators/node/hierarchy.py b/backend/infrahub/core/validators/node/hierarchy.py index 3301072f19..8983f2b023 100644 --- a/backend/infrahub/core/validators/node/hierarchy.py +++ b/backend/infrahub/core/validators/node/hierarchy.py @@ -59,8 +59,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No # ruff: noqa: E501 query = """ MATCH (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rroot:IS_PART_OF]-(n) WHERE all(r in relationships(path) WHERE %(branch_filter)s) RETURN path as full_path, n as active_node @@ -70,8 +69,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No WITH full_path, active_node WITH full_path, active_node WHERE all(r in relationships(full_path) WHERE r.status = "active") - CALL { - WITH active_node + CALL (active_node) { MATCH path = (active_node)%(to_children)s-[hrel1:IS_RELATED]-%(to_parent)s(:Relationship {name: "parent__child"})%(to_children)s-[hrel2:IS_RELATED]-%(to_parent)s(peer:Node) WHERE all( r in relationships(path) @@ -91,8 +89,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No collect([branch_level_sum, from_times, active_relationship_count, hierarchy_path, deepest_branch_name]) as enriched_paths, start_node, peer_node - CALL { - WITH enriched_paths, peer_node + CALL (enriched_paths, peer_node) { UNWIND enriched_paths as path_to_check RETURN path_to_check[3] as current_path, path_to_check[4] as branch_name, peer_node as current_peer ORDER BY diff --git a/backend/infrahub/core/validators/query.py b/backend/infrahub/core/validators/query.py index 5368b342ee..bfe082fb20 100644 --- a/backend/infrahub/core/validators/query.py +++ b/backend/infrahub/core/validators/query.py @@ -20,8 +20,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ MATCH (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rr:IS_PART_OF]-(n) WHERE all( r in relationships(path) @@ -32,7 +31,6 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No LIMIT 1 } WITH full_path, node, root_relationship - WITH full_path, node, root_relationship WHERE all(r in relationships(full_path) WHERE r.status = "active") """ % {"branch_filter": branch_filter, "node_kind": self.node_schema.kind} diff --git a/backend/infrahub/core/validators/relationship/count.py b/backend/infrahub/core/validators/relationship/count.py index 66c7d046b4..99befa5c89 100644 --- a/backend/infrahub/core/validators/relationship/count.py +++ b/backend/infrahub/core/validators/relationship/count.py @@ -50,8 +50,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No query = """ // get the nodes on these branches nodes MATCH (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rroot:IS_PART_OF]-(n) WHERE all(r in relationships(path) WHERE %(branch_filter)s) RETURN path as full_path, n as active_node @@ -60,11 +59,9 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No } // filter to only the active nodes WITH full_path, active_node - WITH full_path, active_node WHERE all(r in relationships(full_path) WHERE r.status = "active") // get the relationships using the given identifier for each node - CALL { - WITH active_node + CALL (active_node) { MATCH path = (active_node)-[rrel1:IS_RELATED]-(rel:Relationship { name: $relationship_id })-[rrel2:IS_RELATED]-(peer:Node) WHERE ($relationship_direction <> "outbound" OR (startNode(rrel1) = active_node AND startNode(rrel2) = rel)) AND ($relationship_direction <> "inbound" OR (startNode(rrel1) = rel AND startNode(rrel2) = peer)) @@ -87,8 +84,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No start_node, peer_node // make sure to only use the latest version of this particular path - CALL { - WITH enriched_paths, peer_node + CALL (enriched_paths, peer_node) { UNWIND enriched_paths as path_to_check RETURN path_to_check[3] as current_path, path_to_check[4] as branch_name, peer_node as current_peer ORDER BY @@ -100,8 +96,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No } // filter to only the current active paths WITH collect([current_peer, current_path]) as peers_and_paths, start_node, branch_name - CALL { - WITH peers_and_paths + CALL (peers_and_paths) { UNWIND peers_and_paths AS peer_and_path WITH peer_and_path WHERE all(r in relationships(peer_and_path[1]) WHERE r.status = "active") @@ -109,9 +104,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No } // sum all the relationships across branches and identify the violators WITH collect([branch_name, num_relationships_on_branch]) as branches_and_counts, start_node - CALL { - WITH start_node, branches_and_counts - WITH start_node, branches_and_counts, reduce(rel_total = 0, bnc in branches_and_counts | rel_total + bnc[1]) AS total_relationships_count + CALL (start_node, branches_and_counts) { + WITH reduce(rel_total = 0, bnc in branches_and_counts | rel_total + bnc[1]) AS total_relationships_count WHERE (toInteger($min_count) IS NOT NULL AND total_relationships_count < toInteger($min_count)) OR (toInteger($max_count) IS NOT NULL AND total_relationships_count > toInteger($max_count)) diff --git a/backend/infrahub/core/validators/relationship/optional.py b/backend/infrahub/core/validators/relationship/optional.py index 48d3ed031e..eb761a2d74 100644 --- a/backend/infrahub/core/validators/relationship/optional.py +++ b/backend/infrahub/core/validators/relationship/optional.py @@ -30,8 +30,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No // Query all Active Nodes of type // and store their UUID in uuids_active_node MATCH (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH (root:Root)<-[r:IS_PART_OF]-(n) WHERE %(branch_filter)s RETURN n as n1, r as r1 @@ -44,8 +43,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No // identifier all nodes with at least one active member for this relationship // and store their UUID in uuids_with_rel MATCH (n:%(node_kind)s) - CALL { - WITH n, uuids_active_node + CALL (n, uuids_active_node) { MATCH path = (n)-[r:IS_RELATED]-(:Relationship { name: $relationship_id }) WHERE %(branch_filter)s RETURN n as n1, r as r1 diff --git a/backend/infrahub/core/validators/relationship/peer.py b/backend/infrahub/core/validators/relationship/peer.py index dd01df2024..94bf12ca13 100644 --- a/backend/infrahub/core/validators/relationship/peer.py +++ b/backend/infrahub/core/validators/relationship/peer.py @@ -36,8 +36,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No # ruff: noqa: E501 query = """ MATCH (n:%(node_kind)s) - CALL { - WITH n + CALL (n) { MATCH path = (root:Root)<-[rroot:IS_PART_OF]-(n) WHERE all(r in relationships(path) WHERE %(branch_filter)s) RETURN path as full_path, n as active_node @@ -45,10 +44,8 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No LIMIT 1 } WITH full_path, active_node - WITH full_path, active_node WHERE all(r in relationships(full_path) WHERE r.status = "active") - CALL { - WITH active_node + CALL (active_node) { MATCH path = (active_node)-[rrel1:IS_RELATED]-(rel:Relationship { name: $relationship_id })-[rrel2:IS_RELATED]-(peer:Node) WHERE all( r in relationships(path) @@ -68,8 +65,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No collect([branch_level_sum, from_times, active_relationship_count, relationship_path, deepest_branch_name]) as enriched_paths, start_node, peer_node - CALL { - WITH enriched_paths, peer_node + CALL (enriched_paths, peer_node) { UNWIND enriched_paths as path_to_check RETURN path_to_check[3] as current_path, path_to_check[4] as branch_name, peer_node as current_peer ORDER BY @@ -80,7 +76,6 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> No LIMIT 1 } WITH start_node, current_peer, branch_name, current_path - WITH start_node, current_peer, branch_name, current_path WHERE all(r in relationships(current_path) WHERE r.status = "active") AND NOT any(label IN LABELS(current_peer) WHERE label IN $allowed_peer_kinds) """ % {"branch_filter": branch_filter, "node_kind": self.node_schema.kind} diff --git a/backend/infrahub/core/validators/uniqueness/query.py b/backend/infrahub/core/validators/uniqueness/query.py index d4f00d1171..248936d42b 100644 --- a/backend/infrahub/core/validators/uniqueness/query.py +++ b/backend/infrahub/core/validators/uniqueness/query.py @@ -137,12 +137,11 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa # ruff: noqa: E501 query = """ // get attributes for node and its relationships - CALL { + CALL () { %(select_subqueries_str)s } - CALL { + CALL (potential_path) { WITH potential_path - WITH potential_path // workaround for neo4j not allowing WHERE in a WITH of a subquery // only the branches and times we care about WHERE all( r IN relationships(potential_path) WHERE ( @@ -162,8 +161,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa start_node, rel_identifier, potential_attr - CALL { - WITH enriched_paths + CALL (enriched_paths) { UNWIND enriched_paths as path_to_check RETURN path_to_check[0] as current_path, path_to_check[4] as latest_value ORDER BY @@ -173,16 +171,14 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa path_to_check[3] DESC LIMIT 1 } - CALL { + CALL (current_path) { // only active paths WITH current_path - WITH current_path // workaround for neo4j not allowing WHERE in a WITH of a subquery WHERE all(r IN relationships(current_path) WHERE r.status = "active") RETURN current_path as active_path } - CALL { + CALL (active_path) { // get deepest branch name - WITH active_path UNWIND %(branch_name_and_level)s as branch_name_and_level RETURN branch_name_and_level[0] as branch_name ORDER BY branch_name_and_level[1] DESC diff --git a/backend/tests/helpers/constants.py b/backend/tests/helpers/constants.py index 5f61e866db..162966ee4b 100644 --- a/backend/tests/helpers/constants.py +++ b/backend/tests/helpers/constants.py @@ -11,6 +11,6 @@ PORT_BOLT_NEO4J = 7687 PORT_MEMGRAPH = 7687 PORT_PREFECT = 4200 -NEO4J_COMMUNITY_IMAGE = "neo4j:5.20.0-community" -NEO4J_ENTERPRISE_IMAGE = "neo4j:5.20.0-enterprise" +NEO4J_COMMUNITY_IMAGE = "neo4j:2025.03.0-community" +NEO4J_ENTERPRISE_IMAGE = "neo4j:2025.03.0-enterprise" NEO4J_IMAGE = os.getenv("NEO4J_DOCKER_IMAGE", NEO4J_ENTERPRISE_IMAGE) diff --git a/backend/tests/integration/schema_lifecycle/test_generic_migrations.py b/backend/tests/integration/schema_lifecycle/test_generic_migrations.py index e1c419057b..55a291ebe7 100644 --- a/backend/tests/integration/schema_lifecycle/test_generic_migrations.py +++ b/backend/tests/integration/schema_lifecycle/test_generic_migrations.py @@ -1200,8 +1200,7 @@ async def _validate_inherited_schema_fields( MATCH (schema_node)-[:IS_RELATED]-(:Relationship {name: "schema__node__relationships"})-[:IS_RELATED]-(:SchemaRelationship) -[:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[:HAS_VALUE]->(rnv:AttributeValue) WITH DISTINCT schema_node, node_kind, rnv -CALL { - WITH schema_node, rnv +CALL (schema_node, rnv) { MATCH path = (schema_node)-[r1:IS_RELATED]-(:Relationship {name: "schema__node__relationships"})-[r2:IS_RELATED]-(:SchemaRelationship) -[r3:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[r4:HAS_VALUE]->(rnv) WHERE all(r IN relationships(path) WHERE %(branch_filter)s) @@ -1216,8 +1215,7 @@ async def _validate_inherited_schema_fields( MATCH (schema_node)-[:IS_RELATED]-(:Relationship {name: "schema__node__attributes"})-[:IS_RELATED]-(:SchemaAttribute) -[:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[:HAS_VALUE]->(anv:AttributeValue) WITH DISTINCT schema_node, node_kind, relationship_names, anv -CALL { - WITH schema_node, anv +CALL (schema_node, anv) { MATCH path = (schema_node)-[r1:IS_RELATED]-(:Relationship {name: "schema__node__attributes"})-[r2:IS_RELATED]-(:SchemaAttribute) -[r3:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[r4:HAS_VALUE]->(anv) WHERE all(r IN relationships(path) WHERE %(branch_filter)s) diff --git a/backend/tests/unit/core/migrations/graph/test_020.py b/backend/tests/unit/core/migrations/graph/test_020.py index 0a7d680c5c..3d2be8c5ab 100644 --- a/backend/tests/unit/core/migrations/graph/test_020.py +++ b/backend/tests/unit/core/migrations/graph/test_020.py @@ -40,10 +40,9 @@ async def test_duplicate_edges_migration(self, db: InfrahubDatabase, car_person_ CREATE (a)-[duplicate_e:HAS_VALUE]->(av) SET duplicate_e = properties(e) WITH a - CALL { - WITH a + CALL (a) { MATCH (a)-[ve:IS_VISIBLE]->(v) - WITH a, ve, v + WITH ve, v LIMIT 1 CREATE (a)-[new_ve:IS_VISIBLE]->(v) SET new_ve = properties(ve) diff --git a/backend/tests/unit/core/test_query_subquery.py b/backend/tests/unit/core/test_query_subquery.py index c97bbbfd86..22fd916215 100644 --- a/backend/tests/unit/core/test_query_subquery.py +++ b/backend/tests/unit/core/test_query_subquery.py @@ -22,7 +22,6 @@ async def test_build_subquery_filter_attribute_text( ) expected_query = """ - WITH n MATCH path = (n)-[:HAS_ATTRIBUTE]-(i:Attribute { name: $filter1_name })-[:HAS_VALUE]-(av:AttributeValue { value: $filter1_value }) WHERE all(r IN relationships(path) WHERE (PLACEHOLDER)) WITH @@ -34,8 +33,8 @@ async def test_build_subquery_filter_attribute_text( ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC WITH head(collect([is_active, n])) AS latest_node_details WHERE latest_node_details[0] = TRUE - WITH latest_node_details[1] AS n - RETURN n AS filter1 + WITH latest_node_details[1] AS filter1 + RETURN filter1 """ % {"froms_var": db.render_list_comprehension(items="relationships(path)", item_name="from")} assert query == expected_query @@ -60,7 +59,6 @@ async def test_build_subquery_filter_attribute_int( ) expected_query = """ - WITH n MATCH path = (n)-[:HAS_ATTRIBUTE]-(i:Attribute { name: $filter2_name })-[:HAS_VALUE]-(av:AttributeValue { value: $filter2_value }) WHERE all(r IN relationships(path) WHERE (PLACEHOLDER)) WITH @@ -72,8 +70,8 @@ async def test_build_subquery_filter_attribute_int( ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC WITH head(collect([is_active, n])) AS latest_node_details WHERE latest_node_details[0] = TRUE - WITH latest_node_details[1] AS n - RETURN n AS filter2 + WITH latest_node_details[1] AS filter2 + RETURN filter2 """ % {"froms_var": db.render_list_comprehension(items="relationships(path)", item_name="from")} assert query == expected_query @@ -98,7 +96,6 @@ async def test_build_subquery_filter_relationship(db: InfrahubDatabase, default_ # ruff: noqa: E501 expected_query = """ - WITH n MATCH path = (n)-[r1:IS_RELATED]->(rl:Relationship { name: $filter1_rel_name })-[r2:IS_RELATED]->(peer:Node)-[:HAS_ATTRIBUTE]-(i:Attribute { name: $filter1_name })-[:HAS_VALUE]-(av:AttributeValue { value: $filter1_value }) WHERE all(r IN relationships(path) WHERE (PLACEHOLDER)) WITH @@ -110,8 +107,8 @@ async def test_build_subquery_filter_relationship(db: InfrahubDatabase, default_ ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC WITH head(collect([is_active, n])) AS latest_node_details WHERE latest_node_details[0] = TRUE - WITH latest_node_details[1] AS n - RETURN n AS filter1 + WITH latest_node_details[1] AS filter1 + RETURN filter1 """ % {"froms_var": db.render_list_comprehension(items="relationships(path)", item_name="from")} assert query == expected_query @@ -140,7 +137,6 @@ async def test_build_subquery_filter_relationship_ids(db: InfrahubDatabase, defa # ruff: noqa: E501 expected_query = """ - WITH n MATCH path = (n)-[r1:IS_RELATED]->(rl:Relationship { name: $filter1_rel_name })-[r2:IS_RELATED]->(peer:Node) WHERE peer.uuid IN $filter1_peer_ids AND all(r IN relationships(path) WHERE (PLACEHOLDER)) WITH @@ -152,8 +148,8 @@ async def test_build_subquery_filter_relationship_ids(db: InfrahubDatabase, defa ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC WITH head(collect([is_active, n])) AS latest_node_details WHERE latest_node_details[0] = TRUE - WITH latest_node_details[1] AS n - RETURN n AS filter1 + WITH latest_node_details[1] AS filter1 + RETURN filter1 """ % {"froms_var": db.render_list_comprehension(items="relationships(path)", item_name="from")} assert query == expected_query @@ -176,7 +172,6 @@ async def test_build_subquery_order_relationship(db: InfrahubDatabase, default_b ) expected_query = """ - WITH n OPTIONAL MATCH path = (n)-[:IS_RELATED]->(:Relationship { name: $order1_rel_name })-[:IS_RELATED]->(:Node)-[:HAS_ATTRIBUTE]-(:Attribute { name: $order1_name })-[:HAS_VALUE]-(last:AttributeValue) WHERE all(r IN relationships(path) WHERE (PLACEHOLDER)) WITH last, reduce(br_lvl = 0, r in relationships(path) | br_lvl + r.branch_level) AS branch_level, %(froms_var)s AS froms, all(r IN relationships(path) WHERE r.status = "active") AS is_active @@ -208,7 +203,6 @@ async def test_build_subquery_filter_attribute_multiple_values( ) expected_query = """ - WITH n MATCH path = (n)-[:HAS_ATTRIBUTE]-(i:Attribute { name: $filter1_name })-[:HAS_VALUE]-(av:AttributeValue) WHERE av.value IN $filter1_value AND all(r IN relationships(path) WHERE (PLACEHOLDER)) WITH @@ -220,8 +214,8 @@ async def test_build_subquery_filter_attribute_multiple_values( ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC WITH head(collect([is_active, n])) AS latest_node_details WHERE latest_node_details[0] = TRUE - WITH latest_node_details[1] AS n - RETURN n AS filter1 + WITH latest_node_details[1] AS filter1 + RETURN filter1 """ % {"froms_var": db.render_list_comprehension(items="relationships(path)", item_name="from")} assert query == expected_query @@ -248,7 +242,6 @@ async def test_build_subquery_filter_relationship_multiple_values( # ruff: noqa: E501 expected_query = """ - WITH n MATCH path = (n)-[r1:IS_RELATED]->(rl:Relationship { name: $filter1_rel_name })-[r2:IS_RELATED]->(peer:Node)-[:HAS_ATTRIBUTE]-(i:Attribute { name: $filter1_name })-[:HAS_VALUE]-(av:AttributeValue) WHERE av.value IN $filter1_value AND all(r IN relationships(path) WHERE (PLACEHOLDER)) WITH @@ -260,8 +253,8 @@ async def test_build_subquery_filter_relationship_multiple_values( ORDER BY branch_level DESC, froms[-1] DESC, froms[-2] DESC WITH head(collect([is_active, n])) AS latest_node_details WHERE latest_node_details[0] = TRUE - WITH latest_node_details[1] AS n - RETURN n AS filter1 + WITH latest_node_details[1] AS filter1 + RETURN filter1 """ % {"froms_var": db.render_list_comprehension(items="relationships(path)", item_name="from")} assert query == expected_query diff --git a/docker-compose.yml b/docker-compose.yml index 4a6f6fe787..474f8042f1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -158,7 +158,7 @@ services: retries: 3 database: - image: ${NEO4J_DOCKER_IMAGE:-neo4j:5.20.0-community} + image: ${NEO4J_DOCKER_IMAGE:-neo4j:2025.03.0-community} restart: unless-stopped environment: NEO4J_AUTH: ${INFRAHUB_DB_USERNAME:-neo4j}/${INFRAHUB_DB_PASSWORD:-admin} diff --git a/python_testcontainers/infrahub_testcontainers/container.py b/python_testcontainers/infrahub_testcontainers/container.py index d033f5013d..5e2e7d5136 100644 --- a/python_testcontainers/infrahub_testcontainers/container.py +++ b/python_testcontainers/infrahub_testcontainers/container.py @@ -28,7 +28,6 @@ class ContainerService: } PROJECT_ENV_VARIABLES: dict[str, str] = { - "NEO4J_DOCKER_IMAGE": "neo4j:5.20.0-community", "MESSAGE_QUEUE_DOCKER_IMAGE": "rabbitmq:3.13.7-management", "CACHE_DOCKER_IMAGE": "redis:7.2.4", "INFRAHUB_TESTING_DOCKER_IMAGE": "registry.opsmill.io/opsmill/infrahub", diff --git a/python_testcontainers/infrahub_testcontainers/docker-compose.test.yml b/python_testcontainers/infrahub_testcontainers/docker-compose.test.yml index 16420379ac..cdebf1324d 100644 --- a/python_testcontainers/infrahub_testcontainers/docker-compose.test.yml +++ b/python_testcontainers/infrahub_testcontainers/docker-compose.test.yml @@ -50,7 +50,7 @@ services: limits: cpus: ${INFRAHUB_TESTING_DB_CPU_LIMIT:-0.0} memory: ${INFRAHUB_TESTING_DB_MEMORY_LIMIT:-0} - image: ${NEO4J_DOCKER_IMAGE:-neo4j:5.20.0-community} + image: ${NEO4J_DOCKER_IMAGE:-neo4j:2025.03.0-community} restart: unless-stopped environment: NEO4J_AUTH: neo4j/admin diff --git a/tasks/shared.py b/tasks/shared.py index 94e09808bd..80e437ba7d 100644 --- a/tasks/shared.py +++ b/tasks/shared.py @@ -41,7 +41,7 @@ class Namespace(str, Enum): DATABASE_DOCKER_IMAGE = os.getenv("DATABASE_DOCKER_IMAGE", None) MEMGRAPH_DOCKER_IMAGE = os.getenv("MEMGRAPH_DOCKER_IMAGE", "memgraph/memgraph-mage:1.19-memgraph-2.19-no-ml") -NEO4J_DOCKER_IMAGE = os.getenv("NEO4J_DOCKER_IMAGE", "neo4j:5.20.0-enterprise") +NEO4J_DOCKER_IMAGE = os.getenv("NEO4J_DOCKER_IMAGE", "neo4j:2025.03.0-enterprise") MESSAGE_QUEUE_DOCKER_IMAGE = os.getenv( "MESSAGE_QUEUE_DOCKER_IMAGE", "rabbitmq:3.13.7-management" if not INFRAHUB_USE_NATS else "nats:2.10.14-alpine", diff --git a/utilities/db_backup/__main__.py b/utilities/db_backup/__main__.py index f1b306bf90..0e68ee5197 100644 --- a/utilities/db_backup/__main__.py +++ b/utilities/db_backup/__main__.py @@ -120,7 +120,7 @@ def __init__( self.keep_helper_container = keep_helper_container self.docker_client = docker.from_env() self.use_host_network = use_host_network - self.neo4j_docker_image = os.getenv("NEO4J_BACKUP_DOCKER_IMAGE", "neo4j:5.20.0-enterprise") + self.neo4j_docker_image = os.getenv("NEO4J_BACKUP_DOCKER_IMAGE", "neo4j:2025.03.0-enterprise") def _print_message(self, message: str, force_print: bool = False, with_timestamp: bool = True) -> None: if self.be_quiet and not force_print: