Skip to content
This repository was archived by the owner on Jul 10, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sqlc generates **type-safe code** from SQL. Here's how it works:
1. You run sqlc to generate code with type-safe interfaces to those queries.
1. You write application code that calls the generated code.

Check out [an interactive example](https://play.sqlc.dev/) to see it in action.
Check out [an interactive example](https://play.sqlc.dev/) to see it in action, and the [introductory blog post](https://conroy.org/introducing-sqlc) for the motivation behind sqlc.

## Overview

Expand Down
113 changes: 113 additions & 0 deletions docs/guides/using-go-and-pgx.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
================
Using Go and pgx
================

.. note::
Experimental support for :code:`pgx/v5` was added in v1.17.2. Full support will be
included in v1.18.0. Until then, you'll need to pass the :code:`--experimental`
flag to :code:`sqlc generate`.


pgx is a pure Go driver and toolkit for PostgreSQL. It's become the default
PostgreSQL package for many Gophers since lib/pq was put into maitience mode.

^^^^^^^^^^^^^^^
Getting started
^^^^^^^^^^^^^^^

To start generating code that uses pgx, set the :code:`sql_package` field in
your :code:`sqlc.yaml` configuration file. Valid options are :code:`pgx/v4` or
:code:`pgx/v5`

.. code-block:: yaml

version: "2"
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "query.sql"
gen:
go:
package: "db"
sql_package: "pgx/v5"
out: "db"

If you don't have an existing sqlc project on hand, create a directory with the
configuration file above and the following :code:`query.sql` file.

.. code-block:: sql

CREATE TABLE authors (
id BIGSERIAL PRIMARY KEY,
name text NOT NULL,
bio text
);

-- name: GetAuthor :one
SELECT * FROM authors
WHERE id = $1 LIMIT 1;

-- name: ListAuthors :many
SELECT * FROM authors
ORDER BY name;

-- name: CreateAuthor :one
INSERT INTO authors (
name, bio
) VALUES (
$1, $2
)
RETURNING *;

-- name: DeleteAuthor :exec
DELETE FROM authors
WHERE id = $1;


Generating the code will now give you pgx-compatible database access methods.

.. code-block:: bash

sqlc generate --experimental

^^^^^^^^^^^^^^^^^^^^^^^^^^
Generated code walkthrough
^^^^^^^^^^^^^^^^^^^^^^^^^^

The generated code is very similar to the code generated when using
:code:`lib/pq`. However, instead of using :code:`database/sql`, the code uses
pgx types directly.

.. code-block:: go

package main

import (
"context"
"fmt"
"os"

"github.com/jackc/pgx/v5"

"example.com/sqlc-tutorial/db"
)

func main() {
// urlExample := "postgres://username:password@localhost:5432/database_name"
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
os.Exit(1)
}
defer conn.Close(context.Background())

q := db.New(conn)

author, err := q.GetAuthor(context.Background(), 1)
if err != nil {
fmt.Fprintf(os.Stderr, "GetAuthor failed: %v\n", err)
os.Exit(1)
}

fmt.Println(author.Name)
}
110 changes: 110 additions & 0 deletions docs/howto/select.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ func (q *Queries) GetInfoForAuthor(ctx context.Context, id int) (GetInfoForAutho

## Passing a slice as a parameter to a query

### PostgreSQL

In PostgreSQL,
[ANY](https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.28.16)
allows you to check if a value exists in an array expression. Queries using ANY
Expand Down Expand Up @@ -262,3 +264,111 @@ func (q *Queries) ListAuthorsByIDs(ctx context.Context, ids []int) ([]Author, er
return items, nil
}
```

### MySQL

MySQL differs from PostgreSQL in that placeholders must be generated based on
the number of elements in the slice you pass in. Though trivial it is still
something of a nuisance. The passed in slice must not be nil or empty or an
error will be returned (ie not a panic). The placeholder insertion location is
marked by the meta-function `sqlc.slice()` (which is similar to `sqlc.arg()`
that you see documented under [Naming parameters](named_parameters.md)).

To rephrase, the `sqlc.slice('param')` behaves identically to `sqlc.arg()` it
terms of how it maps the explicit argument to the function signature, eg:

* `sqlc.slice('ids')` maps to `ids []GoType` in the function signature
* `sqlc.slice(cust_ids)` maps to `custIds []GoType` in the function signature
(like `sqlc.arg()`, the parameter does not have to be quoted)

This feature is not compatible with `emit_prepared_queries` statement found in the
[Configuration file](../reference/config.md).

```sql
CREATE TABLE authors (
id SERIAL PRIMARY KEY,
bio text NOT NULL,
birth_year int NOT NULL
);

-- name: ListAuthorsByIDs :many
SELECT * FROM authors
WHERE id IN (sqlc.slice('ids'));
```

The above SQL will generate the following code:

```go
package db

import (
"context"
"database/sql"
"fmt"
"strings"
)

type Author struct {
ID int
Bio string
BirthYear int
}

type DBTX interface {
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}

func New(db DBTX) *Queries {
return &Queries{db: db}
}

type Queries struct {
db DBTX
}

func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
}
}

