Skip to content

feat!: return last_insert_rowid as i64, as sqlx-sqlite does - #14

Merged
iamralch merged 1 commit into
mainfrom
feat/last-insert-rowid-i64
Sep 27, 2026
Merged

iamralch merged 1 commit into
mainfrom
feat/last-insert-rowid-i64

Conversation

@iamralch

Copy link
Copy Markdown
Contributor

Problem

QueryResult::last_insert_rowid() returns Option<i64>, but sqlx-sqlite's SqliteQueryResult::last_insert_rowid() returns i64. Code written against sqlx-sqlite therefore doesn't compile on D1 or Durable Objects, even though the drivers otherwise follow sqlx-sqlite wherever JavaScript doesn't force a difference (sqlx-cloudflare-core/src/types.rs). JavaScript doesn't force this one.

This also affects sqlc-gen-sqlx's SQLite output: its :execlastid functions end in Ok(result.last_insert_rowid()) returning i64.

Change

  • last_insert_rowid() returns i64, 0 when the statement inserted no row. QueryResult::new takes an i64 to match.
  • D1 maps a missing meta.last_row_id to 0. DO passes last_insert_rowid() through, and a statement that wrote nothing reports 0, as before but no longer None.
  • Extending a result still keeps the last non-zero rowid, so a trailing SELECT doesn't erase the INSERT before it.
  • Worker test assertions and the DO README follow.

Rowids start at 1 unless a row is given 0 explicitly, so 0 is unambiguous in practice; RETURNING is the way to be certain. sqlx-sqlite reports a stale rowid after a SELECT, so 0 is the more accurate answer of the two.

Breaking

feat!: last_insert_rowid() returns i64, and 0 where it returned None. release-please should bump to 0.2.0.

Verification

  • make check lint test passes, host and wasm32.
  • Clippy on both test Workers for wasm32: only the "very complex type" warning that main already has.
  • sqlc-gen-sqlx's SQLite example output (from the feat/engine-sqlite fork branch), with only the AsExecutor impls retargeted, compiles against both D1 and Do. The :execlastid function compiles unchanged.
  • make test-worker not run locally; CI runs it.

`QueryResult::last_insert_rowid` now returns `i64` rather than
`Option<i64>`, with 0 when the statement inserted no row -- the signature
of sqlx-sqlite's `SqliteQueryResult`, so code written against it compiles
unchanged on D1 and Durable Objects. That includes sqlc-gen-sqlx's SQLite
output, whose `:execlastid` functions return `result.last_insert_rowid()`
as an `i64`. `QueryResult::new` takes an `i64` to match.

Rowids start at 1 unless a row is given 0 explicitly, so 0 is unambiguous
in practice; `RETURNING` is the way to be certain. Extending a result
still keeps the last non-zero rowid, so a trailing SELECT does not erase
the INSERT before it.

BREAKING CHANGE: `last_insert_rowid()` returns `i64`, and 0 where it
returned `None`. `QueryResult::new` takes `last_insert_rowid: i64`.
@iamralch iamralch self-assigned this Sep 27, 2026
@iamralch
iamralch merged commit 3a66fb1 into main Sep 27, 2026
4 checks passed
@iamralch
iamralch deleted the feat/last-insert-rowid-i64 branch September 27, 2026 07:37
@github-actions github-actions Bot mentioned this pull request Sep 27, 2026
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.

1 participant