Skip to content

fix(sqlite-proxy): handle undefined/empty rows in get() method#5537

Open
claygeo wants to merge 1 commit intodrizzle-team:mainfrom
claygeo:fix/sqlite-proxy-get-undefined-rows
Open

fix(sqlite-proxy): handle undefined/empty rows in get() method#5537
claygeo wants to merge 1 commit intodrizzle-team:mainfrom
claygeo:fix/sqlite-proxy-get-undefined-rows

Conversation

@claygeo
Copy link
Copy Markdown

@claygeo claygeo commented Mar 27, 2026

Bug

Fixes #5461

When using drizzle-orm/sqlite-proxy, the get method returns { id: undefined } instead of undefined when no matching row exists. This happens because:

  1. The AsyncRemoteCallback type declares rows: any[] for all methods, so proxy implementers naturally return { rows: [] } for empty results
  2. An empty array [] is truthy, so mapGetResult() treats it as a valid row and maps it to an object with all fields set to undefined

Native SQLite drivers (better-sqlite3, bun:sqlite) return undefined from stmt.get() when no row matches. The sqlite-proxy driver should match this behavior.

Fix

  • Type fix: Updated AsyncRemoteCallback and AsyncBatchRemoteCallback return types from { rows: any[] } to { rows: any[] | undefined }, allowing proxy implementers to return undefined for get with no results
  • Runtime guard: Added normalization in get() to treat empty arrays as undefined, so both { rows: undefined } and { rows: [] } correctly produce undefined
  • Batch guard: Fixed extractRawGetValueFromBatchResult to use optional chaining (rows?.[0]) instead of non-null assertion (rows![0]) to handle undefined rows safely
  • Tests: Added unit tests covering all three cases (undefined rows, empty array rows, valid row)

Verification

All 565 existing tests pass. TypeScript compilation clean. New tests:

  • get() returns undefined when callback returns { rows: undefined }
  • get() returns undefined when callback returns { rows: [] }
  • get() returns mapped row when callback returns valid result ✓

When using sqlite-proxy, the `get` method should return `undefined`
when no matching row is found. Previously, the `AsyncRemoteCallback`
type required `rows: any[]` for all methods, which led proxy
implementers to return `{ rows: [] }` for empty results. The empty
array is truthy, so drizzle treated it as a valid row and returned
`{ id: undefined }` instead of `undefined`.

Changes:
- Update `AsyncRemoteCallback` return type to `{ rows: any[] | undefined }`
  so proxy implementers can return `undefined` for get with no results
- Add runtime guard in `get()` to normalize empty arrays to undefined,
  matching the behavior of native drivers (better-sqlite3, bun:sqlite)
- Guard `extractRawGetValueFromBatchResult` against undefined rows
- Add unit tests covering both undefined and empty array cases

Fixes drizzle-team#5461

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: sqlite-proxy require rows: any[] but runtime expects undefined for get method no-row result

1 participant