Batch Promise iterator row reads - #233
Open
xoxohorses wants to merge 11 commits into
Open
Conversation
xoxohorses
marked this pull request as ready for review
September 14, 2026 17:50
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.
Description
Adds
RowsIterator.nextBatch(maxRows)in Rust and updates the Promise API's existingiterate()wrapper to fetch native row batches while returning standard one-row iterator results.QueryOptions.batchSizecontrols the native batch size and defaults to 1, which preserves current behavior and keeps the existingall()anditerate()signatures unchanged.This was motivated by a production trace of a simple ordered query that returned 9,088 rows: about 280 ms of its 350 ms p50 was attributed to SQLite processing. For that result size, the default
all()path makes 9,088 asynchronous Rust-to-JavaScript round trips. Batching keeps SQLite's row-at-a-time stepping inside Rust and reduces those boundary crossings while the JavaScript iterator still returns one row at a time.Benchmark
The public benchmark prepares the table before timing, reads the same rows through each configuration, and validates every result. These averages were measured on Node 22.13.1 for x64 Linux with an Intel Xeon Platinum 8375C CPU.
all()with batch size 1all(…, { batchSize: 250 })Benchmark source: https://github.com/xoxohorses/libsql-js/blob/cb3e8e4fa0dc14811365033f1cc4bce84e8645d8/perf/perf-libsql-batched-rows.js
How was this change tested?
Built the native module, then ran the public benchmark across 1,000, 10,000, 100,000, and 1,000,000 returned rows. The benchmark validated each result set.
[written by Codex]