Skip to content

Commit 27fffbf

Browse files
Implement emission of pointer types for nullable columns. (#1571)
Co-authored-by: Kyle Conroy <kyle@conroy.org>
1 parent 29a8855 commit 27fffbf

File tree

27 files changed

+617
-87
lines changed

27 files changed

+617
-87
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ mysqlsh:
4444
# $ protoc --version
4545
# libprotoc 3.19.1
4646
# $ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
47-
# $ go install github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto@latest
47+
# $ go install github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto
4848
proto: internal/plugin/codegen.pb.go
4949

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

docs/reference/config.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ packages:
339339
emit_result_struct_pointers: false
340340
emit_params_struct_pointers: false
341341
emit_methods_with_db_argument: false
342+
emit_pointers_for_null_types: false
342343
emit_enum_valid_method: false
343344
emit_all_enum_values: false
344345
json_tags_case_style: "camel"
@@ -383,6 +384,8 @@ Each mapping in the `packages` collection has the following keys:
383384
- If true, parameters are passed as pointers to structs. Defaults to `false`.
384385
- `emit_methods_with_db_argument`:
385386
- If true, generated methods will accept a DBTX argument instead of storing a DBTX on the `*Queries` struct. Defaults to `false`.
387+
- `emit_pointers_for_null_types`:
388+
- If true and `sql_package` is set to `pgx/v4`, generated types for nullable columns are emitted as pointers (ie. `*string`) instead of `database/sql` null types (ie. `NullString`). Defaults to `false`.
386389
- `emit_enum_valid_method`:
387390
- If true, generate a Valid method on enum types,
388391
indicating whether a string is a valid enum value.

internal/cmd/shim.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func pluginGoCode(s config.SQLGo) *plugin.GoCode {
8686
EmitResultStructPointers: s.EmitResultStructPointers,
8787
EmitParamsStructPointers: s.EmitParamsStructPointers,
8888
EmitMethodsWithDbArgument: s.EmitMethodsWithDBArgument,
89+
EmitPointersForNullTypes: s.EmitPointersForNullTypes,
8990
EmitEnumValidMethod: s.EmitEnumValidMethod,
9091
EmitAllEnumValues: s.EmitAllEnumValues,
9192
JsonTagsCaseStyle: s.JSONTagsCaseStyle,

internal/codegen/golang/postgresql_type.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,54 +37,79 @@ func postgresType(req *plugin.CodeGenRequest, col *plugin.Column) string {
3737
columnType := sdk.DataType(col.Type)
3838
notNull := col.NotNull || col.IsArray
3939
driver := parseDriver(req.Settings)
40+
emitPointersForNull := driver == SQLDriverPGXV4 && req.Settings.Go.EmitPointersForNullTypes
4041

4142
switch columnType {
4243
case "serial", "serial4", "pg_catalog.serial4":
4344
if notNull {
4445
return "int32"
4546
}
47+
if emitPointersForNull {
48+
return "*int32"
49+
}
4650
return "sql.NullInt32"
4751

4852
case "bigserial", "serial8", "pg_catalog.serial8":
4953
if notNull {
5054
return "int64"
5155
}
56+
if emitPointersForNull {
57+
return "*int64"
58+
}
5259
return "sql.NullInt64"
5360

5461
case "smallserial", "serial2", "pg_catalog.serial2":
5562
if notNull {
5663
return "int16"
5764
}
65+
if emitPointersForNull {
66+
return "*int16"
67+
}
5868
return "sql.NullInt16"
5969

6070
case "integer", "int", "int4", "pg_catalog.int4":
6171
if notNull {
6272
return "int32"
6373
}
74+
if emitPointersForNull {
75+
return "*int32"
76+
}
6477
return "sql.NullInt32"
6578

6679
case "bigint", "int8", "pg_catalog.int8":
6780
if notNull {
6881
return "int64"
6982
}
83+
if emitPointersForNull {
84+
return "*int64"
85+
}
7086
return "sql.NullInt64"
7187

7288
case "smallint", "int2", "pg_catalog.int2":
7389
if notNull {
7490
return "int16"
7591
}
92+
if emitPointersForNull {
93+
return "*int16"
94+
}
7695
return "sql.NullInt16"
7796

7897
case "float", "double precision", "float8", "pg_catalog.float8":
7998
if notNull {
8099
return "float64"
81100
}
101+
if emitPointersForNull {
102+
return "*float64"
103+
}
82104
return "sql.NullFloat64"
83105

84106
case "real", "float4", "pg_catalog.float4":
85107
if notNull {
86108
return "float32"
87109
}
110+
if emitPointersForNull {
111+
return "*float32"
112+
}
88113
return "sql.NullFloat64" // TODO: Change to sql.NullFloat32 after updating the go.mod file
89114

90115
case "numeric", "pg_catalog.numeric", "money":
@@ -98,12 +123,18 @@ func postgresType(req *plugin.CodeGenRequest, col *plugin.Column) string {
98123
if notNull {
99124
return "string"
100125
}
126+
if emitPointersForNull {
127+
return "*string"
128+
}
101129
return "sql.NullString"
102130

103131
case "boolean", "bool", "pg_catalog.bool":
104132
if notNull {
105133
return "bool"
106134
}
135+
if emitPointersForNull {
136+
return "*bool"
137+
}
107138
return "sql.NullBool"
108139

109140
case "json":
@@ -141,30 +172,45 @@ func postgresType(req *plugin.CodeGenRequest, col *plugin.Column) string {
141172
if notNull {
142173
return "time.Time"
143174
}
175+
if emitPointersForNull {
176+
return "*time.Time"
177+
}
144178
return "sql.NullTime"
145179

146180
case "pg_catalog.time", "pg_catalog.timetz":
147181
if notNull {
148182
return "time.Time"
149183
}
184+
if emitPointersForNull {
185+
return "*time.Time"
186+
}
150187
return "sql.NullTime"
151188

152189
case "pg_catalog.timestamp", "pg_catalog.timestamptz", "timestamptz":
153190
if notNull {
154191
return "time.Time"
155192
}
193+
if emitPointersForNull {
194+
return "*time.Time"
195+
}
156196
return "sql.NullTime"
157197

158198
case "text", "pg_catalog.varchar", "pg_catalog.bpchar", "string":
159199
if notNull {
160200
return "string"
161201
}
202+
if emitPointersForNull {
203+
return "*string"
204+
}
162205
return "sql.NullString"
163206

164207
case "uuid":
165208
if notNull {
166209
return "uuid.UUID"
167210
}
211+
if emitPointersForNull {
212+
return "*uuid.UUID"
213+
}
168214
return "uuid.NullUUID"
169215

170216
case "inet":
@@ -206,12 +252,18 @@ func postgresType(req *plugin.CodeGenRequest, col *plugin.Column) string {
206252
if notNull {
207253
return "string"
208254
}
255+
if emitPointersForNull {
256+
return "*string"
257+
}
209258
return "sql.NullString"
210259

211260
case "interval", "pg_catalog.interval":
212261
if notNull {
213262
return "int64"
214263
}
264+
if emitPointersForNull {
265+
return "*int64"
266+
}
215267
return "sql.NullInt64"
216268

217269
case "daterange":
@@ -299,6 +351,9 @@ func postgresType(req *plugin.CodeGenRequest, col *plugin.Column) string {
299351
if notNull {
300352
return "string"
301353
}
354+
if emitPointersForNull {
355+
return "*string"
356+
}
302357
return "sql.NullString"
303358
}
304359
}

internal/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ type SQLGo struct {
119119
EmitResultStructPointers bool `json:"emit_result_struct_pointers" yaml:"emit_result_struct_pointers"`
120120
EmitParamsStructPointers bool `json:"emit_params_struct_pointers" yaml:"emit_params_struct_pointers"`
121121
EmitMethodsWithDBArgument bool `json:"emit_methods_with_db_argument,omitempty" yaml:"emit_methods_with_db_argument"`
122+
EmitPointersForNullTypes bool `json:"emit_pointers_for_null_types" yaml:"emit_pointers_for_null_types"`
122123
EmitEnumValidMethod bool `json:"emit_enum_valid_method,omitempty" yaml:"emit_enum_valid_method"`
123124
EmitAllEnumValues bool `json:"emit_all_enum_values,omitempty" yaml:"emit_all_enum_values"`
124125
JSONTagsCaseStyle string `json:"json_tags_case_style,omitempty" yaml:"json_tags_case_style"`

internal/config/v_one.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type v1PackageSettings struct {
3232
EmitResultStructPointers bool `json:"emit_result_struct_pointers" yaml:"emit_result_struct_pointers"`
3333
EmitParamsStructPointers bool `json:"emit_params_struct_pointers" yaml:"emit_params_struct_pointers"`
3434
EmitMethodsWithDBArgument bool `json:"emit_methods_with_db_argument" yaml:"emit_methods_with_db_argument"`
35+
EmitPointersForNullTypes bool `json:"emit_pointers_for_null_types" yaml:"emit_pointers_for_null_types"`
3536
EmitEnumValidMethod bool `json:"emit_enum_valid_method,omitempty" yaml:"emit_enum_valid_method"`
3637
EmitAllEnumValues bool `json:"emit_all_enum_values,omitempty" yaml:"emit_all_enum_values"`
3738
JSONTagsCaseStyle string `json:"json_tags_case_style,omitempty" yaml:"json_tags_case_style"`
@@ -130,6 +131,7 @@ func (c *V1GenerateSettings) Translate() Config {
130131
EmitResultStructPointers: pkg.EmitResultStructPointers,
131132
EmitParamsStructPointers: pkg.EmitParamsStructPointers,
132133
EmitMethodsWithDBArgument: pkg.EmitMethodsWithDBArgument,
134+
EmitPointersForNullTypes: pkg.EmitPointersForNullTypes,
133135
EmitEnumValidMethod: pkg.EmitEnumValidMethod,
134136
EmitAllEnumValues: pkg.EmitAllEnumValues,
135137
Package: pkg.Name,

internal/endtoend/testdata/emit_pointers_for_null_types/pgx/go/db.go

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/emit_pointers_for_null_types/pgx/go/models.go

Lines changed: 111 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- Character Types
2+
-- https://www.postgresql.org/docs/current/datatype-character.html
3+
CREATE TABLE dt_character (
4+
a text,
5+
b character varying(32),
6+
c varchar(32),
7+
d character(32),
8+
e char(32)
9+
);
10+
11+
CREATE TABLE dt_character_not_null (
12+
a text NOT NULL,
13+
b character varying(32) NOT NULL,
14+
c varchar(32) NOT NULL,
15+
d character(32) NOT NULL,
16+
e char(32) NOT NULL
17+
);

0 commit comments

Comments
 (0)