also looking at this
fix(client): returningAll() is returning('*'), so it works on MySQL
#1160
2 files
+189
-66
| @@ -7562,34 +7562,22 @@ export function createQueryBuilder<DB extends AnyDatabaseSchema>(state?: Partial | ||
| 7562 | 7562 | return result |
| 7563 | 7563 | }, |
| 7564 | 7564 | returningAll() { |
| 7565 | // As in returning(): no rows inserted, nothing to return. | |
| 7566 | if (noRows) | |
| 7567 | return emptyReturningBuilder() | |
| 7568 | const returningSql = `${sqlText} RETURNING *` | |
| 7569 | const q = prepareQuery(returningSql, params) | |
| 7570 | const runFirst = async () => { | |
| 7571 | const result = await runWithHooks<any[]>(q, 'insert') | |
| 7572 | return Array.isArray(result) ? result[0] : result | |
| 7573 | } | |
| 7574 | return { | |
| 7575 | toSQL: () => makeExecutableQuery(q, returningSql) as any, | |
| 7576 | execute: () => runWithHooks<any[]>(q, 'insert'), | |
| 7577 | get: () => runWithHooks<any[]>(q, 'insert'), | |
| 7578 | first: runFirst, | |
| 7579 | executeTakeFirst: runFirst, | |
| 7580 | async firstOrFail() { | |
| 7581 | const row = await runFirst() | |
| 7582 | if (!row) | |
| 7583 | throw new Error('Insert with RETURNING returned no rows') | |
| 7584 | return row | |
| 7585 | }, | |
| 7586 | async executeTakeFirstOrThrow() { | |
| 7587 | const row = await runFirst() | |
| 7588 | if (!row) | |
| 7589 | throw new Error('Insert with RETURNING returned no rows') | |
| 7590 | return row | |
| 7591 | }, | |
| 7592 | } as any | |
| 7565 | /* | |
| 7566 | * `RETURNING *` is `returning('*')`, so this defers to it. | |
| 7567 | * | |
| 7568 | * It used to append the clause itself, a second implementation of | |
| 7569 | * the same idea, and the two drifted: every fix returning() gained | |
| 7570 | * stopped here. Most of all the MySQL branch, so `returningAll()` | |
| 7571 | * emitted `RETURNING *` at a server that has no RETURNING and every | |
| 7572 | * such write was a syntax error rather than a write - 63 call sites | |
| 7573 | * in Stacks alone (stacksjs/stacks#2637). It also never reached the | |
| 7574 | * empty-batch guard, and its handle was missing row accessors the | |
| 7575 | * return type declares. | |
| 7576 | * | |
| 7577 | * mysqlReturningBuilder already reads `*` as "every column", so the | |
| 7578 | * MySQL read-back needs nothing further. | |
| 7579 | */ | |
| 7580 | return (this as any).returning('*') | |
| 7593 | 7581 | }, |
| 7594 | 7582 | } as any as TypedInsertQueryBuilder<DB, TTable> |
| 7595 | 7583 | }, |
| @@ -7909,26 +7897,17 @@ export function createQueryBuilder<DB extends AnyDatabaseSchema>(state?: Partial | ||
| 7909 | 7897 | return { numUpdatedRows: result } |
| 7910 | 7898 | }, |
| 7911 | 7899 | returningAll() { |
| 7912 | // Deferred for the same reason as returning(): holding this handle | |
| 7913 | // while the parent gains a predicate must not execute the statement | |
| 7914 | // as it stood beforehand. See #1110. | |
| 7915 | const retAllText = () => `${sqlText} RETURNING *` | |
| 7916 | const build = () => (params.length > 0 ? prepareQuery(retAllText(), params) : prepareQuery(retAllText())) | |
| 7917 | return { | |
| 7918 | toSQL: () => makeExecutableQuery(build(), retAllText()) as any, | |
| 7919 | execute: () => runWithHooks<any[]>(build(), 'update'), | |
| 7920 | async executeTakeFirst() { | |
| 7921 | const result = await runWithHooks<any[]>(build(), 'update') | |
| 7922 | return Array.isArray(result) ? result[0] : result | |
| 7923 | }, | |
| 7924 | async executeTakeFirstOrThrow() { | |
| 7925 | const result = await runWithHooks<any[]>(build(), 'update') | |
| 7926 | const first = Array.isArray(result) ? result[0] : result | |
| 7927 | if (!first) | |
| 7928 | throw new Error('Update with RETURNING failed') | |
| 7929 | return first | |
| 7930 | }, | |
| 7931 | } as any | |
| 7900 | /* | |
| 7901 | * `returning('*')`, for the reasons given on insertInto's. | |
| 7902 | * | |
| 7903 | * The duplicate here missed the MySQL branch, which reads the rows | |
| 7904 | * by the ids the predicate matched *before* the write, so on MySQL | |
| 7905 | * this emitted `UPDATE ... RETURNING *` and wrote nothing at all | |
| 7906 | * (stacksjs/stacks#2637). It also could not take a predicate added | |
| 7907 | * after it - the #1110 shape - because the handle it returned had no | |
| 7908 | * where() to delegate. | |
| 7909 | */ | |
| 7910 | return (this as any).returning('*') | |
| 7932 | 7911 | }, |
| 7933 | 7912 | } |
| 7934 | 7913 | }, |
| @@ -8183,24 +8162,15 @@ export function createQueryBuilder<DB extends AnyDatabaseSchema>(state?: Partial | ||
| 8183 | 8162 | return { numDeletedRows: result } |
| 8184 | 8163 | }, |
| 8185 | 8164 | returningAll() { |
| 8186 | // Deferred, as returning() is — see #1110. | |
| 8187 | const retAllText = () => `${sqlText} RETURNING *` | |
| 8188 | const build = () => (delParams.length > 0 ? prepareQuery(retAllText(), delParams) : prepareQuery(retAllText())) | |
| 8189 | return { | |
| 8190 | toSQL: () => makeExecutableQuery(build(), retAllText()) as any, | |
| 8191 | execute: () => runWithHooks<any[]>(build(), 'delete'), | |
| 8192 | async executeTakeFirst() { | |
| 8193 | const result = await runWithHooks<any[]>(build(), 'delete') | |
| 8194 | return Array.isArray(result) ? result[0] : result | |
| 8195 | }, | |
| 8196 | async executeTakeFirstOrThrow() { | |
| 8197 | const result = await runWithHooks<any[]>(build(), 'delete') | |
| 8198 | const first = Array.isArray(result) ? result[0] : result | |
| 8199 | if (!first) | |
| 8200 | throw new Error('Delete with RETURNING failed') | |
| 8201 | return first | |
| 8202 | }, | |
| 8203 | } as any | |
| 8165 | /* | |
| 8166 | * `returning('*')`, for the reasons given on insertInto's. | |
| 8167 | * | |
| 8168 | * Besides emitting `RETURNING *` at MySQL (stacksjs/stacks#2637), | |
| 8169 | * the duplicate here skipped beforeDelete/afterDelete entirely, so | |
| 8170 | * `.returningAll()` walked straight past an application delete | |
| 8171 | * guard - the same defect returning() was fixed for. | |
| 8172 | */ | |
| 8173 | return (this as any).returning('*') | |
| 8204 | 8174 | }, |
| 8205 | 8175 | } |
| 8206 | 8176 | }, |