|
25 | 25 | * nothing outside it; |
26 | 26 | * - `restrict` refuses with the ADR-0112 envelope naming the tree's own object |
27 | 27 | * as the dependent, and keeps the row; a leaf still deletes; |
| 28 | + * - a REQUIRED tree's `set_null` escalates to that refusal, as a required |
| 29 | + * `lookup`'s does; |
28 | 30 | * - a cycle in the data terminates: a corrupt row pointing at its own |
29 | 31 | * descendant, and a row pointing at itself; |
30 | 32 | * - a subtree cascade is one unit of work: a refusal from a node deep in it |
@@ -300,6 +302,28 @@ describe('[#22957] a tree field\'s deleteBehavior takes effect on a parent delet |
300 | 302 | }); |
301 | 303 | }); |
302 | 304 |
|
| 305 | + describe('required', () => { |
| 306 | + it('a required tree\'s set_null cannot clear the parent, so the parent delete is refused', async () => { |
| 307 | + // The escalation a required `lookup` already takes: a parent that must |
| 308 | + // be present cannot be cleared, so the delete is refused rather than |
| 309 | + // answered with the child's own `required` refusal. |
| 310 | + const { engine, driver } = await makeEngine([ |
| 311 | + treeObject('zt_rooted', parsedTree('zt_rooted', { required: true })), |
| 312 | + ]); |
| 313 | + // A required hierarchy's top points at itself; the engine refuses a |
| 314 | + // reference to a row that does not exist yet, so it is written at the |
| 315 | + // driver. |
| 316 | + const root = await driver.create('zt_rooted', { id: 'root', name: 'root', parent: 'root' }); |
| 317 | + const c = await engine.insert('zt_rooted', { name: 'C', parent: root.id }); |
| 318 | + |
| 319 | + const err = await refusalOf(engine.delete('zt_rooted', { where: { id: root.id } } as any)); |
| 320 | + |
| 321 | + expect(err).toMatchObject({ code: 'DELETE_RESTRICTED', status: 409, dependentObject: 'zt_rooted' }); |
| 322 | + expect(driver.rowOf('zt_rooted', root.id)).toMatchObject({ name: 'root' }); |
| 323 | + expect(driver.rowOf('zt_rooted', c.id)).toMatchObject({ name: 'C', parent: root.id }); |
| 324 | + }); |
| 325 | + }); |
| 326 | + |
303 | 327 | describe('multiple: true', () => { |
304 | 328 | it('is refused on a tree by the spec\'s parse, so no multi-valued tree reaches the walk through it', () => { |
305 | 329 | const result = FieldSchema.safeParse({ type: 'tree', reference: 'zt_multi', multiple: true }); |
|
0 commit comments