|
17 | 17 | * |
18 | 18 | * Pinned here: the parent delete refuses with an error that is NOT the |
19 | 19 | * stale-roll-up refusal, on the atomic plan (nothing stored changes) and on a |
20 | | - * runtime that cannot roll back (the parent is still stored); a refusal that |
21 | | - * escapes a caller's own `transaction()` that rolls back is converted the same |
22 | | - * way. Controls: a delete of the dependent itself — its own write landed, only |
| 20 | + * runtime that cannot roll back (the parent is still stored), by id and by |
| 21 | + * predicate; a refusal that |
| 22 | + * escapes a caller's own `transaction()` (engine or scoped context) that rolls |
| 23 | + * back is converted the same way. Controls: a delete of the dependent itself — its own write landed, only |
23 | 24 | * its recompute failed — still answers `ERR_SUMMARY_RECOMPUTE` carrying its |
24 | 25 | * result, and so does a caller's transaction that catches it and commits. |
25 | 26 | * |
@@ -81,6 +82,11 @@ function makeDriver(transactional: boolean) { |
81 | 82 | return row; |
82 | 83 | }, |
83 | 84 | async delete(o: string, id: string) { return storeFor(o).delete(String(id)); }, |
| 85 | + async deleteMany(o: string, ast: any) { |
| 86 | + const doomed = Array.from(storeFor(o).values()).filter((r) => matches(r, ast?.where)); |
| 87 | + for (const r of doomed) storeFor(o).delete(String(r.id)); |
| 88 | + return doomed.length; |
| 89 | + }, |
84 | 90 | async count(o: string, ast: any) { return (await this.find(o, ast)).length; }, |
85 | 91 | async bulkCreate(o: string, rows: Row[]) { return Promise.all(rows.map((r) => this.create(o, r))); }, |
86 | 92 | async bulkUpdate() { return []; }, async bulkDelete() {}, |
@@ -157,6 +163,15 @@ describe('a cascade dependent\'s ERR_SUMMARY_RECOMPUTE never answers for a paren |
157 | 163 | expect(ids(driver.rowsOf('line'))).toEqual(['l2']); |
158 | 164 | }); |
159 | 165 |
|
| 166 | + it('a predicate delete (multi) on a runtime that cannot roll back: refused the same way, the parent still stored', async () => { |
| 167 | + const { engine, driver } = await makeEngine(false); |
| 168 | + const err: any = await engine.delete('acct', { where: { name: 'A' }, multi: true } as any).then(() => null, (e: unknown) => e); |
| 169 | + expect(err).toBeInstanceOf(Error); |
| 170 | + expect(err.code).toBeUndefined(); |
| 171 | + expect(err.cause?.code).toBe('ERR_SUMMARY_RECOMPUTE'); |
| 172 | + expect(ids(driver.rowsOf('acct'))).toEqual(['a1']); |
| 173 | + }); |
| 174 | + |
160 | 175 | it('a caller\'s own transaction that the refusal rolls back: refused with another error, nothing stored', async () => { |
161 | 176 | const { engine, driver } = await makeEngine(true); |
162 | 177 | const err: any = await engine |
|
0 commit comments