From 97be417b40e13f9031a60a85a798b1807522fc03 Mon Sep 17 00:00:00 2001 From: Andrew Benton Date: Mon, 16 Oct 2023 10:59:31 -0700 Subject: [PATCH 1/3] docs: Update examples to use pgx/v5 --- examples/authors/postgresql/db.go | 13 +- examples/authors/postgresql/models.go | 4 +- examples/authors/postgresql/query.sql.go | 16 +- examples/authors/sqlc.yaml | 3 +- examples/batch/postgresql/batch.go | 23 ++- examples/batch/postgresql/db.go | 4 +- examples/batch/postgresql/models.go | 25 ++- examples/batch/postgresql/querier.go | 2 +- examples/batch/postgresql/query.sql.go | 2 +- examples/batch/sqlc.json | 2 +- examples/booktest/postgresql/db.go | 13 +- examples/booktest/postgresql/models.go | 5 +- examples/booktest/postgresql/query.sql.go | 44 ++--- examples/booktest/sqlc.json | 3 +- examples/jets/postgresql/db.go | 13 +- .../jets/postgresql/query-building.sql.go | 9 +- examples/jets/sqlc.json | 1 + examples/ondeck/postgresql/city.sql.go | 11 +- examples/ondeck/postgresql/db.go | 164 +----------------- examples/ondeck/postgresql/models.go | 18 +- examples/ondeck/postgresql/venue.sql.go | 32 ++-- examples/ondeck/sqlc.json | 3 +- 22 files changed, 123 insertions(+), 287 deletions(-) diff --git a/examples/authors/postgresql/db.go b/examples/authors/postgresql/db.go index f5d9de7305..00b0ad854b 100644 --- a/examples/authors/postgresql/db.go +++ b/examples/authors/postgresql/db.go @@ -6,14 +6,15 @@ package authors import ( "context" - "database/sql" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" ) type DBTX interface { - ExecContext(context.Context, string, ...interface{}) (sql.Result, error) - PrepareContext(context.Context, string) (*sql.Stmt, error) - QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) - QueryRowContext(context.Context, string, ...interface{}) *sql.Row + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row } func New(db DBTX) *Queries { @@ -24,7 +25,7 @@ type Queries struct { db DBTX } -func (q *Queries) WithTx(tx *sql.Tx) *Queries { +func (q *Queries) WithTx(tx pgx.Tx) *Queries { return &Queries{ db: tx, } diff --git a/examples/authors/postgresql/models.go b/examples/authors/postgresql/models.go index ec61702f5a..6961baa5fe 100644 --- a/examples/authors/postgresql/models.go +++ b/examples/authors/postgresql/models.go @@ -5,11 +5,11 @@ package authors import ( - "database/sql" + "github.com/jackc/pgx/v5/pgtype" ) type Author struct { ID int64 Name string - Bio sql.NullString + Bio pgtype.Text } diff --git a/examples/authors/postgresql/query.sql.go b/examples/authors/postgresql/query.sql.go index a3864f0d97..a8c3d59966 100644 --- a/examples/authors/postgresql/query.sql.go +++ b/examples/authors/postgresql/query.sql.go @@ -7,7 +7,8 @@ package authors import ( "context" - "database/sql" + + "github.com/jackc/pgx/v5/pgtype" ) const createAuthor = `-- name: CreateAuthor :one @@ -21,11 +22,11 @@ RETURNING id, name, bio type CreateAuthorParams struct { Name string - Bio sql.NullString + Bio pgtype.Text } func (q *Queries) CreateAuthor(ctx context.Context, arg CreateAuthorParams) (Author, error) { - row := q.db.QueryRowContext(ctx, createAuthor, arg.Name, arg.Bio) + 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 @@ -37,7 +38,7 @@ WHERE id = $1 ` func (q *Queries) DeleteAuthor(ctx context.Context, id int64) error { - _, err := q.db.ExecContext(ctx, deleteAuthor, id) + _, err := q.db.Exec(ctx, deleteAuthor, id) return err } @@ -47,7 +48,7 @@ WHERE id = $1 LIMIT 1 ` func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) { - row := q.db.QueryRowContext(ctx, getAuthor, id) + row := q.db.QueryRow(ctx, getAuthor, id) var i Author err := row.Scan(&i.ID, &i.Name, &i.Bio) return i, err @@ -59,7 +60,7 @@ ORDER BY name ` func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { - rows, err := q.db.QueryContext(ctx, listAuthors) + rows, err := q.db.Query(ctx, listAuthors) if err != nil { return nil, err } @@ -72,9 +73,6 @@ func (q *Queries) ListAuthors(ctx context.Context) ([]Author, error) { } items = append(items, i) } - if err := rows.Close(); err != nil { - return nil, err - } if err := rows.Err(); err != nil { return nil, err } diff --git a/examples/authors/sqlc.yaml b/examples/authors/sqlc.yaml index 9ba523c0d6..cc36949653 100644 --- a/examples/authors/sqlc.yaml +++ b/examples/authors/sqlc.yaml @@ -15,6 +15,7 @@ sql: gen: go: package: authors + sql_package: pgx/v5 out: postgresql - schema: mysql/schema.sql queries: mysql/query.sql @@ -45,4 +46,4 @@ rules: 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" \ No newline at end of file + rule: "has(mysql.explain.query_block.cost_info) && double(mysql.explain.query_block.cost_info.query_cost) > 2.0" diff --git a/examples/batch/postgresql/batch.go b/examples/batch/postgresql/batch.go index aa905c88cf..ca42f2a919 100644 --- a/examples/batch/postgresql/batch.go +++ b/examples/batch/postgresql/batch.go @@ -8,10 +8,9 @@ package batch import ( "context" "errors" - "time" - "github.com/jackc/pgtype" - "github.com/jackc/pgx/v4" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" ) var ( @@ -114,13 +113,13 @@ type CreateBookBatchResults struct { } 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 time.Time `json:"available"` - Tags []string `json:"tags"` + 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 { @@ -328,10 +327,10 @@ func (q *Queries) GetBiography(ctx context.Context, authorID []int32) *GetBiogra return &GetBiographyBatchResults{br, len(authorID), false} } -func (b *GetBiographyBatchResults) QueryRow(f func(int, pgtype.JSONB, error)) { +func (b *GetBiographyBatchResults) QueryRow(f func(int, []byte, error)) { defer b.br.Close() for t := 0; t < b.tot; t++ { - var biography pgtype.JSONB + var biography []byte if b.closed { if f != nil { f(t, biography, ErrBatchAlreadyClosed) diff --git a/examples/batch/postgresql/db.go b/examples/batch/postgresql/db.go index c9a9445f74..330c3e0f64 100644 --- a/examples/batch/postgresql/db.go +++ b/examples/batch/postgresql/db.go @@ -7,8 +7,8 @@ package batch import ( "context" - "github.com/jackc/pgconn" - "github.com/jackc/pgx/v4" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" ) type DBTX interface { diff --git a/examples/batch/postgresql/models.go b/examples/batch/postgresql/models.go index fdb04683f4..124769fadb 100644 --- a/examples/batch/postgresql/models.go +++ b/examples/batch/postgresql/models.go @@ -7,9 +7,8 @@ package batch import ( "database/sql/driver" "fmt" - "time" - "github.com/jackc/pgtype" + "github.com/jackc/pgx/v5/pgtype" ) type BookType string @@ -55,18 +54,18 @@ func (ns NullBookType) Value() (driver.Value, error) { } type Author struct { - AuthorID int32 `json:"author_id"` - Name string `json:"name"` - Biography pgtype.JSONB `json:"biography"` + 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 time.Time `json:"available"` - Tags []string `json:"tags"` + 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"` } diff --git a/examples/batch/postgresql/querier.go b/examples/batch/postgresql/querier.go index b103b84eec..cca7f58716 100644 --- a/examples/batch/postgresql/querier.go +++ b/examples/batch/postgresql/querier.go @@ -7,7 +7,7 @@ package batch import ( "context" - "github.com/jackc/pgconn" + "github.com/jackc/pgx/v5/pgconn" ) type Querier interface { diff --git a/examples/batch/postgresql/query.sql.go b/examples/batch/postgresql/query.sql.go index f6a6a42b5b..08b6ae4bf2 100644 --- a/examples/batch/postgresql/query.sql.go +++ b/examples/batch/postgresql/query.sql.go @@ -8,7 +8,7 @@ package batch import ( "context" - "github.com/jackc/pgconn" + "github.com/jackc/pgx/v5/pgconn" ) const createAuthor = `-- name: CreateAuthor :one diff --git a/examples/batch/sqlc.json b/examples/batch/sqlc.json index 32124f3959..5b81b40786 100644 --- a/examples/batch/sqlc.json +++ b/examples/batch/sqlc.json @@ -19,7 +19,7 @@ "rules": [ "sqlc/db-prepare" ], - "sql_package": "pgx/v4", + "sql_package": "pgx/v5", "emit_json_tags": true, "emit_prepared_queries": true, "emit_interface": true diff --git a/examples/booktest/postgresql/db.go b/examples/booktest/postgresql/db.go index 3014364432..34e435ebe1 100644 --- a/examples/booktest/postgresql/db.go +++ b/examples/booktest/postgresql/db.go @@ -6,14 +6,15 @@ package booktest import ( "context" - "database/sql" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" ) type DBTX interface { - ExecContext(context.Context, string, ...interface{}) (sql.Result, error) - PrepareContext(context.Context, string) (*sql.Stmt, error) - QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) - QueryRowContext(context.Context, string, ...interface{}) *sql.Row + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row } func New(db DBTX) *Queries { @@ -24,7 +25,7 @@ type Queries struct { db DBTX } -func (q *Queries) WithTx(tx *sql.Tx) *Queries { +func (q *Queries) WithTx(tx pgx.Tx) *Queries { return &Queries{ db: tx, } diff --git a/examples/booktest/postgresql/models.go b/examples/booktest/postgresql/models.go index 3bfe237f71..d5b27aceed 100644 --- a/examples/booktest/postgresql/models.go +++ b/examples/booktest/postgresql/models.go @@ -7,7 +7,8 @@ package booktest import ( "database/sql/driver" "fmt" - "time" + + "github.com/jackc/pgx/v5/pgtype" ) type BookType string @@ -64,6 +65,6 @@ type Book struct { BookType BookType Title string Year int32 - Available time.Time + Available pgtype.Timestamptz Tags []string } diff --git a/examples/booktest/postgresql/query.sql.go b/examples/booktest/postgresql/query.sql.go index 34e55ad96c..9cc621bee1 100644 --- a/examples/booktest/postgresql/query.sql.go +++ b/examples/booktest/postgresql/query.sql.go @@ -7,10 +7,8 @@ package booktest import ( "context" - "database/sql" - "time" - "github.com/lib/pq" + "github.com/jackc/pgx/v5/pgtype" ) const booksByTags = `-- name: BooksByTags :many @@ -28,13 +26,13 @@ WHERE tags && $1::varchar[] type BooksByTagsRow struct { BookID int32 Title string - Name sql.NullString + Name pgtype.Text Isbn string Tags []string } func (q *Queries) BooksByTags(ctx context.Context, dollar_1 []string) ([]BooksByTagsRow, error) { - rows, err := q.db.QueryContext(ctx, booksByTags, pq.Array(dollar_1)) + rows, err := q.db.Query(ctx, booksByTags, dollar_1) if err != nil { return nil, err } @@ -47,15 +45,12 @@ func (q *Queries) BooksByTags(ctx context.Context, dollar_1 []string) ([]BooksBy &i.Title, &i.Name, &i.Isbn, - pq.Array(&i.Tags), + &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 } @@ -73,7 +68,7 @@ type BooksByTitleYearParams struct { } func (q *Queries) BooksByTitleYear(ctx context.Context, arg BooksByTitleYearParams) ([]Book, error) { - rows, err := q.db.QueryContext(ctx, booksByTitleYear, arg.Title, arg.Year) + rows, err := q.db.Query(ctx, booksByTitleYear, arg.Title, arg.Year) if err != nil { return nil, err } @@ -89,15 +84,12 @@ func (q *Queries) BooksByTitleYear(ctx context.Context, arg BooksByTitleYearPara &i.Title, &i.Year, &i.Available, - pq.Array(&i.Tags), + &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 } @@ -110,7 +102,7 @@ RETURNING author_id, name ` func (q *Queries) CreateAuthor(ctx context.Context, name string) (Author, error) { - row := q.db.QueryRowContext(ctx, createAuthor, name) + row := q.db.QueryRow(ctx, createAuthor, name) var i Author err := row.Scan(&i.AuthorID, &i.Name) return i, err @@ -143,19 +135,19 @@ type CreateBookParams struct { BookType BookType Title string Year int32 - Available time.Time + Available pgtype.Timestamptz Tags []string } func (q *Queries) CreateBook(ctx context.Context, arg CreateBookParams) (Book, error) { - row := q.db.QueryRowContext(ctx, createBook, + row := q.db.QueryRow(ctx, createBook, arg.AuthorID, arg.Isbn, arg.BookType, arg.Title, arg.Year, arg.Available, - pq.Array(arg.Tags), + arg.Tags, ) var i Book err := row.Scan( @@ -166,7 +158,7 @@ func (q *Queries) CreateBook(ctx context.Context, arg CreateBookParams) (Book, e &i.Title, &i.Year, &i.Available, - pq.Array(&i.Tags), + &i.Tags, ) return i, err } @@ -177,7 +169,7 @@ WHERE book_id = $1 ` func (q *Queries) DeleteBook(ctx context.Context, bookID int32) error { - _, err := q.db.ExecContext(ctx, deleteBook, bookID) + _, err := q.db.Exec(ctx, deleteBook, bookID) return err } @@ -187,7 +179,7 @@ WHERE author_id = $1 ` func (q *Queries) GetAuthor(ctx context.Context, authorID int32) (Author, error) { - row := q.db.QueryRowContext(ctx, getAuthor, authorID) + row := q.db.QueryRow(ctx, getAuthor, authorID) var i Author err := row.Scan(&i.AuthorID, &i.Name) return i, err @@ -199,7 +191,7 @@ WHERE book_id = $1 ` func (q *Queries) GetBook(ctx context.Context, bookID int32) (Book, error) { - row := q.db.QueryRowContext(ctx, getBook, bookID) + row := q.db.QueryRow(ctx, getBook, bookID) var i Book err := row.Scan( &i.BookID, @@ -209,7 +201,7 @@ func (q *Queries) GetBook(ctx context.Context, bookID int32) (Book, error) { &i.Title, &i.Year, &i.Available, - pq.Array(&i.Tags), + &i.Tags, ) return i, err } @@ -227,7 +219,7 @@ type UpdateBookParams struct { } func (q *Queries) UpdateBook(ctx context.Context, arg UpdateBookParams) error { - _, err := q.db.ExecContext(ctx, updateBook, arg.Title, pq.Array(arg.Tags), arg.BookID) + _, err := q.db.Exec(ctx, updateBook, arg.Title, arg.Tags, arg.BookID) return err } @@ -245,9 +237,9 @@ type UpdateBookISBNParams struct { } func (q *Queries) UpdateBookISBN(ctx context.Context, arg UpdateBookISBNParams) error { - _, err := q.db.ExecContext(ctx, updateBookISBN, + _, err := q.db.Exec(ctx, updateBookISBN, arg.Title, - pq.Array(arg.Tags), + arg.Tags, arg.BookID, arg.Isbn, ) diff --git a/examples/booktest/sqlc.json b/examples/booktest/sqlc.json index b1453a2e37..8f5ddad6e6 100644 --- a/examples/booktest/sqlc.json +++ b/examples/booktest/sqlc.json @@ -10,6 +10,7 @@ "schema": "postgresql/schema.sql", "queries": "postgresql/query.sql", "engine": "postgresql", + "sql_package": "pgx/v5", "database": { "managed": true }, @@ -47,4 +48,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/examples/jets/postgresql/db.go b/examples/jets/postgresql/db.go index bee0af2640..96af127ff2 100644 --- a/examples/jets/postgresql/db.go +++ b/examples/jets/postgresql/db.go @@ -6,14 +6,15 @@ package jets import ( "context" - "database/sql" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" ) type DBTX interface { - ExecContext(context.Context, string, ...interface{}) (sql.Result, error) - PrepareContext(context.Context, string) (*sql.Stmt, error) - QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) - QueryRowContext(context.Context, string, ...interface{}) *sql.Row + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row } func New(db DBTX) *Queries { @@ -24,7 +25,7 @@ type Queries struct { db DBTX } -func (q *Queries) WithTx(tx *sql.Tx) *Queries { +func (q *Queries) WithTx(tx pgx.Tx) *Queries { return &Queries{ db: tx, } diff --git a/examples/jets/postgresql/query-building.sql.go b/examples/jets/postgresql/query-building.sql.go index 64db2dfdf8..15e4900d51 100644 --- a/examples/jets/postgresql/query-building.sql.go +++ b/examples/jets/postgresql/query-building.sql.go @@ -14,7 +14,7 @@ SELECT COUNT(*) FROM pilots ` func (q *Queries) CountPilots(ctx context.Context) (int64, error) { - row := q.db.QueryRowContext(ctx, countPilots) + row := q.db.QueryRow(ctx, countPilots) var count int64 err := row.Scan(&count) return count, err @@ -25,7 +25,7 @@ DELETE FROM pilots WHERE id = $1 ` func (q *Queries) DeletePilot(ctx context.Context, id int32) error { - _, err := q.db.ExecContext(ctx, deletePilot, id) + _, err := q.db.Exec(ctx, deletePilot, id) return err } @@ -34,7 +34,7 @@ SELECT id, name FROM pilots LIMIT 5 ` func (q *Queries) ListPilots(ctx context.Context) ([]Pilot, error) { - rows, err := q.db.QueryContext(ctx, listPilots) + rows, err := q.db.Query(ctx, listPilots) if err != nil { return nil, err } @@ -47,9 +47,6 @@ func (q *Queries) ListPilots(ctx context.Context) ([]Pilot, error) { } items = append(items, i) } - if err := rows.Close(); err != nil { - return nil, err - } if err := rows.Err(); err != nil { return nil, err } diff --git a/examples/jets/sqlc.json b/examples/jets/sqlc.json index 14e80c4291..d664966753 100644 --- a/examples/jets/sqlc.json +++ b/examples/jets/sqlc.json @@ -10,6 +10,7 @@ "schema": "postgresql/schema.sql", "queries": "postgresql/query-building.sql", "engine": "postgresql", + "sql_package": "pgx/v5", "database": { "managed": true }, diff --git a/examples/ondeck/postgresql/city.sql.go b/examples/ondeck/postgresql/city.sql.go index a054b1b8d8..ae036edbdc 100644 --- a/examples/ondeck/postgresql/city.sql.go +++ b/examples/ondeck/postgresql/city.sql.go @@ -28,7 +28,7 @@ type CreateCityParams struct { // 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) + row := q.db.QueryRow(ctx, createCity, arg.Name, arg.Slug) var i City err := row.Scan(&i.Slug, &i.Name) return i, err @@ -41,7 +41,7 @@ WHERE slug = $1 ` func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) { - row := q.queryRow(ctx, q.getCityStmt, getCity, slug) + row := q.db.QueryRow(ctx, getCity, slug) var i City err := row.Scan(&i.Slug, &i.Name) return i, err @@ -54,7 +54,7 @@ ORDER BY name ` func (q *Queries) ListCities(ctx context.Context) ([]City, error) { - rows, err := q.query(ctx, q.listCitiesStmt, listCities) + rows, err := q.db.Query(ctx, listCities) if err != nil { return nil, err } @@ -67,9 +67,6 @@ func (q *Queries) ListCities(ctx context.Context) ([]City, error) { } items = append(items, i) } - if err := rows.Close(); err != nil { - return nil, err - } if err := rows.Err(); err != nil { return nil, err } @@ -88,6 +85,6 @@ type UpdateCityNameParams struct { } func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error { - _, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Slug, arg.Name) + _, err := q.db.Exec(ctx, updateCityName, arg.Slug, arg.Name) return err } diff --git a/examples/ondeck/postgresql/db.go b/examples/ondeck/postgresql/db.go index 06afcda08e..e52be1d678 100644 --- a/examples/ondeck/postgresql/db.go +++ b/examples/ondeck/postgresql/db.go @@ -6,173 +6,27 @@ package ondeck import ( "context" - "database/sql" - "fmt" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" ) type DBTX interface { - ExecContext(context.Context, string, ...interface{}) (sql.Result, error) - PrepareContext(context.Context, string) (*sql.Stmt, error) - QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) - QueryRowContext(context.Context, string, ...interface{}) *sql.Row + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.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 ...interface{}) (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 ...interface{}) (*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 ...interface{}) *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 + db DBTX } -func (q *Queries) WithTx(tx *sql.Tx) *Queries { +func (q *Queries) WithTx(tx pgx.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, + db: tx, } } diff --git a/examples/ondeck/postgresql/models.go b/examples/ondeck/postgresql/models.go index 5f32237c2e..fc565e59c5 100644 --- a/examples/ondeck/postgresql/models.go +++ b/examples/ondeck/postgresql/models.go @@ -5,10 +5,10 @@ package ondeck import ( - "database/sql" "database/sql/driver" "fmt" - "time" + + "github.com/jackc/pgx/v5/pgtype" ) // Venues can be either open or closed @@ -65,11 +65,11 @@ type Venue struct { 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"` + Slug string `json:"slug"` + Name string `json:"name"` + City string `json:"city"` + SpotifyPlaylist string `json:"spotify_playlist"` + SongkickID pgtype.Text `json:"songkick_id"` + Tags []string `json:"tags"` + CreatedAt pgtype.Timestamp `json:"created_at"` } diff --git a/examples/ondeck/postgresql/venue.sql.go b/examples/ondeck/postgresql/venue.sql.go index 212c4bd94a..1780225961 100644 --- a/examples/ondeck/postgresql/venue.sql.go +++ b/examples/ondeck/postgresql/venue.sql.go @@ -7,8 +7,6 @@ package ondeck import ( "context" - - "github.com/lib/pq" ) const createVenue = `-- name: CreateVenue :one @@ -44,14 +42,14 @@ type CreateVenueParams struct { } func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (int32, error) { - row := q.queryRow(ctx, q.createVenueStmt, createVenue, + row := q.db.QueryRow(ctx, createVenue, arg.Slug, arg.Name, arg.City, arg.SpotifyPlaylist, arg.Status, - pq.Array(arg.Statuses), - pq.Array(arg.Tags), + arg.Statuses, + arg.Tags, ) var id int32 err := row.Scan(&id) @@ -64,7 +62,7 @@ WHERE slug = $1 AND slug = $1 ` func (q *Queries) DeleteVenue(ctx context.Context, slug string) error { - _, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, slug) + _, err := q.db.Exec(ctx, deleteVenue, slug) return err } @@ -80,18 +78,18 @@ type GetVenueParams struct { } func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) { - row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City) + row := q.db.QueryRow(ctx, getVenue, arg.Slug, arg.City) var i Venue err := row.Scan( &i.ID, &i.Status, - pq.Array(&i.Statuses), + &i.Statuses, &i.Slug, &i.Name, &i.City, &i.SpotifyPlaylist, &i.SongkickID, - pq.Array(&i.Tags), + &i.Tags, &i.CreatedAt, ) return i, err @@ -105,7 +103,7 @@ ORDER BY name ` func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) { - rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city) + rows, err := q.db.Query(ctx, listVenues, city) if err != nil { return nil, err } @@ -116,22 +114,19 @@ func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) if err := rows.Scan( &i.ID, &i.Status, - pq.Array(&i.Statuses), + &i.Statuses, &i.Slug, &i.Name, &i.City, &i.SpotifyPlaylist, &i.SongkickID, - pq.Array(&i.Tags), + &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 } @@ -151,7 +146,7 @@ type UpdateVenueNameParams struct { } func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) (int32, error) { - row := q.queryRow(ctx, q.updateVenueNameStmt, updateVenueName, arg.Slug, arg.Name) + row := q.db.QueryRow(ctx, updateVenueName, arg.Slug, arg.Name) var id int32 err := row.Scan(&id) return id, err @@ -172,7 +167,7 @@ type VenueCountByCityRow struct { } func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) { - rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity) + rows, err := q.db.Query(ctx, venueCountByCity) if err != nil { return nil, err } @@ -185,9 +180,6 @@ func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, } items = append(items, i) } - if err := rows.Close(); err != nil { - return nil, err - } if err := rows.Err(); err != nil { return nil, err } diff --git a/examples/ondeck/sqlc.json b/examples/ondeck/sqlc.json index 0eed50f9d7..2ab7db4635 100644 --- a/examples/ondeck/sqlc.json +++ b/examples/ondeck/sqlc.json @@ -10,6 +10,7 @@ "schema": "postgresql/schema", "queries": "postgresql/query", "engine": "postgresql", + "sql_package": "pgx/v5", "database": { "managed": true }, @@ -56,4 +57,4 @@ "emit_interface": true } ] -} \ No newline at end of file +} From 9adb266ef389034bb074f70ad4ec442210e8d03b Mon Sep 17 00:00:00 2001 From: Andrew Benton Date: Mon, 16 Oct 2023 16:04:01 -0700 Subject: [PATCH 2/3] test: Update example tests to work correctly with pgx v5 --- examples/authors/postgresql/db_test.go | 12 ++++++------ examples/batch/postgresql/db_test.go | 7 ++++--- examples/booktest/postgresql/db_test.go | 20 +++++++++---------- examples/ondeck/postgresql/db_test.go | 26 ++++--------------------- 4 files changed, 24 insertions(+), 41 deletions(-) diff --git a/examples/authors/postgresql/db_test.go b/examples/authors/postgresql/db_test.go index d2df436ae3..bdcd90a547 100644 --- a/examples/authors/postgresql/db_test.go +++ b/examples/authors/postgresql/db_test.go @@ -5,23 +5,23 @@ package authors import ( "context" - "database/sql" "testing" - _ "github.com/lib/pq" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" "github.com/sqlc-dev/sqlc/internal/sqltest/hosted" ) func TestAuthors(t *testing.T) { + ctx := context.Background() uri := hosted.PostgreSQL(t, []string{"schema.sql"}) - db, err := sql.Open("postgres", uri) + db, err := pgx.Connect(ctx, uri) if err != nil { t.Fatal(err) } - defer db.Close() + defer db.Close(ctx) - ctx := context.Background() q := New(db) // list all authors @@ -34,7 +34,7 @@ func TestAuthors(t *testing.T) { // create an author insertedAuthor, err := q.CreateAuthor(ctx, CreateAuthorParams{ Name: "Brian Kernighan", - Bio: sql.NullString{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true}, + Bio: pgtype.Text{String: "Co-author of The C Programming Language and The Go Programming Language", Valid: true}, }) if err != nil { t.Fatal(err) diff --git a/examples/batch/postgresql/db_test.go b/examples/batch/postgresql/db_test.go index fd3ce4e72b..6ec33a6a27 100644 --- a/examples/batch/postgresql/db_test.go +++ b/examples/batch/postgresql/db_test.go @@ -8,7 +8,8 @@ import ( "testing" "time" - "github.com/jackc/pgx/v4" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" "github.com/sqlc-dev/sqlc/internal/sqltest/hosted" ) @@ -31,7 +32,7 @@ func TestBatchBooks(t *testing.T) { t.Fatal(err) } - now := time.Now() + now := pgtype.Timestamptz{Time: time.Now()} // batch insert new books newBooksParams := []CreateBookParams{ @@ -114,7 +115,7 @@ func TestBatchBooks(t *testing.T) { }) for _, book := range books0 { - t.Logf("Book %d (%s): %s available: %s\n", book.BookID, book.BookType, book.Title, book.Available.Format(time.RFC822Z)) + 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) diff --git a/examples/booktest/postgresql/db_test.go b/examples/booktest/postgresql/db_test.go index 9716f56844..e489fa5103 100644 --- a/examples/booktest/postgresql/db_test.go +++ b/examples/booktest/postgresql/db_test.go @@ -5,24 +5,24 @@ package booktest import ( "context" - "database/sql" "testing" "time" - _ "github.com/lib/pq" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" "github.com/sqlc-dev/sqlc/internal/sqltest/hosted" ) func TestBooks(t *testing.T) { - uri := hosted.PostgreSQL(t, []string{"schema.sql"}) - db, err := sql.Open("postgres", uri) + ctx := context.Background() + uri := hosted.PostgreSQL(t, []string{"schema"}) + db, err := pgx.Connect(ctx, uri) if err != nil { t.Fatal(err) } - defer db.Close() + defer db.Close(ctx) - ctx := context.Background() dq := New(db) // create an author @@ -32,7 +32,7 @@ func TestBooks(t *testing.T) { } // create transaction - tx, err := db.Begin() + tx, err := db.Begin(ctx) if err != nil { t.Fatal(err) } @@ -40,7 +40,7 @@ func TestBooks(t *testing.T) { tq := dq.WithTx(tx) // save first book - now := time.Now() + now := pgtype.Timestamptz{Time: time.Now()} _, err = tq.CreateBook(ctx, CreateBookParams{ AuthorID: a.AuthorID, Isbn: "1", @@ -107,7 +107,7 @@ func TestBooks(t *testing.T) { } // tx commit - err = tx.Commit() + err = tx.Commit(ctx) if err != nil { t.Fatal(err) } @@ -132,7 +132,7 @@ func TestBooks(t *testing.T) { 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)) + 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) diff --git a/examples/ondeck/postgresql/db_test.go b/examples/ondeck/postgresql/db_test.go index c4e4ce8bbf..2715031499 100644 --- a/examples/ondeck/postgresql/db_test.go +++ b/examples/ondeck/postgresql/db_test.go @@ -5,11 +5,10 @@ package ondeck import ( "context" - "database/sql" "testing" "github.com/google/go-cmp/cmp" - _ "github.com/lib/pq" + "github.com/jackc/pgx/v5" "github.com/sqlc-dev/sqlc/internal/sqltest/hosted" ) @@ -123,33 +122,16 @@ func runOnDeckQueries(t *testing.T, q *Queries) { } } -func TestPrepared(t *testing.T) { - t.Parallel() - - uri := hosted.PostgreSQL(t, []string{"schema"}) - db, err := sql.Open("postgres", uri) - if err != nil { - t.Fatal(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() + ctx := context.Background() uri := hosted.PostgreSQL(t, []string{"schema"}) - db, err := sql.Open("postgres", uri) + db, err := pgx.Connect(ctx, uri) if err != nil { t.Fatal(err) } - defer db.Close() + defer db.Close(ctx) runOnDeckQueries(t, New(db)) } From 514517980c636ddc83398121ddd7a4d212e88cdc Mon Sep 17 00:00:00 2001 From: Andrew Benton Date: Mon, 16 Oct 2023 16:45:59 -0700 Subject: [PATCH 3/3] test: Fix examples tests --- examples/batch/postgresql/db_test.go | 2 +- examples/booktest/postgresql/db_test.go | 4 +- examples/ondeck/postgresql/city.sql.go | 11 +- examples/ondeck/postgresql/db.go | 164 ++++++++++++++++++++++-- examples/ondeck/postgresql/db_test.go | 26 +++- examples/ondeck/postgresql/models.go | 18 +-- examples/ondeck/postgresql/venue.sql.go | 32 +++-- examples/ondeck/sqlc.json | 2 +- 8 files changed, 217 insertions(+), 42 deletions(-) diff --git a/examples/batch/postgresql/db_test.go b/examples/batch/postgresql/db_test.go index 6ec33a6a27..c39bd0b5ed 100644 --- a/examples/batch/postgresql/db_test.go +++ b/examples/batch/postgresql/db_test.go @@ -32,7 +32,7 @@ func TestBatchBooks(t *testing.T) { t.Fatal(err) } - now := pgtype.Timestamptz{Time: time.Now()} + now := pgtype.Timestamptz{Time: time.Now(), Valid: true} // batch insert new books newBooksParams := []CreateBookParams{ diff --git a/examples/booktest/postgresql/db_test.go b/examples/booktest/postgresql/db_test.go index e489fa5103..8eeb10518c 100644 --- a/examples/booktest/postgresql/db_test.go +++ b/examples/booktest/postgresql/db_test.go @@ -16,7 +16,7 @@ import ( func TestBooks(t *testing.T) { ctx := context.Background() - uri := hosted.PostgreSQL(t, []string{"schema"}) + uri := hosted.PostgreSQL(t, []string{"schema.sql"}) db, err := pgx.Connect(ctx, uri) if err != nil { t.Fatal(err) @@ -40,7 +40,7 @@ func TestBooks(t *testing.T) { tq := dq.WithTx(tx) // save first book - now := pgtype.Timestamptz{Time: time.Now()} + now := pgtype.Timestamptz{Time: time.Now(), Valid: true} _, err = tq.CreateBook(ctx, CreateBookParams{ AuthorID: a.AuthorID, Isbn: "1", diff --git a/examples/ondeck/postgresql/city.sql.go b/examples/ondeck/postgresql/city.sql.go index ae036edbdc..a054b1b8d8 100644 --- a/examples/ondeck/postgresql/city.sql.go +++ b/examples/ondeck/postgresql/city.sql.go @@ -28,7 +28,7 @@ type CreateCityParams struct { // 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.db.QueryRow(ctx, createCity, arg.Name, arg.Slug) + row := q.queryRow(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug) var i City err := row.Scan(&i.Slug, &i.Name) return i, err @@ -41,7 +41,7 @@ WHERE slug = $1 ` func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) { - row := q.db.QueryRow(ctx, getCity, slug) + row := q.queryRow(ctx, q.getCityStmt, getCity, slug) var i City err := row.Scan(&i.Slug, &i.Name) return i, err @@ -54,7 +54,7 @@ ORDER BY name ` func (q *Queries) ListCities(ctx context.Context) ([]City, error) { - rows, err := q.db.Query(ctx, listCities) + rows, err := q.query(ctx, q.listCitiesStmt, listCities) if err != nil { return nil, err } @@ -67,6 +67,9 @@ func (q *Queries) ListCities(ctx context.Context) ([]City, error) { } items = append(items, i) } + if err := rows.Close(); err != nil { + return nil, err + } if err := rows.Err(); err != nil { return nil, err } @@ -85,6 +88,6 @@ type UpdateCityNameParams struct { } func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error { - _, err := q.db.Exec(ctx, updateCityName, arg.Slug, arg.Name) + _, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Slug, arg.Name) return err } diff --git a/examples/ondeck/postgresql/db.go b/examples/ondeck/postgresql/db.go index e52be1d678..06afcda08e 100644 --- a/examples/ondeck/postgresql/db.go +++ b/examples/ondeck/postgresql/db.go @@ -6,27 +6,173 @@ package ondeck import ( "context" - - "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgconn" + "database/sql" + "fmt" ) type DBTX interface { - Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) - Query(context.Context, string, ...interface{}) (pgx.Rows, error) - QueryRow(context.Context, string, ...interface{}) pgx.Row + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row } func New(db DBTX) *Queries { return &Queries{db: db} } +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 ...interface{}) (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 ...interface{}) (*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 ...interface{}) *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 + 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 pgx.Tx) *Queries { +func (q *Queries) WithTx(tx *sql.Tx) *Queries { return &Queries{ - db: tx, + 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, } } diff --git a/examples/ondeck/postgresql/db_test.go b/examples/ondeck/postgresql/db_test.go index 2715031499..c4e4ce8bbf 100644 --- a/examples/ondeck/postgresql/db_test.go +++ b/examples/ondeck/postgresql/db_test.go @@ -5,10 +5,11 @@ package ondeck import ( "context" + "database/sql" "testing" "github.com/google/go-cmp/cmp" - "github.com/jackc/pgx/v5" + _ "github.com/lib/pq" "github.com/sqlc-dev/sqlc/internal/sqltest/hosted" ) @@ -122,16 +123,33 @@ func runOnDeckQueries(t *testing.T, q *Queries) { } } +func TestPrepared(t *testing.T) { + t.Parallel() + + uri := hosted.PostgreSQL(t, []string{"schema"}) + db, err := sql.Open("postgres", uri) + if err != nil { + t.Fatal(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() - ctx := context.Background() uri := hosted.PostgreSQL(t, []string{"schema"}) - db, err := pgx.Connect(ctx, uri) + db, err := sql.Open("postgres", uri) if err != nil { t.Fatal(err) } - defer db.Close(ctx) + defer db.Close() runOnDeckQueries(t, New(db)) } diff --git a/examples/ondeck/postgresql/models.go b/examples/ondeck/postgresql/models.go index fc565e59c5..5f32237c2e 100644 --- a/examples/ondeck/postgresql/models.go +++ b/examples/ondeck/postgresql/models.go @@ -5,10 +5,10 @@ package ondeck import ( + "database/sql" "database/sql/driver" "fmt" - - "github.com/jackc/pgx/v5/pgtype" + "time" ) // Venues can be either open or closed @@ -65,11 +65,11 @@ type Venue struct { 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 pgtype.Text `json:"songkick_id"` - Tags []string `json:"tags"` - CreatedAt pgtype.Timestamp `json:"created_at"` + 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"` } diff --git a/examples/ondeck/postgresql/venue.sql.go b/examples/ondeck/postgresql/venue.sql.go index 1780225961..212c4bd94a 100644 --- a/examples/ondeck/postgresql/venue.sql.go +++ b/examples/ondeck/postgresql/venue.sql.go @@ -7,6 +7,8 @@ package ondeck import ( "context" + + "github.com/lib/pq" ) const createVenue = `-- name: CreateVenue :one @@ -42,14 +44,14 @@ type CreateVenueParams struct { } func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (int32, error) { - row := q.db.QueryRow(ctx, createVenue, + row := q.queryRow(ctx, q.createVenueStmt, createVenue, arg.Slug, arg.Name, arg.City, arg.SpotifyPlaylist, arg.Status, - arg.Statuses, - arg.Tags, + pq.Array(arg.Statuses), + pq.Array(arg.Tags), ) var id int32 err := row.Scan(&id) @@ -62,7 +64,7 @@ WHERE slug = $1 AND slug = $1 ` func (q *Queries) DeleteVenue(ctx context.Context, slug string) error { - _, err := q.db.Exec(ctx, deleteVenue, slug) + _, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, slug) return err } @@ -78,18 +80,18 @@ type GetVenueParams struct { } func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) { - row := q.db.QueryRow(ctx, getVenue, arg.Slug, arg.City) + row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City) var i Venue err := row.Scan( &i.ID, &i.Status, - &i.Statuses, + pq.Array(&i.Statuses), &i.Slug, &i.Name, &i.City, &i.SpotifyPlaylist, &i.SongkickID, - &i.Tags, + pq.Array(&i.Tags), &i.CreatedAt, ) return i, err @@ -103,7 +105,7 @@ ORDER BY name ` func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) { - rows, err := q.db.Query(ctx, listVenues, city) + rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city) if err != nil { return nil, err } @@ -114,19 +116,22 @@ func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) if err := rows.Scan( &i.ID, &i.Status, - &i.Statuses, + pq.Array(&i.Statuses), &i.Slug, &i.Name, &i.City, &i.SpotifyPlaylist, &i.SongkickID, - &i.Tags, + 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 } @@ -146,7 +151,7 @@ type UpdateVenueNameParams struct { } func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) (int32, error) { - row := q.db.QueryRow(ctx, updateVenueName, arg.Slug, arg.Name) + row := q.queryRow(ctx, q.updateVenueNameStmt, updateVenueName, arg.Slug, arg.Name) var id int32 err := row.Scan(&id) return id, err @@ -167,7 +172,7 @@ type VenueCountByCityRow struct { } func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) { - rows, err := q.db.Query(ctx, venueCountByCity) + rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity) if err != nil { return nil, err } @@ -180,6 +185,9 @@ func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, } items = append(items, i) } + if err := rows.Close(); err != nil { + return nil, err + } if err := rows.Err(); err != nil { return nil, err } diff --git a/examples/ondeck/sqlc.json b/examples/ondeck/sqlc.json index 2ab7db4635..2e94b30d9b 100644 --- a/examples/ondeck/sqlc.json +++ b/examples/ondeck/sqlc.json @@ -10,7 +10,7 @@ "schema": "postgresql/schema", "queries": "postgresql/query", "engine": "postgresql", - "sql_package": "pgx/v5", + "sql_package": "database/sql", "database": { "managed": true },