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

Fixes natural deletion order flag #249

Merged
merged 1 commit into from
Nov 16, 2023
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
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
Loading