snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-16 02:17:34 +05:00
commit 0f4df23290
7340 changed files with 238743 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package authors
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *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,
}
}

View File

@@ -0,0 +1,53 @@
//go:build examples
package authors
import (
"context"
"database/sql"
"testing"
_ "github.com/go-sql-driver/mysql"
"github.com/sqlc-dev/sqlc/internal/sqltest/local"
)
func TestAuthors(t *testing.T) {
ctx := context.Background()
uri := local.MySQL(t, []string{"schema.sql"})
sdb, err := sql.Open("mysql", uri)
if err != nil {
t.Fatal(err)
}
defer sdb.Close()
db := New(sdb)
// list all authors
authors, err := db.ListAuthors(ctx)
if err != nil {
t.Fatal(err)
}
t.Log(authors)
// create an author
result, err := db.CreateAuthor(ctx, CreateAuthorParams{
Name: "Brian Kernighan",
Bio: sql.NullString{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true},
})
if err != nil {
t.Fatal(err)
}
authorID, err := result.LastInsertId()
if err != nil {
t.Fatal(err)
}
t.Log(authorID)
// get the author we just inserted
fetchedAuthor, err := db.GetAuthor(ctx, authorID)
if err != nil {
t.Fatal(err)
}
t.Log(fetchedAuthor)
}

View File

@@ -0,0 +1,15 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package authors
import (
"database/sql"
)
type Author struct {
ID int64
Name string
Bio sql.NullString
}

View File

@@ -0,0 +1,18 @@
/* name: GetAuthor :one */
SELECT * FROM authors
WHERE id = ? LIMIT 1;
/* name: ListAuthors :many */
SELECT * FROM authors
ORDER BY name;
/* name: CreateAuthor :execresult */
INSERT INTO authors (
name, bio
) VALUES (
?, ?
);
/* name: DeleteAuthor :exec */
DELETE FROM authors
WHERE id = ?;

View File

@@ -0,0 +1,78 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: query.sql
package authors
import (
"context"
"database/sql"
)
const createAuthor = `-- name: CreateAuthor :execresult
INSERT INTO authors (
name, bio
) VALUES (
?, ?
)
`
type CreateAuthorParams struct {
Name string
Bio sql.NullString
}
func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (sql.Result, error) {
return q.db.ExecContext(ctx, createAuthor, arg.Name, arg.Bio)
}
const deleteAuthor = `-- name: DeleteAuthor :exec
DELETE FROM authors
WHERE id = ?
`
func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, deleteAuthor, id)
return err
}
const getAuthor = `-- name: GetAuthor :one
SELECT id, name, bio FROM authors
WHERE id = ? LIMIT 1
`
func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) {
row := q.db.QueryRowContext(ctx, getAuthor, id)
var i Author
err := row.Scan(&i.ID, &i.Name, &i.Bio)
return i, err
}
const listAuthors = `-- name: ListAuthors :many
SELECT id, name, bio FROM authors
ORDER BY name
`
func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) {
rows, err := q.db.QueryContext(ctx, listAuthors)
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.Name, &i.Bio); 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
}

View File

@@ -0,0 +1,5 @@
CREATE TABLE authors (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name text NOT NULL,
bio text
);

View File

@@ -0,0 +1,32 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package authors
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
type DBTX interface {
Exec(context.Context, string, ...any) (pgconn.CommandTag, error)
Query(context.Context, string, ...any) (pgx.Rows, error)
QueryRow(context.Context, string, ...any) pgx.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
return &Queries{
db: tx,
}
}

View File

@@ -0,0 +1,49 @@
//go:build examples
package authors
import (
"context"
"testing"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
"github.com/sqlc-dev/sqlc/internal/sqltest/local"
)
func TestAuthors(t *testing.T) {
ctx := context.Background()
uri := local.PostgreSQL(t, []string{"schema.sql"})
db, err := pgx.Connect(ctx, uri)
if err != nil {
t.Fatal(err)
}
defer db.Close(ctx)
q := New(db)
// list all authors
authors, err := q.ListAuthors(ctx)
if err != nil {
t.Fatal(err)
}
t.Log(authors)
// create an author
insertedAuthor, err := q.CreateAuthor(ctx, CreateAuthorParams{
Name: "Brian Kernighan",
Bio: pgtype.Text{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true},
})
if err != nil {
t.Fatal(err)
}
t.Log(insertedAuthor)
// get the author we just inserted
fetchedAuthor, err := q.GetAuthor(ctx, insertedAuthor.ID)
if err != nil {
t.Fatal(err)
}
t.Log(fetchedAuthor)
}

View File

@@ -0,0 +1,15 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package authors
import (
"github.com/jackc/pgx/v5/pgtype"
)
type Author struct {
ID int64
Name string
Bio pgtype.Text
}

View File

@@ -0,0 +1,19 @@
-- 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;

View File

@@ -0,0 +1,80 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: query.sql
package authors
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const createAuthor = `-- name: CreateAuthor :one
INSERT INTO authors (
name, bio
) VALUES (
$1, $2
)
RETURNING id, name, bio
`
type CreateAuthorParams struct {
Name string
Bio pgtype.Text
}
func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) {
row := q.db.QueryRow(ctx, createAuthor, arg.Name, arg.Bio)
var i Author
err := row.Scan(&i.ID, &i.Name, &i.Bio)
return i, err
}
const deleteAuthor = `-- name: DeleteAuthor :exec
DELETE FROM authors
WHERE id = $1
`
func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error {
_, err := q.db.Exec(ctx, deleteAuthor, id)
return err
}
const getAuthor = `-- name: GetAuthor :one
SELECT id, name, bio FROM authors
WHERE id = $1 LIMIT 1
`
func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) {
row := q.db.QueryRow(ctx, getAuthor, id)
var i Author
err := row.Scan(&i.ID, &i.Name, &i.Bio)
return i, err
}
const listAuthors = `-- name: ListAuthors :many
SELECT id, name, bio FROM authors
ORDER BY name
`
func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) {
rows, err := q.db.Query(ctx, listAuthors)
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.Name, &i.Bio); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}

View File

@@ -0,0 +1,5 @@
CREATE TABLE authors (
id BIGSERIAL PRIMARY KEY,
name text NOT NULL,
bio text
);

View File

@@ -0,0 +1,52 @@
version: '2'
cloud:
project: "01HAQMMECEYQYKFJN8MP16QC41"
sql:
- name: postgresql
schema: postgresql/schema.sql
queries: postgresql/query.sql
engine: postgresql
database:
uri: "${VET_TEST_EXAMPLES_POSTGRES_AUTHORS}"
analyzer:
database: false
rules:
- sqlc/db-prepare
- postgresql-query-too-costly
gen:
go:
package: authors
sql_package: pgx/v5
out: postgresql
- name: mysql
schema: mysql/schema.sql
queries: mysql/query.sql
engine: mysql
database:
uri: "${VET_TEST_EXAMPLES_MYSQL_AUTHORS}"
rules:
- sqlc/db-prepare
# - mysql-query-too-costly
gen:
go:
package: authors
out: mysql
- name: sqlite
schema: sqlite/schema.sql
queries: sqlite/query.sql
engine: sqlite
database:
uri: file:authors?mode=memory&cache=shared
rules:
- sqlc/db-prepare
gen:
go:
package: authors
out: sqlite
rules:
- name: postgresql-query-too-costly
message: "Too costly"
rule: "postgresql.explain.plan.total_cost > 300.0"
- name: mysql-query-too-costly
message: "Too costly"
rule: "has(mysql.explain.query_block.cost_info) && double(mysql.explain.query_block.cost_info.query_cost) > 2.0"

View File

@@ -0,0 +1,31 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package authors
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *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,
}
}

View File

@@ -0,0 +1,48 @@
//go:build examples
package authors
import (
"context"
"database/sql"
"testing"
"github.com/sqlc-dev/sqlc/internal/sqltest"
)
func TestAuthors(t *testing.T) {
sdb, cleanup := sqltest.SQLite(t, []string{"schema.sql"})
defer sdb.Close()
defer cleanup()
ctx := context.Background()
db := New(sdb)
// list all authors
authors, err := db.ListAuthors(ctx)
if err != nil {
t.Fatal(err)
}
t.Log(authors)
// create an author
result, err := db.CreateAuthor(ctx, CreateAuthorParams{
Name: "Brian Kernighan",
Bio: sql.NullString{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true},
})
if err != nil {
t.Fatal(err)
}
authorID, err := result.LastInsertId()
if err != nil {
t.Fatal(err)
}
t.Log(authorID)
// get the author we just inserted
fetchedAuthor, err := db.GetAuthor(ctx, authorID)
if err != nil {
t.Fatal(err)
}
t.Log(fetchedAuthor)
}

View File

@@ -0,0 +1,15 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package authors
import (
"database/sql"
)
type Author struct {
ID int64
Name string
Bio sql.NullString
}

View File

@@ -0,0 +1,18 @@
/* name: GetAuthor :one */
SELECT * FROM authors
WHERE id = ? LIMIT 1;
/* name: ListAuthors :many */
SELECT * FROM authors
ORDER BY name;
/* name: CreateAuthor :execresult */
INSERT INTO authors (
name, bio
) VALUES (
?, ?
);
/* name: DeleteAuthor :exec */
DELETE FROM authors
WHERE id = ?;

View File

@@ -0,0 +1,78 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: query.sql
package authors
import (
"context"
"database/sql"
)
const createAuthor = `-- name: CreateAuthor :execresult
INSERT INTO authors (
name, bio
) VALUES (
?, ?
)
`
type CreateAuthorParams struct {
Name string
Bio sql.NullString
}
func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (sql.Result, error) {
return q.db.ExecContext(ctx, createAuthor, arg.Name, arg.Bio)
}
const deleteAuthor = `-- name: DeleteAuthor :exec
DELETE FROM authors
WHERE id = ?
`
func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error {
_, err := q.db.ExecContext(ctx, deleteAuthor, id)
return err
}
const getAuthor = `-- name: GetAuthor :one
SELECT id, name, bio FROM authors
WHERE id = ? LIMIT 1
`
func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) {
row := q.db.QueryRowContext(ctx, getAuthor, id)
var i Author
err := row.Scan(&i.ID, &i.Name, &i.Bio)
return i, err
}
const listAuthors = `-- name: ListAuthors :many
SELECT id, name, bio FROM authors
ORDER BY name
`
func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) {
rows, err := q.db.QueryContext(ctx, listAuthors)
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.Name, &i.Bio); 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
}

View File

@@ -0,0 +1,5 @@
CREATE TABLE authors (
id integer PRIMARY KEY AUTOINCREMENT,
name text NOT NULL,
bio text
);

View File

@@ -0,0 +1,404 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: batch.go
package batch
import (
"context"
"errors"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
)
var (
ErrBatchAlreadyClosed = errors.New("batch already closed")
)
const booksByYear = `-- name: BooksByYear :batchmany
SELECT book_id, author_id, isbn, book_type, title, year, available, tags FROM books
WHERE year = $1
`
type BooksByYearBatchResults struct {
br pgx.BatchResults
tot int
closed bool
}
func (q *Queries) BooksByYear(ctx context.Context, year []int32) *BooksByYearBatchResults {
batch := &pgx.Batch{}
for _, a := range year {
vals := []any{
a,
}
batch.Queue(booksByYear, vals...)
}
br := q.db.SendBatch(ctx, batch)
return &BooksByYearBatchResults{br, len(year), false}
}
func (b *BooksByYearBatchResults) Query(f func(int, []Book, error)) {
defer b.br.Close()
for t := 0; t < b.tot; t++ {
var items []Book
if b.closed {
if f != nil {
f(t, items, ErrBatchAlreadyClosed)
}
continue
}
err := func() error {
rows, err := b.br.Query()
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var i Book
if err := rows.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Year,
&i.Available,
&i.Tags,
); err != nil {
return err
}
items = append(items, i)
}
return rows.Err()
}()
if f != nil {
f(t, items, err)
}
}
}
func (b *BooksByYearBatchResults) Close() error {
b.closed = true
return b.br.Close()
}
const createBook = `-- name: CreateBook :batchone
INSERT INTO books (
author_id,
isbn,
book_type,
title,
year,
available,
tags
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7
)
RETURNING book_id, author_id, isbn, book_type, title, year, available, tags
`
type CreateBookBatchResults struct {
br pgx.BatchResults
tot int
closed bool
}
type CreateBookParams struct {
AuthorID int32 `json:"author_id"`
Isbn string `json:"isbn"`
BookType BookType `json:"book_type"`
Title string `json:"title"`
Year int32 `json:"year"`
Available pgtype.Timestamptz `json:"available"`
Tags []string `json:"tags"`
}
func (q *Queries) CreateBook(ctx context.Context, arg []CreateBookParams) *CreateBookBatchResults {
batch := &pgx.Batch{}
for _, a := range arg {
vals := []any{
a.AuthorID,
a.Isbn,
a.BookType,
a.Title,
a.Year,
a.Available,
a.Tags,
}
batch.Queue(createBook, vals...)
}
br := q.db.SendBatch(ctx, batch)
return &CreateBookBatchResults{br, len(arg), false}
}
func (b *CreateBookBatchResults) QueryRow(f func(int, Book, error)) {
defer b.br.Close()
for t := 0; t < b.tot; t++ {
var i Book
if b.closed {
if f != nil {
f(t, i, ErrBatchAlreadyClosed)
}
continue
}
row := b.br.QueryRow()
err := row.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Year,
&i.Available,
&i.Tags,
)
if f != nil {
f(t, i, err)
}
}
}
func (b *CreateBookBatchResults) Close() error {
b.closed = true
return b.br.Close()
}
const deleteBook = `-- name: DeleteBook :batchexec
DELETE FROM books
WHERE book_id = $1
`
type DeleteBookBatchResults struct {
br pgx.BatchResults
tot int
closed bool
}
func (q *Queries) DeleteBook(ctx context.Context, bookID []int32) *DeleteBookBatchResults {
batch := &pgx.Batch{}
for _, a := range bookID {
vals := []any{
a,
}
batch.Queue(deleteBook, vals...)
}
br := q.db.SendBatch(ctx, batch)
return &DeleteBookBatchResults{br, len(bookID), false}
}
func (b *DeleteBookBatchResults) Exec(f func(int, error)) {
defer b.br.Close()
for t := 0; t < b.tot; t++ {
if b.closed {
if f != nil {
f(t, ErrBatchAlreadyClosed)
}
continue
}
_, err := b.br.Exec()
if f != nil {
f(t, err)
}
}
}
func (b *DeleteBookBatchResults) Close() error {
b.closed = true
return b.br.Close()
}
const deleteBookNamedFunc = `-- name: DeleteBookNamedFunc :batchexec
DELETE FROM books
WHERE book_id = $1
`
type DeleteBookNamedFuncBatchResults struct {
br pgx.BatchResults
tot int
closed bool
}
func (q *Queries) DeleteBookNamedFunc(ctx context.Context, bookID []int32) *DeleteBookNamedFuncBatchResults {
batch := &pgx.Batch{}
for _, a := range bookID {
vals := []any{
a,
}
batch.Queue(deleteBookNamedFunc, vals...)
}
br := q.db.SendBatch(ctx, batch)
return &DeleteBookNamedFuncBatchResults{br, len(bookID), false}
}
func (b *DeleteBookNamedFuncBatchResults) Exec(f func(int, error)) {
defer b.br.Close()
for t := 0; t < b.tot; t++ {
if b.closed {
if f != nil {
f(t, ErrBatchAlreadyClosed)
}
continue
}
_, err := b.br.Exec()
if f != nil {
f(t, err)
}
}
}
func (b *DeleteBookNamedFuncBatchResults) Close() error {
b.closed = true
return b.br.Close()
}
const deleteBookNamedSign = `-- name: DeleteBookNamedSign :batchexec
DELETE FROM books
WHERE book_id = $1
`
type DeleteBookNamedSignBatchResults struct {
br pgx.BatchResults
tot int
closed bool
}
func (q *Queries) DeleteBookNamedSign(ctx context.Context, bookID []int32) *DeleteBookNamedSignBatchResults {
batch := &pgx.Batch{}
for _, a := range bookID {
vals := []any{
a,
}
batch.Queue(deleteBookNamedSign, vals...)
}
br := q.db.SendBatch(ctx, batch)
return &DeleteBookNamedSignBatchResults{br, len(bookID), false}
}
func (b *DeleteBookNamedSignBatchResults) Exec(f func(int, error)) {
defer b.br.Close()
for t := 0; t < b.tot; t++ {
if b.closed {
if f != nil {
f(t, ErrBatchAlreadyClosed)
}
continue
}
_, err := b.br.Exec()
if f != nil {
f(t, err)
}
}
}
func (b *DeleteBookNamedSignBatchResults) Close() error {
b.closed = true
return b.br.Close()
}
const getBiography = `-- name: GetBiography :batchone
SELECT biography FROM authors
WHERE author_id = $1
`
type GetBiographyBatchResults struct {
br pgx.BatchResults
tot int
closed bool
}
func (q *Queries) GetBiography(ctx context.Context, authorID []int32) *GetBiographyBatchResults {
batch := &pgx.Batch{}
for _, a := range authorID {
vals := []any{
a,
}
batch.Queue(getBiography, vals...)
}
br := q.db.SendBatch(ctx, batch)
return &GetBiographyBatchResults{br, len(authorID), false}
}
func (b *GetBiographyBatchResults) QueryRow(f func(int, []byte, error)) {
defer b.br.Close()
for t := 0; t < b.tot; t++ {
var biography []byte
if b.closed {
if f != nil {
f(t, biography, ErrBatchAlreadyClosed)
}
continue
}
row := b.br.QueryRow()
err := row.Scan(&biography)
if f != nil {
f(t, biography, err)
}
}
}
func (b *GetBiographyBatchResults) Close() error {
b.closed = true
return b.br.Close()
}
const updateBook = `-- name: UpdateBook :batchexec
UPDATE books
SET title = $1, tags = $2
WHERE book_id = $3
`
type UpdateBookBatchResults struct {
br pgx.BatchResults
tot int
closed bool
}
type UpdateBookParams struct {
Title string `json:"title"`
Tags []string `json:"tags"`
BookID int32 `json:"book_id"`
}
func (q *Queries) UpdateBook(ctx context.Context, arg []UpdateBookParams) *UpdateBookBatchResults {
batch := &pgx.Batch{}
for _, a := range arg {
vals := []any{
a.Title,
a.Tags,
a.BookID,
}
batch.Queue(updateBook, vals...)
}
br := q.db.SendBatch(ctx, batch)
return &UpdateBookBatchResults{br, len(arg), false}
}
func (b *UpdateBookBatchResults) Exec(f func(int, error)) {
defer b.br.Close()
for t := 0; t < b.tot; t++ {
if b.closed {
if f != nil {
f(t, ErrBatchAlreadyClosed)
}
continue
}
_, err := b.br.Exec()
if f != nil {
f(t, err)
}
}
}
func (b *UpdateBookBatchResults) Close() error {
b.closed = true
return b.br.Close()
}

