feat!: emit free functions instead of Queries<E> methods#17
Merged
Conversation
Replace the generated Queries<E> wrapper with free functions at module scope. Each query becomes:
pub async fn get_author<E: AsExecutor>(mut db: E, id: i64) -> ...
pub fn batch_get_author<'a, E, I>(db: E, items: I) -> impl Stream + 'a
The executor is taken by value, generic over AsExecutor — which is implemented on the natural sqlx reference types (&PgPool, &mut PgConnection, &mut Transaction, &mut PoolConnection, &mut T of each). Callers pass &pool, &mut conn, or &mut tx directly:
queries::get_author(&pool, 1).await?;
queries::get_author(&mut conn, 1).await?;
queries::get_author(&mut tx, 1).await?;
The Queries<E> struct, its new/into_inner methods, and the impl Queries<E> collector block are removed. The AsExecutor trait and all its impls are kept.
Updates the four example crates and eight e2e expect.rs cases to the new shape, regenerates examples/*/src/queries.rs via mise run generate, and rewrites the README. Adds a design spec and implementation plan under docs/superpowers/.
BREAKING CHANGE: callers using Queries::new(executor).foo(...) must switch to queries::foo(executor, ...).
jrandolf
added a commit
that referenced
this pull request
May 9, 2026
🤖 I have created a release *beep* *boop* --- ## [0.2.0](v0.1.7...v0.2.0) (2026-05-09) ### ⚠ BREAKING CHANGES * callers using Queries::new(executor).foo(...) must switch to queries::foo(executor, ...). ### Features * Emit free functions instead of Queries<E> methods ([#17](#17)) ([cd79857](cd79857)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
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.
Summary
Replaces the generated
Queries<E>wrapper with free functions at module scope. Each query becomes:The executor is taken by value, generic over
AsExecutor— which is implemented on the natural sqlx reference types (&PgPool,&mut PgConnection,&mut Transaction,&mut PoolConnection,&mut Tof each). Callers pass&pool,&mut conn, or&mut txdirectly:The
Queries<E>struct, itsnew/into_innermethods, and theimpl Queries<E>collector block are removed. TheAsExecutortrait and all its impls are kept.Why
The wrapper added a layer of indirection without earning its keep — it didn't share state, didn't cache anything, and didn't enable any pattern free functions can't express. Removing it makes the API simpler to call, simpler to import piecemeal, and easier to use across multiple executors in the same scope.
What changed
src/codegen/{mod,query,batch,copyfrom}.rs— generators emit free functions;mod.rsno longer collects into an impl block;AsExecutortrait + impls hoisted above type defs.tests/codegen.rs— assertions updated to verify the new shape (noQueries<E>, freepub async fn, executor parameter).tests/snapshots/codegen__*.snap(20 files) — regenerated.tests/e2e/cases/**/expect.rs(8 files) — call sites migrated.examples/*/src/main.rs(4 files) — call sites migrated.examples/*/src/queries.rs(4 files) — regenerated viamise run generate.README.md— "What it generates" section rewritten to match.sqlc.yaml— auto-updated WASM sha256.BREAKING CHANGE
Callers using
Queries::new(executor).foo(...)must switch toqueries::foo(executor, ...).Test plan
cargo test --lib --test codegen(21/21 pass — snapshots + new shape assertions)cargo test --test e2e(testcontainer-managed Postgres; all e2e cases pass)cargo test -p basic -p batch -p advanced-types -p enumsagainst a live Postgres (4/4 pass)cargo clippy --workspace --all-targets -- -D warnings(clean)cargo fmt --all --check(clean)cargo build --target wasm32-wasip1(clean)