const listAuthorsByIDs = `-- name: ListAuthorsByIDs :many
SELECT id, bio, birth_year FROM authors
WHERE id IN (/*SLICE:ids*/?)
`

func (q *Queries) ListAuthorsByIDs(ctx context.Context, ids []int64) ([]Author, error) {
sql := listAuthorsByIDs
var queryParams []interface{}
if len(ids) == 0 {
return nil, fmt.Errorf("slice ids must have at least one element")
}
for _, v := range ids {
queryParams = append(queryParams, v)
}
sql = strings.Replace(sql, "/*SLICE:ids*/?", strings.Repeat(",?", len(ids))[1:], 1)
rows, err := q.db.QueryContext(ctx, sql, queryParams...)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Author
for rows.Next() {
var i Author
if err := rows.Scan(&i.ID, &i.Bio, &i.BirthYear); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
```
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ code ever again.
:caption: Conceptual Guides
:hidden:

guides/using-go-and-pgx.rst
guides/development.md
guides/plugins.md
guides/privacy.md
3 changes: 2 additions & 1 deletion docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ sql:
Each mapping in the `sql` collection has the following keys:

- `engine`:
- Either `postgresql` or `mysql`.
- One of `postgresql`, `mysql` or `sqlite`.
- `schema`:
- Directory of SQL migrations or path to single SQL file; or a list of paths.
- `queries`:
Expand Down Expand Up @@ -213,6 +213,7 @@ sql:
import: "a/b/v2"
package: "b"
type: "MyType"
pointer: true
```

When generating code, entries using the `column` key will always have preference over
Expand Down
22 changes: 22 additions & 0 deletions docs/reference/environment-variables.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Environment variables

## SQLCCACHE

The `SQLCCACHE` environment variable dictates where `sqlc` will store cached
WASM-based plugins and modules. By default `sqlc` follows the [XDG Base
Directory
Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).

## SQLCDEBUG

The `SQLCDEBUG` variable controls debugging variables within the runtime. It is
Expand Down Expand Up @@ -110,3 +117,18 @@ log showing the execution time for each package.
0.046042779 . 5148212 1 region writefiles started (duration: 1.718259ms)
0.047767781 . 1725002 1 task end
```

### processplugins

Setting this value to `0` disables process-based plugins. If a process-based
plugin is declared in the configuration file, running any `sqlc` command will
return an error.

`SQLCDEBUG=processplugins=0`

## SQLCTMPDIR

If specified, use the given directory as the base for temporary folders. Only
applies when using WASM-based codegen plugins. When not specified, this
defaults to passing an empty string to
[`os.MkdirTemp`](https://pkg.go.dev/os#MkdirTemp).
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/kyleconroy/sqlc
go 1.20

require (
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1
github.com/bytecodealliance/wasmtime-go/v5 v5.0.0
github.com/cubicdaiya/gonp v1.0.4
github.com/davecgh/go-spew v1.1.1
Expand All @@ -25,7 +25,7 @@ require (
require (
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
)

require (
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1 h1:X8MJ0fnN5FPdcGF5Ij2/OW+HgiJrRg3AfHAx1PJtIzM=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bytecodealliance/wasmtime-go/v5 v5.0.0 h1:Ue3eBDElMrdzWoUtr7uPr7NeDZriuR5oIivp5EHknQU=
Expand Down Expand Up @@ -201,8 +201,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4=
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
Expand Down
Loading