Skip to content

Commit e601c03

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-22379-permission-sets-packaged-lock
2 parents d14bbcf + c8c803c commit e601c03

5 files changed

Lines changed: 947 additions & 166 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@objectstack/objectql': patch
3+
---
4+
5+
Deleting a record no longer fails because of a record that the same delete removes. Before this fix, when a record's delete cascaded to two kinds of children, and one child held a required lookup to the other, the delete could answer `409 DELETE_RESTRICTED` naming the child that holds the lookup. Whether it did depended on which object was registered first. A measured example: an account cascades to its contacts and to its contracts, and each contract has a required lookup to a contact. With the contacts registered first, deleting the account was refused, naming a contract that the same delete was about to remove. With the contracts registered first, the same delete succeeded.
6+
7+
Clause-②: no
8+
9+
A by-id cascade delete now collects, before any refusal is judged, every record it will delete across its cascading relations, the root record included. A `restrict` raised by a record in that set against another record in the set is no longer a refusal. That covers an authored `deleteBehavior: 'restrict'` and a required lookup whose `set_null` cannot clear it. A `set_null` writes nothing to a record in the set, so that record's hooks and audit rows show the delete without an earlier update. A refusal from a record outside the set is unchanged. It still answers `409 DELETE_RESTRICTED` and names the dependent object, and on a single datasource the whole delete still rolls back. The refusal now counts only rows outside the set.
10+
11+
The cascade also no longer re-enters a record it is already deleting. A cycle in the data, such as two rows that cascade to each other, now deletes both rows. Before, the walk re-entered the same rows without end. A row that two cascade paths reach is deleted once, instead of the second path answering `404`.
12+
13+
The cost is one more read for each cascading relation of each record the cascade deletes: the set is collected by a read-only walk before the existing walk deletes. No key, export or error code changes.

‎content/docs/api/data-api.mdx‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,16 @@ emptied that way reads back as `[]` — never `null`, so a client that branches
257257
`packages/spec/src/data/field.zod.ts`, rendered in the
258258
[Field reference](/docs/references/data/field)).
259259

260+
A record that the same delete removes never blocks it. Before any refusal is
261+
judged, the delete collects every record its cascade reaches, the deleted
262+
record included. A `restrict` held by a record in that set is not a refusal,
263+
and neither is the `restrict` that a required `set_null` becomes. A `set_null`
264+
writes nothing to a record in that set. So when an account cascades to its
265+
contacts and its contracts, and a contract's required lookup points at a
266+
contact, deleting the account removes all three, whichever object was
267+
registered first. A `restrict` from any record outside the set still refuses
268+
with `409 DELETE_RESTRICTED`, and `dependentCount` counts only those records.
269+
260270
---
261271

262272
## Batch Operations

0 commit comments

Comments
 (0)