Skip to content

feat!: emit free functions instead of Queries<E> methods#17

Merged
jrandolf merged 1 commit intomainfrom
feat/flatten-queries-into-free-functions
May 9, 2026
Merged

feat!: emit free functions instead of Queries<E> methods#17
jrandolf merged 1 commit intomainfrom
feat/flatten-queries-into-free-functions

Conversation

@jrandolf
Copy link
Copy Markdown
Contributor

@jrandolf jrandolf commented May 9, 2026

Summary

Replaces 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) -> Result<GetAuthorRow, sqlx::Error> { ... }
pub fn batch_get_author<'a, E, I>(db: E, items: I) -> impl Stream + 'a where E: AsExecutor + '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.

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.rs no longer collects into an impl block; AsExecutor trait + impls hoisted above type defs.
  • tests/codegen.rs — assertions updated to verify the new shape (no Queries<E>, free pub 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 via mise 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 to queries::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 enums against 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)

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 jrandolf merged commit cd79857 into main May 9, 2026
2 checks passed
@jrandolf jrandolf deleted the feat/flatten-queries-into-free-functions branch May 9, 2026 12:08
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&lt;E&gt; 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).
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