View File

@@ -0,0 +1,33 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package batch
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
type DBTX interface {
Exec(context.Context, string, ...any) (pgconn.CommandTag, error)
Query(context.Context, string, ...any) (pgx.Rows, error)
QueryRow(context.Context, string, ...any) pgx.Row
SendBatch(context.Context, *pgx.Batch) pgx.BatchResults
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
return &Queries{
db: tx,
}
}

View File

@@ -0,0 +1,153 @@
//go:build examples
package batch
import (
"context"
"testing"
"time"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
"github.com/sqlc-dev/sqlc/internal/sqltest/local"
)
func TestBatchBooks(t *testing.T) {
uri := local.PostgreSQL(t, []string{"schema.sql"})
ctx := context.Background()
db, err := pgx.Connect(ctx, uri)
if err != nil {
t.Fatal(err)
}
defer db.Close(ctx)
dq := New(db)
// create an author
a, err := dq.CreateAuthor(ctx, "Unknown Master")
if err != nil {
t.Fatal(err)
}
now := pgtype.Timestamptz{Time: time.Now(), Valid: true}
// batch insert new books
newBooksParams := []CreateBookParams{
{
AuthorID: a.AuthorID,
Isbn: "1",
Title: "my book title",
BookType: BookTypeFICTION,
Year: 2016,
Available: now,
Tags: []string{},
},
{
AuthorID: a.AuthorID,
Isbn: "2",
Title: "the second book",
BookType: BookTypeFICTION,
Year: 2016,
Available: now,
Tags: []string{"cool", "unique"},
},
{
AuthorID: a.AuthorID,
Isbn: "3",
Title: "the third book",
BookType: BookTypeFICTION,
Year: 2001,
Available: now,
Tags: []string{"cool"},
},
{
AuthorID: a.AuthorID,
Isbn: "4",
Title: "4th place finisher",
BookType: BookTypeNONFICTION,
Year: 2011,
Available: now,
Tags: []string{"other"},
},
}
newBooks := make([]Book, len(newBooksParams))
var cnt int
dq.CreateBook(ctx, newBooksParams).QueryRow(func(i int, b Book, err error) {
if err != nil {
t.Fatalf("failed inserting book (%s): %s", b.Title, err)
}
newBooks[i] = b
cnt = i
})
// first i was 0, so add 1
cnt++
numBooksExpected := len(newBooks)
if cnt != numBooksExpected {
t.Fatalf("expected to insert %d books; got %d", numBooksExpected, cnt)
}
// batch update the title and tags
updateBooksParams := []UpdateBookParams{
{
BookID: newBooks[1].BookID,
Title: "changed second title",
Tags: []string{"cool", "disastor"},
},
}
dq.UpdateBook(ctx, updateBooksParams).Exec(func(i int, err error) {
if err != nil {
t.Fatalf("error updating book %d: %s", updateBooksParams[i].BookID, err)
}
})
// batch many to retrieve books by year
selectBooksByTitleYearParams := []int32{2001, 2016}
var books0 []Book
dq.BooksByYear(ctx, selectBooksByTitleYearParams).Query(func(i int, books []Book, err error) {
if err != nil {
t.Fatal(err)
}
t.Logf("num books for %d: %d", selectBooksByTitleYearParams[i], len(books))
books0 = append(books0, books...)
})
for _, book := range books0 {
t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Time.Format(time.RFC822Z))
author, err := dq.GetAuthor(ctx, book.AuthorID)
if err != nil {
t.Fatal(err)
}
t.Logf("Book %d author: %s\n", book.BookID, author.Name)
}
// batch delete books
deleteBooksParams := make([]int32, len(newBooks))
for i, book := range newBooks {
deleteBooksParams[i] = book.BookID
}
batchDelete := dq.DeleteBook(ctx, deleteBooksParams)
numDeletesProcessed := 0
wantNumDeletesProcessed := 2
batchDelete.Exec(func(i int, err error) {
if err != nil && err.Error() != "batch already closed" {
t.Fatalf("error deleting book %d: %s", deleteBooksParams[i], err)
}
if err == nil {
numDeletesProcessed++
}
if i == wantNumDeletesProcessed-1 {
// close batch operation before processing all errors from delete operation
if err := batchDelete.Close(); err != nil {
t.Fatalf("failed to close batch operation: %s", err)
}
}
})
if numDeletesProcessed != wantNumDeletesProcessed {
t.Fatalf("expected Close to short-circuit record processing (expected %d; got %d)", wantNumDeletesProcessed, numDeletesProcessed)
}
}

View File

@@ -0,0 +1,71 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package batch
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgx/v5/pgtype"
)
type BookType string
const (
BookTypeFICTION BookType = "FICTION"
BookTypeNONFICTION BookType = "NONFICTION"
)
func (e *BookType) Scan(src any) error {
switch s := src.(type) {
case []byte:
*e = BookType(s)
case string:
*e = BookType(s)
default:
return fmt.Errorf("unsupported scan type for BookType: %T", src)
}
return nil
}
type NullBookType struct {
BookType BookType `json:"book_type"`
Valid bool `json:"valid"` // Valid is true if BookType is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullBookType) Scan(value any) error {
if value == nil {
ns.BookType, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.BookType.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullBookType) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.BookType), nil
}
type Author struct {
AuthorID int32 `json:"author_id"`
Name string `json:"name"`
Biography []byte `json:"biography"`
}
type Book struct {
BookID int32 `json:"book_id"`
AuthorID int32 `json:"author_id"`
Isbn string `json:"isbn"`
BookType BookType `json:"book_type"`
Title string `json:"title"`
Year int32 `json:"year"`
Available pgtype.Timestamptz `json:"available"`
Tags []string `json:"tags"`
}

View File

@@ -0,0 +1,26 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package batch
import (
"context"
"github.com/jackc/pgx/v5/pgconn"
)
type Querier interface {
BooksByYear(ctx context.Context, year []int32) *BooksByYearBatchResults
CreateAuthor(ctx context.Context, name string) (Author, error)
CreateBook(ctx context.Context, arg []CreateBookParams) *CreateBookBatchResults
DeleteBook(ctx context.Context, bookID []int32) *DeleteBookBatchResults
DeleteBookExecResult(ctx context.Context, bookID int32) (pgconn.CommandTag, error)
DeleteBookNamedFunc(ctx context.Context, bookID []int32) *DeleteBookNamedFuncBatchResults
DeleteBookNamedSign(ctx context.Context, bookID []int32) *DeleteBookNamedSignBatchResults
GetAuthor(ctx context.Context, authorID int32) (Author, error)
GetBiography(ctx context.Context, authorID []int32) *GetBiographyBatchResults
UpdateBook(ctx context.Context, arg []UpdateBookParams) *UpdateBookBatchResults
}
var _ Querier = (*Queries)(nil)

View File

@@ -0,0 +1,56 @@
-- name: GetAuthor :one
SELECT * FROM authors
WHERE author_id = $1;
-- name: DeleteBookExecResult :execresult
DELETE FROM books
WHERE book_id = $1;
-- name: DeleteBook :batchexec
DELETE FROM books
WHERE book_id = $1;
-- name: DeleteBookNamedFunc :batchexec
DELETE FROM books
WHERE book_id = sqlc.arg (book_id);
-- name: DeleteBookNamedSign :batchexec
DELETE FROM books
WHERE book_id = @book_id;
-- name: BooksByYear :batchmany
SELECT * FROM books
WHERE year = $1;
-- name: CreateAuthor :one
INSERT INTO authors (name) VALUES ($1)
RETURNING *;
-- name: CreateBook :batchone
INSERT INTO books (
author_id,
isbn,
book_type,
title,
year,
available,
tags
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7
)
RETURNING *;
-- name: UpdateBook :batchexec
UPDATE books
SET title = $1, tags = $2
WHERE book_id = $3;
-- name: GetBiography :batchone
SELECT biography FROM authors
WHERE author_id = $1;

View File

@@ -0,0 +1,45 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: query.sql
package batch
import (
"context"
"github.com/jackc/pgx/v5/pgconn"
)
const createAuthor = `-- name: CreateAuthor :one
INSERT INTO authors (name) VALUES ($1)
RETURNING author_id, name, biography
`
func (q *Queries) CreateAuthor(ctx context.Context, name string) (Author, error) {
row := q.db.QueryRow(ctx, createAuthor, name)
var i Author
err := row.Scan(&i.AuthorID, &i.Name, &i.Biography)
return i, err
}
const deleteBookExecResult = `-- name: DeleteBookExecResult :execresult
DELETE FROM books
WHERE book_id = $1
`
func (q *Queries) DeleteBookExecResult(ctx context.Context, bookID int32) (pgconn.CommandTag, error) {
return q.db.Exec(ctx, deleteBookExecResult, bookID)
}
const getAuthor = `-- name: GetAuthor :one
SELECT author_id, name, biography FROM authors
WHERE author_id = $1
`
func (q *Queries) GetAuthor(ctx context.Context, authorID int32) (Author, error) {
row := q.db.QueryRow(ctx, getAuthor, authorID)
var i Author
err := row.Scan(&i.AuthorID, &i.Name, &i.Biography)
return i, err
}

View File

@@ -0,0 +1,21 @@
CREATE TABLE authors (
author_id SERIAL PRIMARY KEY,
name text NOT NULL DEFAULT '',
biography JSONB
);
CREATE TYPE book_type AS ENUM (
'FICTION',
'NONFICTION'
);
CREATE TABLE books (
book_id SERIAL PRIMARY KEY,
author_id integer NOT NULL REFERENCES authors(author_id),
isbn text NOT NULL DEFAULT '' UNIQUE,
book_type book_type NOT NULL DEFAULT 'FICTION',
title text NOT NULL DEFAULT '',
year integer NOT NULL DEFAULT 2000,
available timestamp with time zone NOT NULL DEFAULT 'NOW()',
tags varchar[] NOT NULL DEFAULT '{}'
);

28
examples/batch/sqlc.json Normal file
View File

@@ -0,0 +1,28 @@
{
"version": "1",
"cloud": {
"project": "01HAQMMECEYQYKFJN8MP16QC41"
},
"packages": [
{
"path": "postgresql",
"name": "batch",
"schema": "postgresql/schema.sql",
"queries": "postgresql/query.sql",
"engine": "postgresql",
"database": {
"uri": "${VET_TEST_EXAMPLES_POSTGRES_BATCH}"
},
"analyzer": {
"database": false
},
"rules": [
"sqlc/db-prepare"
],
"sql_package": "pgx/v5",
"emit_json_tags": true,
"emit_prepared_queries": true,
"emit_interface": true
}
]
}

View File

@@ -0,0 +1,31 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package booktest
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *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,
}
}

View File

