{"id":23733449,"url":"https://github.com/jschaf/pggen","last_synced_at":"2025-10-24T00:20:19.094Z","repository":{"id":39638747,"uuid":"330568713","full_name":"jschaf/pggen","owner":"jschaf","description":"Generate type-safe Go for any Postgres query. If Postgres can run the query, pggen can generate code for it.","archived":false,"fork":false,"pushed_at":"2024-01-26T18:13:45.000Z","size":1072,"stargazers_count":277,"open_issues_count":19,"forks_count":26,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-06-18T23:03:12.773Z","etag":null,"topics":["orm","postgres","query-compiler","sql-queries"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jschaf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-18T05:55:25.000Z","updated_at":"2024-06-17T01:29:14.000Z","dependencies_parsed_at":"2024-01-25T07:27:27.866Z","dependency_job_id":"0d8962b5-6ea9-4a05-b350-d0d7c8bc0849","html_url":"https://github.com/jschaf/pggen","commit_stats":null,"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jschaf%2Fpggen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jschaf%2Fpggen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jschaf%2Fpggen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jschaf%2Fpggen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jschaf","download_url":"https://codeload.github.com/jschaf/pggen/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231944888,"owners_count":18449789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["orm","postgres","query-compiler","sql-queries"],"created_at":"2024-12-31T05:01:38.357Z","updated_at":"2025-10-24T00:20:19.031Z","avatar_url":"https://github.com/jschaf.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"[![Test](https://github.com/jschaf/pggen/workflows/Test/badge.svg)](https://github.com/jschaf/pggen/actions?query=workflow%3ATest) \n[![Lint](https://github.com/jschaf/pggen/workflows/Lint/badge.svg)](https://github.com/jschaf/pggen/actions?query=workflow%3ALint) \n[![GoReportCard](https://goreportcard.com/badge/github.com/jschaf/pggen)](https://goreportcard.com/report/github.com/jschaf/pggen)\n\n# pggen - generate type safe Go methods from Postgres SQL queries\n\npggen generates Go code to provide a typesafe wrapper to run Postgres queries.\nIf Postgres can run the query, pggen can generate code for it. The generated \ncode is strongly-typed with rich mappings between Postgres types and Go types\nwithout relying on `interface{}`. pggen uses prepared queries, so you don't \nhave to worry about SQL injection attacks. \n\nHow to use pggen in three steps:\n\n1.  Write arbitrarily complex SQL queries with a name and a `:one`, `:many`, or\n    `:exec` annotation. Declare inputs with `pggen.arg('input_name')`.\n\n    ```sql\n    -- name: SearchScreenshots :many\n    SELECT ss.id, array_agg(bl) AS blocks\n    FROM screenshots ss\n      JOIN blocks bl ON bl.screenshot_id = ss.id\n    WHERE bl.body LIKE pggen.arg('body') || '%'\n    GROUP BY ss.id\n    ORDER BY ss.id\n    LIMIT pggen.arg('limit') OFFSET pggen.arg('offset');\n    ```\n\n2.  Run pggen to generate Go code to create type-safe methods for each query.\n   \n    ```bash\n    pggen gen go \\\n        --schema-glob schema.sql \\\n        --query-glob 'screenshots/*.sql' \\\n        --go-type 'int8=int' \\\n        --go-type 'text=string'\n    ```\n    \n    That command generates methods and type definitions like below. The full\n    example is in [./example/composite/query.sql.go].\n    \n    ```go\n    type SearchScreenshotsParams struct {\n        Body   string\n        Limit  int\n        Offset int\n    }\n\n    type SearchScreenshotsRow struct {\n        ID     int      `json:\"id\"`\n        Blocks []Blocks `json:\"blocks\"`\n    }\n    \n    // Blocks represents the Postgres composite type \"blocks\".\n    type Blocks struct {\n        ID           int    `json:\"id\"`\n        ScreenshotID int    `json:\"screenshot_id\"`\n        Body         string `json:\"body\"`\n    }\n    \n    func (q *DBQuerier) SearchScreenshots(\n        ctx context.Context,\n        params SearchScreenshotsParams,\n    ) ([]SearchScreenshotsRow, error) {\n        /* omitted */\n    }\n    ```\n    \n3.  Use the generated code.\n\n    ```go\n    var conn *pgx.Conn\n\tq := NewQuerier(conn)\n    rows, err := q.SearchScreenshots(ctx, SearchScreenshotsParams{\n        Body:   \"some_prefix\",\n        Limit:  50,\n        Offset: 200,\n    })\n    ```\n[./example/composite/query.sql.go]: ./example/composite/query.sql.go\n\n## Pitch\n\nWhy should you use `pggen` instead of the [myriad] of Go SQL bindings?\n\n- pggen generates code by introspecting the database system catalogs, so you \n  can use *any* database extensions or custom methods, and it will just work.\n  For database types that pggen doesn't recognize, you can provide your own\n  type mappings.\n\n- pggen scales to Postgres databases of any size and supports incremental \n  adoption. pggen is narrowly tailored to only generate code for queries you \n  write in SQL. pggen will not create a model for every database object. \n  Instead, pggen only generates structs necessary to run the queries you \n  specify.\n\n- pggen works with any Postgres database with any extensions. Under the hood, \n  pggen runs each query and uses the Postgres catalog tables, `pg_type`, \n  `pg_class`, and `pg_attribute`, to get **perfect type information** for both \n  the query parameters and result columns.\n  \n- pggen works with all Postgres queries. If Postgres can run the query, pggen\n  can generate Go code for the query.\n  \n- pggen uses [pgx], a faster replacement for [lib/pq], the original Go Postgres\n  library that's now in maintenance mode.\n\n- pggen provides a batch (aka query pipelining) interface for each generated \n  query with [`pgx.Batch`]. Query pipelining is the reason Postgres sits atop\n  the [TechEmpower benchmarks]. Using a batch enables sending multiple queries\n  in a single network round-trip instead of one network round-trip per query.\n  \n[TechEmpower benchmarks]: https://www.techempower.com/benchmarks/#section=data-r20\u0026hw=ph\u0026test=query\n[pgx]: https://github.com/jackc/pgx\n[lib/pq]: https://github.com/lib/pq\n\n## Anti-pitch\n\nI'd like to try to convince you why you *shouldn't* use pggen. Often, this\nis far more revealing than the pitch.\n\n- You want auto-generated models for every table in your database. pggen only\n  generates code for each query in a query file. pggen requires custom SQL for\n  even the simplest CRUD queries. Use [gorm] or any of alternatives listed\n  at [awesome Go ORMs].\n\n- You use a database other than Postgres. pggen only supports Postgres. [sqlc],\n  a similar tool which inspired pggen, has early support for MySQL.\n\n- You want an active-record pattern where models have methods like `find`, \n  `create`, `update`, and `delete`. pggen only generates code for queries you \n  write. Use [gorm].\n  \n- You prefer building queries in a Go dialect instead of SQL. I'd recommend \n  investing in really learning SQL; it will payoff. Otherwise, use \n  [squirrel], [goqu], or [go-sqlbuilder]\n  \n- You don't want to add a Postgres or Docker dependency to your build phase.\n  Use [sqlc], though you might still need Docker. sqlc generates code by parsing\n  the schema file and queries in Go without using Postgres.\n\n[myriad]: https://github.com/d-tsuji/awesome-go-orms\n[sqlc]: https://github.com/kyleconroy/sqlc\n[gorm]: https://gorm.io/index.html\n[squirrel]: https://github.com/Masterminds/squirrel\n[goqu]: https://github.com/doug-martin/goqu\n[go-sqlbuilder]: https://github.com/huandu/go-sqlbuilder\n[awesome Go ORMs]: https://github.com/d-tsuji/awesome-go-orms\n\n# Install\n\n### Download precompiled binaries\n\nPrecompiled binaries from the latest release. Change `~/bin` if you want to\ninstall to a different directory. All assets are listed on the [releases] page.\n\n[releases]: https://github.com/jschaf/pggen/releases\n\n-   MacOS Apple Silicon (arm64)\n\n    ```shell\n    mkdir -p ~/bin \\\n      \u0026\u0026 curl --silent --show-error --location --fail 'https://github.com/jschaf/pggen/releases/latest/download/pggen-darwin-arm64.tar.xz' \\\n      | tar -xJf - -C ~/bin/    \n    ```\n    \n-   MacOS Intel (amd64)\n\n    ```shell\n    mkdir -p ~/bin \\\n      \u0026\u0026 curl --silent --show-error --location --fail 'https://github.com/jschaf/pggen/releases/latest/download/pggen-darwin-amd64.tar.xz' \\\n      | tar -xJf - -C ~/bin/    \n    ```\n\n-   Linux (amd64)\n\n    ```shell\n    mkdir -p ~/bin \\\n      \u0026\u0026 curl --silent --show-error --location --fail 'https://github.com/jschaf/pggen/releases/latest/download/pggen-linux-amd64.tar.xz' \\\n      | tar -xJf - -C ~/bin/    \n    ```\n    \n-   Windows (amd64)\n\n    ```shell\n    mkdir -p ~/bin \\\n      \u0026\u0026 curl --silent --show-error --location --fail 'https://github.com/jschaf/pggen/releases/latest/download/pggen-windows-amd64.tar.xz' \\\n      | tar -xJf - -C ~/bin/    \n    ```\n\nMake sure pggen works:\n\n```bash\npggen gen go --help\n```\n\n### Install from source\n\nRequires Go 1.16 because pggen uses `go:embed`. Installs to `$GOPATH/bin`.\n\n```shell\ngo install github.com/jschaf/pggen/cmd/pggen@latest\n```\n    \nMake sure pggen works:\n\n```bash\npggen gen go --help\n```\n\n## Usage\n\nGenerate code using Docker to create the Postgres database from a schema file:\n\n```bash\n# --schema-glob runs all matching files on Dockerized Postgres during database \n# creation.\npggen gen go \\\n    --schema-glob author/schema.sql \\\n    --query-glob author/query.sql\n\n# Output: author/query.go.sql\n\n# Or with multiple schema files. The schema files run on Postgres\n# in the order they appear on the command line.\npggen gen go \\\n    --schema-glob author/schema.sql \\\n    --schema-glob book/schema.sql \\\n    --schema-glob publisher/schema.sql \\\n    --query-glob author/query.sql\n\n# Output: author/query.sql.go\n```\n\nGenerate code using an existing Postgres database (useful for custom setups):\n\n```bash\npggen gen go \\\n    --query-glob author/query.sql \\\n    --postgres-connection \"user=postgres port=5555 dbname=pggen\"\n\n# Output: author/query.sql.go\n```\n\nGenerate code for multiple query files. All the query files must reside in\nthe same directory. If query files reside in different directories, you can use\n`--output-dir` to set a single output directory:\n\n```bash\npggen gen go \\\n    --schema-glob schema.sql \\\n    --query-glob author/fiction.sql \\\n    --query-glob author/nonfiction.sql \\\n    --query-glob author/bestselling.sql\n\n# Output: author/fiction.sql.go\n#         author/nonfiction.sql.go\n#         author/bestselling.sql.go\n\n# Or, using a glob. Notice quotes around glob pattern to prevent shell \n# expansion.\npggen gen go \\\n    --schema-glob schema.sql \\\n    --query-glob 'author/*.sql'\n```\n\n# Examples\n\nExamples embedded in the repo:\n\n- [./example/acceptance_test.go] - End-to-end examples of how to call pggen.\n- [./example/author] - A single table schema with simple queries.\n- [./example/composite] - Arrays of composite (aka row or table) types.\n- [./example/custom_types] - Mapping new Postgres types to Go types.\n- [./example/device] - Complex queries with a 1:many relationship between a \n  `user` table and `device` table.\n- [./example/enums] - Postgres and Go enums.\n- [./example/erp] - A few tables with mildly complex queries.\n- [./example/go_pointer_types] - Mapping to pointer types like `*int` instead\n  of `pgtype.Int8`.\n- [./example/ltree] - Support for the ltree Postgres extension.\n- [./example/nested] - Complex, nested composite (aka row or table) types.\n- [./example/pgcrypto] - pgcrypto Postgres extension.\n- [./example/syntax] - A smoke test of interesting SQL syntax.\n- [./example/void] - Support for void in select columns.\n\n[./example/acceptance_test.go]: ./example/acceptance_test.go\n[./example/author]: ./example/author\n[./example/composite]: ./example/composite\n[./example/custom_types]: ./example/custom_types\n[./example/device]: ./example/device\n[./example/enums]: ./example/enums\n[./example/erp]: ./example/erp\n[./example/go_pointer_types]: ./example/go_pointer_types\n[./example/ltree]: ./example/ltree\n[./example/nested]: ./example/nested\n[./example/syntax]: ./example/syntax\n[./example/pgcrypto]: ./example/pgcrypto\n[./example/void]: ./example/void\n\n# Features\n\n-   **JSON struct tags**: All `\u003cquery_name\u003eRow` structs include JSON struct tags\n    using the Postgres column name. To change the struct tag, use an SQL column \n    alias.\n  \n    ```sql\n    -- name: FindAuthors :many\n    SELECT first_name, last_name as family_name FROM author;\n    ```\n    \n    Generates:\n    \n    ```go\n    type FindAuthorsRow struct {\n        FirstName   string `json:\"first_name\"`\n        FamilyName  string `json:\"family_name\"`\n    }\n    ```\n\n-   **Acronyms**: Custom acronym support so that `author_id` renders as \n    `AuthorID` instead of `AuthorId`. Supports two formats:\n    \n    1. Long form: `--acronym \u003cword\u003e=\u003crelacement\u003e`: replaces `\u003cword\u003e` with \n       `\u003creplacement\u003e` literally. Useful for plural acronyms like `author_ids` \n       which should render as `AuthorIDs`, not `AuthorIds`. For the IDs example,\n        use `--acronym ids=IDs`.\n       \n    2. Short form: `--acronym \u003cword\u003e`: replaces `\u003cword\u003e` with uppercase \n       `\u003cWORD\u003e`. Equivalent to `--acronym \u003cword\u003e=\u003cWORD\u003e`\n       \n    By default, pggen includes `--acronym id` to render `id` as `ID`.\n\n-   **Enums**: Postgres enums map to Go string constant enums. The Postgres \n    type:\n    \n    ```sql\n    CREATE TYPE device_type AS ENUM ('undefined', 'phone', 'ipad');\n    ```\n    \n    pggen generates the following Go code when used in a query:\n    \n    ```go\n    // DeviceType represents the Postgres enum device_type.\n    type DeviceType string\n\n    const (\n        DeviceTypeUndefined DeviceType = \"undefined\"\n        DeviceTypePhone     DeviceType = \"phone\"\n        DeviceTypeIpad      DeviceType = \"ipad\"\n    )\n\n    func (d DeviceType) String() string { return string(d) }\n    ```\n\n-   **Custom types**: Use a custom Go type to represent a Postgres type with the \n    `--go-type` flag. The format is `\u003cpg_type\u003e=\u003cqualified_go_type\u003e`. For \n    example:\n\n    ```sh\n    pggen gen go \\\n        --schema-glob example/custom_types/schema.sql \\\n        --query-glob example/custom_types/query.sql \\\n        --go-type 'int8=*int' \\\n        --go-type 'int4=int' \\\n        --go-type '_int4=[]int' \\\n        --go-type 'text=*github.com/jschaf/pggen/mytype.String' \\\n        --go-type '_text=[]*github.com/jschaf/pggen/mytype.String'\n    ```\n    \n    pgx must be able to decode the Postgres type using the given Go type. That \n    means the Go type must fulfill at least one of following:\n    \n    - The Go type is a wrapper around primitive type, like `type AuthorID int`.\n      pgx will use decode methods on the underlying primitive type.\n\n    - The Go type implements both [`pgtype.BinaryDecoder`] and \n      [`pgtype.TextDecoder`]. pgx will use the correct decoder based on the wire\n      format. See the [pgtype repo] for many example types.\n      \n    - The pgx connection executing the query must have registered a data type \n      using the Go type with [`ConnInfo.RegisterDataType`]. See the \n      [example/custom_types test] for an example.\n      \n      ```go\n      ci := conn.ConnInfo()\n      \n      ci.RegisterDataType(pgtype.DataType{\n      \tValue: new(pgtype.Int2),\n      \tName:  \"my_int\",\n      \tOID:   myIntOID,\n      })\n      ```\n      \n    - The Go type implements [`sql.Scanner`].\n    \n    - pgx is able to use reflection to build an object to write fields into.\n\n-   **Nested structs (composite types)**: pggen creates child structs to \n    represent Postgres [composite types] that appear in output columns.\n\n    ```sql\n    -- name: FindCompositeUser :one\n    SELECT ROW (15, 'qux')::\"user\" AS \"user\";\n    ```\n    \n    pggen generates the following Go code:\n    \n    ```go\n    // User represents the Postgres composite type \"user\".\n    type User struct {\n        ID   pgtype.Int8\n        Name pgtype.Text\n    }\n    \n    func (q *DBQuerier) FindCompositeUser(ctx context.Context) (User, error) {}\n    ```\n\n[pgtype repo]: https://github.com/jackc/pgtype\n[`pgtype.BinaryDecoder`]: https://pkg.go.dev/github.com/jackc/pgtype#BinaryDecoder\n[`pgtype.TextDecoder`]: https://pkg.go.dev/github.com/jackc/pgtype#TextDecoder\n[`ConnInfo.RegisterDataType`]: https://pkg.go.dev/github.com/jackc/pgtype#ConnInfo.RegisterDataType\n[`sql.Scanner`]: https://golang.org/pkg/database/sql/#Scanner\n[composite types]: https://www.postgresql.org/docs/current/rowtypes.html\n[example/custom_types test]: ./example/custom_types/query.sql_test.go\n\n# IDE integration\n\nIf your IDE provides SQL autocomplete, you may want to get rid of its warnings\nby declaring the following DDL schema.\n\n```sql\n-- Exists solely so editors don't underline every pggen.arg() expression in\n-- squiggly red.\nCREATE SCHEMA pggen;\n\n-- pggen.arg defines a named parameter that's eventually compiled into a\n-- placeholder for a prepared query: $1, $2, etc.\nCREATE FUNCTION pggen.arg(param TEXT) RETURNS text AS $$SELECT null$$ LANGUAGE sql;\n```\n\n# Tutorial\n\nLet's say we have a database with the following schema in `author/schema.sql`:\n\n```sql\nCREATE TABLE author (\n  author_id  serial PRIMARY KEY,\n  first_name text NOT NULL,\n  last_name  text NOT NULL,\n  suffix     text NULL\n)\n```\n\nFirst, write a query in the file `author/query.sql`. The query name is \n`FindAuthors` and the query returns `:many` rows. A query can return `:many` \nrows, `:one` row, or `:exec` for update, insert, and delete queries.\n\n```sql\n-- FindAuthors finds authors by first name.\n-- name: FindAuthors :many\nSELECT * FROM author WHERE first_name = pggen.arg('first_name');\n```\n\nSecond, use pggen to generate Go code to `author/query.sql.go`:\n\n```bash\npggen gen go \\\n    --schema-glob author/schema.sql \\\n    --query-glob author/query.sql\n```\n\nWe'll walk through the generated file `author/query.sql.go`:\n\n-   The `Querier` interface defines the interface with methods for each SQL \n    query. Each SQL query compiles into three methods, one method for to run \n    the query by itself, and two methods to support batching a query with \n    [`pgx.Batch`]. \n  \n    ```go\n    // Querier is a typesafe Go interface backed by SQL queries.\n    //\n    // Methods ending with Batch enqueue a query to run later in a pgx.Batch. After\n    // calling SendBatch on pgx.Conn, pgxpool.Pool, or pgx.Tx, use the Scan methods\n    // to parse the results.\n    type Querier interface {\n        // FindAuthors finds authors by first name.\n        FindAuthors(ctx context.Context, firstName string) ([]FindAuthorsRow, error)\n        // FindAuthorsBatch enqueues a FindAuthors query into batch to be executed\n        // later by the batch.\n        FindAuthorsBatch(batch *pgx.Batch, firstName string)\n        // FindAuthorsScan scans the result of an executed FindAuthorsBatch query.\n        FindAuthorsScan(results pgx.BatchResults) ([]FindAuthorsRow, error)\n    }\n    ```\n    \n    To use the batch interface, create a `*pgx.Batch`, call the \n    `\u003cquery_name\u003eBatch` methods, send the batch, and finally get the results \n    with the `\u003cquery_name\u003eScan` methods. See [example/author/query.sql_test.go] \n    for complete example.\n    \n    ```sql\n\tq := NewQuerier(conn)\n\tbatch := \u0026pgx.Batch{}\n\tq.FindAuthorsBatch(batch, \"alice\")\n\tq.FindAuthorsBatch(batch, \"bob\")\n\tresults := conn.SendBatch(context.Background(), batch)\n\taliceAuthors, err := q.FindAuthorsScan(results)\n\tbobAuthors, err := q.FindAuthorsScan(results)\n    ```\n\n-   The `DBQuerier` struct implements the `Querier` interface with concrete\n    implementations of each query method.\n\n    ```sql\n    type DBQuerier struct {\n        conn genericConn\n    }\n    ```\n\n-   Create `DBQuerier` with `NewQuerier`. The `genericConn` parameter is an \n    interface over the different pgx connection transports so that `DBQuerier` \n    doesn't force you to use a specific connection transport. [`*pgx.Conn`], \n    [`pgx.Tx`], and [`*pgxpool.Pool`] all implement `genericConn`.\n\n    ```sql\n    // NewQuerier creates a DBQuerier that implements Querier. conn is typically\n    // *pgx.Conn, pgx.Tx, or *pgxpool.Pool.\n    func NewQuerier(conn genericConn) *DBQuerier {\n        return \u0026DBQuerier{\n            conn: conn,\n        }\n    }\n    ```\n    \n-   pggen embeds the SQL query formatted for a Postgres `PREPARE` statement with\n    parameters indicated by `$1`, `$2`, etc. instead of \n    `pggen.arg('first_name')`.\n\n    ```sql\n    const findAuthorsSQL = `SELECT * FROM author WHERE first_name = $1;`\n    ```\n    \n-   pggen generates a row struct for each query named `\u003cquery_name\u003eRow`.\n    pggen transforms the output column names into struct field names from\n    `lower_snake_case` to `UpperCamelCase` in [internal/casing/casing.go]. \n    pggen derives JSON struct tags from the Postgres column names. To change the\n    JSON struct name, change the column name in the query.\n    \n    ```sql\n    type FindAuthorsRow struct {\n        AuthorID  int32       `json:\"author_id\"`\n        FirstName string      `json:\"first_name\"`\n        LastName  string      `json:\"last_name\"`\n        Suffix    pgtype.Text `json:\"suffix\"`\n    }\n    ```\n\n    As a convenience, if a query only generates a single column, pggen skips\n    creating the `\u003cquery_name\u003eRow` struct and returns the type directly.  For\n    example, the generated query for `SELECT author_id from author` returns \n    `int32`, not a `\u003cquery_name\u003eRow` struct.\n    \n    pggen infers struct field types by preparing the query. When Postgres\n    prepares a query, Postgres returns the parameter and column types as OIDs.\n    pggen finds the type name from the returned OIDs in\n    [internal/codegen/golang/gotype/types.go].\n    \n    Choosing an appropriate type is more difficult than might seem at first \n    glance due to `null`. When Postgres reports that a column has a type `text`,\n    that column can have  both `text` and `null` values. So, the Postgres `text`\n    represented in Go can be either a `string` or `nil`. [`pgtype`] provides \n    nullable types for all built-in Postgres types. pggen tries to infer if a \n    column is nullable or non-nullable. If a column is nullable, pggen uses a \n    `pgtype` Go type like `pgtype.Text`. If a column is non-nullable, pggen uses\n     a more ergonomic type like `string`. pggen's nullability inference\n     implemented in [internal/pginfer/nullability.go] is rudimentary; a proper\n     approach requires a full explain-plan with some control flow analysis.\n    \n-   Lastly, pggen generates the implementation for each query.\n\n    As a convenience, if a there are only one or two query parameters, pggen\n    inlines the parameters into the method definition, as with `firstName` \n    below. If there are three or more parameters, pggen creates a struct named\n    `\u003cquery_name\u003eParams` to pass the parameters to the query method.\n    \n    ```sql\n    // FindAuthors implements Querier.FindAuthors.\n    func (q *DBQuerier) FindAuthors(ctx context.Context, firstName string) ([]FindAuthorsRow, error) {\n        rows, err := q.conn.Query(ctx, findAuthorsSQL, firstName)\n        if rows != nil {\n            defer rows.Close()\n        }\n        if err != nil {\n            return nil, fmt.Errorf(\"query FindAuthors: %w\", err)\n        }\n        items := []FindAuthorsRow{}\n        for rows.Next() {\n            var item FindAuthorsRow\n            if err := rows.Scan(\u0026item.AuthorID, \u0026item.FirstName, \u0026item.LastName, \u0026item.Suffix); err != nil {\n                return nil, fmt.Errorf(\"scan FindAuthors row: %w\", err)\n            }\n            items = append(items, item)\n        }\n        if err := rows.Err(); err != nil {\n            return nil, err\n        }\n        return items, err\n    }\n    ```\n\n[example/author/query.sql_test.go]: ./example/author/query.sql_test.go\n[`pgx.Batch`]: https://pkg.go.dev/github.com/jackc/pgx#Batch\n[`*pgx.Conn`]: https://pkg.go.dev/github.com/jackc/pgx#Conn\n[`pgx.Tx`]: https://pkg.go.dev/github.com/jackc/pgx#Tx\n[`*pgxpool.Pool`]: https://pkg.go.dev/github.com/jackc/pgx/v4/pgxpool#Pool\n[internal/casing/casing.go]: ./internal/casing/casing.go\n[internal/codegen/golang/gotype/types.go]: ./internal/codegen/golang/gotype/types.go\n[`pgtype`]: https://pkg.go.dev/github.com/jackc/pgtype\n[internal/pginfer/nullability.go]: ./internal/pginfer/nullability.go\n\n# Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) and [ARCHITECTURE.md](ARCHITECTURE.md).\n\n# Acknowledgments\n\npggen was directly inspired by [sqlc]. The primary difference between pggen and\nsqlc is how each tool infers the type and nullability of the input parameters\nand output columns for SQL queries.\n\nsqlc parses the queries in Go code, using Cgo to call the Postgres `parser.c` \nlibrary. After parsing, sqlc infers the types of the query parameters and result\ncolumns using custom logic in Go. In contrast, pggen gets the same type \ninformation by running the queries on Postgres and then fetching the type \ninformation for Postgres catalog tables. \n\nUse sqlc if you don't wish to run Postgres to generate code or if you need\nbetter nullability analysis than pggen provides.\n\nUse pggen if you can run Postgres for code generation, and you use complex \nqueries that sqlc is unable to parse. Additionally, use pggen if you have a \ncustom database setup that's difficult to replicate in a schema file. pggen\nsupports running on any database with any extensions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjschaf%2Fpggen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjschaf%2Fpggen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjschaf%2Fpggen/lists"}