fix(sqlite): single row RETURNING codegen#124
Open
okuuva wants to merge 5 commits intowsporto:mainfrom
Open
Conversation
INSERT…RETURNING: throw on 0 rows. UPDATE/DELETE…RETURNING: return T|null when no row matches. Widen single-row U/D RETURNING return type to T|null.
Fix INSERT…RETURNING to throw on 0 rows. Add UPDATE/DELETE…RETURNING branch (was indexing ResultSet object as array). Single-row returns T|null.
Add RETURNING branch (was missing entirely; fell through to .run() path which dropped the row). INSERT throws on 0 rows; UPDATE/DELETE single-row returns T|null.
Fix INSERT…RETURNING to throw on 0 rows (was silently dropping). Add UPDATE/DELETE…RETURNING branch with single-row T|null.
…RNING_NO_ROWS_ERROR const
c97c851 to
48e7121
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #122.
Summary
Fixes broken or missing
RETURNINGcodegen forINSERT/UPDATE/DELETEstatements across all 4 SQLite drivers (better-sqlite3, libsql, bun:sqlite, d1). Each driver had a distinct defect; pg and mysql2 codegen are unchanged.What was broken
mapArrayTo<T>(res)with no null guard —.get()returnsundefinedon 0 rows, producing crashes or garbage.ResultSetas if it were an array, with no 0-row handling and no multi-row map.UPDATE/DELETE … RETURNINGfell into the.run()path and silently dropped output while the type signature lied.rows.map(...)[0], returningundefinedon 0 rows with noINSERTguard and no multi-row path.What changed
Per-driver,
RETURNINGcodegen now uses the correct accessor for that driver's row representation and respects result cardinality:UPDATE/DELETE … RETURNINGreturnsT | nullwith an explicit empty-result guard.UPDATE/DELETE … RETURNINGreturnsT[]viarows.map(...).INSERT … RETURNING(single-row): returnsT, throwsError('INSERT ... RETURNING returned no rows')if the row vanishes (e.g. concurrent constraint violation handled outside the wrapper).INSERT … RETURNING(multi-row): returnsT[]viarows.map(...).Also extracts a shared
writeRowsResultMappinghelper for the U/D RETURNING shape and a module-scopeINSERT_RETURNING_NO_ROWS_ERRORconstant to remove duplicated error literals across the 4 driver branches.The
orNullreturn-type rule is widened so single-row U/D RETURNING getsT | nullregardless of driver.Known limitation (followup)
The SQLite analyzer in
src/sqlite-query-analyzer/parser.tscurrently hardcodesmultipleRowsResult: falsefor all DML schema results. As a consequence, the new multi-rowRETURNINGcodegen branches are correct-by-construction but currently unreachable through the publicgenerateTsCodeAPI. They are kept in place — and tagged withTODOcomments — so they will Just Work the moment the analyzer is fixed in a followup.Until the followup lands, queries like
INSERT … VALUES (?,?),(?,?) RETURNING *orUPDATE … RETURNING *(withoutLIMIT 1) emit single-row codegen, which type-lies for the multi-row case.Test plan
npm test(sqlite codegen suite) — 102 passingUPDATE/DELETERETURNING fixtures added for libsql, bun:sqlite, d1; existing better-sqlite3 fixtures updated toT | nullshapeINSERT … RETURNINGthrow-guard fixtures across all 4 drivers🤖 Generated with Claude Code using Opus 4.7