@@ -0,0 +1,174 @@
//go:build examples
package booktest
import (
"context"
"database/sql"
"testing"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/sqlc-dev/sqlc/internal/sqltest/local"
)
func TestBooks(t *testing.T) {
ctx := context.Background()
uri := local.MySQL(t, []string{"schema.sql"})
db, err := sql.Open("mysql", uri)
if err != nil {
t.Fatal(err)
}
defer db.Close()
dq := New(db)
// create an author
result, err := dq.CreateAuthor(ctx, "Unknown Master")
if err != nil {
t.Fatal(err)
}
authorID, err := result.LastInsertId()
if err != nil {
t.Fatal(err)
}
// create transaction
tx, err := db.Begin()
if err != nil {
t.Fatal(err)
}
tq := dq.WithTx(tx)
// save first book
now := time.Now()
_, err = tq.CreateBook(ctx, CreateBookParams{
AuthorID: int32(authorID),
Isbn: "1",
Title: "my book title",
BookType: BooksBookTypeFICTION,
Yr: 2016,
Available: now,
})
if err != nil {
t.Fatal(err)
}
// save second book
result, err = tq.CreateBook(ctx, CreateBookParams{
AuthorID: int32(authorID),
Isbn: "2",
Title: "the second book",
BookType: BooksBookTypeFICTION,
Yr: 2016,
Available: now,
Tags: "cool,unique",
})
if err != nil {
t.Fatal(err)
}
bookOneID, err := result.LastInsertId()
if err != nil {
t.Fatal(err)
}
// update the title and tags
err = tq.UpdateBook(ctx, UpdateBookParams{
BookID: int32(bookOneID),
Title: "changed second title",
Tags: "cool,disastor",
})
if err != nil {
t.Fatal(err)
}
// save third book
_, err = tq.CreateBook(ctx, CreateBookParams{
AuthorID: int32(authorID),
Isbn: "3",
Title: "the third book",
BookType: BooksBookTypeFICTION,
Yr: 2001,
Available: now,
Tags: "cool",
})
if err != nil {
t.Fatal(err)
}
// save fourth book
result, err = tq.CreateBook(ctx, CreateBookParams{
AuthorID: int32(authorID),
Isbn: "4",
Title: "4th place finisher",
BookType: BooksBookTypeNONFICTION,
Yr: 2011,
Available: now,
Tags: "other",
})
if err != nil {
t.Fatal(err)
}
bookThreeID, err := result.LastInsertId()
if err != nil {
t.Fatal(err)
}
// tx commit
err = tx.Commit()
if err != nil {
t.Fatal(err)
}
// upsert, changing ISBN and title
err = dq.UpdateBookISBN(ctx, UpdateBookISBNParams{
BookID: int32(bookThreeID),
Isbn: "NEW ISBN",
Title: "never ever gonna finish, a quatrain",
Tags: "someother",
})
if err != nil {
t.Fatal(err)
}
// retrieve first book
books0, err := dq.BooksByTitleYear(ctx, BooksByTitleYearParams{
Title: "my book title",
Yr: 2016,
})
if err != nil {
t.Fatal(err)
}
for _, book := range books0 {
t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Format(time.RFC822Z))
author, err := dq.GetAuthor(ctx, book.AuthorID)
if err != nil {
t.Fatal(err)
}
t.Logf("Book %d author: %s\n", book.BookID, author.Name)
}
// find a book with either "cool" or "other" tag
t.Logf("---------\nTag search results:\n")
res, err := dq.BooksByTags(ctx, "cool")
if err != nil {
t.Fatal(err)
}
for _, ab := range res {
t.Logf("Book %d: '%s', Author: '%s', ISBN: '%s' Tags: '%v'\n", ab.BookID, ab.Title, ab.Name.String, ab.Isbn, ab.Tags)
}
// TODO: call say_hello(varchar)
// get book 4 and delete
b5, err := dq.GetBook(ctx, int32(bookThreeID))
if err != nil {
t.Fatal(err)
}
if err := dq.DeleteBook(ctx, b5.BookID); err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,69 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package booktest
import (
"database/sql/driver"
"fmt"
"time"
)
type BooksBookType string
const (
BooksBookTypeFICTION BooksBookType = "FICTION"
BooksBookTypeNONFICTION BooksBookType = "NONFICTION"
)
func (e *BooksBookType) Scan(src any) error {
switch s := src.(type) {
case []byte:
*e = BooksBookType(s)
case string:
*e = BooksBookType(s)
default:
return fmt.Errorf("unsupported scan type for BooksBookType: %T", src)
}
return nil
}
type NullBooksBookType struct {
BooksBookType BooksBookType
Valid bool // Valid is true if BooksBookType is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullBooksBookType) Scan(value any) error {
if value == nil {
ns.BooksBookType, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.BooksBookType.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullBooksBookType) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.BooksBookType), nil
}
type Author struct {
AuthorID int32
Name string
}
type Book struct {
BookID int32
AuthorID int32
Isbn string
BookType BooksBookType
Title string
Yr int32
Available time.Time
Tags string
}

View File

@@ -0,0 +1,63 @@
/* name: GetAuthor :one */
SELECT * FROM authors
WHERE author_id = ?;
/* name: GetBook :one */
SELECT * FROM books
WHERE book_id = ?;
/* name: DeleteBook :exec */
DELETE FROM books
WHERE book_id = ?;
/* name: BooksByTitleYear :many */
SELECT * FROM books
WHERE title = ? AND yr = ?;
/* name: BooksByTags :many */
SELECT
book_id,
title,
name,
isbn,
tags
FROM books
LEFT JOIN authors ON books.author_id = authors.author_id
WHERE tags = ?;
/* name: CreateAuthor :execresult */
INSERT INTO authors (name) VALUES (?);
/* name: CreateBook :execresult */
INSERT INTO books (
author_id,
isbn,
book_type,
title,
yr,
available,
tags
) VALUES (
?,
?,
?,
?,
?,
?,
?
);
/* name: UpdateBook :exec */
UPDATE books
SET title = ?, tags = ?
WHERE book_id = ?;
/* name: UpdateBookISBN :exec */
UPDATE books
SET title = ?, tags = ?, isbn = ?
WHERE book_id = ?;
/* name: DeleteAuthorBeforeYear :exec */
DELETE FROM books
WHERE yr < ? AND author_id = ?;
-- WHERE yr < sqlc.arg(min_publish_year) AND author_id = ?;

View File

@@ -0,0 +1,251 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: query.sql
package booktest
import (
"context"
"database/sql"
"time"
)
const booksByTags = `-- name: BooksByTags :many
SELECT
book_id,
title,
name,
isbn,
tags
FROM books
LEFT JOIN authors ON books.author_id = authors.author_id
WHERE tags = ?
`
type BooksByTagsRow struct {
BookID int32
Title string
Name sql.NullString
Isbn string
Tags string
}
func (q *Queries) BooksByTags(ctx context.Context, tags string) ([]BooksByTagsRow, error) {
rows, err := q.db.QueryContext(ctx, booksByTags, tags)
if err != nil {
return nil, err
}
defer rows.Close()
var items []BooksByTagsRow
for rows.Next() {
var i BooksByTagsRow
if err := rows.Scan(
&i.BookID,
&i.Title,
&i.Name,
&i.Isbn,
&i.Tags,
); 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
}
const booksByTitleYear = `-- name: BooksByTitleYear :many
SELECT book_id, author_id, isbn, book_type, title, yr, available, tags FROM books
WHERE title = ? AND yr = ?
`
type BooksByTitleYearParams struct {
Title string
Yr int32
}
func (q *Queries) BooksByTitleYear(ctx context.Context, arg BooksByTitleYearParams) ([]Book, error) {
rows, err := q.db.QueryContext(ctx, booksByTitleYear, arg.Title, arg.Yr)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Book
for rows.Next() {
var i Book
if err := rows.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Yr,
&i.Available,
&i.Tags,
); 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
}
const createAuthor = `-- name: CreateAuthor :execresult
INSERT INTO authors (name) VALUES (?)
`
func (q *Queries) CreateAuthor(ctx context.Context, name string) (sql.Result, error) {
return q.db.ExecContext(ctx, createAuthor, name)
}
const createBook = `-- name: CreateBook :execresult
INSERT INTO books (
author_id,
isbn,
book_type,
title,
yr,
available,
tags
) VALUES (
?,
?,
?,
?,
?,
?,
?
)
`
type CreateBookParams struct {
AuthorID int32
Isbn string
BookType BooksBookType
Title string
Yr int32
Available time.Time
Tags string
}
func (q *Queries) CreateBook(ctx context.Context, arg CreateBookParams) (sql.Result, error) {
return q.db.ExecContext(ctx, createBook,
arg.AuthorID,
arg.Isbn,
arg.BookType,
arg.Title,
arg.Yr,
arg.Available,
arg.Tags,
)
}
const deleteAuthorBeforeYear = `-- name: DeleteAuthorBeforeYear :exec
DELETE FROM books
WHERE yr < ? AND author_id = ?
`
type DeleteAuthorBeforeYearParams struct {
Yr int32
AuthorID int32
}
func (q *Queries) DeleteAuthorBeforeYear(ctx context.Context, arg DeleteAuthorBeforeYearParams) error {
_, err := q.db.ExecContext(ctx, deleteAuthorBeforeYear, arg.Yr, arg.AuthorID)
return err
}
const deleteBook = `-- name: DeleteBook :exec
DELETE FROM books
WHERE book_id = ?
`
func (q *Queries) DeleteBook(ctx context.Context, bookID int32) error {
_, err := q.db.ExecContext(ctx, deleteBook, bookID)
return err
}
const getAuthor = `-- name: GetAuthor :one
SELECT author_id, name FROM authors
WHERE author_id = ?
`
func (q *Queries) GetAuthor(ctx context.Context, authorID int32) (Author, error) {
row := q.db.QueryRowContext(ctx, getAuthor, authorID)
var i Author
err := row.Scan(&i.AuthorID, &i.Name)
return i, err
}
const getBook = `-- name: GetBook :one
SELECT book_id, author_id, isbn, book_type, title, yr, available, tags FROM books
WHERE book_id = ?
`
func (q *Queries) GetBook(ctx context.Context, bookID int32) (Book, error) {
row := q.db.QueryRowContext(ctx, getBook, bookID)
var i Book
err := row.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Yr,
&i.Available,
&i.Tags,
)
return i, err
}
const updateBook = `-- name: UpdateBook :exec
UPDATE books
SET title = ?, tags = ?
WHERE book_id = ?
`
type UpdateBookParams struct {
Title string
Tags string
BookID int32
}
func (q *Queries) UpdateBook(ctx context.Context, arg UpdateBookParams) error {
_, err := q.db.ExecContext(ctx, updateBook, arg.Title, arg.Tags, arg.BookID)
return err
}
const updateBookISBN = `-- name: UpdateBookISBN :exec
UPDATE books
SET title = ?, tags = ?, isbn = ?
WHERE book_id = ?
`
type UpdateBookISBNParams struct {
Title string
Tags string
Isbn string
BookID int32
}
func (q *Queries) UpdateBookISBN(ctx context.Context, arg UpdateBookISBNParams) error {
_, err := q.db.ExecContext(ctx, updateBookISBN,
arg.Title,
arg.Tags,
arg.Isbn,
arg.BookID,
)
return err
}

View File

@@ -0,0 +1,26 @@
CREATE TABLE authors (
author_id integer NOT NULL AUTO_INCREMENT PRIMARY KEY,
name text NOT NULL
) ENGINE=InnoDB;
CREATE INDEX authors_name_idx ON authors(name(255));
CREATE TABLE books (
book_id integer NOT NULL AUTO_INCREMENT PRIMARY KEY,
author_id integer NOT NULL,
isbn varchar(255) NOT NULL DEFAULT '' UNIQUE,
book_type ENUM('FICTION', 'NONFICTION') NOT NULL DEFAULT 'FICTION',
title text NOT NULL,
yr integer NOT NULL DEFAULT 2000,
available datetime NOT NULL DEFAULT NOW(),
tags text NOT NULL
-- CONSTRAINT FOREIGN KEY (author_id) REFERENCES authors(author_id)
) ENGINE=InnoDB;
CREATE INDEX books_title_idx ON books(title(255), yr);
/*
CREATE FUNCTION say_hello(s text) RETURNS text
DETERMINISTIC
RETURN CONCAT('hello ', s);
*/

View File

@@ -0,0 +1,32 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package booktest
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
type DBTX interface {
Exec(context.Context, string, ...any) (pgconn.CommandTag, error)
Query(context.Context, string, ...any) (pgx.Rows, error)
QueryRow(context.Context, string, ...any) pgx.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
return &Queries{
db: tx,
}
}

View File

@@ -0,0 +1,174 @@
//go:build examples
package booktest
import (
"context"
"testing"
"time"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
"github.com/sqlc-dev/sqlc/internal/sqltest/local"
)
func TestBooks(t *testing.T) {
ctx := context.Background()
uri := local.PostgreSQL(t, []string{"schema.sql"})
db, err := pgx.Connect(ctx, uri)
if err != nil {
t.Fatal(err)
}
defer db.Close(ctx)
dq := New(db)
// create an author
a, err := dq.CreateAuthor(ctx, "Unknown Master")
if err != nil {
t.Fatal(err)
}
// create transaction
tx, err := db.Begin(ctx)
if err != nil {
t.Fatal(err)
}
tq := dq.WithTx(tx)
// save first book
now := pgtype.Timestamptz{Time: time.Now(), Valid: true}
_, err = tq.CreateBook(ctx, CreateBookParams{
AuthorID: a.AuthorID,
Isbn: "1",
Title: "my book title",
BookType: BookTypeFICTION,
Year: 2016,
Available: now,
Tags: []string{},
})
if err != nil {
t.Fatal(err)
}
// save second book
b1, err := tq.CreateBook(ctx, CreateBookParams{
AuthorID: a.AuthorID,
Isbn: "2",
Title: "the second book",
BookType: BookTypeFICTION,
Year: 2016,
Available: now,
Tags: []string{"cool", "unique"},
})
if err != nil {
t.Fatal(err)
}
// update the title and tags
err = tq.UpdateBook(ctx, UpdateBookParams{
BookID: b1.BookID,
Title: "changed second title",
Tags: []string{"cool", "disastor"},
})
if err != nil {
t.Fatal(err)
}
// save third book
_, err = tq.CreateBook(ctx, CreateBookParams{
AuthorID: a.AuthorID,
Isbn: "3",
Title: "the third book",
BookType: BookTypeFICTION,
Year: 2001,
Available: now,
Tags: []string{"cool"},
})
if err != nil {
t.Fatal(err)
}
// save fourth book
b3, err := tq.CreateBook(ctx, CreateBookParams{
AuthorID: a.AuthorID,
Isbn: "4",
Title: "4th place finisher",
BookType: BookTypeNONFICTION,
Year: 2011,
Available: now,
Tags: []string{"other"},
})
if err != nil {
t.Fatal(err)
}
// tx commit
err = tx.Commit(ctx)
if err != nil {
t.Fatal(err)
}
// upsert, changing ISBN and title
err = dq.UpdateBookISBN(ctx, UpdateBookISBNParams{
BookID: b3.BookID,
Isbn: "NEW ISBN",
Title: "never ever gonna finish, a quatrain",
Tags: []string{"someother"},
})
if err != nil {
t.Fatal(err)
}
// retrieve first book
books0, err := dq.BooksByTitleYear(ctx, BooksByTitleYearParams{
Title: "my book title",
Year: 2016,
})
if err != nil {
t.Fatal(err)
}
for _, book := range books0 {
t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Time.Format(time.RFC822Z))
author, err := dq.GetAuthor(ctx, book.AuthorID)
if err != nil {
t.Fatal(err)
}
t.Logf("Book %d author: %s\n", book.BookID, author.Name)
}
// find a book with either "cool" or "other" tag
t.Logf("---------\nTag search results:\n")
res, err := dq.BooksByTags(ctx, []string{"cool", "other", "someother"})
if err != nil {
t.Fatal(err)
}
for _, ab := range res {
t.Logf("Book %d: '%s', Author: '%s', ISBN: '%s' Tags: '%v'\n", ab.BookID, ab.Title, ab.Name.String, ab.Isbn, ab.Tags)
}
// call function
pgText, err := dq.SayHello(ctx, "world")
if err != nil {
t.Fatal(err)
}
str, err := pgText.Value()
if err != nil {
t.Fatal(err)
}
if str != "hello world" {
t.Fatal("expected function result to be \"hello world\". actual:", str)
}
// get book 4 and delete
b5, err := dq.GetBook(ctx, b3.BookID)
if err != nil {
t.Fatal(err)
}
if err := dq.DeleteBook(ctx, b5.BookID); err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,70 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package booktest
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgx/v5/pgtype"
)
type BookType string
const (
BookTypeFICTION BookType = "FICTION"
BookTypeNONFICTION BookType = "NONFICTION"
)
func (e *BookType) Scan(src any) error {
switch s := src.(type) {
case []byte:
*e = BookType(s)
case string:
*e = BookType(s)
default:
return fmt.Errorf("unsupported scan type for BookType: %T", src)
}
return nil
}
type NullBookType struct {
BookType BookType
Valid bool // Valid is true if BookType is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullBookType) Scan(value any) error {
if value == nil {
ns.BookType, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.BookType.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullBookType) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.BookType), nil
}
type Author struct {
AuthorID int32
Name string
}
type Book struct {
BookID int32
AuthorID int32
Isbn string
BookType BookType
Title string
Year int32
Available pgtype.Timestamptz
Tags []string
}

