sqlc-go-codegen-metaquery

module
v1.2.0-rc2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 10, 2026 License: MIT

README

sqlc-go-codegen-metaquery

A fork of sqlc-gen-go that emits per-query metadata alongside the usual sqlc output, plus a small runtime that wraps any query as a CTE so you can compose filters, ordering, pagination, and aggregations dynamically — without ever modifying the original SQL.

Built for Go + sqlc, with adapters for Postgres + pgx/v5 and SQLite + database/sql. Drop-in compatible with stock sqlc-gen-go: the existing q.ListAuthors(ctx) methods are unchanged; the metaquery surface is purely additive.

// Your sqlc query:
// -- name: ListAuthors :many
// SELECT id, name, bio FROM authors ORDER BY name;

// Wrap it, add filters/pagination, run it — all at runtime:
res, _ := mqpgx.Scan[db.Author](ctx, conn,
    db.WrapListAuthors().
        ApplyFilter(db.ListAuthorsCols.Name.ILike("%ada%")).
        ApplyOrder(db.ListAuthorsCols.CreatedAt.Desc()).
        ApplyPagination(metaquery.PageRequest{Page: 0, Size: 20, Total: true}))

// res.Data is []db.Author
// res.Meta has the applied Filter/OrderBy/Pagination + column metadata,
// ready to serialize as an HTTP response body.

See examples/pgx/ for a full runnable demo (docker-compose pg17, migrations, seed, JSON-output CLI), or examples/sqlite/ for the same demo against a local SQLite file (pure-Go driver, no Docker).

Why use this

Stock sqlc is great for static queries but painful once you need dynamic filtering, pagination, or admin UIs on top. Typical workarounds:

  • Write N variants of a query — explodes quickly
  • Drop to database/sql + a query builder — loses sqlc's type safety
  • Build your own metadata indirection — what this project is

This fork keeps sqlc's compile-time query validation and generated types, adds a typed wrapper per query, and gives you a runtime API that's JSON-round-trippable for HTTP endpoints and admin consoles.

Installation

Latest release — v1.1.1
plugins:
- name: metaquery
  wasm:
    url: https://github.com/IodeSystems/sqlc-go-codegen-metaquery/releases/download/v1.1.1/sqlc-go-codegen-metaquery.wasm
    sha256: feb4d49fa9cc10945685b888790e4467aad8828b7bb43ad5711b99e45e8e7f52
From source
git clone https://github.com/iodesystems/sqlc-go-codegen-metaquery.git
cd sqlc-go-codegen-metaquery
make all       # produces bin/sqlc-go-codegen-metaquery (+ .wasm)

Point sqlc at the binary:

# sqlc.yaml
version: '2'
plugins:
- name: metaquery
  process:
    cmd: /path/to/sqlc-go-codegen-metaquery
sql:
- schema: schema.sql
  queries: query.sql
  engine: postgresql
  codegen:
  - plugin: metaquery
    out: db
    options:
      package: db
      sql_package: pgx/v5
      emit_db_tags: true
      emit_json_tags: true
      emit_metaquery: cols    # off | meta | wrap | cols (default: cols)

Then sqlc generate produces the usual db/query.sql.go + db/models.go + a new db/query.sql.metaquery.go carrying the per-query metadata and typed helpers.

In your Go code, import the runtime and pick the adapter for your engine:

// Postgres + pgx/v5:
import (
    "github.com/iodesystems/sqlc-go-codegen-metaquery/metaquery"
    "github.com/iodesystems/sqlc-go-codegen-metaquery/metaquery/mqpgx"
)

// SQLite + database/sql:
import (
    "github.com/iodesystems/sqlc-go-codegen-metaquery/metaquery"
    "github.com/iodesystems/sqlc-go-codegen-metaquery/metaquery/mqsqlite"
    _ "modernc.org/sqlite" // or any database/sql sqlite driver
)

mqsqlite is driver-agnostic — it talks to database/sql, so it works with modernc.org/sqlite (pure Go), mattn/go-sqlite3, libsql, etc. The wrapped query's Dialect is set automatically by the codegen based on engine: sqlite in sqlc.yaml, and the builder emits ?N placeholders to match.

What it emits

For each query sqlc processes, three symbols (at the default cols level):

Symbol Purpose
MetaListAuthors metaquery.Query Runtime-readable metadata: the SQL text, columns (Name, GoType, DBType, NotNull, Table, …), args, source file, etc. JSON-serializable.
WrapListAuthors(args...) *metaquery.Builder Typed constructor that binds the original query's positional args at compile time and returns a Builder ready for filter/order/pagination/aggregation methods.
ListAuthorsCols struct{...} Typed column references. ListAuthorsCols.Name is a TextCol; ListAuthorsCols.ID is an IntCol. Each exposes ops appropriate to its type (ILike(string) on text, Gt(int64), Between(int64, int64) on int, etc.). Column names and op/value types are compile-time checked.

