Skip to content

fix(backend): make uniqueness constraint query use indexes #6392

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 2, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions backend/infrahub/core/validators/uniqueness/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(
def get_context(self) -> dict[str, str]:
return {"kind": self.query_request.kind}

async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002,PLR0915
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string(), is_isolated=False)
self.params.update(branch_params)
from_times = db.render_list_comprehension(items="relationships(potential_path)", item_name="from")
Expand Down Expand Up @@ -105,16 +105,28 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa
attr_paths_subquery = """
MATCH attr_path = (start_node:%(node_kind)s)-[:HAS_ATTRIBUTE]->(attr:Attribute)-[r:HAS_VALUE]->(attr_value:AttributeValue)
WHERE attr.name in $attribute_names
AND ([attr.name, type(r)] in $attr_paths
OR (attr_value.value in $attr_values AND [attr.name, type(r), attr_value.value] in $attr_paths_with_value))
AND [attr.name, type(r)] in $attr_paths
RETURN start_node, attr_path as potential_path, NULL as rel_identifier, attr.name as potential_attr, attr_value.value as potential_attr_value
""" % {"node_kind": self.query_request.kind}

relationship_attr_paths_with_value_subquery = """
attr_paths_with_value_subquery = """
MATCH attr_path = (start_node:%(node_kind)s)-[:HAS_ATTRIBUTE]->(attr:Attribute)-[r:HAS_VALUE]->(attr_value:AttributeValue)
WHERE attr.name in $attribute_names AND attr_value.value in $attr_values
AND [attr.name, type(r), attr_value.value] in $attr_paths_with_value
RETURN start_node, attr_path as potential_path, NULL as rel_identifier, attr.name as potential_attr, attr_value.value as potential_attr_value
""" % {"node_kind": self.query_request.kind}

relationship_attr_paths_subquery = """
MATCH rel_path = (start_node:%(node_kind)s)-[:IS_RELATED]-(relationship_node:Relationship)-[:IS_RELATED]-(related_n:Node)-[:HAS_ATTRIBUTE]->(rel_attr:Attribute)-[:HAS_VALUE]->(rel_attr_value:AttributeValue)
WHERE relationship_node.name in $relationship_names
AND ([relationship_node.name, rel_attr.name] in $relationship_attr_paths
OR (rel_attr_value.value in $relationship_attr_values AND [relationship_node.name, rel_attr.name, rel_attr_value.value] in $relationship_attr_paths_with_value))
AND [relationship_node.name, rel_attr.name] in $relationship_attr_paths
RETURN start_node, rel_path as potential_path, relationship_node.name as rel_identifier, rel_attr.name as potential_attr, rel_attr_value.value as potential_attr_value
""" % {"node_kind": self.query_request.kind}

relationship_attr_paths_with_value_subquery = """
MATCH rel_path = (start_node:%(node_kind)s)-[:IS_RELATED]-(relationship_node:Relationship)-[:IS_RELATED]-(related_n:Node)-[:HAS_ATTRIBUTE]->(rel_attr:Attribute)-[:HAS_VALUE]->(rel_attr_value:AttributeValue)
WHERE relationship_node.name in $relationship_names AND rel_attr_value.value in $relationship_attr_values
AND [relationship_node.name, rel_attr.name, rel_attr_value.value] in $relationship_attr_paths_with_value
RETURN start_node, rel_path as potential_path, relationship_node.name as rel_identifier, rel_attr.name as potential_attr, rel_attr_value.value as potential_attr_value
""" % {"node_kind": self.query_request.kind}

Expand All @@ -130,9 +142,13 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa
}

select_subqueries = []
if attr_paths or attr_paths_with_value:
if attr_paths:
select_subqueries.append(attr_paths_subquery)
if relationship_attr_paths_with_value or relationship_attr_paths:
if attr_paths_with_value:
select_subqueries.append(attr_paths_with_value_subquery)
if relationship_attr_paths:
select_subqueries.append(relationship_attr_paths_subquery)
if relationship_attr_paths_with_value:
select_subqueries.append(relationship_attr_paths_with_value_subquery)
if relationship_only_attr_paths:
select_subqueries.append(relationship_only_attr_paths_subquery)
Expand Down
Loading