View File

@@ -0,0 +1,63 @@
-- name: GetAuthor :one
SELECT * FROM authors
WHERE author_id = $1;
-- name: GetBook :one
SELECT * FROM books
WHERE book_id = $1;
-- name: DeleteBook :exec
DELETE FROM books
WHERE book_id = $1;
-- name: BooksByTitleYear :many
SELECT * FROM books
WHERE title = $1 AND year = $2;
-- name: BooksByTags :many
SELECT
book_id,
title,
name,
isbn,
tags
FROM books
LEFT JOIN authors ON books.author_id = authors.author_id
WHERE tags && $1::varchar[];
-- name: CreateAuthor :one
INSERT INTO authors (name) VALUES ($1)
RETURNING *;
-- name: CreateBook :one
INSERT INTO books (
author_id,
isbn,
book_type,
title,
year,
available,
tags
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7
)
RETURNING *;
-- name: UpdateBook :exec
UPDATE books
SET title = $1, tags = $2
WHERE book_id = $3;
-- name: UpdateBookISBN :exec
UPDATE books
SET title = $1, tags = $2, isbn = $4
WHERE book_id = $3;
-- name: SayHello :one
select * from say_hello($1);

View File

@@ -0,0 +1,258 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: query.sql
package booktest
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const booksByTags = `-- name: BooksByTags :many
SELECT
book_id,
title,
name,
isbn,
tags
FROM books
LEFT JOIN authors ON books.author_id = authors.author_id
WHERE tags && $1::varchar[]
`
type BooksByTagsRow struct {
BookID int32
Title string
Name pgtype.Text
Isbn string
Tags []string
}
func (q *Queries) BooksByTags(ctx context.Context, dollar_1 []string) ([]BooksByTagsRow, error) {
rows, err := q.db.Query(ctx, booksByTags, dollar_1)
if err != nil {
return nil, err
}
defer rows.Close()
var items []BooksByTagsRow
for rows.Next() {
var i BooksByTagsRow
if err := rows.Scan(
&i.BookID,
&i.Title,
&i.Name,
&i.Isbn,
&i.Tags,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const booksByTitleYear = `-- name: BooksByTitleYear :many
SELECT book_id, author_id, isbn, book_type, title, year, available, tags FROM books
WHERE title = $1 AND year = $2
`
type BooksByTitleYearParams struct {
Title string
Year int32
}
func (q *Queries) BooksByTitleYear(ctx context.Context, arg BooksByTitleYearParams) ([]Book, error) {
rows, err := q.db.Query(ctx, booksByTitleYear, arg.Title, arg.Year)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Book
for rows.Next() {
var i Book
if err := rows.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Year,
&i.Available,
&i.Tags,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const createAuthor = `-- name: CreateAuthor :one
INSERT INTO authors (name) VALUES ($1)
RETURNING author_id, name
`
func (q *Queries) CreateAuthor(ctx context.Context, name string) (Author, error) {
row := q.db.QueryRow(ctx, createAuthor, name)
var i Author
err := row.Scan(&i.AuthorID, &i.Name)
return i, err
}
const createBook = `-- name: CreateBook :one
INSERT INTO books (
author_id,
isbn,
book_type,
title,
year,
available,
tags
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7
)
RETURNING book_id, author_id, isbn, book_type, title, year, available, tags
`
type CreateBookParams struct {
AuthorID int32
Isbn string
BookType BookType
Title string
Year int32
Available pgtype.Timestamptz
Tags []string
}
func (q *Queries) CreateBook(ctx context.Context, arg CreateBookParams) (Book, error) {
row := q.db.QueryRow(ctx, createBook,
arg.AuthorID,
arg.Isbn,
arg.BookType,
arg.Title,
arg.Year,
arg.Available,
arg.Tags,
)
var i Book
err := row.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Year,
&i.Available,
&i.Tags,
)
return i, err
}
const deleteBook = `-- name: DeleteBook :exec
DELETE FROM books
WHERE book_id = $1
`
func (q *Queries) DeleteBook(ctx context.Context, bookID int32) error {
_, err := q.db.Exec(ctx, deleteBook, bookID)
return err
}
const getAuthor = `-- name: GetAuthor :one
SELECT author_id, name FROM authors
WHERE author_id = $1
`
func (q *Queries) GetAuthor(ctx context.Context, authorID int32) (Author, error) {
row := q.db.QueryRow(ctx, getAuthor, authorID)
var i Author
err := row.Scan(&i.AuthorID, &i.Name)
return i, err
}
const getBook = `-- name: GetBook :one
SELECT book_id, author_id, isbn, book_type, title, year, available, tags FROM books
WHERE book_id = $1
`
func (q *Queries) GetBook(ctx context.Context, bookID int32) (Book, error) {
row := q.db.QueryRow(ctx, getBook, bookID)
var i Book
err := row.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Year,
&i.Available,
&i.Tags,
)
return i, err
}
const sayHello = `-- name: SayHello :one
select say_hello from say_hello($1)
`
func (q *Queries) SayHello(ctx context.Context, s string) (pgtype.Text, error) {
row := q.db.QueryRow(ctx, sayHello, s)
var say_hello pgtype.Text
err := row.Scan(&say_hello)
return say_hello, err
}
const updateBook = `-- name: UpdateBook :exec
UPDATE books
SET title = $1, tags = $2
WHERE book_id = $3
`
type UpdateBookParams struct {
Title string
Tags []string
BookID int32
}
func (q *Queries) UpdateBook(ctx context.Context, arg UpdateBookParams) error {
_, err := q.db.Exec(ctx, updateBook, arg.Title, arg.Tags, arg.BookID)
return err
}
const updateBookISBN = `-- name: UpdateBookISBN :exec
UPDATE books
SET title = $1, tags = $2, isbn = $4
WHERE book_id = $3
`
type UpdateBookISBNParams struct {
Title string
Tags []string
BookID int32
Isbn string
}
func (q *Queries) UpdateBookISBN(ctx context.Context, arg UpdateBookISBNParams) error {
_, err := q.db.Exec(ctx, updateBookISBN,
arg.Title,
arg.Tags,
arg.BookID,
arg.Isbn,
)
return err
}

View File

@@ -0,0 +1,32 @@
CREATE TABLE authors (
author_id SERIAL PRIMARY KEY,
name text NOT NULL DEFAULT ''
);
CREATE INDEX authors_name_idx ON authors(name);
CREATE TYPE book_type AS ENUM (
'FICTION',
'NONFICTION'
);
CREATE TABLE books (
book_id SERIAL PRIMARY KEY,
author_id integer NOT NULL REFERENCES authors(author_id),
isbn text NOT NULL DEFAULT '' UNIQUE,
book_type book_type NOT NULL DEFAULT 'FICTION',
title text NOT NULL DEFAULT '',
year integer NOT NULL DEFAULT 2000,
available timestamp with time zone NOT NULL DEFAULT 'NOW()',
tags varchar[] NOT NULL DEFAULT '{}'
);
CREATE INDEX books_title_idx ON books(title, year);
CREATE FUNCTION say_hello(s text) RETURNS text AS $$
BEGIN
RETURN CONCAT('hello ', s);
END;
$$ LANGUAGE plpgsql;
CREATE INDEX books_title_lower_idx ON books(title);

View File

@@ -0,0 +1,51 @@
{
"version": "1",
"cloud": {
"project": "01HAQMMECEYQYKFJN8MP16QC41"
},
"packages": [
{
"name": "booktest",
"path": "postgresql",
"schema": "postgresql/schema.sql",
"queries": "postgresql/query.sql",
"engine": "postgresql",
"sql_package": "pgx/v5",
"database": {
"uri": "${VET_TEST_EXAMPLES_POSTGRES_BOOKTEST}"
},
"analyzer": {
"database": false
},
"rules": [
"sqlc/db-prepare"
]
},
{
"name": "booktest",
"path": "mysql",
"schema": "mysql/schema.sql",
"queries": "mysql/query.sql",
"engine": "mysql",
"database": {
"uri": "${VET_TEST_EXAMPLES_MYSQL_BOOKTEST}"
},
"rules": [
"sqlc/db-prepare"
]
},
{
"name": "booktest",
"path": "sqlite",
"schema": "sqlite/schema.sql",
"queries": "sqlite/query.sql",
"engine": "sqlite",
"database": {
"uri": "file:booktest?mode=memory&cache=shared"
},
"rules": [
"sqlc/db-prepare"
]
}
]
}

View File

@@ -0,0 +1,31 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package booktest
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *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,
}
}

View File

@@ -0,0 +1,163 @@
//go:build examples
package booktest
import (
"context"
"testing"
"time"
"github.com/sqlc-dev/sqlc/internal/sqltest"
)
// TODO: Enum is not yet supported
const (
BooksBookTypeFICTION string = "FICTION"
BooksBookTypeNONFICTION string = "NONFICTION"
)
func TestBooks(t *testing.T) {
db, cleanup := sqltest.SQLite(t, []string{"schema.sql"})
defer db.Close()
defer cleanup()
ctx := context.Background()
dq := New(db)
// create an author
a, err := dq.CreateAuthor(ctx, "Unknown Master")
if err != nil {
t.Fatal(err)
}
// create transaction
tx, err := db.Begin()
if err != nil {
t.Fatal(err)
}
tq := dq.WithTx(tx)
// save first book
now := time.Now()
_, err = tq.CreateBook(ctx, CreateBookParams{
AuthorID: a.AuthorID,
Isbn: "1",
Title: "my book title",
BookType: BooksBookTypeFICTION,
Yr: 2016,
Available: now,
Tag: "",
})
if err != nil {
t.Fatal(err)
}
// save second book
b1, err := tq.CreateBook(ctx, CreateBookParams{
AuthorID: a.AuthorID,
Isbn: "2",
Title: "the second book",
BookType: BooksBookTypeFICTION,
Yr: 2016,
Available: now,
Tag: "unique",
})
if err != nil {
t.Fatal(err)
}
// update the title and tags
err = tq.UpdateBook(ctx, UpdateBookParams{
BookID: b1.BookID,
Title: "changed second title",
Tag: "disastor",
})
if err != nil {
t.Fatal(err)
}
// save third book
_, err = tq.CreateBook(ctx, CreateBookParams{
AuthorID: a.AuthorID,
Isbn: "3",
Title: "the third book",
BookType: BooksBookTypeFICTION,
Yr: 2001,
Available: now,
Tag: "cool",
})
if err != nil {
t.Fatal(err)
}
// save fourth book
b3, err := tq.CreateBook(ctx, CreateBookParams{
AuthorID: a.AuthorID,
Isbn: "4",
Title: "4th place finisher",
BookType: BooksBookTypeFICTION,
Yr: 2011,
Available: now,
Tag: "other",
})
if err != nil {
t.Fatal(err)
}
// tx commit
err = tx.Commit()
if err != nil {
t.Fatal(err)
}
// upsert, changing ISBN and title
err = dq.UpdateBookISBN(ctx, UpdateBookISBNParams{
BookID: b3.BookID,
Isbn: "NEW ISBN",
Title: "never ever gonna finish, a quatrain",
Tag: "someother",
})
if err != nil {
t.Fatal(err)
}
// retrieve first book
books0, err := dq.BooksByTitleYear(ctx, BooksByTitleYearParams{
Title: "my book title",
Yr: 2016,
})
if err != nil {
t.Fatal(err)
}
for _, book := range books0 {
t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Format(time.RFC822Z))
author, err := dq.GetAuthor(ctx, book.AuthorID)
if err != nil {
t.Fatal(err)
}
t.Logf("Book %d author: %s\n", book.BookID, author.Name)
}
// find a book with either "cool" or "other" or "someother" tag
t.Logf("---------\nTag search results:\n")
res, err := dq.BooksByTags(ctx, []string{"cool", "other", "someother"})
if err != nil {
t.Fatal(err)
}
for _, ab := range res {
t.Logf("Book %d: '%s', Author: '%s', ISBN: '%s' Tag: '%v'\n", ab.BookID, ab.Title, ab.Name.String, ab.Isbn, ab.Tag)
}
// TODO: call say_hello(varchar)
// get book 4 and delete
b5, err := dq.GetBook(ctx, b3.BookID)
if err != nil {
t.Fatal(err)
}
if err := dq.DeleteBook(ctx, b5.BookID); err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,25 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package booktest
import (
"time"
)
type Author struct {
AuthorID int64
Name string
}
type Book struct {
BookID int64
AuthorID int64
Isbn string
BookType string
Title string
Yr int64
Available time.Time
Tag string
}

View File

@@ -0,0 +1,64 @@
/* name: GetAuthor :one */
SELECT * FROM authors
WHERE author_id = ?;
/* name: GetBook :one */
SELECT * FROM books
WHERE book_id = ?;
/* name: DeleteBook :exec */
DELETE FROM books
WHERE book_id = ?;
/* name: BooksByTitleYear :many */
SELECT * FROM books
WHERE title = ? AND yr = ?;
/* name: BooksByTags :many */
SELECT
book_id,
title,
name,
isbn,
tag
FROM books
LEFT JOIN authors ON books.author_id = authors.author_id
WHERE tag IN (sqlc.slice(tags));
/* name: CreateAuthor :one */
INSERT INTO authors (name) VALUES (?)
RETURNING *;
/* name: CreateBook :one */
INSERT INTO books (
author_id,
isbn,
book_type,
title,
yr,
available,
tag
) VALUES (
?,
?,
?,
?,
?,
?,
?
)
RETURNING *;
/* name: UpdateBook :exec */
UPDATE books
SET title = ?1, tag = ?2
WHERE book_id = ?3;
/* name: UpdateBookISBN :exec */
UPDATE books
SET title = ?1, tag = ?2, isbn = ?4
WHERE book_id = ?3;
/* name: DeleteAuthorBeforeYear :exec */
DELETE FROM books
WHERE yr < ? AND author_id = ?;

View File

@@ -0,0 +1,279 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: query.sql
package booktest
import (
"context"
"database/sql"
"strings"
"time"
)
const booksByTags = `-- name: BooksByTags :many
SELECT
book_id,
title,
name,
isbn,
tag
FROM books
LEFT JOIN authors ON books.author_id = authors.author_id
WHERE tag IN (/*SLICE:tags*/?)
`
type BooksByTagsRow struct {
BookID int64
Title string
Name sql.NullString
Isbn string
Tag string
}
func (q *Queries) BooksByTags(ctx context.Context, tags []string) ([]BooksByTagsRow, error) {
query := booksByTags
var queryParams []any
if len(tags) > 0 {
for _, v := range tags {
queryParams = append(queryParams, v)
}
query = strings.Replace(query, "/*SLICE:tags*/?", strings.Repeat(",?", len(tags))[1:], 1)
} else {
query = strings.Replace(query, "/*SLICE:tags*/?", "NULL", 1)
}
rows, err := q.db.QueryContext(ctx, query, queryParams...)
if err != nil {
return nil, err
}
defer rows.Close()
var items []BooksByTagsRow
for rows.Next() {
var i BooksByTagsRow
if err := rows.Scan(
&i.BookID,
&i.Title,
&i.Name,
&i.Isbn,
&i.Tag,
); 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
}
const booksByTitleYear = `-- name: BooksByTitleYear :many
SELECT book_id, author_id, isbn, book_type, title, yr, available, tag FROM books
WHERE title = ? AND yr = ?
`
type BooksByTitleYearParams struct {
Title string
Yr int64
}
func (q *Queries) BooksByTitleYear(ctx context.Context, arg BooksByTitleYearParams) ([]Book, error) {
rows, err := q.db.QueryContext(ctx, booksByTitleYear, arg.Title, arg.Yr)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Book
for rows.Next() {
var i Book
if err := rows.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Yr,
&i.Available,
&i.Tag,
); 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
}
const createAuthor = `-- name: CreateAuthor :one
INSERT INTO authors (name) VALUES (?)
RETURNING author_id, name
`
func (q *Queries) CreateAuthor(ctx context.Context, name string) (Author, error) {
row := q.db.QueryRowContext(ctx, createAuthor, name)
var i Author
err := row.Scan(&i.AuthorID, &i.Name)
return i, err
}
const createBook = `-- name: CreateBook :one
INSERT INTO books (
author_id,
isbn,
book_type,
title,
yr,
available,
tag
) VALUES (
?,
?,
?,
?,
?,
?,
?
)
RETURNING book_id, author_id, isbn, book_type, title, yr, available, tag
`
type CreateBookParams struct {
AuthorID int64
Isbn string
BookType string
Title string
Yr int64
Available time.Time
Tag string
}
func (q *Queries) CreateBook(ctx context.Context, arg CreateBookParams) (Book, error) {
row := q.db.QueryRowContext(ctx, createBook,
arg.AuthorID,
arg.Isbn,
arg.BookType,
arg.Title,
arg.Yr,
arg.Available,
arg.Tag,
)
var i Book
err := row.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Yr,
&i.Available,
&i.Tag,
)
return i, err
}
const deleteAuthorBeforeYear = `-- name: DeleteAuthorBeforeYear :exec
DELETE FROM books
WHERE yr < ? AND author_id = ?
`
type DeleteAuthorBeforeYearParams struct {
Yr int64
AuthorID int64
}
func (q *Queries) DeleteAuthorBeforeYear(ctx context.Context, arg DeleteAuthorBeforeYearParams) error {
_, err := q.db.ExecContext(ctx, deleteAuthorBeforeYear, arg.Yr, arg.AuthorID)
return err
}
const deleteBook = `-- name: DeleteBook :exec
DELETE FROM books
WHERE book_id = ?
`
func (q *Queries) DeleteBook(ctx context.Context, bookID int64) error {
_, err := q.db.ExecContext(ctx, deleteBook, bookID)
return err
}
const getAuthor = `-- name: GetAuthor :one
SELECT author_id, name FROM authors
WHERE author_id = ?
`
func (q *Queries) GetAuthor(ctx context.Context, authorID int64) (Author, error) {
row := q.db.QueryRowContext(ctx, getAuthor, authorID)
var i Author
err := row.Scan(&i.AuthorID, &i.Name)
return i, err
}
const getBook = `-- name: GetBook :one
SELECT book_id, author_id, isbn, book_type, title, yr, available, tag FROM books
WHERE book_id = ?
`
func (q *Queries) GetBook(ctx context.Context, bookID int64) (Book, error) {
row := q.db.QueryRowContext(ctx, getBook, bookID)
var i Book
err := row.Scan(
&i.BookID,
&i.AuthorID,
&i.Isbn,
&i.BookType,
&i.Title,
&i.Yr,
&i.Available,
&i.Tag,
)
return i, err
}
const updateBook = `-- name: UpdateBook :exec
UPDATE books
SET title = ?1, tag = ?2
WHERE book_id = ?3
`
type UpdateBookParams struct {
Title string
Tag string
BookID int64
}
func (q *Queries) UpdateBook(ctx context.Context, arg UpdateBookParams) error {
_, err := q.db.ExecContext(ctx, updateBook, arg.Title, arg.Tag, arg.BookID)
return err
}
const updateBookISBN = `-- name: UpdateBookISBN :exec
UPDATE books
SET title = ?1, tag = ?2, isbn = ?4
WHERE book_id = ?3
`
type UpdateBookISBNParams struct {
Title string
Tag string
BookID int64
Isbn string
}
func (q *Queries) UpdateBookISBN(ctx context.Context, arg UpdateBookISBNParams) error {
_, err := q.db.ExecContext(ctx, updateBookISBN,
arg.Title,
arg.Tag,
arg.BookID,
arg.Isbn,
)
return err
}

View File

@@ -0,0 +1,20 @@
CREATE TABLE authors (
author_id integer NOT NULL PRIMARY KEY AUTOINCREMENT,
name text NOT NULL
);
CREATE INDEX authors_name_idx ON authors(name);
CREATE TABLE books (
book_id integer NOT NULL PRIMARY KEY AUTOINCREMENT,
author_id integer NOT NULL,
isbn varchar(255) NOT NULL DEFAULT '' UNIQUE,
book_type text NOT NULL DEFAULT 'FICTION',
title text NOT NULL,
yr integer NOT NULL DEFAULT 2000,
available datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
tag text NOT NULL,
CHECK (book_type = 'FICTION' OR book_type = 'NONFICTION')
);
CREATE INDEX books_title_idx ON books(title, yr);

3
examples/jets/README.md Normal file
View File

@@ -0,0 +1,3 @@
This database schema and query selection is taken from the
[SQLBoiler](https://github.com/volatiletech/sqlboiler#features--examples)
README.

View File

@@ -0,0 +1,32 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package jets
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
type DBTX interface {
Exec(context.Context, string, ...any) (pgconn.CommandTag, error)
Query(context.Context, string, ...any) (pgx.Rows, error)
QueryRow(context.Context, string, ...any) pgx.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
return &Queries{
db: tx,
}
}

View File

@@ -0,0 +1,28 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package jets
type Jet struct {
ID int32
PilotID int32
Age int32
Name string
Color string
}
type Language struct {
ID int32
Language string
}
type Pilot struct {
ID int32
Name string
}
type PilotLanguage struct {
PilotID int32
LanguageID int32
}

View File

@@ -0,0 +1,8 @@
-- name: CountPilots :one
SELECT COUNT(*) FROM pilots;
-- name: ListPilots :many
SELECT * FROM pilots LIMIT 5;
-- name: DeletePilot :exec
DELETE FROM pilots WHERE id = $1;

View File

@@ -0,0 +1,54 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: query-building.sql
package jets
import (
"context"
)
const countPilots = `-- name: CountPilots :one
SELECT COUNT(*) FROM pilots
`
func (q *Queries) CountPilots(ctx context.Context) (int64, error) {
row := q.db.QueryRow(ctx, countPilots)
var count int64
err := row.Scan(&count)
return count, err
}
const deletePilot = `-- name: DeletePilot :exec
DELETE FROM pilots WHERE id = $1
`
func (q *Queries) DeletePilot(ctx context.Context, id int32) error {
_, err := q.db.Exec(ctx, deletePilot, id)
return err
}
const listPilots = `-- name: ListPilots :many
SELECT id, name FROM pilots LIMIT 5
`
func (q *Queries) ListPilots(ctx context.Context) ([]Pilot, error) {
rows, err := q.db.Query(ctx, listPilots)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Pilot
for rows.Next() {
var i Pilot
if err := rows.Scan(&i.ID, &i.Name); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}

View File

@@ -0,0 +1,35 @@
CREATE TABLE pilots (
id integer NOT NULL,
name text NOT NULL
);
ALTER TABLE pilots ADD CONSTRAINT pilot_pkey PRIMARY KEY (id);
CREATE TABLE jets (
id integer NOT NULL,
pilot_id integer NOT NULL,
age integer NOT NULL,
name text NOT NULL,
color text NOT NULL
);
ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);
ALTER TABLE jets ADD CONSTRAINT jet_pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
CREATE TABLE languages (
id integer NOT NULL,
language text NOT NULL
);
ALTER TABLE languages ADD CONSTRAINT language_pkey PRIMARY KEY (id);
-- Join table
CREATE TABLE pilot_languages (
pilot_id integer NOT NULL,
language_id integer NOT NULL
);
-- Composite primary key
ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);
ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);

