Repository navigation
perf: prepare postgres.js statements so a run takes one round trip - #107
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
No configured credential can serve this run. Your Claude Pro/Max subscription has hit its usage limit, which resets at 2026-10-26 08:00 UTC. Re-trigger after it resets, or add an API key for this provider, which Pullfrog falls back to automatically. The providers' responses
|
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.

postgres.js's
unsafe()prepares nothing by default (prepare: false), and for a query with parameters it then sends Parse and Describe, waits for the answer, and only then sends Bind and Execute. Every.run()on a postgres.js client therefore took two round trips, on every run. Reylo now passes{ prepare: true }, so the statement is prepared on the connection the first time and each later run takes one round trip, as postgres.js's own tagged queries do.A client created with
prepare: false, as one behind a pooler in transaction mode is, still prepares nothing: postgres.js takes the client's option over the query's (q.prepare = options.prepare && …inconnection.js). A query without parameters still goes over the simple protocol, as before. Bun.sql, which prepares by itself, is unchanged.Measured locally through a proxy adding 5 ms to each round trip,
select id, name from users where id = $1::int:unsafe(text, [1]), beforeunsafe(text, [1], { prepare: true }), afterprepare: falseWhat it touches:
unsafe(text, args, options); a wrapper of postgres.js's shape ignores the extra argument.select *whose table gained a column) fails its next run withcached plan must not change result type; postgres.js prepares it again and retries, transparently outside a transaction. Inside a transaction the retry cannot run, so that run fails once on that connection, exactly as postgres.js's own queries do. The freshness check is unchanged: it still fails a call whose columns changed.Tests:
tests/execute.test.tschecks the option is passed to postgres.js and not to Bun.sql, and on a live server readspg_prepared_statementson a reserved connection after two runs: one statement run twice on a default client, none on a client created withprepare: false, and the same statement reused insidesql.begin. The driver matrix's postgres.js and Drizzle-over-postgres.js jobs (209 rows) matchRESULTS.md.The postgres page and the agent skill say that Reylo's queries are prepared on postgres.js, and that a client behind a pooler in transaction mode takes
prepare: false.