Validate and mutate without yielding; restore both tables on any failure.
This operation joins an active transaction on its owner task. Otherwise its
shared lock covers backend graph writers only, so it is not yet a public
full-pass contract.
Source code in src/symfonic/memory/backends/in_memory_bulk_apply.py
| def apply(store: Any, scope: StorageScope, plan: BulkDedupPlan) -> int:
"""Validate and mutate without yielding; restore both tables on any failure.
This operation joins an active transaction on its owner task. Otherwise its
shared lock covers backend graph writers only, so it is not yet a public
full-pass contract.
"""
from symfonic.core.scope import TenantScope
from symfonic.memory.janitor_bulk_plan import BulkDedupPlan
if not isinstance(scope, TenantScope) or not isinstance(plan, BulkDedupPlan):
raise TypeError("Legacy TenantScope and BulkDedupPlan required")
_validate(store, scope, plan)
tenant = scope.tenant_id
original_nodes = dict(store._nodes.get(tenant, {}))
saved_nodes = deepcopy(original_nodes)
original_edges = dict(store._edges.get(tenant, {}))
try:
for action in plan.actions:
if action.kind == "update":
_update(store, scope, action)
else:
_delete(store, scope, action.node_id)
except BaseException:
try:
for identifier, original in original_nodes.items():
saved = saved_nodes[identifier]
# saved is already detached; copying again can fail mid-restore.
fields = dict(saved.__dict__)
fields_set = saved.__pydantic_fields_set__.copy()
object.__setattr__(original, "__dict__", fields)
object.__setattr__(original, "__pydantic_fields_set__", fields_set)
object.__setattr__(original, "__pydantic_private__",
saved.__pydantic_private__.copy())
finally:
store._nodes[tenant] = original_nodes
store._edges[tenant] = original_edges
raise
return plan.merged_count
|