25
examples/jets/sqlc.json Normal file
View File

@@ -0,0 +1,25 @@
{
"version": "1",
"cloud": {
"project": "01HAQMMECEYQYKFJN8MP16QC41"
},
"packages": [
{
"path": "postgresql",
"name": "jets",
"schema": "postgresql/schema.sql",
"queries": "postgresql/query-building.sql",
"engine": "postgresql",
"sql_package": "pgx/v5",
"database": {
"uri": "${VET_TEST_EXAMPLES_POSTGRES_JETS}"
},
"analyzer": {
"database": false
},
"rules": [
"sqlc/db-prepare"
]
}
]
}

View File

@@ -0,0 +1,88 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: city.sql
package ondeck
import (
"context"
)
const createCity = `-- name: CreateCity :exec
INSERT INTO city (
name,
slug
) VALUES (
?,
?
)
`
type CreateCityParams struct {
Name string `json:"name"`
Slug string `json:"slug"`
}
func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) error {
_, err := q.exec(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug)
return err
}
const getCity = `-- name: GetCity :one
SELECT slug, name
FROM city
WHERE slug = ?
`
func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) {
row := q.queryRow(ctx, q.getCityStmt, getCity, slug)
var i City
err := row.Scan(&i.Slug, &i.Name)
return i, err
}
const listCities = `-- name: ListCities :many
SELECT slug, name
FROM city
ORDER BY name
`
func (q *Queries) ListCities(ctx context.Context) ([]City, error) {
rows, err := q.query(ctx, q.listCitiesStmt, listCities)
if err != nil {
return nil, err
}
defer rows.Close()
var items []City
for rows.Next() {
var i City
if err := rows.Scan(&i.Slug, &i.Name); 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
}
const updateCityName = `-- name: UpdateCityName :exec
UPDATE city
SET name = ?
WHERE slug = ?
`
type UpdateCityNameParams struct {
Name string `json:"name"`
Slug string `json:"slug"`
}
func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error {
_, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Name, arg.Slug)
return err
}

178
examples/ondeck/mysql/db.go Normal file
View File

@@ -0,0 +1,178 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package ondeck
import (
"context"
"database/sql"
"fmt"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
q := Queries{db: db}
var err error
if q.createCityStmt, err = db.PrepareContext(ctx, createCity); err != nil {
return nil, fmt.Errorf("error preparing query CreateCity: %w", err)
}
if q.createVenueStmt, err = db.PrepareContext(ctx, createVenue); err != nil {
return nil, fmt.Errorf("error preparing query CreateVenue: %w", err)
}
if q.deleteVenueStmt, err = db.PrepareContext(ctx, deleteVenue); err != nil {
return nil, fmt.Errorf("error preparing query DeleteVenue: %w", err)
}
if q.getCityStmt, err = db.PrepareContext(ctx, getCity); err != nil {
return nil, fmt.Errorf("error preparing query GetCity: %w", err)
}
if q.getVenueStmt, err = db.PrepareContext(ctx, getVenue); err != nil {
return nil, fmt.Errorf("error preparing query GetVenue: %w", err)
}
if q.listCitiesStmt, err = db.PrepareContext(ctx, listCities); err != nil {
return nil, fmt.Errorf("error preparing query ListCities: %w", err)
}
if q.listVenuesStmt, err = db.PrepareContext(ctx, listVenues); err != nil {
return nil, fmt.Errorf("error preparing query ListVenues: %w", err)
}
if q.updateCityNameStmt, err = db.PrepareContext(ctx, updateCityName); err != nil {
return nil, fmt.Errorf("error preparing query UpdateCityName: %w", err)
}
if q.updateVenueNameStmt, err = db.PrepareContext(ctx, updateVenueName); err != nil {
return nil, fmt.Errorf("error preparing query UpdateVenueName: %w", err)
}
if q.venueCountByCityStmt, err = db.PrepareContext(ctx, venueCountByCity); err != nil {
return nil, fmt.Errorf("error preparing query VenueCountByCity: %w", err)
}
return &q, nil
}
func (q *Queries) Close() error {
var err error
if q.createCityStmt != nil {
if cerr := q.createCityStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing createCityStmt: %w", cerr)
}
}
if q.createVenueStmt != nil {
if cerr := q.createVenueStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing createVenueStmt: %w", cerr)
}
}
if q.deleteVenueStmt != nil {
if cerr := q.deleteVenueStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteVenueStmt: %w", cerr)
}
}
if q.getCityStmt != nil {
if cerr := q.getCityStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getCityStmt: %w", cerr)
}
}
if q.getVenueStmt != nil {
if cerr := q.getVenueStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getVenueStmt: %w", cerr)
}
}
if q.listCitiesStmt != nil {
if cerr := q.listCitiesStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listCitiesStmt: %w", cerr)
}
}
if q.listVenuesStmt != nil {
if cerr := q.listVenuesStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listVenuesStmt: %w", cerr)
}
}
if q.updateCityNameStmt != nil {
if cerr := q.updateCityNameStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateCityNameStmt: %w", cerr)
}
}
if q.updateVenueNameStmt != nil {
if cerr := q.updateVenueNameStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateVenueNameStmt: %w", cerr)
}
}
if q.venueCountByCityStmt != nil {
if cerr := q.venueCountByCityStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing venueCountByCityStmt: %w", cerr)
}
}
return err
}
func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...)
case stmt != nil:
return stmt.ExecContext(ctx, args...)
default:
return q.db.ExecContext(ctx, query, args...)
}
}
func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...)
case stmt != nil:
return stmt.QueryContext(ctx, args...)
default:
return q.db.QueryContext(ctx, query, args...)
}
}
func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...)
case stmt != nil:
return stmt.QueryRowContext(ctx, args...)
default:
return q.db.QueryRowContext(ctx, query, args...)
}
}
type Queries struct {
db DBTX
tx *sql.Tx
createCityStmt *sql.Stmt
createVenueStmt *sql.Stmt
deleteVenueStmt *sql.Stmt
getCityStmt *sql.Stmt
getVenueStmt *sql.Stmt
listCitiesStmt *sql.Stmt
listVenuesStmt *sql.Stmt
updateCityNameStmt *sql.Stmt
updateVenueNameStmt *sql.Stmt
venueCountByCityStmt *sql.Stmt
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
tx: tx,
createCityStmt: q.createCityStmt,
createVenueStmt: q.createVenueStmt,
deleteVenueStmt: q.deleteVenueStmt,
getCityStmt: q.getCityStmt,
getVenueStmt: q.getVenueStmt,
listCitiesStmt: q.listCitiesStmt,
listVenuesStmt: q.listVenuesStmt,
updateCityNameStmt: q.updateCityNameStmt,
updateVenueNameStmt: q.updateVenueNameStmt,
venueCountByCityStmt: q.venueCountByCityStmt,
}
}

