Skip to content

Commit 94b35cd

Browse files
authored
add support for merging relationship properties (#4593)
* support relationship properties in merge queries * more tests and finish support for relationship properties
1 parent a846181 commit 94b35cd

File tree

3 files changed

+618
-137
lines changed

3 files changed

+618
-137
lines changed

backend/infrahub/core/diff/merger/serializer.py

Lines changed: 89 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ async def serialize_diff(
104104
attribute_diff, attribute_property_diff = self._serialize_attribute(
105105
attribute_diff=attr_diff, node_uuid=node.uuid, node_kind=node.kind
106106
)
107-
attribute_diffs.append(attribute_diff)
107+
if attribute_diff:
108+
attribute_diffs.append(attribute_diff)
108109
serialized_property_diffs.append(attribute_property_diff)
109110
relationship_diffs = []
110111
for rel_diff in node.relationships:
@@ -113,7 +114,9 @@ async def serialize_diff(
113114
)
114115
for relationship_element_diff in rel_diff.relationships:
115116
element_diffs, relationship_property_diffs = self._serialize_relationship_element(
116-
relationship_diff=relationship_element_diff, relationship_identifier=relationship_identifier
117+
relationship_diff=relationship_element_diff,
118+
relationship_identifier=relationship_identifier,
119+
node_uuid=node.uuid,
117120
)
118121
relationship_diffs.extend(element_diffs)
119122
serialized_property_diffs.extend(relationship_property_diffs)
@@ -153,13 +156,13 @@ def _get_property_actions_and_values(
153156
final_value = self._convert_property_value(
154157
property_type=property_diff.property_type, raw_value=raw_value, value_type=python_value_type
155158
)
156-
if final_value:
159+
if final_value is not None:
157160
actions_and_values.append((action, final_value))
158161
return actions_and_values
159162

160163
def _serialize_attribute(
161164
self, attribute_diff: EnrichedDiffAttribute, node_uuid: str, node_kind: str
162-
) -> tuple[AttributeMergeDict, AttributePropertyMergeDict]:
165+
) -> tuple[AttributeMergeDict | None, AttributePropertyMergeDict]:
163166
prop_dicts: list[PropertyMergeDict] = []
164167
python_type = self._get_property_type_for_attribute_value(
165168
schema_kind=node_kind, attribute_name=attribute_diff.name
@@ -169,38 +172,105 @@ def _serialize_attribute(
169172
property_diff=property_diff, python_value_type=python_type
170173
)
171174
for action, value in actions_and_values:
175+
# we only delete attributes when the whole attribute is deleted
176+
if action is DiffAction.REMOVED and attribute_diff.action is not DiffAction.REMOVED:
177+
continue
172178
prop_dicts.append(
173179
PropertyMergeDict(
174180
property_type=property_diff.property_type.value,
175181
action=self._to_action_str(action=action),
176182
value=value,
177183
)
178184
)
179-
attr_dict = AttributeMergeDict(
180-
name=attribute_diff.name,
181-
action=self._to_action_str(action=attribute_diff.action),
182-
)
185+
attr_dict = None
186+
if attribute_diff.action in (DiffAction.ADDED, DiffAction.REMOVED):
187+
attr_dict = AttributeMergeDict(
188+
name=attribute_diff.name,
189+
action=self._to_action_str(action=attribute_diff.action),
190+
)
183191
attr_prop_dict = AttributePropertyMergeDict(
184192
node_uuid=node_uuid, attribute_name=attribute_diff.name, properties=prop_dicts
185193
)
186194
return attr_dict, attr_prop_dict
187195

188196
def _serialize_relationship_element(
189-
self, relationship_diff: EnrichedDiffSingleRelationship, relationship_identifier: str
197+
self, relationship_diff: EnrichedDiffSingleRelationship, relationship_identifier: str, node_uuid: str
190198
) -> tuple[list[RelationshipMergeDict], list[RelationshipPropertyMergeDict]]:
191199
relationship_dicts = []
200+
# start with default values for IS_VISIBLE and IS_PROTECTED b/c we always want to update them during a merge
201+
added_property_dicts: dict[DatabaseEdgeType, PropertyMergeDict] = {
202+
DatabaseEdgeType.IS_VISIBLE: PropertyMergeDict(
203+
property_type=DatabaseEdgeType.IS_VISIBLE.value,
204+
action=self._to_action_str(DiffAction.ADDED),
205+
value=None,
206+
),
207+
DatabaseEdgeType.IS_PROTECTED: PropertyMergeDict(
208+
property_type=DatabaseEdgeType.IS_PROTECTED.value,
209+
action=self._to_action_str(DiffAction.ADDED),
210+
value=None,
211+
),
212+
}
213+
removed_property_dicts: dict[DatabaseEdgeType, PropertyMergeDict] = {
214+
DatabaseEdgeType.IS_VISIBLE: PropertyMergeDict(
215+
property_type=DatabaseEdgeType.IS_VISIBLE.value,
216+
action=self._to_action_str(DiffAction.REMOVED),
217+
value=None,
218+
),
219+
DatabaseEdgeType.IS_PROTECTED: PropertyMergeDict(
220+
property_type=DatabaseEdgeType.IS_PROTECTED.value,
221+
action=self._to_action_str(DiffAction.REMOVED),
222+
value=None,
223+
),
224+
}
225+
added_peer_id: str | None = None
226+
removed_peer_id: str | None = None
192227
for property_diff in relationship_diff.properties:
193-
if property_diff.property_type is not DatabaseEdgeType.IS_RELATED:
194-
continue
195-
# TODO: next PR will add properties to this method
228+
python_value_type: type = str
229+
if property_diff.property_type in (DatabaseEdgeType.IS_VISIBLE, DatabaseEdgeType.IS_PROTECTED):
230+
python_value_type = bool
196231
actions_and_values = self._get_property_actions_and_values(
197-
property_diff=property_diff, python_value_type=str
232+
property_diff=property_diff, python_value_type=python_value_type
198233
)
199-
200-
for action, value in actions_and_values:
201-
relationship_dicts.append(
202-
RelationshipMergeDict(
203-
peer_id=str(value), name=relationship_identifier, action=self._to_action_str(action=action)
234+
if property_diff.property_type is DatabaseEdgeType.IS_RELATED:
235+
for action, value in actions_and_values:
236+
peer_id = str(value)
237+
if action is DiffAction.ADDED:
238+
added_peer_id = peer_id
239+
elif action is DiffAction.REMOVED:
240+
removed_peer_id = peer_id
241+
relationship_dicts.append(
242+
RelationshipMergeDict(
243+
peer_id=peer_id, name=relationship_identifier, action=self._to_action_str(action=action)
244+
)
204245
)
246+
else:
247+
for action, value in actions_and_values:
248+
property_dict = PropertyMergeDict(
249+
property_type=property_diff.property_type.value,
250+
action=self._to_action_str(action=action),
251+
value=value,
252+
)
253+
if action is DiffAction.ADDED:
254+
added_property_dicts[property_diff.property_type] = property_dict
255+
elif action is DiffAction.REMOVED:
256+
removed_property_dicts[property_diff.property_type] = property_dict
257+
relationship_property_dicts = []
258+
if added_peer_id and added_property_dicts:
259+
relationship_property_dicts.append(
260+
RelationshipPropertyMergeDict(
261+
node_uuid=node_uuid,
262+
relationship_id=relationship_identifier,
263+
peer_uuid=added_peer_id,
264+
properties=list(added_property_dicts.values()),
205265
)
206-
return relationship_dicts, []
266+
)
267+
if removed_peer_id and removed_property_dicts:
268+
relationship_property_dicts.append(
269+
RelationshipPropertyMergeDict(
270+
node_uuid=node_uuid,
271+
relationship_id=relationship_identifier,
272+
peer_uuid=removed_peer_id,
273+
properties=list(removed_property_dicts.values()),
274+
)
275+
)
276+
return relationship_dicts, relationship_property_dicts

0 commit comments

Comments
 (0)