Skip to content

Commit

Permalink
fixes natural deletion order flag
Browse files Browse the repository at this point in the history
Prior to this change, if natural deletion order was set on a parent
model and that model had no changes, children would not be recursed
through.
  • Loading branch information
Kircheneer committed Nov 15, 2023
1 parent 94b5500 commit a5f035a
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
4 changes: 3 additions & 1 deletion diffsync/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,13 @@ def sync_diff_element(self, element: DiffElement, parent_model: Optional["DiffSy
natural_deletion_order = bool(dst_model.model_flags & DiffSyncModelFlags.NATURAL_DELETION_ORDER)
skip_children = bool(dst_model.model_flags & DiffSyncModelFlags.SKIP_CHILDREN_ON_DELETE)

# Recurse through children to delete if we are supposed to delete the current diff element
changed = False
if natural_deletion_order and self.action == DiffSyncActions.DELETE and not skip_children:
for child in element.get_children():
changed |= self.sync_diff_element(child, parent_model=dst_model)

# Sync the current model - this will delete the current model if self.action is DELETE
changed, modified_model = self.sync_model(src_model=src_model, dst_model=dst_model, ids=ids, attrs=attrs)
dst_model = modified_model or dst_model

Expand All @@ -396,7 +398,7 @@ def sync_diff_element(self, element: DiffElement, parent_model: Optional["DiffSy

self.incr_elements_processed()

if not natural_deletion_order:
if not natural_deletion_order or self.action is not DiffSyncActions.DELETE:
for child in element.get_children():
changed |= self.sync_diff_element(child, parent_model=dst_model)

Expand Down
64 changes: 64 additions & 0 deletions tests/unit/test_diffsync_model_flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,67 @@ def load(self):
source.remove(source.get("parent", {"name": "Test-Parent"}), remove_children=True)
source.sync_to(destination)
assert call_order == ["Test-Child", "Test-Parent"]


def test_natural_deletion_order_with_noop_parent():
"""Test whether children are recursed through when natural deletion order is set and the parent has no changes."""
call_order = []

class ChildModel(DiffSyncModel):
"""Test child model that reports when its update method is called."""

_modelname = "child"
_identifiers = ("name",)
_attributes = ("attribute",)

name: str
attribute: str

def update(self, attrs):
call_order.append("Update on child")
return super().update(attrs)

class ParentModel(DiffSyncModel):
"""Test parent model."""

_modelname = "parent"
_identifiers = ("name",)
_attributes = ("attribute",)
_children = {"child": "children"}

name: str
attribute: str
children: List[ChildModel] = []

class Adapter(DiffSync):
"""Test adapter."""

top_level = ["parent"]

parent = ParentModel
child = ChildModel

def load(self, is_source=False) -> None:
"""Test load method. Generate a difference with the is_source parameter."""
parent = self.parent(name="Test Parent", attribute="This doesn't change")
parent.model_flags |= DiffSyncModelFlags.NATURAL_DELETION_ORDER
self.add(parent)
if is_source:
child = self.child(name="Test Child", attribute="Attribute from source")
child.model_flags |= DiffSyncModelFlags.NATURAL_DELETION_ORDER
parent.add_child(child)
self.add(child)
else:
child = self.child(name="Test Child", attribute="Attribute from destination")
child.model_flags |= DiffSyncModelFlags.NATURAL_DELETION_ORDER
parent.add_child(child)
self.add(child)

source_adapter = Adapter()
source_adapter.load(is_source=True)
destination_adapter = Adapter()
destination_adapter.load()

source_adapter.sync_to(destination_adapter)

assert "Update on child" in call_order

0 comments on commit a5f035a

Please sign in to comment.