View File

@@ -0,0 +1,172 @@
//go:build examples
package ondeck
import (
"context"
"database/sql"
"strings"
"testing"
_ "github.com/go-sql-driver/mysql"
"github.com/google/go-cmp/cmp"
"github.com/sqlc-dev/sqlc/internal/sqltest/local"
)
func join(vals ...string) sql.NullString {
if len(vals) == 0 {
return sql.NullString{}
}
return sql.NullString{
Valid: true,
String: strings.Join(vals, ","),
}
}
func runOnDeckQueries(t *testing.T, q *Queries) {
ctx := context.Background()
err := q.CreateCity(ctx, CreateCityParams{
Slug: "san-francisco",
Name: "San Francisco",
})
if err != nil {
t.Fatal(err)
}
city, err := q.GetCity(ctx, "san-francisco")
if err != nil {
t.Fatal(err)
}
venueResult, err := q.CreateVenue(ctx, CreateVenueParams{
Slug: "the-fillmore",
Name: "The Fillmore",
City: city.Slug,
SpotifyPlaylist: "spotify:uri",
Status: VenueStatusOpen,
Statuses: join(string(VenueStatusOpen), string(VenueStatusClosed)),
Tags: join("rock", "punk"),
})
if err != nil {
t.Fatal(err)
}
venueID, err := venueResult.LastInsertId()
if err != nil {
t.Fatal(err)
}
venue, err := q.GetVenue(ctx, GetVenueParams{
Slug: "the-fillmore",
City: city.Slug,
})
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(venue.ID, uint64(venueID)); diff != "" {
t.Errorf("venue ID mismatch:\n%s", diff)
}
{
actual, err := q.VenueCountByCity(ctx)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, []VenueCountByCityRow{
{city.Slug, int64(1)},
}); diff != "" {
t.Errorf("venue count mismatch:\n%s", diff)
}
}
{
actual, err := q.ListCities(ctx)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, []City{city}); diff != "" {
t.Errorf("list city mismatch:\n%s", diff)
}
}
{
actual, err := q.ListVenues(ctx, city.Slug)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, []Venue{venue}); diff != "" {
t.Errorf("list venue mismatch:\n%s", diff)
}
}
{
err := q.UpdateCityName(ctx, UpdateCityNameParams{
Slug: city.Slug,
Name: "SF",
})
if err != nil {
t.Error(err)
}
}
{
expected := "Fillmore"
err := q.UpdateVenueName(ctx, UpdateVenueNameParams{
Slug: venue.Slug,
Name: expected,
})
if err != nil {
t.Error(err)
}
fresh, err := q.GetVenue(ctx, GetVenueParams{
Slug: venue.Slug,
City: city.Slug,
})
if diff := cmp.Diff(expected, fresh.Name); diff != "" {
t.Errorf("update venue mismatch:\n%s", diff)
}
}
{
err := q.DeleteVenue(ctx, DeleteVenueParams{
Slug: venue.Slug,
Slug_2: venue.Slug,
})
if err != nil {
t.Error(err)
}
}
}
func TestPrepared(t *testing.T) {
t.Parallel()
uri := local.MySQL(t, []string{"schema"})
db, err := sql.Open("mysql", uri)
if err != nil {
t.Fatalf("%s: %s", uri, err)
}
defer db.Close()
q, err := Prepare(context.Background(), db)
if err != nil {
t.Fatal(err)
}
runOnDeckQueries(t, q)
}
func TestQueries(t *testing.T) {
t.Parallel()
uri := local.MySQL(t, []string{"schema"})
db, err := sql.Open("mysql", uri)
if err != nil {
t.Fatalf("%s: %s", uri, err)
}
defer db.Close()
runOnDeckQueries(t, New(db))
}

View File

@@ -0,0 +1,75 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package ondeck
import (
"database/sql"
"database/sql/driver"
"fmt"
"time"
)
type VenueStatus string
const (
VenueStatusOpen VenueStatus = "open"
VenueStatusClosed VenueStatus = "closed"
)
func (e *VenueStatus) Scan(src any) error {
switch s := src.(type) {
case []byte:
*e = VenueStatus(s)
case string:
*e = VenueStatus(s)
default:
return fmt.Errorf("unsupported scan type for VenueStatus: %T", src)
}
return nil
}
type NullVenueStatus struct {
VenueStatus VenueStatus `json:"venue_status"`
Valid bool `json:"valid"` // Valid is true if VenueStatus is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullVenueStatus) Scan(value any) error {
if value == nil {
ns.VenueStatus, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.VenueStatus.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullVenueStatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.VenueStatus), nil
}
type City struct {
Slug string `json:"slug"`
Name string `json:"name"`
}
// Venues are places where muisc happens
type Venue struct {
ID uint64 `json:"id"`
// Venues can be either open or closed
Status VenueStatus `json:"status"`
Statuses sql.NullString `json:"statuses"`
// This value appears in public URLs
Slug string `json:"slug"`
Name string `json:"name"`
City string `json:"city"`
SpotifyPlaylist string `json:"spotify_playlist"`
SongkickID sql.NullString `json:"songkick_id"`
Tags sql.NullString `json:"tags"`
CreatedAt time.Time `json:"created_at"`
}

View File

@@ -0,0 +1,25 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package ondeck
import (
"context"
"database/sql"
)
type Querier interface {
CreateCity(ctx context.Context, arg CreateCityParams) error
CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error)
DeleteVenue(ctx context.Context, arg DeleteVenueParams) error
GetCity(ctx context.Context, slug string) (City, error)
GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error)
ListCities(ctx context.Context) ([]City, error)
ListVenues(ctx context.Context, city string) ([]Venue, error)
UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error
UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error
VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error)
}
var _ Querier = (*Queries)(nil)

View File

@@ -0,0 +1,23 @@
/* name: ListCities :many */
SELECT *
FROM city
ORDER BY name;
/* name: GetCity :one */
SELECT *
FROM city
WHERE slug = ?;
/* name: CreateCity :exec */
INSERT INTO city (
name,
slug
) VALUES (
?,
?
);
/* name: UpdateCityName :exec */
UPDATE city
SET name = ?
WHERE slug = ?;

View File

@@ -0,0 +1,48 @@
/* name: ListVenues :many */
SELECT *
FROM venue
WHERE city = ?
ORDER BY name;
/* name: DeleteVenue :exec */
DELETE FROM venue
WHERE slug = ? AND slug = ?;
/* name: GetVenue :one */
SELECT *
FROM venue
WHERE slug = ? AND city = ?;
/* name: CreateVenue :execresult */
INSERT INTO venue (
slug,
name,
city,
created_at,
spotify_playlist,
status,
statuses,
tags
) VALUES (
?,
?,
?,
NOW(),
?,
?,
?,
?
);
/* name: UpdateVenueName :exec */
UPDATE venue
SET name = ?
WHERE slug = ?;
/* name: VenueCountByCity :many */
SELECT
city,
count(*)
FROM venue
GROUP BY 1
ORDER BY 1;

View File

@@ -0,0 +1,4 @@
CREATE TABLE city (
slug varchar(255) PRIMARY KEY,
name text NOT NULL
);

View File

@@ -0,0 +1,12 @@
CREATE TABLE venues (
id SERIAL primary key,
dropped text,
status ENUM('open', 'closed') not null COMMENT 'Venues can be either open or closed',
statuses text, -- status[],
slug text not null COMMENT 'This value appears in public URLs',
name varchar(255) not null,
city varchar(255) not null references city(slug),
spotify_playlist varchar(255) not null,
songkick_id text,
tags text -- text[]
) COMMENT='Venues are places where muisc happens';

View File

@@ -0,0 +1,3 @@
ALTER TABLE venues RENAME TO venue;
ALTER TABLE venue ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT NOW();
ALTER TABLE venue DROP COLUMN dropped;

View File

@@ -0,0 +1,193 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: venue.sql
package ondeck
import (
"context"
"database/sql"
)
const createVenue = `-- name: CreateVenue :execresult
INSERT INTO venue (
slug,
name,
city,
created_at,
spotify_playlist,
status,
statuses,
tags
) VALUES (
?,
?,
?,
NOW(),
?,
?,
?,
?
)
`
type CreateVenueParams struct {
Slug string `json:"slug"`
Name string `json:"name"`
City string `json:"city"`
SpotifyPlaylist string `json:"spotify_playlist"`
Status VenueStatus `json:"status"`
Statuses sql.NullString `json:"statuses"`
Tags sql.NullString `json:"tags"`
}
func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) {
return q.exec(ctx, q.createVenueStmt, createVenue,
arg.Slug,
arg.Name,
arg.City,
arg.SpotifyPlaylist,
arg.Status,
arg.Statuses,
arg.Tags,
)
}
const deleteVenue = `-- name: DeleteVenue :exec
DELETE FROM venue
WHERE slug = ? AND slug = ?
`
type DeleteVenueParams struct {
Slug string `json:"slug"`
Slug_2 string `json:"slug_2"`
}
func (q *Queries) DeleteVenue(ctx context.Context, arg DeleteVenueParams) error {
_, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, arg.Slug, arg.Slug_2)
return err
}
const getVenue = `-- name: GetVenue :one
SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at
FROM venue
WHERE slug = ? AND city = ?
`
type GetVenueParams struct {
Slug string `json:"slug"`
City string `json:"city"`
}
func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) {
row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City)
var i Venue
err := row.Scan(
&i.ID,
&i.Status,
&i.Statuses,
&i.Slug,
&i.Name,
&i.City,
&i.SpotifyPlaylist,
&i.SongkickID,
&i.Tags,
&i.CreatedAt,
)
return i, err
}
const listVenues = `-- name: ListVenues :many
SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at
FROM venue
WHERE city = ?
ORDER BY name
`
func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) {
rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Venue
for rows.Next() {
var i Venue
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Statuses,
&i.Slug,
&i.Name,
&i.City,
&i.SpotifyPlaylist,
&i.SongkickID,
&i.Tags,
&i.CreatedAt,
); 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
}
const updateVenueName = `-- name: UpdateVenueName :exec
UPDATE venue
SET name = ?
WHERE slug = ?
`
type UpdateVenueNameParams struct {
Name string `json:"name"`
Slug string `json:"slug"`
}
func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error {
_, err := q.exec(ctx, q.updateVenueNameStmt, updateVenueName, arg.Name, arg.Slug)
return err
}
const venueCountByCity = `-- name: VenueCountByCity :many
SELECT
city,
count(*)
FROM venue
GROUP BY 1
ORDER BY 1
`
type VenueCountByCityRow struct {
City string `json:"city"`
Count int64 `json:"count"`
}
func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) {
rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity)
if err != nil {
return nil, err
}
defer rows.Close()
var items []VenueCountByCityRow
for rows.Next() {
var i VenueCountByCityRow
if err := rows.Scan(&i.City, &i.Count); 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
}

View File

@@ -0,0 +1,95 @@
//go:build examples
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: city.sql
package ondeck
import (
"context"
)
const createCity = `-- name: CreateCity :one
INSERT INTO city (
name,
slug
) VALUES (
$1,
$2
) RETURNING slug, name
`
type CreateCityParams struct {
Name string `json:"name"`
Slug string `json:"slug"`
}
// Create a new city. The slug must be unique.
// This is the second line of the comment
// This is the third line
func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) (City, error) {
row := q.queryRow(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug)
var i City
err := row.Scan(&i.Slug, &i.Name)
return i, err
}
const getCity = `-- name: GetCity :one
SELECT slug, name
FROM city
WHERE slug = $1
`
func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) {
row := q.queryRow(ctx, q.getCityStmt, getCity, slug)
var i City
err := row.Scan(&i.Slug, &i.Name)
return i, err
}
const listCities = `-- name: ListCities :many
SELECT slug, name
FROM city
ORDER BY name
`
func (q *Queries) ListCities(ctx context.Context) ([]City, error) {
rows, err := q.query(ctx, q.listCitiesStmt, listCities)
if err != nil {
return nil, err
}
defer rows.Close()
var items []City
for rows.Next() {
var i City
if err := rows.Scan(&i.Slug, &i.Name); 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
}
const updateCityName = `-- name: UpdateCityName :exec
UPDATE city
SET name = $2
WHERE slug = $1
`
type UpdateCityNameParams struct {
Slug string `json:"slug"`
Name string `json:"name"`
}
func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error {
_, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Slug, arg.Name)
return err
}

View File

@@ -0,0 +1,180 @@
//go:build examples
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package ondeck
import (
"context"
"database/sql"
"fmt"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
q := Queries{db: db}
var err error
if q.createCityStmt, err = db.PrepareContext(ctx, createCity); err != nil {
return nil, fmt.Errorf("error preparing query CreateCity: %w", err)
}
if q.createVenueStmt, err = db.PrepareContext(ctx, createVenue); err != nil {
return nil, fmt.Errorf("error preparing query CreateVenue: %w", err)
}
if q.deleteVenueStmt, err = db.PrepareContext(ctx, deleteVenue); err != nil {
return nil, fmt.Errorf("error preparing query DeleteVenue: %w", err)
}
if q.getCityStmt, err = db.PrepareContext(ctx, getCity); err != nil {
return nil, fmt.Errorf("error preparing query GetCity: %w", err)
}
if q.getVenueStmt, err = db.PrepareContext(ctx, getVenue); err != nil {
return nil, fmt.Errorf("error preparing query GetVenue: %w", err)
}
if q.listCitiesStmt, err = db.PrepareContext(ctx, listCities); err != nil {
return nil, fmt.Errorf("error preparing query ListCities: %w", err)
}
if q.listVenuesStmt, err = db.PrepareContext(ctx, listVenues); err != nil {
return nil, fmt.Errorf("error preparing query ListVenues: %w", err)
}
if q.updateCityNameStmt, err = db.PrepareContext(ctx, updateCityName); err != nil {
return nil, fmt.Errorf("error preparing query UpdateCityName: %w", err)
}
if q.updateVenueNameStmt, err = db.PrepareContext(ctx, updateVenueName); err != nil {
return nil, fmt.Errorf("error preparing query UpdateVenueName: %w", err)
}
if q.venueCountByCityStmt, err = db.PrepareContext(ctx, venueCountByCity); err != nil {
return nil, fmt.Errorf("error preparing query VenueCountByCity: %w", err)
}
return &q, nil
}
func (q *Queries) Close() error {
var err error
if q.createCityStmt != nil {
if cerr := q.createCityStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing createCityStmt: %w", cerr)
}
}
if q.createVenueStmt != nil {
if cerr := q.createVenueStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing createVenueStmt: %w", cerr)
}
}
if q.deleteVenueStmt != nil {
if cerr := q.deleteVenueStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteVenueStmt: %w", cerr)
}
}
if q.getCityStmt != nil {
if cerr := q.getCityStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getCityStmt: %w", cerr)
}
}
if q.getVenueStmt != nil {
if cerr := q.getVenueStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getVenueStmt: %w", cerr)
}
}
if q.listCitiesStmt != nil {
if cerr := q.listCitiesStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listCitiesStmt: %w", cerr)
}
}
if q.listVenuesStmt != nil {
if cerr := q.listVenuesStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listVenuesStmt: %w", cerr)
}
}
if q.updateCityNameStmt != nil {
if cerr := q.updateCityNameStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateCityNameStmt: %w", cerr)
}
}
if q.updateVenueNameStmt != nil {
if cerr := q.updateVenueNameStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateVenueNameStmt: %w", cerr)
}
}
if q.venueCountByCityStmt != nil {
if cerr := q.venueCountByCityStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing venueCountByCityStmt: %w", cerr)
}
}
return err
}
func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...)
case stmt != nil:
return stmt.ExecContext(ctx, args...)
default:
return q.db.ExecContext(ctx, query, args...)
}
}
func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...)
case stmt != nil:
return stmt.QueryContext(ctx, args...)
default:
return q.db.QueryContext(ctx, query, args...)
}
}
func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...)
case stmt != nil:
return stmt.QueryRowContext(ctx, args...)
default:
return q.db.QueryRowContext(ctx, query, args...)
}
}
type Queries struct {
db DBTX
tx *sql.Tx
createCityStmt *sql.Stmt
createVenueStmt *sql.Stmt
deleteVenueStmt *sql.Stmt
getCityStmt *sql.Stmt
getVenueStmt *sql.Stmt
listCitiesStmt *sql.Stmt
listVenuesStmt *sql.Stmt
updateCityNameStmt *sql.Stmt
updateVenueNameStmt *sql.Stmt
venueCountByCityStmt *sql.Stmt
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
tx: tx,
createCityStmt: q.createCityStmt,
createVenueStmt: q.createVenueStmt,
deleteVenueStmt: q.deleteVenueStmt,
getCityStmt: q.getCityStmt,
getVenueStmt: q.getVenueStmt,
listCitiesStmt: q.listCitiesStmt,
listVenuesStmt: q.listVenuesStmt,
updateCityNameStmt: q.updateCityNameStmt,
updateVenueNameStmt: q.updateVenueNameStmt,
venueCountByCityStmt: q.venueCountByCityStmt,
}
}

