Skip to content

Commit 304ba5d

Browse files
authored
add support for custom Go struct tags (#1569)
* internal/config: use strings.Trim{Prefix,Suffix} This is equivalent and slightly simpler. * Makefile: fix vtproto 'go install' command * internal/codegen/golang: simplify template tag condition Rather than modeling when .Tag will be empty, check directly whether .Tag is empty. This simplifies the template and reduces the number of places that must be touched when adding new sources of struct tags. * internal/codegen/golang: tweak tag formatting Rather than inserting the colon at tag construction time, insert it at tag formatting time. This makes the input look a bit more natural. This matters more, as we are about to add another, more distant, place where we insert tags. * all: add support for custom Go struct tags This change adds a new type of override: go_struct_tag. When provided for a field, it adds that struct tag to the generated code. The provided struct tag is parsed according to the standard package reflect rules, and its components are updated independently. This allows struct tag overrides to be compatible with (and optionally override) autogenerated json and db struct tags. Fixes #534 * go.mod: bump to Go 1.18 The code uses some 1.18-only features, like strings.Cut and testing.F. The CI requires Go 1.18. Since Go 1.18 is now required, reflect that in the go.mod.
1 parent 8c3d70b commit 304ba5d

File tree

36 files changed

+817
-272
lines changed

36 files changed

+817
-272
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ mysqlsh:
3838
# $ protoc --version
3939
# libprotoc 3.19.1
4040
# $ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
41-
# $ go install github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto
41+
# $ go install github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto@latest
4242
proto: internal/plugin/codegen.pb.go internal/python/ast/ast.pb.go
4343

4444
internal/plugin/codegen.pb.go: protos/plugin/codegen.proto

docs/howto/structs.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,7 @@ type Author struct {
4646
CreatedAt time.Time `json:"created_at"`
4747
}
4848
```
49+
50+
## More control
51+
52+
See the Type Overrides section of the Configuration File docs for fine-grained control over struct field types and tags.

docs/reference/config.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ Each override document has the following keys:
225225
- The PostgreSQL or MySQL type to override. Find the full list of supported types in [postgresql_type.go](https://github.com/kyleconroy/sqlc/blob/main/internal/codegen/golang/postgresql_type.go#L12) or [mysql_type.go](https://github.com/kyleconroy/sqlc/blob/main/internal/codegen/golang/mysql_type.go#L12). Note that for Postgres you must use the pg_catalog prefixed names where available.
226226
- `go_type`:
227227
- A fully qualified name to a Go type to use in the generated code.
228+
- `go_struct_tag`:
229+
- A reflect-style struct tag to use in the generated code, e.g. `a:"b" x:"y,z"`.
230+
If you want general json/db tags for all fields, use `emit_db_tags` and/or `emit_json_tags` instead.
228231
- `nullable`:
229232
- If true, use this type when a column is nullable. Defaults to `false`.
230233

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/kyleconroy/sqlc
22

3-
go 1.17
3+
go 1.18
44

55
require (
66
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220209173558-ad29539cd2e9

internal/cmd/shim.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ func pluginGoType(o config.Override) *plugin.ParsedGoType {
109109
Package: o.GoPackage,
110110
TypeName: o.GoTypeName,
111111
BasicType: o.GoBasicType,
112+
StructTags: o.GoStructTags,
112113
}
113114
}
114115

internal/codegen/golang/field.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type Field struct {
1919
func (gf Field) Tag() string {
2020
tags := make([]string, 0, len(gf.Tags))
2121
for key, val := range gf.Tags {
22-
tags = append(tags, fmt.Sprintf("%s\"%s\"", key, val))
22+
tags = append(tags, fmt.Sprintf("%s:\"%s\"", key, val))
2323
}
2424
if len(tags) == 0 {
2525
return ""

internal/codegen/golang/go_type.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ import (
55
"github.com/kyleconroy/sqlc/internal/plugin"
66
)
77

8+
func addExtraGoStructTags(tags map[string]string, req *plugin.CodeGenRequest, col *plugin.Column) {
9+
for _, oride := range req.Settings.Overrides {
10+
if oride.GoType.StructTags == nil {
11+
continue
12+
}
13+
if !sdk.Matches(oride, col.Table, req.Catalog.DefaultSchema) {
14+
// Different table.
15+
continue
16+
}
17+
if !sdk.MatchString(oride.ColumnName, col.Name) {
18+
// Different column.
19+
continue
20+
}
21+
// Add the extra tags.
22+
for k, v := range oride.GoType.StructTags {
23+
tags[k] = v
24+
}
25+
}
26+
}
27+
828
func goType(req *plugin.CodeGenRequest, col *plugin.Column) string {
929
// Check if the column's type has been overridden
1030
for _, oride := range req.Settings.Overrides {

internal/codegen/golang/result.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,12 @@ func buildStructs(req *plugin.CodeGenRequest) []Struct {
7474
for _, column := range table.Columns {
7575
tags := map[string]string{}
7676
if req.Settings.Go.EmitDbTags {
77-
tags["db:"] = column.Name
77+
tags["db"] = column.Name
7878
}
7979
if req.Settings.Go.EmitJsonTags {
80-
tags["json:"] = JSONTagName(column.Name, req.Settings)
80+
tags["json"] = JSONTagName(column.Name, req.Settings)
8181
}
82+
addExtraGoStructTags(tags, req, column)
8283
s.Fields = append(s.Fields, Field{
8384
Name: StructName(column.Name, req.Settings),
8485
Type: goType(req, column),
@@ -283,10 +284,10 @@ func columnsToStruct(req *plugin.CodeGenRequest, name string, columns []goColumn
283284
}
284285
tags := map[string]string{}
285286
if req.Settings.Go.EmitDbTags {
286-
tags["db:"] = tagName
287+
tags["db"] = tagName
287288
}
288289
if req.Settings.Go.EmitJsonTags {
289-
tags["json:"] = JSONTagName(tagName, req.Settings)
290+
tags["json"] = JSONTagName(tagName, req.Settings)
290291
}
291292
gs.Fields = append(gs.Fields, Field{
292293
Name: fieldName,

internal/codegen/golang/templates/pgx/batchCode.tmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ type {{.MethodName}}BatchResults struct {
1212

1313
{{if .Arg.EmitStruct}}
1414
type {{.Arg.Type}} struct { {{- range .Arg.Struct.Fields}}
15-
{{.Name}} {{.Type}} {{if or ($.EmitJSONTags) ($.EmitDBTags)}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}}
15+
{{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}}
1616
{{- end}}
1717
}
1818
{{end}}
1919

2020
{{if .Ret.EmitStruct}}
2121
type {{.Ret.Type}} struct { {{- range .Ret.Struct.Fields}}
22-
{{.Name}} {{.Type}} {{if or ($.EmitJSONTags) ($.EmitDBTags)}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}}
22+
{{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}}
2323
{{- end}}
2424
}
2525
{{end}}

internal/codegen/golang/templates/pgx/queryCode.tmpl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ const {{.ConstantName}} = {{$.Q}}-- name: {{.MethodName}} {{.Cmd}}
1010
{{if ne (hasPrefix .Cmd ":batch") true}}
1111
{{if .Arg.EmitStruct}}
1212
type {{.Arg.Type}} struct { {{- range .Arg.Struct.Fields}}
13-
{{.Name}} {{.Type}} {{if or ($.EmitJSONTags) ($.EmitDBTags)}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}}
13+
{{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}}
1414
{{- end}}
1515
}
1616
{{end}}
1717

1818
{{if .Ret.EmitStruct}}
1919
type {{.Ret.Type}} struct { {{- range .Ret.Struct.Fields}}
20-
{{.Name}} {{.Type}} {{if or ($.EmitJSONTags) ($.EmitDBTags)}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}}
20+
{{.Name}} {{.Type}} {{if .Tag}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}}
2121
{{- end}}
2222
}
2323
{{end}}

0 commit comments

Comments
 (0)