Six column kinds ship by default (Text/Int/Float/Bool/Time/Bytes), with AnyCol as the escape hatch for arrays, enums, pgtype.Numeric, UUIDs, etc.

Emission levels

You pay only for what you use. Set globally via emit_metaquery or per-query with -- metaquery: <level>:

Level Emits Typical use
off nothing Query is only called via the regular sqlc method; no dynamic wrapping needed
meta Meta<Name> only You want runtime introspection (schema export, generic API handler) without the builder surface
wrap + Wrap<Name>(args...) Typed wrappers but filter against column names as strings
cols (default) + <Name>Cols Full Tier 2 — typed wrappers + typed column refs

Per-query override example:

-- name: TruncateAll :exec
-- metaquery: off
-- (Only called from seed/migration code; no builder needed.)
TRUNCATE authors RESTART IDENTITY CASCADE;

Safety surface

Failure mode Caught How
Wrong wrapper arg type compile time WrapGetAuthor("not an int") won't compile
Unknown column in .Where/.OrderBy/etc compile time (via typed cols) or pre-query (via whitelist) ListAuthorsCols.Typo → compile error; .Where("typo",...) → Build-time error
Wrong op for column type compile time (typed cols) or pre-query (ValidateFilter) IntCol has no .ILike; Filter{Op: OpILike} on an int column → op "ILIKE" not valid for column "id" (int64/int)
Wrong value type compile time (typed cols) or pre-query (ValidateFilter) IntCol.Eq takes int64; JSON-driven filters with string values for int columns are rejected before any query runs
Scan-struct shape drift pre-query Validate[T] reflects on T and diffs against b.OutputColumns()
Malformed raw SQL in WhereExpr/Agg query time Passed through to Postgres verbatim; caller owns safety

The validator is also callable as a library function (metaquery.ValidateFilter(q, f)) so JSON-driven HTTP handlers can fail fast on bad client input, using the same rules the builder applies internally.

Relationship to upstream

This is a clean fork of github.com/sqlc-dev/sqlc-gen-go, not a registered GitHub fork. Upstream is tracked as a git remote:

git remote -v
# origin    git@github.com:IodeSystems/sqlc-go-codegen-metaquery.git
# upstream  https://github.com/sqlc-dev/sqlc-gen-go.git

To sync upstream updates:

git fetch upstream
git merge upstream/main   # resolve conflicts in the three touched files
                          #   (internal/gen.go, internal/result.go, go.mod + Makefile)
                          # import-path conflicts resolve mechanically with sed.

Caveats / non-goals

  • Postgres (pgx/v5) and SQLite (database/sql) are supported. MySQL isn't blocked by the runtime design but doesn't yet have an adapter.
  • ILIKE on SQLite is auto-translated to LIKE at Build time. SQLite's LIKE is case-insensitive for ASCII by default — same effective behavior as Postgres ILIKE for typical text columns. For Unicode-aware case-insensitive matching, use WhereExpr with LOWER(...).
  • The builder wraps, never rewrites. A filter references the output columns of the original query. If you need to filter on a column the query doesn't project, either widen the query or use WhereExpr.
  • Sum/Avg/Min/Max aggregates project the source column's type without null-safety — aggregates over empty groups return NULL. Use Agg("x", "coalesce(sum(y), 0)", "int64") as the escape hatch.

License

MIT — same as upstream. See LICENSE.

Directories

Path Synopsis
Package metaquery provides runtime metadata types and a CTE-based query builder for queries generated by sqlc-go-codegen-metaquery.
Package metaquery provides runtime metadata types and a CTE-based query builder for queries generated by sqlc-go-codegen-metaquery.
codegen
Package codegen exposes the metaquery code generator as a library — the same function sqlc invokes when it spawns the `plugin` binary, but importable from any Go program.
Package codegen exposes the metaquery code generator as a library — the same function sqlc invokes when it spawns the `plugin` binary, but importable from any Go program.
dataset
Package dataset turns a single DataSetRequest (search + partition + ordering + pagination) into a fully-shaped metaquery builder, so any metaquery select becomes a searchable/sortable/paginated "DataSet" in one call.
Package dataset turns a single DataSetRequest (search + partition + ordering + pagination) into a fully-shaped metaquery builder, so any metaquery select becomes a searchable/sortable/paginated "DataSet" in one call.
mqpgx
Package mqpgx is the pgx/v5 adapter for metaquery builders.
Package mqpgx is the pgx/v5 adapter for metaquery builders.
mqsqlite
Package mqsqlite is the database/sql adapter for metaquery builders targeting SQLite.
Package mqsqlite is the database/sql adapter for metaquery builders targeting SQLite.
search
Package search implements the DataSet search DSL on top of metaquery.
Package search implements the DataSet search DSL on top of metaquery.
Standalone plugin binary.
Standalone plugin binary.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL