Skip to content

Commit f80fed9

Browse files
committed
truncate delete
1 parent dca51ea commit f80fed9

File tree

1 file changed

+33
-19
lines changed

1 file changed

+33
-19
lines changed

netbox_branching/models/branches.py

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -531,30 +531,43 @@ def _collapse_changes_for_object(changes, logger):
531531
"""
532532
Collapse a list of ObjectChanges for a single object.
533533
Returns: (final_action, merged_data, last_change)
534+
535+
Simplified DELETE logic: If DELETE appears anywhere in the changes,
536+
ignore all other changes and keep only the DELETE.
534537
"""
535538
if not changes:
536539
return None, None, None
537540

538541
# Sort by time (oldest first)
539542
changes = sorted(changes, key=lambda c: c.time)
540543

541-
first_action = changes[0].action
542-
last_action = changes[-1].action
543-
last_change = changes[-1]
544+
# Check if there's a DELETE anywhere in the changes
545+
has_delete = any(c.action == 'delete' for c in changes)
546+
has_create = any(c.action == 'create' for c in changes)
547+
548+
logger.debug(f" Collapsing {len(changes)} changes...")
549+
550+
if has_delete:
551+
if has_create:
552+
# CREATE + DELETE = skip entirely
553+
logger.debug(" -> Action: SKIP (created and deleted in branch)")
554+
return 'skip', None, changes[-1]
555+
else:
556+
# Just DELETE (ignore all other changes like updates)
557+
# Use prechange_data from first ObjectChange (the original state)
558+
logger.debug(f" -> Action: DELETE (keeping only DELETE, ignoring {len(changes) - 1} other changes)")
559+
delete_change = next(c for c in changes if c.action == 'delete')
544560

545-
logger.debug(f" Collapsing {len(changes)} changes: first={first_action}, last={last_action}")
561+
# Copy prechange_data from first change to ensure we have the original state
562+
delete_change.prechange_data = changes[0].prechange_data
546563

547-
# Case 1: Created then deleted -> skip entirely
548-
if first_action == 'create' and last_action == 'delete':
549-
logger.debug(" -> Action: SKIP (created and deleted in branch)")
550-
return 'skip', None, last_change
564+
return 'delete', delete_change.prechange_data, delete_change
551565

552-
# Case 2: Deleted -> just delete (should be only one delete)
553-
if last_action == 'delete':
554-
logger.debug(" -> Action: DELETE")
555-
return 'delete', changes[-1].prechange_data, last_change
566+
# No DELETE - handle CREATE or UPDATEs
567+
first_action = changes[0].action
568+
last_change = changes[-1]
556569

557-
# Case 3: Created (with possible updates) -> single create
570+
# Created (with possible updates) -> single create
558571
if first_action == 'create':
559572
merged_data = {}
560573
for change in changes:
@@ -564,7 +577,7 @@ def _collapse_changes_for_object(changes, logger):
564577
logger.debug(f" -> Action: CREATE (collapsed {len(changes)} changes)")
565578
return 'create', merged_data, last_change
566579

567-
# Case 4: Only updates -> single update
580+
# Only updates -> single update
568581
merged_data = {}
569582
# Start with prechange_data of first change as baseline
570583
if changes[0].prechange_data:
@@ -776,28 +789,29 @@ def _order_collapsed_changes(collapsed_changes, logger):
776789
ordered_keys = Branch._topological_sort_with_cycle_detection(to_process, logger)
777790

778791
# Group by model and refine order within each model
779-
logger.info("Refining order within models (updates before creates)...")
792+
logger.info("Refining order within models (deletes before creates to free unique constraints)...")
780793
by_model = defaultdict(list)
781794
for key in ordered_keys:
782795
collapsed = to_process[key]
783796
by_model[collapsed.model_class].append(collapsed)
784797

785-
# Within each model: updates, then creates, then deletes
798+
# Within each model: updates, then deletes, then creates
799+
# This ensures deletes free up unique constraints (like slugs) before creates claim them
786800
result = []
787801
for model_class, changes in by_model.items():
788802
updates = [c for c in changes if c.final_action == 'update']
789-
creates = [c for c in changes if c.final_action == 'create']
790803
deletes = [c for c in changes if c.final_action == 'delete']
804+
creates = [c for c in changes if c.final_action == 'create']
791805

792806
if updates or creates or deletes:
793807
logger.debug(
794808
f" {model_class.__name__}: {len(updates)} updates, "
795-
f"{len(creates)} creates, {len(deletes)} deletes"
809+
f"{len(deletes)} deletes, {len(creates)} creates"
796810
)
797811

798812
result.extend(updates)
799-
result.extend(creates)
800813
result.extend(deletes)
814+
result.extend(creates)
801815

802816
logger.info(f"Ordering complete: {len(result)} changes to apply")
803817
return result

0 commit comments

Comments
 (0)