View File

@@ -0,0 +1,154 @@
//go:build examples
package ondeck
import (
"context"
"database/sql"
"testing"
"github.com/google/go-cmp/cmp"
_ "github.com/lib/pq"
"github.com/sqlc-dev/sqlc/internal/sqltest/local"
)
func runOnDeckQueries(t *testing.T, q *Queries) {
ctx := context.Background()
city, err := q.CreateCity(ctx, CreateCityParams{
Slug: "san-francisco",
Name: "San Francisco",
})
if err != nil {
t.Fatal(err)
}
venueID, err := q.CreateVenue(ctx, CreateVenueParams{
Slug: "the-fillmore",
Name: "The Fillmore",
City: city.Slug,
SpotifyPlaylist: "spotify:uri",
Status: StatusOpen,
Statuses: []Status{StatusOpen, StatusClosed},
Tags: []string{"rock", "punk"},
})
if err != nil {
t.Fatal(err)
}
venue, err := q.GetVenue(ctx, GetVenueParams{
Slug: "the-fillmore",
City: city.Slug,
})
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(venue.ID, venueID); diff != "" {
t.Errorf("venue ID mismatch:\n%s", diff)
}
{
actual, err := q.GetCity(ctx, city.Slug)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, city); diff != "" {
t.Errorf("get city mismatch:\n%s", diff)
}
}
{
actual, err := q.VenueCountByCity(ctx)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, []VenueCountByCityRow{
{city.Slug, 1},
}); diff != "" {
t.Errorf("venue county mismatch:\n%s", diff)
}
}
{
actual, err := q.ListCities(ctx)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, []City{city}); diff != "" {
t.Errorf("list city mismatch:\n%s", diff)
}
}
{
actual, err := q.ListVenues(ctx, city.Slug)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, []Venue{venue}); diff != "" {
t.Errorf("list venue mismatch:\n%s", diff)
}
}
{
err := q.UpdateCityName(ctx, UpdateCityNameParams{
Slug: city.Slug,
Name: "SF",
})
if err != nil {
t.Error(err)
}
}
{
id, err := q.UpdateVenueName(ctx, UpdateVenueNameParams{
Slug: venue.Slug,
Name: "Fillmore",
})
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(id, venue.ID); diff != "" {
t.Errorf("update venue mismatch:\n%s", diff)
}
}
{
err := q.DeleteVenue(ctx, venue.Slug)
if err != nil {
t.Error(err)
}
}
}
func TestPrepared(t *testing.T) {
t.Parallel()
uri := local.PostgreSQL(t, []string{"schema"})
db, err := sql.Open("postgres", uri)
if err != nil {
t.Fatalf("%s: %s", uri, err)
}
defer db.Close()
q, err := Prepare(context.Background(), db)
if err != nil {
t.Fatal(err)
}
runOnDeckQueries(t, q)
}
func TestQueries(t *testing.T) {
t.Parallel()
uri := local.PostgreSQL(t, []string{"schema"})
db, err := sql.Open("postgres", uri)
if err != nil {
t.Fatalf("%s: %s", uri, err)
}
defer db.Close()
runOnDeckQueries(t, New(db))
}

View File

@@ -0,0 +1,77 @@
//go:build examples
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package ondeck
import (
"database/sql"
"database/sql/driver"
"fmt"
"time"
)
// Venues can be either open or closed
type Status string
const (
StatusOpen Status = "op!en"
StatusClosed Status = "clo@sed"
)
func (e *Status) Scan(src any) error {
switch s := src.(type) {
case []byte:
*e = Status(s)
case string:
*e = Status(s)
default:
return fmt.Errorf("unsupported scan type for Status: %T", src)
}
return nil
}
type NullStatus struct {
Status Status `json:"status"`
Valid bool `json:"valid"` // Valid is true if Status is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullStatus) Scan(value any) error {
if value == nil {
ns.Status, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.Status.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullStatus) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.Status), nil
}
type City struct {
Slug string `json:"slug"`
Name string `json:"name"`
}
// Venues are places where muisc happens
type Venue struct {
ID int32 `json:"id"`
Status Status `json:"status"`
Statuses []Status `json:"statuses"`
// This value appears in public URLs
Slug string `json:"slug"`
Name string `json:"name"`
City string `json:"city"`
SpotifyPlaylist string `json:"spotify_playlist"`
SongkickID sql.NullString `json:"songkick_id"`
Tags []string `json:"tags"`
CreatedAt time.Time `json:"created_at"`
}

View File

@@ -0,0 +1,29 @@
//go:build examples
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package ondeck
import (
"context"
)
type Querier interface {
// Create a new city. The slug must be unique.
// This is the second line of the comment
// This is the third line
CreateCity(ctx context.Context, arg CreateCityParams) (City, error)
CreateVenue(ctx context.Context, arg CreateVenueParams) (int32, error)
DeleteVenue(ctx context.Context, slug string) error
GetCity(ctx context.Context, slug string) (City, error)
GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error)
ListCities(ctx context.Context) ([]City, error)
ListVenues(ctx context.Context, city string) ([]Venue, error)
UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error
UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) (int32, error)
VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error)
}
var _ Querier = (*Queries)(nil)

View File

@@ -0,0 +1,26 @@
-- name: ListCities :many
SELECT *
FROM city
ORDER BY name;
-- name: GetCity :one
SELECT *
FROM city
WHERE slug = $1;
-- name: CreateCity :one
-- Create a new city. The slug must be unique.
-- This is the second line of the comment
-- This is the third line
INSERT INTO city (
name,
slug
) VALUES (
$1,
$2
) RETURNING *;
-- name: UpdateCityName :exec
UPDATE city
SET name = $2
WHERE slug = $1;

View File

@@ -0,0 +1,49 @@
-- name: ListVenues :many
SELECT *
FROM venue
WHERE city = $1
ORDER BY name;
-- name: DeleteVenue :exec
DELETE FROM venue
WHERE slug = $1 AND slug = $1;
-- name: GetVenue :one
SELECT *
FROM venue
WHERE slug = $1 AND city = $2;
-- name: CreateVenue :one
INSERT INTO venue (
slug,
name,
city,
created_at,
spotify_playlist,
status,
statuses,
tags
) VALUES (
$1,
$2,
$3,
NOW(),
$4,
$5,
$6,
$7
) RETURNING id;
-- name: UpdateVenueName :one
UPDATE venue
SET name = $2
WHERE slug = $1
RETURNING id;
-- name: VenueCountByCity :many
SELECT
city,
count(*)
FROM venue
GROUP BY 1
ORDER BY 1;

View File

@@ -0,0 +1,4 @@
CREATE TABLE city (
slug text PRIMARY KEY,
name text NOT NULL
)

View File

@@ -0,0 +1,18 @@
CREATE TYPE status AS ENUM ('op!en', 'clo@sed');
COMMENT ON TYPE status IS 'Venues can be either open or closed';
CREATE TABLE venues (
id SERIAL primary key,
dropped text,
status status not null,
statuses status[],
slug text not null,
name varchar(255) not null,
city text not null references city(slug),
spotify_playlist varchar not null,
songkick_id text,
tags text[]
);
COMMENT ON TABLE venues IS 'Venues are places where muisc happens';
COMMENT ON COLUMN venues.slug IS 'This value appears in public URLs';

View File

@@ -0,0 +1,3 @@
ALTER TABLE venues RENAME TO venue;
ALTER TABLE venue ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT NOW();
ALTER TABLE venue DROP COLUMN dropped;

View File

@@ -0,0 +1,197 @@
//go:build examples
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: venue.sql
package ondeck
import (
"context"
"github.com/lib/pq"
)
const createVenue = `-- name: CreateVenue :one
INSERT INTO venue (
slug,
name,
city,
created_at,
spotify_playlist,
status,
statuses,
tags
) VALUES (
$1,
$2,
$3,
NOW(),
$4,
$5,
$6,
$7
) RETURNING id
`
type CreateVenueParams struct {
Slug string `json:"slug"`
Name string `json:"name"`
City string `json:"city"`
SpotifyPlaylist string `json:"spotify_playlist"`
Status Status `json:"status"`
Statuses []Status `json:"statuses"`
Tags []string `json:"tags"`
}
func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (int32, error) {
row := q.queryRow(ctx, q.createVenueStmt, createVenue,
arg.Slug,
arg.Name,
arg.City,
arg.SpotifyPlaylist,
arg.Status,
pq.Array(arg.Statuses),
pq.Array(arg.Tags),
)
var id int32
err := row.Scan(&id)
return id, err
}
const deleteVenue = `-- name: DeleteVenue :exec
DELETE FROM venue
WHERE slug = $1 AND slug = $1
`
func (q *Queries) DeleteVenue(ctx context.Context, slug string) error {
_, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, slug)
return err
}
const getVenue = `-- name: GetVenue :one
SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at
FROM venue
WHERE slug = $1 AND city = $2
`
type GetVenueParams struct {
Slug string `json:"slug"`
City string `json:"city"`
}
func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) {
row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City)
var i Venue
err := row.Scan(
&i.ID,
&i.Status,
pq.Array(&i.Statuses),
&i.Slug,
&i.Name,
&i.City,
&i.SpotifyPlaylist,
&i.SongkickID,
pq.Array(&i.Tags),
&i.CreatedAt,
)
return i, err
}
const listVenues = `-- name: ListVenues :many
SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at
FROM venue
WHERE city = $1
ORDER BY name
`
func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) {
rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Venue
for rows.Next() {
var i Venue
if err := rows.Scan(
&i.ID,
&i.Status,
pq.Array(&i.Statuses),
&i.Slug,
&i.Name,
&i.City,
&i.SpotifyPlaylist,
&i.SongkickID,
pq.Array(&i.Tags),
&i.CreatedAt,
); 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
}
const updateVenueName = `-- name: UpdateVenueName :one
UPDATE venue
SET name = $2
WHERE slug = $1
RETURNING id
`
type UpdateVenueNameParams struct {
Slug string `json:"slug"`
Name string `json:"name"`
}
func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) (int32, error) {
row := q.queryRow(ctx, q.updateVenueNameStmt, updateVenueName, arg.Slug, arg.Name)
var id int32
err := row.Scan(&id)
return id, err
}
const venueCountByCity = `-- name: VenueCountByCity :many
SELECT
city,
count(*)
FROM venue
GROUP BY 1
ORDER BY 1
`
type VenueCountByCityRow struct {
City string `json:"city"`
Count int64 `json:"count"`
}
func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) {
rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity)
if err != nil {
return nil, err
}
defer rows.Close()
var items []VenueCountByCityRow
for rows.Next() {
var i VenueCountByCityRow
if err := rows.Scan(&i.City, &i.Count); 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
}

61
examples/ondeck/sqlc.json Normal file
View File

@@ -0,0 +1,61 @@
{
"version": "1",
"cloud": {
"project": "01HAQMMECEYQYKFJN8MP16QC41"
},
"packages": [
{
"path": "postgresql",
"name": "ondeck",
"schema": "postgresql/schema",
"queries": "postgresql/query",
"engine": "postgresql",
"sql_package": "database/sql",
"database": {
"uri": "${VET_TEST_EXAMPLES_POSTGRES_ONDECK}"
},
"analyzer": {
"database": false
},
"rules": [
"sqlc/db-prepare"
],
"build_tags": "examples",
"emit_json_tags": true,
"emit_prepared_queries": true,
"emit_interface": true
},
{
"path": "mysql",
"name": "ondeck",
"schema": "mysql/schema",
"queries": "mysql/query",
"engine": "mysql",
"database": {
"uri": "${VET_TEST_EXAMPLES_MYSQL_ONDECK}"
},
"rules": [
"sqlc/db-prepare"
],
"emit_json_tags": true,
"emit_prepared_queries": true,
"emit_interface": true
},
{
"path": "sqlite",
"name": "ondeck",
"schema": "sqlite/schema",
"queries": "sqlite/query",
"engine": "sqlite",
"database": {
"uri": "file:ondeck?mode=memory&cache=shared"
},
"rules": [
"sqlc/db-prepare"
],
"emit_json_tags": true,
"emit_prepared_queries": true,
"emit_interface": true
}
]
}

View File

@@ -0,0 +1,88 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: city.sql
package ondeck
import (
"context"
)
const createCity = `-- name: CreateCity :exec
INSERT INTO city (
name,
slug
) VALUES (
?,
?
)
`
type CreateCityParams struct {
Name string `json:"name"`
Slug string `json:"slug"`
}
func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) error {
_, err := q.exec(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug)
return err
}
const getCity = `-- name: GetCity :one
SELECT slug, name
FROM city
WHERE slug = ?
`
func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) {
row := q.queryRow(ctx, q.getCityStmt, getCity, slug)
var i City
err := row.Scan(&i.Slug, &i.Name)
return i, err
}
const listCities = `-- name: ListCities :many
SELECT slug, name
FROM city
ORDER BY name
`
func (q *Queries) ListCities(ctx context.Context) ([]City, error) {
rows, err := q.query(ctx, q.listCitiesStmt, listCities)
if err != nil {
return nil, err
}
defer rows.Close()
var items []City
for rows.Next() {
var i City
if err := rows.Scan(&i.Slug, &i.Name); 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
}
const updateCityName = `-- name: UpdateCityName :exec
UPDATE city
SET name = ?
WHERE slug = ?
`
type UpdateCityNameParams struct {
Name string `json:"name"`
Slug string `json:"slug"`
}
func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error {
_, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Name, arg.Slug)
return err
}

