From 4aa82ffc0c25c226e6f6274ff19f82bb6998f29a Mon Sep 17 00:00:00 2001 From: pdeantihuman Date: Sat, 21 Aug 2021 16:15:53 +0800 Subject: [PATCH 1/2] :bug: resolve https://github.com/kyleconroy/sqlc/issues/1067 by replacing "string" with sql.NullString in the case of "sql_package": "pgx/v4" :white_check_mark: add a test case contributed by https://github.com/kyleconroy/sqlc/issues/1067 broke some tests --- internal/codegen/golang/postgresql_type.go | 3 ++ .../testdata/datatype_numeric/pgx/go/db.go | 30 +++++++++++++++++++ .../datatype_numeric/pgx/go/models.go | 17 +++++++++++ .../datatype_numeric/pgx/go/query.sql.go | 26 ++++++++++++++++ .../datatype_numeric/pgx/sql/query.sql | 3 ++ .../datatype_numeric/pgx/sql/schema.sql | 6 ++++ .../testdata/datatype_numeric/pgx/sqlc.json | 13 ++++++++ 7 files changed, 98 insertions(+) create mode 100644 internal/endtoend/testdata/datatype_numeric/pgx/go/db.go create mode 100644 internal/endtoend/testdata/datatype_numeric/pgx/go/models.go create mode 100644 internal/endtoend/testdata/datatype_numeric/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/datatype_numeric/pgx/sql/query.sql create mode 100644 internal/endtoend/testdata/datatype_numeric/pgx/sql/schema.sql create mode 100644 internal/endtoend/testdata/datatype_numeric/pgx/sqlc.json diff --git a/internal/codegen/golang/postgresql_type.go b/internal/codegen/golang/postgresql_type.go index 42b4be0da0..bf2fa96cda 100644 --- a/internal/codegen/golang/postgresql_type.go +++ b/internal/codegen/golang/postgresql_type.go @@ -61,6 +61,9 @@ func postgresType(r *compiler.Result, col *compiler.Column, settings config.Comb // returns numerics as strings. // // https://github.com/lib/pq/issues/648 + if settings.Go.SQLPackage == "pgx/v4" { + return "sql.NullString" + } if notNull { return "string" } diff --git a/internal/endtoend/testdata/datatype_numeric/pgx/go/db.go b/internal/endtoend/testdata/datatype_numeric/pgx/go/db.go new file mode 100644 index 0000000000..2936aad1d9 --- /dev/null +++ b/internal/endtoend/testdata/datatype_numeric/pgx/go/db.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. + +package datatype + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +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 +} + +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, + } +} diff --git a/internal/endtoend/testdata/datatype_numeric/pgx/go/models.go b/internal/endtoend/testdata/datatype_numeric/pgx/go/models.go new file mode 100644 index 0000000000..d26f733474 --- /dev/null +++ b/internal/endtoend/testdata/datatype_numeric/pgx/go/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. + +package datatype + +import ( + "database/sql" + "time" + + "github.com/google/uuid" +) + +type Example struct { + ExampleID uuid.UUID + Value sql.NullString + CreateTime time.Time + UpdateTime time.Time +} diff --git a/internal/endtoend/testdata/datatype_numeric/pgx/go/query.sql.go b/internal/endtoend/testdata/datatype_numeric/pgx/go/query.sql.go new file mode 100644 index 0000000000..2d69c08ece --- /dev/null +++ b/internal/endtoend/testdata/datatype_numeric/pgx/go/query.sql.go @@ -0,0 +1,26 @@ +// Code generated by sqlc. DO NOT EDIT. +// source: query.sql + +package datatype + +import ( + "context" + "database/sql" +) + +const createExample = `-- name: CreateExample :one +INSERT INTO examples (value) VALUES ($1) +RETURNING example_id, value, create_time, update_time +` + +func (q *Queries) CreateExample(ctx context.Context, value sql.NullString) (Example, error) { + row := q.db.QueryRow(ctx, createExample, value) + var i Example + err := row.Scan( + &i.ExampleID, + &i.Value, + &i.CreateTime, + &i.UpdateTime, + ) + return i, err +} diff --git a/internal/endtoend/testdata/datatype_numeric/pgx/sql/query.sql b/internal/endtoend/testdata/datatype_numeric/pgx/sql/query.sql new file mode 100644 index 0000000000..c97f5250e0 --- /dev/null +++ b/internal/endtoend/testdata/datatype_numeric/pgx/sql/query.sql @@ -0,0 +1,3 @@ +-- name: CreateExample :one +INSERT INTO examples (value) VALUES ($1) +RETURNING *; \ No newline at end of file diff --git a/internal/endtoend/testdata/datatype_numeric/pgx/sql/schema.sql b/internal/endtoend/testdata/datatype_numeric/pgx/sql/schema.sql new file mode 100644 index 0000000000..df1a0b137f --- /dev/null +++ b/internal/endtoend/testdata/datatype_numeric/pgx/sql/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS examples ( + example_id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + value numeric NOT NULL, + create_time timestamp with time zone NOT NULL DEFAULT now(), + update_time timestamp with time zone NOT NULL DEFAULT now() +); \ No newline at end of file diff --git a/internal/endtoend/testdata/datatype_numeric/pgx/sqlc.json b/internal/endtoend/testdata/datatype_numeric/pgx/sqlc.json new file mode 100644 index 0000000000..a007c153fc --- /dev/null +++ b/internal/endtoend/testdata/datatype_numeric/pgx/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "datatype", + "schema": "sql/schema.sql", + "queries": "sql/query.sql" + } + ] +} From c1431e7afa5f6927ade71fb4a9bf6c971862d763 Mon Sep 17 00:00:00 2001 From: pdeantihuman Date: Sun, 22 Aug 2021 21:18:41 +0800 Subject: [PATCH 2/2] :adhesive_bandage: replace sql.NullString with pgtype.Numeric :pencil2: make use of parseDriver --- internal/codegen/golang/imports.go | 1 + internal/codegen/golang/postgresql_type.go | 18 ++++++++++-------- .../testdata/datatype/pgx/go/models.go | 6 ++++-- .../testdata/datatype_numeric/pgx/go/models.go | 4 ++-- .../datatype_numeric/pgx/go/query.sql.go | 5 +++-- .../postgresql/pgx/go/models.go | 4 +++- .../postgresql/pgx/go/query.sql.go | 6 ++++-- 7 files changed, 27 insertions(+), 17 deletions(-) diff --git a/internal/codegen/golang/imports.go b/internal/codegen/golang/imports.go index 0f6dca633e..e40bddd779 100644 --- a/internal/codegen/golang/imports.go +++ b/internal/codegen/golang/imports.go @@ -136,6 +136,7 @@ var pgtypeTypes = map[string]struct{}{ "pgtype.CIDR": {}, "pgtype.Inet": {}, "pgtype.Macaddr": {}, + "pgtype.Numeric": {}, } var pqtypeTypes = map[string]struct{}{ diff --git a/internal/codegen/golang/postgresql_type.go b/internal/codegen/golang/postgresql_type.go index eb64076651..5c723bbf20 100644 --- a/internal/codegen/golang/postgresql_type.go +++ b/internal/codegen/golang/postgresql_type.go @@ -58,15 +58,17 @@ func postgresType(r *compiler.Result, col *compiler.Column, settings config.Comb return "sql.NullFloat64" // TODO: Change to sql.NullFloat32 after updating the go.mod file case "numeric", "pg_catalog.numeric", "money": - // Since the Go standard library does not have a decimal type, lib/pq - // returns numerics as strings. - // - // https://github.com/lib/pq/issues/648 - if settings.Go.SQLPackage == "pgx/v4" { - return "sql.NullString" - } if notNull { - return "string" + switch driver { + case SQLDriverPGXV4: + return "pgtype.Numeric" + default: + // Since the Go standard library does not have a decimal type, lib/pq + // returns numerics as strings. + // + // https://github.com/lib/pq/issues/648 + return "string" + } } return "sql.NullString" diff --git a/internal/endtoend/testdata/datatype/pgx/go/models.go b/internal/endtoend/testdata/datatype/pgx/go/models.go index 0527cfff54..31f24031ea 100644 --- a/internal/endtoend/testdata/datatype/pgx/go/models.go +++ b/internal/endtoend/testdata/datatype/pgx/go/models.go @@ -5,6 +5,8 @@ package datatype import ( "database/sql" "time" + + "github.com/jackc/pgtype" ) type DtCharacter struct { @@ -65,8 +67,8 @@ type DtNumericNotNull struct { A int16 B int32 C int64 - D string - E string + D pgtype.Numeric + E pgtype.Numeric F float32 G float64 H int16 diff --git a/internal/endtoend/testdata/datatype_numeric/pgx/go/models.go b/internal/endtoend/testdata/datatype_numeric/pgx/go/models.go index d26f733474..54322de332 100644 --- a/internal/endtoend/testdata/datatype_numeric/pgx/go/models.go +++ b/internal/endtoend/testdata/datatype_numeric/pgx/go/models.go @@ -3,15 +3,15 @@ package datatype import ( - "database/sql" "time" "github.com/google/uuid" + "github.com/jackc/pgtype" ) type Example struct { ExampleID uuid.UUID - Value sql.NullString + Value pgtype.Numeric CreateTime time.Time UpdateTime time.Time } diff --git a/internal/endtoend/testdata/datatype_numeric/pgx/go/query.sql.go b/internal/endtoend/testdata/datatype_numeric/pgx/go/query.sql.go index 2d69c08ece..0fba74ec82 100644 --- a/internal/endtoend/testdata/datatype_numeric/pgx/go/query.sql.go +++ b/internal/endtoend/testdata/datatype_numeric/pgx/go/query.sql.go @@ -5,7 +5,8 @@ package datatype import ( "context" - "database/sql" + + "github.com/jackc/pgtype" ) const createExample = `-- name: CreateExample :one @@ -13,7 +14,7 @@ INSERT INTO examples (value) VALUES ($1) RETURNING example_id, value, create_time, update_time ` -func (q *Queries) CreateExample(ctx context.Context, value sql.NullString) (Example, error) { +func (q *Queries) CreateExample(ctx context.Context, value pgtype.Numeric) (Example, error) { row := q.db.QueryRow(ctx, createExample, value) var i Example err := row.Scan( diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/go/models.go b/internal/endtoend/testdata/params_location/postgresql/pgx/go/models.go index 2a3630d6b8..465cd087e7 100644 --- a/internal/endtoend/testdata/params_location/postgresql/pgx/go/models.go +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/go/models.go @@ -4,11 +4,13 @@ package querytest import ( "database/sql" + + "github.com/jackc/pgtype" ) type Order struct { ID int32 - Price string + Price pgtype.Numeric UserID int32 } diff --git a/internal/endtoend/testdata/params_location/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/params_location/postgresql/pgx/go/query.sql.go index 63de450bcb..ba01fa1e28 100644 --- a/internal/endtoend/testdata/params_location/postgresql/pgx/go/query.sql.go +++ b/internal/endtoend/testdata/params_location/postgresql/pgx/go/query.sql.go @@ -6,6 +6,8 @@ package querytest import ( "context" "database/sql" + + "github.com/jackc/pgtype" ) const getUserByID = `-- name: GetUserByID :one @@ -82,10 +84,10 @@ WHERE orders.price > $1 type ListUserOrdersRow struct { ID sql.NullInt32 FirstName sql.NullString - Price string + Price pgtype.Numeric } -func (q *Queries) ListUserOrders(ctx context.Context, minPrice string) ([]ListUserOrdersRow, error) { +func (q *Queries) ListUserOrders(ctx context.Context, minPrice pgtype.Numeric) ([]ListUserOrdersRow, error) { rows, err := q.db.Query(ctx, listUserOrders, minPrice) if err != nil { return nil, err