Skip to content
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

IFC-585 diff relationship cardinality #4196

Merged
merged 2 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
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
10 changes: 2 additions & 8 deletions backend/infrahub/core/diff/combiner.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from typing import Iterable
from uuid import uuid4

from infrahub.core import registry
from infrahub.core.constants import DiffAction, RelationshipCardinality

from .model.path import (
Expand All @@ -25,7 +24,6 @@ class NodePair:

class DiffCombiner:
def __init__(self) -> None:
self.schema_manager = registry.schema
# {child_uuid: (parent_uuid, parent_rel_name)}
self._child_parent_uuid_map: dict[str, tuple[str, str]] = {}
self._parent_node_uuids: set[str] = set()
Expand Down Expand Up @@ -244,9 +242,7 @@ def _combine_relationships(
self,
earlier_relationships: set[EnrichedDiffRelationship],
later_relationships: set[EnrichedDiffRelationship],
node_kind: str,
) -> set[EnrichedDiffRelationship]:
node_schema = self.schema_manager.get_node_schema(name=node_kind, branch=self.diff_branch_name, duplicate=False)
earlier_rels_by_name = {rel.name: rel for rel in earlier_relationships}
later_rels_by_name = {rel.name: rel for rel in later_relationships}
common_rel_names = set(earlier_rels_by_name.keys()) & set(later_rels_by_name.keys())
Expand All @@ -257,12 +253,10 @@ def _combine_relationships(
copied.nodes = set()
combined_relationships.add(copied)
continue
relationship_schema = node_schema.get_relationship(name=earlier_relationship.name)
is_cardinality_one = relationship_schema.cardinality is RelationshipCardinality.ONE
later_relationship = later_rels_by_name[earlier_relationship.name]
if len(earlier_relationship.relationships) == 0 and len(later_relationship.relationships) == 0:
combined_relationship_elements = set()
elif is_cardinality_one:
elif earlier_relationship.cardinality is RelationshipCardinality.ONE:
combined_relationship_elements = {
self._combine_cardinality_one_relationship_elements(
elements=(earlier_relationship.relationships | later_relationship.relationships)
Expand All @@ -275,6 +269,7 @@ def _combine_relationships(
combined_relationship = EnrichedDiffRelationship(
name=later_relationship.name,
label=later_relationship.label,
cardinality=later_relationship.cardinality,
changed_at=later_relationship.changed_at or earlier_relationship.changed_at,
action=self._combine_actions(earlier=earlier_relationship.action, later=later_relationship.action),
path_identifier=later_relationship.path_identifier,
Expand Down Expand Up @@ -315,7 +310,6 @@ def _combine_nodes(self, node_pairs: list[NodePair]) -> set[EnrichedDiffNode]:
combined_relationships = self._combine_relationships(
earlier_relationships=node_pair.earlier.relationships,
later_relationships=node_pair.later.relationships,
node_kind=node_pair.later.kind,
)
combined_action = self._combine_actions(earlier=node_pair.earlier.action, later=node_pair.later.action)
combined_nodes.add(
Expand Down
2 changes: 2 additions & 0 deletions backend/infrahub/core/diff/enricher/hierarchy.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ async def _enrich_hierarchical_nodes(
parent_kind=ancestor.kind,
parent_label="",
parent_rel_name=parent_rel.name,
parent_rel_cardinality=parent_rel.cardinality,
parent_rel_label=parent_rel.label or "",
)

Expand Down Expand Up @@ -149,6 +150,7 @@ async def _enrich_nodes_with_parent(
parent_kind=peer_parent.peer_kind,
parent_label="",
parent_rel_name=parent_rel.name,
parent_rel_cardinality=parent_rel.cardinality,
parent_rel_label=parent_rel.label or "",
)

Expand Down
33 changes: 7 additions & 26 deletions backend/infrahub/core/diff/model/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from dataclasses import dataclass, field, replace
from enum import Enum
from typing import TYPE_CHECKING, Any, Optional, Self
from typing import TYPE_CHECKING, Any, Optional
from uuid import uuid4

from infrahub.core.constants import DiffAction, RelationshipDirection, RelationshipStatus
from infrahub.core.constants import DiffAction, RelationshipCardinality, RelationshipDirection, RelationshipStatus
from infrahub.core.constants.database import DatabaseEdgeType
from infrahub.core.timestamp import Timestamp

Expand Down Expand Up @@ -193,6 +193,7 @@ def from_calculated_element(cls, calculated_element: DiffSingleRelationship) ->
class EnrichedDiffRelationship(BaseSummary):
name: str
label: str
cardinality: RelationshipCardinality
path_identifier: str = field(default="", kw_only=True)
changed_at: Timestamp | None = field(default=None, kw_only=True)
action: DiffAction
Expand All @@ -219,6 +220,7 @@ def from_calculated_relationship(cls, calculated_relationship: DiffRelationship)
return EnrichedDiffRelationship(
name=calculated_relationship.name,
label="",
cardinality=calculated_relationship.cardinality,
changed_at=calculated_relationship.changed_at,
action=calculated_relationship.action,
relationships={
Expand All @@ -228,22 +230,6 @@ def from_calculated_relationship(cls, calculated_relationship: DiffRelationship)
nodes=set(),
)

@classmethod
def from_graph(cls, node: Neo4jNode) -> Self:
timestamp_str = node.get("changed_at")
return cls(
name=node.get("name"),
label=node.get("label"),
changed_at=Timestamp(timestamp_str) if timestamp_str else None,
action=DiffAction(str(node.get("action"))),
path_identifier=str(node.get("path_identifier")),
num_added=int(node.get("num_added")),
num_conflicts=int(node.get("num_conflicts")),
num_removed=int(node.get("num_removed")),
num_updated=int(node.get("num_updated")),
contains_conflict=str(node.get("contains_conflict")).lower() == "true",
)


@dataclass
class ParentNodeInfo:
Expand Down Expand Up @@ -357,14 +343,6 @@ def from_calculated_node(cls, calculated_node: DiffNode) -> EnrichedDiffNode:
},
)

def add_relationship_from_DiffRelationship(self, diff_rel: Neo4jNode) -> bool:
if self.has_relationship(name=diff_rel.get("name")):
return False

rel = EnrichedDiffRelationship.from_graph(node=diff_rel)
self.relationships.add(rel)
return True


@dataclass
class EnrichedDiffRoot(BaseSummary):
Expand Down Expand Up @@ -423,6 +401,7 @@ def add_parent(
parent_kind: str,
parent_label: str,
parent_rel_name: str,
parent_rel_cardinality: RelationshipCardinality,
parent_rel_label: str = "",
) -> EnrichedDiffNode:
node = self.get_node(node_uuid=node_id)
Expand All @@ -447,6 +426,7 @@ def add_parent(
EnrichedDiffRelationship(
name=parent_rel_name,
label=parent_rel_label,
cardinality=parent_rel_cardinality,
changed_at=None,
action=DiffAction.UNCHANGED,
nodes={parent},
Expand Down Expand Up @@ -516,6 +496,7 @@ class DiffSingleRelationship:
@dataclass
class DiffRelationship:
name: str
cardinality: RelationshipCardinality
changed_at: Timestamp
action: DiffAction
relationships: list[DiffSingleRelationship] = field(default_factory=list)
Expand Down
1 change: 1 addition & 0 deletions backend/infrahub/core/diff/query/save_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ def _build_diff_relationship_params(self, enriched_relationship: EnrichedDiffRel
"node_properties": {
"name": enriched_relationship.name,
"label": enriched_relationship.label,
"cardinality": enriched_relationship.cardinality.value,
"changed_at": enriched_relationship.changed_at.to_string()
if enriched_relationship.changed_at
else None,
Expand Down
6 changes: 5 additions & 1 deletion backend/infrahub/core/diff/query_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,11 @@ def to_diff_relationship(self, from_time: Timestamp) -> DiffRelationship:
):
action = single_relationships[0].action
return DiffRelationship(
name=self.name, changed_at=last_changed_at, action=action, relationships=single_relationships
name=self.name,
changed_at=last_changed_at,
action=action,
relationships=single_relationships,
cardinality=self.cardinality,
)


Expand Down
32 changes: 23 additions & 9 deletions backend/infrahub/core/diff/repository/deserializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from neo4j.graph import Node as Neo4jNode
from neo4j.graph import Path as Neo4jPath

from infrahub.core.constants import DiffAction
from infrahub.core.constants import DiffAction, RelationshipCardinality
from infrahub.core.constants.database import DatabaseEdgeType
from infrahub.core.query import QueryResult
from infrahub.core.timestamp import Timestamp
Expand Down Expand Up @@ -89,15 +89,14 @@ def _deserialize_relationships(
) -> None:
for relationship_result in result.get_nested_node_collection("diff_relationships"):
group_node, element_node, element_conflict, property_node, property_conflict = relationship_result
if group_node is not None and element_node is None and property_node is None:
enriched_node.add_relationship_from_DiffRelationship(diff_rel=group_node)
continue
if group_node is None or element_node is None or property_node is None:
enriched_relationship_group = None
if group_node:
enriched_relationship_group = self._deserialize_diff_relationship_group(
relationship_group_node=group_node, enriched_root=enriched_root, enriched_node=enriched_node
)
if element_node is None or property_node is None or enriched_relationship_group is None:
continue

enriched_relationship_group = self._deserialize_diff_relationship_group(
relationship_group_node=group_node, enriched_root=enriched_root, enriched_node=enriched_node
)
enriched_relationship_element = self._deserialize_diff_relationship_element(
relationship_element_node=element_node,
enriched_relationship_group=enriched_relationship_group,
Expand Down Expand Up @@ -137,6 +136,7 @@ def _deserialize_parents(self, result: QueryResult, enriched_root: EnrichedDiffR
parent_kind=parent.get("kind"),
parent_label=parent.get("label"),
parent_rel_name=rel.get("name"),
parent_rel_cardinality=RelationshipCardinality(rel.get("cardinality")),
parent_rel_label=rel.get("label"),
)
current_node_uuid = parent.get("uuid")
Expand Down Expand Up @@ -232,7 +232,21 @@ def _deserialize_diff_relationship_group(
if rel_key in self._diff_node_rel_group_map:
return self._diff_node_rel_group_map[rel_key]

enriched_relationship = EnrichedDiffRelationship.from_graph(node=relationship_group_node)
timestamp_str = relationship_group_node.get("changed_at")
enriched_relationship = EnrichedDiffRelationship(
name=relationship_group_node.get("name"),
label=relationship_group_node.get("label"),
cardinality=RelationshipCardinality(relationship_group_node.get("cardinality")),
changed_at=Timestamp(timestamp_str) if timestamp_str else None,
action=DiffAction(str(relationship_group_node.get("action"))),
path_identifier=str(relationship_group_node.get("path_identifier")),
num_added=int(relationship_group_node.get("num_added")),
num_conflicts=int(relationship_group_node.get("num_conflicts")),
num_removed=int(relationship_group_node.get("num_removed")),
num_updated=int(relationship_group_node.get("num_updated")),
contains_conflict=str(relationship_group_node.get("contains_conflict")).lower() == "true",
)

self._diff_node_rel_group_map[rel_key] = enriched_relationship
enriched_node.relationships.add(enriched_relationship)
return enriched_relationship
Expand Down
5 changes: 4 additions & 1 deletion backend/infrahub/graphql/queries/diff/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from infrahub_sdk.utils import extract_fields

from infrahub.core import registry
from infrahub.core.constants import DiffAction
from infrahub.core.constants import DiffAction, RelationshipCardinality
from infrahub.core.diff.model.path import NameTrackingId
from infrahub.core.diff.repository.repository import DiffRepository
from infrahub.core.timestamp import Timestamp
Expand All @@ -31,6 +31,7 @@
from infrahub.graphql import GraphqlContext

GrapheneDiffActionEnum = GrapheneEnum.from_enum(DiffAction)
GrapheneCardinalityEnum = GrapheneEnum.from_enum(RelationshipCardinality)


class ConflictDetails(ObjectType):
Expand Down Expand Up @@ -85,6 +86,7 @@ class DiffRelationship(DiffSummaryCounts):
name = String(required=True)
label = String(required=False)
last_changed_at = DateTime(required=False)
cardinality = Field(GrapheneCardinalityEnum, required=True)
status = Field(GrapheneDiffActionEnum, required=True)
path_identifier = String(required=True)
elements = List(DiffSingleRelationship, required=True)
Expand Down Expand Up @@ -220,6 +222,7 @@ def to_diff_relationship(
label=enriched_relationship.label,
last_changed_at=enriched_relationship.changed_at.obj if enriched_relationship.changed_at else None,
status=enriched_relationship.action,
cardinality=enriched_relationship.cardinality,
path_identifier=enriched_relationship.path_identifier,
elements=diff_elements,
contains_conflict=enriched_relationship.contains_conflict,
Expand Down
Loading
Loading