Skip to content

Commit 833ed62

Browse files
author
Leo Kirchner
committed
fixes natural deletion order flag
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.
1 parent 94b5500 commit 833ed62

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

diffsync/helpers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,11 +369,13 @@ def sync_diff_element(self, element: DiffElement, parent_model: Optional["DiffSy
369369
natural_deletion_order = bool(dst_model.model_flags & DiffSyncModelFlags.NATURAL_DELETION_ORDER)
370370
skip_children = bool(dst_model.model_flags & DiffSyncModelFlags.SKIP_CHILDREN_ON_DELETE)
371371

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

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

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

397399
self.incr_elements_processed()
398400

399-
if not natural_deletion_order:
401+
if not natural_deletion_order or self.action is None:
400402
for child in element.get_children():
401403
changed |= self.sync_diff_element(child, parent_model=dst_model)
402404

tests/unit/test_diffsync_model_flags.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,60 @@ def load(self):
162162
source.remove(source.get("parent", {"name": "Test-Parent"}), remove_children=True)
163163
source.sync_to(destination)
164164
assert call_order == ["Test-Child", "Test-Parent"]
165+
166+
167+
def test_natural_deletion_order_with_noop_parent():
168+
"""Test whether children are recursed through when natural deletion order is set and the parent has no changes."""
169+
call_order = []
170+
171+
class ChildModel(DiffSyncModel):
172+
_modelname = "child"
173+
_identifiers = ("name",)
174+
_attributes = ("attribute",)
175+
176+
name: str
177+
attribute: str
178+
179+
def update(self, attrs):
180+
call_order.append("Update on child")
181+
return super().update(attrs)
182+
183+
class ParentModel(DiffSyncModel):
184+
_modelname = "parent"
185+
_identifiers = ("name",)
186+
_attributes = ("attribute",)
187+
_children = {"child": "children"}
188+
189+
name: str
190+
attribute: str
191+
children: List[ChildModel] = []
192+
193+
class Adapter(DiffSync):
194+
top_level = ["parent"]
195+
196+
parent = ParentModel
197+
child = ChildModel
198+
199+
def load(self, is_source=False) -> None:
200+
parent = self.parent(name="Test Parent", attribute="This doesn't change")
201+
parent.model_flags |= DiffSyncModelFlags.NATURAL_DELETION_ORDER
202+
self.add(parent)
203+
if is_source:
204+
child = self.child(name="Test Child", attribute="Attribute from source")
205+
child.model_flags |= DiffSyncModelFlags.NATURAL_DELETION_ORDER
206+
parent.add_child(child)
207+
self.add(child)
208+
else:
209+
child = self.child(name="Test Child", attribute="Attribute from destination")
210+
child.model_flags |= DiffSyncModelFlags.NATURAL_DELETION_ORDER
211+
parent.add_child(child)
212+
self.add(child)
213+
214+
source_adapter = Adapter()
215+
source_adapter.load(is_source=True)
216+
destination_adapter = Adapter()
217+
destination_adapter.load()
218+
219+
source_adapter.sync_to(destination_adapter)
220+
221+
assert "Update on child" in call_order

0 commit comments

Comments
 (0)