Skip to content

Commit 8243ddb

Browse files
authored
Merge pull request #249 from networktocode/fix-natural-deletion-order
Fixes natural deletion order flag
2 parents 94b5500 + a5f035a commit 8243ddb

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

diffsync/helpers.py

+3-1
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 not DiffSyncActions.DELETE:
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

+64
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,67 @@ 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+
"""Test child model that reports when its update method is called."""
173+
174+
_modelname = "child"
175+
_identifiers = ("name",)
176+
_attributes = ("attribute",)
177+
178+
name: str
179+
attribute: str
180+
181+
def update(self, attrs):
182+
call_order.append("Update on child")
183+
return super().update(attrs)
184+
185+
class ParentModel(DiffSyncModel):
186+
"""Test parent model."""
187+
188+
_modelname = "parent"
189+
_identifiers = ("name",)
190+
_attributes = ("attribute",)
191+
_children = {"child": "children"}
192+
193+
name: str
194+
attribute: str
195+
children: List[ChildModel] = []
196+
197+
class Adapter(DiffSync):
198+
"""Test adapter."""
199+
200+
top_level = ["parent"]
201+
202+
parent = ParentModel
203+
child = ChildModel
204+
205+
def load(self, is_source=False) -> None:
206+
"""Test load method. Generate a difference with the is_source parameter."""
207+
parent = self.parent(name="Test Parent", attribute="This doesn't change")
208+
parent.model_flags |= DiffSyncModelFlags.NATURAL_DELETION_ORDER
209+
self.add(parent)
210+
if is_source:
211+
child = self.child(name="Test Child", attribute="Attribute from source")
212+
child.model_flags |= DiffSyncModelFlags.NATURAL_DELETION_ORDER
213+
parent.add_child(child)
214+
self.add(child)
215+
else:
216+
child = self.child(name="Test Child", attribute="Attribute from destination")
217+
child.model_flags |= DiffSyncModelFlags.NATURAL_DELETION_ORDER
218+
parent.add_child(child)
219+
self.add(child)
220+
221+
source_adapter = Adapter()
222+
source_adapter.load(is_source=True)
223+
destination_adapter = Adapter()
224+
destination_adapter.load()
225+
226+
source_adapter.sync_to(destination_adapter)
227+
228+
assert "Update on child" in call_order

0 commit comments

Comments
 (0)