View File

@@ -0,0 +1,178 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package ondeck
import (
"context"
"database/sql"
"fmt"
)
type DBTX interface {
ExecContext(context.Context, string, ...any) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...any) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
q := Queries{db: db}
var err error
if q.createCityStmt, err = db.PrepareContext(ctx, createCity); err != nil {
return nil, fmt.Errorf("error preparing query CreateCity: %w", err)
}
if q.createVenueStmt, err = db.PrepareContext(ctx, createVenue); err != nil {
return nil, fmt.Errorf("error preparing query CreateVenue: %w", err)
}
if q.deleteVenueStmt, err = db.PrepareContext(ctx, deleteVenue); err != nil {
return nil, fmt.Errorf("error preparing query DeleteVenue: %w", err)
}
if q.getCityStmt, err = db.PrepareContext(ctx, getCity); err != nil {
return nil, fmt.Errorf("error preparing query GetCity: %w", err)
}
if q.getVenueStmt, err = db.PrepareContext(ctx, getVenue); err != nil {
return nil, fmt.Errorf("error preparing query GetVenue: %w", err)
}
if q.listCitiesStmt, err = db.PrepareContext(ctx, listCities); err != nil {
return nil, fmt.Errorf("error preparing query ListCities: %w", err)
}
if q.listVenuesStmt, err = db.PrepareContext(ctx, listVenues); err != nil {
return nil, fmt.Errorf("error preparing query ListVenues: %w", err)
}
if q.updateCityNameStmt, err = db.PrepareContext(ctx, updateCityName); err != nil {
return nil, fmt.Errorf("error preparing query UpdateCityName: %w", err)
}
if q.updateVenueNameStmt, err = db.PrepareContext(ctx, updateVenueName); err != nil {
return nil, fmt.Errorf("error preparing query UpdateVenueName: %w", err)
}
if q.venueCountByCityStmt, err = db.PrepareContext(ctx, venueCountByCity); err != nil {
return nil, fmt.Errorf("error preparing query VenueCountByCity: %w", err)
}
return &q, nil
}
func (q *Queries) Close() error {
var err error
if q.createCityStmt != nil {
if cerr := q.createCityStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing createCityStmt: %w", cerr)
}
}
if q.createVenueStmt != nil {
if cerr := q.createVenueStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing createVenueStmt: %w", cerr)
}
}
if q.deleteVenueStmt != nil {
if cerr := q.deleteVenueStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing deleteVenueStmt: %w", cerr)
}
}
if q.getCityStmt != nil {
if cerr := q.getCityStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getCityStmt: %w", cerr)
}
}
if q.getVenueStmt != nil {
if cerr := q.getVenueStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing getVenueStmt: %w", cerr)
}
}
if q.listCitiesStmt != nil {
if cerr := q.listCitiesStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listCitiesStmt: %w", cerr)
}
}
if q.listVenuesStmt != nil {
if cerr := q.listVenuesStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing listVenuesStmt: %w", cerr)
}
}
if q.updateCityNameStmt != nil {
if cerr := q.updateCityNameStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateCityNameStmt: %w", cerr)
}
}
if q.updateVenueNameStmt != nil {
if cerr := q.updateVenueNameStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing updateVenueNameStmt: %w", cerr)
}
}
if q.venueCountByCityStmt != nil {
if cerr := q.venueCountByCityStmt.Close(); cerr != nil {
err = fmt.Errorf("error closing venueCountByCityStmt: %w", cerr)
}
}
return err
}
func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (sql.Result, error) {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...)
case stmt != nil:
return stmt.ExecContext(ctx, args...)
default:
return q.db.ExecContext(ctx, query, args...)
}
}
func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...any) (*sql.Rows, error) {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...)
case stmt != nil:
return stmt.QueryContext(ctx, args...)
default:
return q.db.QueryContext(ctx, query, args...)
}
}
func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...any) *sql.Row {
switch {
case stmt != nil && q.tx != nil:
return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...)
case stmt != nil:
return stmt.QueryRowContext(ctx, args...)
default:
return q.db.QueryRowContext(ctx, query, args...)
}
}
type Queries struct {
db DBTX
tx *sql.Tx
createCityStmt *sql.Stmt
createVenueStmt *sql.Stmt
deleteVenueStmt *sql.Stmt
getCityStmt *sql.Stmt
getVenueStmt *sql.Stmt
listCitiesStmt *sql.Stmt
listVenuesStmt *sql.Stmt
updateCityNameStmt *sql.Stmt
updateVenueNameStmt *sql.Stmt
venueCountByCityStmt *sql.Stmt
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
tx: tx,
createCityStmt: q.createCityStmt,
createVenueStmt: q.createVenueStmt,
deleteVenueStmt: q.deleteVenueStmt,
getCityStmt: q.getCityStmt,
getVenueStmt: q.getVenueStmt,
listCitiesStmt: q.listCitiesStmt,
listVenuesStmt: q.listVenuesStmt,
updateCityNameStmt: q.updateCityNameStmt,
updateVenueNameStmt: q.updateVenueNameStmt,
venueCountByCityStmt: q.venueCountByCityStmt,
}
}

View File

@@ -0,0 +1,171 @@
//go:build examples
package ondeck
import (
"context"
"database/sql"
"strings"
"testing"
"github.com/sqlc-dev/sqlc/internal/sqltest"
"github.com/google/go-cmp/cmp"
)
// TODO: Enum is not yet supported
const (
VenuesStatusOpen string = "open"
VenuesStatusClosed string = "closed"
)
func join(vals ...string) sql.NullString {
if len(vals) == 0 {
return sql.NullString{}
}
return sql.NullString{
Valid: true,
String: strings.Join(vals, ","),
}
}
func runOnDeckQueries(t *testing.T, q *Queries) {
ctx := context.Background()
err := q.CreateCity(ctx, CreateCityParams{
Slug: "san-francisco",
Name: "San Francisco",
})
if err != nil {
t.Fatal(err)
}
city, err := q.GetCity(ctx, "san-francisco")
if err != nil {
t.Fatal(err)
}
venueResult, err := q.CreateVenue(ctx, CreateVenueParams{
Slug: "the-fillmore",
Name: "The Fillmore",
City: city.Slug,
SpotifyPlaylist: "spotify:uri",
Status: VenuesStatusOpen,
Statuses: join(string(VenuesStatusOpen), string(VenuesStatusClosed)),
Tags: join("rock", "punk"),
})
if err != nil {
t.Fatal(err)
}
venueID, err := venueResult.LastInsertId()
if err != nil {
t.Fatal(err)
}
venue, err := q.GetVenue(ctx, GetVenueParams{
Slug: "the-fillmore",
City: city.Slug,
})
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(venue.ID, venueID); diff != "" {
t.Errorf("venue ID mismatch:\n%s", diff)
}
{
actual, err := q.VenueCountByCity(ctx)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, []VenueCountByCityRow{
{city.Slug, int64(1)},
}); diff != "" {
t.Errorf("venue count mismatch:\n%s", diff)
}
}
{
actual, err := q.ListCities(ctx)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, []City{city}); diff != "" {
t.Errorf("list city mismatch:\n%s", diff)
}
}
{
actual, err := q.ListVenues(ctx, city.Slug)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(actual, []Venue{venue}); diff != "" {
t.Errorf("list venue mismatch:\n%s", diff)
}
}
{
err := q.UpdateCityName(ctx, UpdateCityNameParams{
Slug: city.Slug,
Name: "SF",
})
if err != nil {
t.Error(err)
}
}
{
expected := "Fillmore"
err := q.UpdateVenueName(ctx, UpdateVenueNameParams{
Slug: venue.Slug,
Name: expected,
})
if err != nil {
t.Error(err)
}
fresh, err := q.GetVenue(ctx, GetVenueParams{
Slug: venue.Slug,
City: city.Slug,
})
if diff := cmp.Diff(expected, fresh.Name); diff != "" {
t.Errorf("update venue mismatch:\n%s", diff)
}
}
{
err := q.DeleteVenue(ctx, DeleteVenueParams{
Slug: venue.Slug,
Slug_2: venue.Slug,
})
if err != nil {
t.Error(err)
}
}
}
func TestPrepared(t *testing.T) {
t.Parallel()
sdb, cleanup := sqltest.SQLite(t, []string{"schema"})
defer sdb.Close()
defer cleanup()
q, err := Prepare(context.Background(), sdb)
if err != nil {
t.Fatal(err)
}
runOnDeckQueries(t, q)
}
func TestQueries(t *testing.T) {
t.Parallel()
sdb, cleanup := sqltest.SQLite(t, []string{"schema"})
defer sdb.Close()
defer cleanup()
runOnDeckQueries(t, New(sdb))
}

View File

@@ -0,0 +1,28 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package ondeck
import (
"database/sql"
"time"
)
type City struct {
Slug string `json:"slug"`
Name string `json:"name"`
}
type Venue struct {
ID int64 `json:"id"`
Status string `json:"status"`
Statuses sql.NullString `json:"statuses"`
Slug string `json:"slug"`
Name string `json:"name"`
City string `json:"city"`
SpotifyPlaylist string `json:"spotify_playlist"`
SongkickID sql.NullString `json:"songkick_id"`
Tags sql.NullString `json:"tags"`
CreatedAt time.Time `json:"created_at"`
}

View File

@@ -0,0 +1,25 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
package ondeck
import (
"context"
"database/sql"
)
type Querier interface {
CreateCity(ctx context.Context, arg CreateCityParams) error
CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error)
DeleteVenue(ctx context.Context, arg DeleteVenueParams) error
GetCity(ctx context.Context, slug string) (City, error)
GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error)
ListCities(ctx context.Context) ([]City, error)
ListVenues(ctx context.Context, city string) ([]Venue, error)
UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error
UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error
VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error)
}
var _ Querier = (*Queries)(nil)

View File

@@ -0,0 +1,23 @@
/* name: ListCities :many */
SELECT *
FROM city
ORDER BY name;
/* name: GetCity :one */
SELECT *
FROM city
WHERE slug = ?;
/* name: CreateCity :exec */
INSERT INTO city (
name,
slug
) VALUES (
?,
?
);
/* name: UpdateCityName :exec */
UPDATE city
SET name = ?
WHERE slug = ?;

View File

@@ -0,0 +1,48 @@
/* name: ListVenues :many */
SELECT *
FROM venue
WHERE city = ?
ORDER BY name;
/* name: DeleteVenue :exec */
DELETE FROM venue
WHERE slug = ? AND slug = ?;
/* name: GetVenue :one */
SELECT *
FROM venue
WHERE slug = ? AND city = ?;
/* name: CreateVenue :execresult */
INSERT INTO venue (
slug,
name,
city,
created_at,
spotify_playlist,
status,
statuses,
tags
) VALUES (
?,
?,
?,
CURRENT_TIMESTAMP,
?,
?,
?,
?
);
/* name: UpdateVenueName :exec */
UPDATE venue
SET name = ?
WHERE slug = ?;
/* name: VenueCountByCity :many */
SELECT
city,
count(*)
FROM venue
GROUP BY 1
ORDER BY 1;

View File

@@ -0,0 +1,4 @@
CREATE TABLE city (
slug varchar(255) PRIMARY KEY,
name text NOT NULL
)

View File

@@ -0,0 +1,13 @@
CREATE TABLE venues (
id integer primary key AUTOINCREMENT,
dropped text,
status text not null,
statuses text, -- status[]
slug text not null,
name varchar(255) not null,
city text not null references city(slug),
spotify_playlist varchar(255) not null,
songkick_id text,
tags text, -- tags[]
CHECK (status = 'open' OR status = 'closed')
);

View File

@@ -0,0 +1,3 @@
ALTER TABLE venues RENAME TO venue;
ALTER TABLE venue ADD COLUMN created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE venue DROP COLUMN dropped;

View File

@@ -0,0 +1,193 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: venue.sql
package ondeck
import (
"context"
"database/sql"
)
const createVenue = `-- name: CreateVenue :execresult
INSERT INTO venue (
slug,
name,
city,
created_at,
spotify_playlist,
status,
statuses,
tags
) VALUES (
?,
?,
?,
CURRENT_TIMESTAMP,
?,
?,
?,
?
)
`
type CreateVenueParams struct {
Slug string `json:"slug"`
Name string `json:"name"`
City string `json:"city"`
SpotifyPlaylist string `json:"spotify_playlist"`
Status string `json:"status"`
Statuses sql.NullString `json:"statuses"`
Tags sql.NullString `json:"tags"`
}
func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) {
return q.exec(ctx, q.createVenueStmt, createVenue,
arg.Slug,
arg.Name,
arg.City,
arg.SpotifyPlaylist,
arg.Status,
arg.Statuses,
arg.Tags,
)
}
const deleteVenue = `-- name: DeleteVenue :exec
DELETE FROM venue
WHERE slug = ? AND slug = ?
`
type DeleteVenueParams struct {
Slug string `json:"slug"`
Slug_2 string `json:"slug_2"`
}
func (q *Queries) DeleteVenue(ctx context.Context, arg DeleteVenueParams) error {
_, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, arg.Slug, arg.Slug_2)
return err
}
const getVenue = `-- name: GetVenue :one
SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at
FROM venue
WHERE slug = ? AND city = ?
`
type GetVenueParams struct {
Slug string `json:"slug"`
City string `json:"city"`
}
func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) {
row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City)
var i Venue
err := row.Scan(
&i.ID,
&i.Status,
&i.Statuses,
&i.Slug,
&i.Name,
&i.City,
&i.SpotifyPlaylist,
&i.SongkickID,
&i.Tags,
&i.CreatedAt,
)
return i, err
}
const listVenues = `-- name: ListVenues :many
SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at
FROM venue
WHERE city = ?
ORDER BY name
`
func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) {
rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Venue
for rows.Next() {
var i Venue
if err := rows.Scan(
&i.ID,
&i.Status,
&i.Statuses,
&i.Slug,
&i.Name,
&i.City,
&i.SpotifyPlaylist,
&i.SongkickID,
&i.Tags,
&i.CreatedAt,
); 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
}
const updateVenueName = `-- name: UpdateVenueName :exec
UPDATE venue
SET name = ?
WHERE slug = ?
`
type UpdateVenueNameParams struct {
Name string `json:"name"`
Slug string `json:"slug"`
}
func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error {
_, err := q.exec(ctx, q.updateVenueNameStmt, updateVenueName, arg.Name, arg.Slug)
return err
}
const venueCountByCity = `-- name: VenueCountByCity :many
SELECT
city,
count(*)
FROM venue
GROUP BY 1
ORDER BY 1
`
type VenueCountByCityRow struct {
City string `json:"city"`
Count int64 `json:"count"`
}
func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) {
rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity)
if err != nil {
return nil, err
}
defer rows.Close()
var items []VenueCountByCityRow
for rows.Next() {
var i VenueCountByCityRow
if err := rows.Scan(&i.City, &i.Count); 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
}