Skip to content

Commit 3e14416

Browse files
committed
Added support for v5 of the pgx Go driver (#1823)
* 'pgx/v5' option requires '--experimental' cli flag. * array, ranges, multiranges uses generic version for 'pgx/v5'. It supports multidemensional arrays. * 'pgx/v5' implementation prefers use pgtype types. For example, pgtype.Bool instead of sql.NullBool. * added support for new pg types: * datemultirange * tsmultirange * tstzmultirange * nummultirange * int4multirange * int8multirange * bit * varbit * cid * oid * tid * circle * line * lseg * path * point * polygon
1 parent efa6acf commit 3e14416

File tree

14 files changed

+330
-106
lines changed

14 files changed

+330
-106
lines changed

docs/reference/config.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ The `gen` mapping supports the following keys:
5050
- `out`:
5151
- Output directory for generated code.
5252
- `sql_package`:
53-
- Either `pgx/v4` or `database/sql`. Defaults to `database/sql`.
53+
- Either `pgx/v4`, `pgx/v5` or `database/sql`. Defaults to `database/sql`.
5454
- `emit_db_tags`:
5555
- If true, add DB tags to generated structs. Defaults to `false`.
5656
- `emit_prepared_queries`:
@@ -311,7 +311,7 @@ Each mapping in the `packages` collection has the following keys:
311311
- `engine`:
312312
- Either `postgresql` or `mysql`. Defaults to `postgresql`.
313313
- `sql_package`:
314-
- Either `pgx/v4` or `database/sql`. Defaults to `database/sql`.
314+
- Either `pgx/v4`, `pgx/v5` or `database/sql`. Defaults to `database/sql`.
315315
- `emit_db_tags`:
316316
- If true, add DB tags to generated structs. Defaults to `false`.
317317
- `emit_prepared_queries`:

docs/reference/query-annotations.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func (q *Queries) GetAuthor(ctx context.Context, id int64) (Author, error) {
115115

116116
## `:batchexec`
117117

118-
__NOTE: This command only works with PostgreSQL using the `pgx` driver and outputting Go code.__
118+
__NOTE: This command only works with PostgreSQL using the `pgx/v4` and `pgx/v5` drivers and outputting Go code.__
119119

120120
The generated method will return a batch object. The batch object will have
121121
the following methods:
@@ -147,7 +147,7 @@ func (b *DeleteBookBatchResults) Close() error {
147147

148148
## `:batchmany`
149149

150-
__NOTE: This command only works with PostgreSQL using the `pgx` driver and outputting Go code.__
150+
__NOTE: This command only works with PostgreSQL using the `pgx/v4` and `pgx/v5` drivers and outputting Go code.__
151151

152152
The generated method will return a batch object. The batch object will have
153153
the following methods:
@@ -183,7 +183,7 @@ func (b *BooksByTitleYearBatchResults) Close() error {
183183

184184
## `:batchone`
185185

186-
__NOTE: This command only works with PostgreSQL using the `pgx` driver and outputting Go code.__
186+
__NOTE: This command only works with PostgreSQL using the `pgx/v4` and `pgx/v5` drivers and outputting Go code.__
187187

188188
The generated method will return a batch object. The batch object will have
189189
the following methods:

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ require (
3434
github.com/jackc/pgpassfile v1.0.0 // indirect
3535
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
3636
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
37-
github.com/jackc/pgtype v1.12.0 // indirect
37+
github.com/jackc/pgtype v1.12.0
3838
github.com/kr/pretty v0.2.1 // indirect
3939
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
4040
github.com/pingcap/log v0.0.0-20210906054005-afc726e70354 // indirect

internal/cmd/cmd.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import (
1111

1212
"github.com/spf13/cobra"
1313
"github.com/spf13/pflag"
14-
yaml "gopkg.in/yaml.v3"
14+
"gopkg.in/yaml.v3"
1515

16+
"github.com/kyleconroy/sqlc/internal/codegen/golang"
1617
"github.com/kyleconroy/sqlc/internal/config"
1718
"github.com/kyleconroy/sqlc/internal/debug"
1819
"github.com/kyleconroy/sqlc/internal/info"
@@ -112,6 +113,16 @@ func ParseEnv(c *cobra.Command) Env {
112113
}
113114
}
114115

116+
func (e *Env) Validate(cfg *config.Config) error {
117+
for _, sql := range cfg.SQL {
118+
if sql.Gen.Go != nil && sql.Gen.Go.SQLPackage == golang.SQLPackagePGXV5 && !e.ExperimentalFeatures {
119+
return fmt.Errorf("'pgx/v5' golang sql package requires enabled '--experimental' flag")
120+
}
121+
}
122+
123+
return nil
124+
}
125+
115126
func getConfigPath(stderr io.Writer, f *pflag.Flag) (string, string) {
116127
if f != nil && f.Changed {
117128
file := f.Value.String()

internal/cmd/generate.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ func Generate(ctx context.Context, e Env, dir, filename string, stderr io.Writer
130130
return nil, err
131131
}
132132

133+
if err := e.Validate(conf); err != nil {
134+
fmt.Fprintf(stderr, "error validating %s: %s\n", base, err)
135+
return nil, err
136+
}
137+
133138
output := map[string]string{}
134139
errored := false
135140

@@ -218,7 +223,7 @@ func Generate(ctx context.Context, e Env, dir, filename string, stderr io.Writer
218223
trace.Logf(ctx, "", "name=%s dir=%s plugin=%s", name, dir, lang)
219224
}
220225

221-
result, failed := parse(ctx, e, name, dir, sql.SQL, combo, parseOpts, stderr)
226+
result, failed := parse(ctx, name, dir, sql.SQL, combo, parseOpts, stderr)
222227
if failed {
223228
if packageRegion != nil {
224229
packageRegion.End()
@@ -257,7 +262,7 @@ func Generate(ctx context.Context, e Env, dir, filename string, stderr io.Writer
257262
return output, nil
258263
}
259264

260-
func parse(ctx context.Context, e Env, name, dir string, sql config.SQL, combo config.CombinedSettings, parserOpts opts.Parser, stderr io.Writer) (*compiler.Result, bool) {
265+
func parse(ctx context.Context, name, dir string, sql config.SQL, combo config.CombinedSettings, parserOpts opts.Parser, stderr io.Writer) (*compiler.Result, bool) {
261266
if debug.Traced {
262267
defer trace.StartRegion(ctx, "parse").End()
263268
}

internal/codegen/golang/driver.go

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,41 @@
11
package golang
22

3-
import (
4-
"github.com/kyleconroy/sqlc/internal/plugin"
5-
)
6-
73
type SQLDriver int
84

5+
const (
6+
SQLPackagePGXV4 string = "pgx/v4"
7+
SQLPackagePGXV5 string = "pgx/v5"
8+
SQLPackageStandard string = "database/sql"
9+
)
10+
911
const (
1012
SQLDriverPGXV4 SQLDriver = iota
13+
SQLDriverPGXV5
1114
SQLDriverLibPQ
1215
)
1316

14-
func parseDriver(settings *plugin.Settings) SQLDriver {
15-
if settings.Go.SqlPackage == "pgx/v4" {
17+
func parseDriver(sqlPackage string) SQLDriver {
18+
switch sqlPackage {
19+
case SQLPackagePGXV4:
1620
return SQLDriverPGXV4
17-
} else {
21+
case SQLPackagePGXV5:
22+
return SQLDriverPGXV5
23+
default:
1824
return SQLDriverLibPQ
1925
}
2026
}
27+
28+
func (d SQLDriver) IsPGX() bool {
29+
return d == SQLDriverPGXV4 || d == SQLDriverPGXV5
30+
}
31+
32+
func (d SQLDriver) Package() string {
33+
switch d {
34+
case SQLDriverPGXV4:
35+
return SQLPackagePGXV4
36+
case SQLDriverPGXV5:
37+
return SQLPackagePGXV5
38+
default:
39+
return SQLPackageStandard
40+
}
41+
}

internal/codegen/golang/gen.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
type tmplCtx struct {
1919
Q string
2020
Package string
21-
SQLPackage SQLPackage
21+
SQLDriver SQLDriver
2222
Enums []Enum
2323
Structs []Struct
2424
GoQueries []Query
@@ -91,7 +91,7 @@ func generate(req *plugin.CodeGenRequest, enums []Enum, structs []Struct, querie
9191
EmitAllEnumValues: golang.EmitAllEnumValues,
9292
UsesCopyFrom: usesCopyFrom(queries),
9393
UsesBatch: usesBatch(queries),
94-
SQLPackage: SQLPackageFromString(golang.SqlPackage),
94+
SQLDriver: parseDriver(golang.SqlPackage),
9595
Q: "`",
9696
Package: golang.Package,
9797
GoQueries: queries,
@@ -100,11 +100,11 @@ func generate(req *plugin.CodeGenRequest, enums []Enum, structs []Struct, querie
100100
SqlcVersion: req.SqlcVersion,
101101
}
102102

103-
if tctx.UsesCopyFrom && tctx.SQLPackage != SQLPackagePGX {
103+
if tctx.UsesCopyFrom && !tctx.SQLDriver.IsPGX() {
104104
return nil, errors.New(":copyfrom is only supported by pgx")
105105
}
106106

107-
if tctx.UsesBatch && tctx.SQLPackage != SQLPackagePGX {
107+
if tctx.UsesBatch && !tctx.SQLDriver.IsPGX() {
108108
return nil, errors.New(":batch* commands are only supported by pgx")
109109
}
110110

internal/codegen/golang/go_type.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ func goType(req *plugin.CodeGenRequest, col *plugin.Column) string {
3838
}
3939
typ := goInnerType(req, col)
4040
if col.IsArray {
41+
if parseDriver(req.Settings.Go.SqlPackage) == SQLDriverPGXV5 {
42+
return "pgtype.Array[" + typ + "]"
43+
}
4144
return "[]" + typ
4245
}
4346
return typ

internal/codegen/golang/imports.go

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func (i *importer) Imports(filename string) [][]ImportSpec {
102102
case copyfromFileName:
103103
return mergeImports(i.copyfromImports())
104104
case batchFileName:
105-
return mergeImports(i.batchImports(filename))
105+
return mergeImports(i.batchImports())
106106
default:
107107
return mergeImports(i.queryImports(filename))
108108
}
@@ -114,11 +114,14 @@ func (i *importer) dbImports() fileImports {
114114
{Path: "context"},
115115
}
116116

117-
sqlpkg := SQLPackageFromString(i.Settings.Go.SqlPackage)
117+
sqlpkg := parseDriver(i.Settings.Go.SqlPackage)
118118
switch sqlpkg {
119-
case SQLPackagePGX:
119+
case SQLDriverPGXV4:
120120
pkg = append(pkg, ImportSpec{Path: "github.com/jackc/pgconn"})
121121
pkg = append(pkg, ImportSpec{Path: "github.com/jackc/pgx/v4"})
122+
case SQLDriverPGXV5:
123+
pkg = append(pkg, ImportSpec{Path: "github.com/jackc/pgx/v5/pgconn"})
124+
pkg = append(pkg, ImportSpec{Path: "github.com/jackc/pgx/v5"})
122125
default:
123126
std = append(std, ImportSpec{Path: "database/sql"})
124127
if i.Settings.Go.EmitPreparedQueries {
@@ -136,22 +139,8 @@ var stdlibTypes = map[string]string{
136139
"time.Time": "time",
137140
"net.IP": "net",
138141
"net.HardwareAddr": "net",
139-
}
140-
141-
var pgtypeTypes = map[string]struct{}{
142-
"pgtype.CIDR": {},
143-
"pgtype.Daterange": {},
144-
"pgtype.Inet": {},
145-
"pgtype.Int4range": {},
146-
"pgtype.Int8range": {},
147-
"pgtype.JSON": {},
148-
"pgtype.JSONB": {},
149-
"pgtype.Hstore": {},
150-
"pgtype.Macaddr": {},
151-
"pgtype.Numeric": {},
152-
"pgtype.Numrange": {},
153-
"pgtype.Tsrange": {},
154-
"pgtype.Tstzrange": {},
142+
"netip.Addr": "net/netip",
143+
"netip.Prefix": "net/netip",
155144
}
156145

157146
var pqtypeTypes = map[string]struct{}{
@@ -169,12 +158,14 @@ func buildImports(settings *plugin.Settings, queries []Query, uses func(string)
169158
std["database/sql"] = struct{}{}
170159
}
171160

172-
sqlpkg := SQLPackageFromString(settings.Go.SqlPackage)
161+
sqlpkg := parseDriver(settings.Go.SqlPackage)
173162
for _, q := range queries {
174163
if q.Cmd == metadata.CmdExecResult {
175164
switch sqlpkg {
176-
case SQLPackagePGX:
165+
case SQLDriverPGXV4:
177166
pkg[ImportSpec{Path: "github.com/jackc/pgconn"}] = struct{}{}
167+
case SQLDriverPGXV5:
168+
pkg[ImportSpec{Path: "github.com/jackc/pgx/v5/pgconn"}] = struct{}{}
178169
default:
179170
std["database/sql"] = struct{}{}
180171
}
@@ -187,15 +178,18 @@ func buildImports(settings *plugin.Settings, queries []Query, uses func(string)
187178
}
188179
}
189180

190-
for typeName, _ := range pgtypeTypes {
191-
if uses(typeName) {
181+
if uses("pgtype.") {
182+
if sqlpkg == SQLDriverPGXV5 {
183+
pkg[ImportSpec{Path: "github.com/jackc/pgx/v5/pgtype"}] = struct{}{}
184+
} else {
192185
pkg[ImportSpec{Path: "github.com/jackc/pgtype"}] = struct{}{}
193186
}
194187
}
195188

196189
for typeName, _ := range pqtypeTypes {
197190
if uses(typeName) {
198191
pkg[ImportSpec{Path: "github.com/tabbed/pqtype"}] = struct{}{}
192+
break
199193
}
200194
}
201195

@@ -373,8 +367,8 @@ func (i *importer) queryImports(filename string) fileImports {
373367
std["context"] = struct{}{}
374368
}
375369

376-
sqlpkg := SQLPackageFromString(i.Settings.Go.SqlPackage)
377-
if sliceScan() && sqlpkg != SQLPackagePGX {
370+
sqlpkg := parseDriver(i.Settings.Go.SqlPackage)
371+
if sliceScan() && !sqlpkg.IsPGX() {
378372
pkg[ImportSpec{Path: "github.com/lib/pq"}] = struct{}{}
379373
}
380374

@@ -409,7 +403,7 @@ func (i *importer) copyfromImports() fileImports {
409403
return sortedImports(std, pkg)
410404
}
411405

412-
func (i *importer) batchImports(filename string) fileImports {
406+
func (i *importer) batchImports() fileImports {
413407
batchQueries := make([]Query, 0, len(i.Queries))
414408
for _, q := range i.Queries {
415409
if usesBatch([]Query{q}) {
@@ -452,7 +446,13 @@ func (i *importer) batchImports(filename string) fileImports {
452446

453447
std["context"] = struct{}{}
454448
std["errors"] = struct{}{}
455-
pkg[ImportSpec{Path: "github.com/jackc/pgx/v4"}] = struct{}{}
449+
sqlpkg := parseDriver(i.Settings.Go.SqlPackage)
450+
switch sqlpkg {
451+
case SQLDriverPGXV4:
452+
pkg[ImportSpec{Path: "github.com/jackc/pgx/v4"}] = struct{}{}
453+
case SQLDriverPGXV5:
454+
pkg[ImportSpec{Path: "github.com/jackc/pgx/v5"}] = struct{}{}
455+
}
456456

457457
return sortedImports(std, pkg)
458458
}

0 commit comments

Comments
 (0)