Coverage for backend/django/flowsheetInternals/unitops/services/edit_operations/lifecycle.py: 96%
44 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-07-22 05:22 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-07-22 05:22 +0000
1from __future__ import annotations
3from copy import copy
4from dataclasses import dataclass
6from django.db import models
9@dataclass
10class DeletedProperty:
11 """Property instance retained long enough to emit its post-delete event."""
13 instance: models.Model
16def before_replay_deletions(changes: list[dict]) -> list[DeletedProperty]:
17 """Run pre-delete hooks after validation but before generic row deletion."""
18 from core.auxiliary.models.PropertyInfo import PropertyInfo
19 from core.auxiliary.models.PropertyValue import PropertyValue
20 from core.auxiliary.property_events import property_info_deleting
22 deleted: list[DeletedProperty] = []
23 for change in changes:
24 if change["action"] != "delete":
25 continue
26 queryset = change["spec"].model._base_manager.filter(pk=change["pk"])
27 if change["model"] == "core_auxiliary.propertyinfo":
28 queryset = queryset.select_related("set")
29 elif change["model"] == "core_auxiliary.propertyvalue":
30 queryset = queryset.select_related("property", "property__set")
31 instance = queryset.first()
32 if instance is None: 32 ↛ 33line 32 didn't jump to line 33 because the condition on line 32 was never true
33 continue
34 if isinstance(instance, PropertyInfo):
35 property_info_deleting(instance)
36 # Django clears the primary key on an object passed to delete().
37 # Keep an intact instance for post-delete domain reconciliation.
38 deleted.append(DeletedProperty(copy(instance)))
39 elif isinstance(instance, PropertyValue):
40 # Preserve the cached PropertyInfo because it may be deleted later
41 # in the same aggregate change-set.
42 deleted.append(DeletedProperty(copy(instance)))
43 return deleted
46def after_replay(
47 changes: list[dict],
48 deleted_properties: list[DeletedProperty],
49) -> None:
50 """Reconcile property-owned derived state once restored rows are complete."""
51 from core.auxiliary.models.PropertyInfo import PropertyInfo
52 from core.auxiliary.models.PropertyValue import PropertyValue
53 from core.auxiliary.property_events import (
54 property_info_deleted,
55 property_info_saved,
56 property_value_deleted,
57 property_value_saved,
58 )
60 for deleted in deleted_properties:
61 if isinstance(deleted.instance, PropertyInfo):
62 property_info_deleted(deleted.instance)
63 elif isinstance(deleted.instance, PropertyValue): 63 ↛ 60line 63 didn't jump to line 60 because the condition on line 63 was always true
64 property_value_deleted(deleted.instance)
66 changed_info_ids = {
67 change["pk"]
68 for change in changes
69 if change["model"] == "core_auxiliary.propertyinfo"
70 and change["action"] in {"create", "update"}
71 }
72 changed_value_ids = {
73 change["pk"]
74 for change in changes
75 if change["model"] == "core_auxiliary.propertyvalue"
76 and change["action"] in {"create", "update"}
77 }
78 for property_info in PropertyInfo._base_manager.filter(pk__in=changed_info_ids):
79 property_info_saved(property_info)
80 for property_value in PropertyValue._base_manager.filter(
81 pk__in=changed_value_ids
82 ).select_related("property"):
83 property_value_saved(property_value)