Skip to content

Commit 7ed2d3c

Browse files
authored
internal/sqlc: Add support for composite types (#311)
1 parent a963622 commit 7ed2d3c

File tree

9 files changed

+193
-24
lines changed

9 files changed

+193
-24
lines changed

internal/catalog/build.go

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,29 @@ func Update(c *pg.Catalog, stmt nodes.Node) error {
225225
}
226226
}
227227

228+
case nodes.CompositeTypeStmt:
229+
fqn, err := ParseRange(n.Typevar)
230+
if err != nil {
231+
return err
232+
}
233+
schema, exists := c.Schemas[fqn.Schema]
234+
if !exists {
235+
return wrap(pg.ErrorSchemaDoesNotExist(fqn.Schema), raw.StmtLocation)
236+
}
237+
// Because tables have associated data types, the type name must also
238+
// be distinct from the name of any existing table in the same
239+
// schema.
240+
// https://www.postgresql.org/docs/current/sql-createtype.html
241+
if _, exists := schema.Tables[fqn.Rel]; exists {
242+
return wrap(pg.ErrorRelationAlreadyExists(fqn.Rel), raw.StmtLocation)
243+
}
244+
if _, exists := schema.Types[fqn.Rel]; exists {
245+
return wrap(pg.ErrorRelationAlreadyExists(fqn.Rel), raw.StmtLocation)
246+
}
247+
schema.Types[fqn.Rel] = pg.CompositeType{
248+
Name: fqn.Rel,
249+
}
250+
228251
case nodes.CreateStmt:
229252
fqn, err := ParseRange(n.Relation)
230253
if err != nil {
@@ -264,10 +287,17 @@ func Update(c *pg.Catalog, stmt nodes.Node) error {
264287
if !exists {
265288
return wrap(pg.ErrorSchemaDoesNotExist(fqn.Schema), raw.StmtLocation)
266289
}
267-
if _, exists := schema.Enums[fqn.Rel]; exists {
290+
// Because tables have associated data types, the type name must also
291+
// be distinct from the name of any existing table in the same
292+
// schema.
293+
// https://www.postgresql.org/docs/current/sql-createtype.html
294+
if _, exists := schema.Tables[fqn.Rel]; exists {
295+
return wrap(pg.ErrorRelationAlreadyExists(fqn.Rel), raw.StmtLocation)
296+
}
297+
if _, exists := schema.Types[fqn.Rel]; exists {
268298
return wrap(pg.ErrorTypeAlreadyExists(fqn.Rel), raw.StmtLocation)
269299
}
270-
schema.Enums[fqn.Rel] = pg.Enum{
300+
schema.Types[fqn.Rel] = pg.Enum{
271301
Name: fqn.Rel,
272302
Vals: stringSlice(n.Vals),
273303
}
@@ -311,8 +341,8 @@ func Update(c *pg.Catalog, stmt nodes.Node) error {
311341
}
312342

313343
case nodes.OBJECT_TYPE:
314-
if _, exists := schema.Enums[fqn.Rel]; exists {
315-
delete(schema.Enums, fqn.Rel)
344+
if _, exists := schema.Types[fqn.Rel]; exists {
345+
delete(schema.Types, fqn.Rel)
316346
} else if !n.MissingOk {
317347
return wrap(pg.ErrorTypeDoesNotExist(fqn.Rel), raw.StmtLocation)
318348
}
@@ -507,16 +537,19 @@ func Update(c *pg.Catalog, stmt nodes.Node) error {
507537
if !exists {
508538
return wrap(pg.ErrorSchemaDoesNotExist(fqn.Schema), raw.StmtLocation)
509539
}
510-
enum, exists := schema.Enums[fqn.Rel]
540+
typ, exists := schema.Types[fqn.Rel]
511541
if !exists {
512542
return wrap(pg.ErrorRelationDoesNotExist(fqn.Rel), raw.StmtLocation)
513543
}
514-
if n.Comment != nil {
515-
enum.Comment = *n.Comment
516-
} else {
517-
enum.Comment = ""
544+
switch t := typ.(type) {
545+
case pg.Enum:
546+
if n.Comment != nil {
547+
t.Comment = *n.Comment
548+
} else {
549+
t.Comment = ""
550+
}
551+
schema.Types[fqn.Rel] = t
518552
}
519-
schema.Enums[fqn.Rel] = enum
520553

521554
}
522555

internal/catalog/build_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func TestUpdate(t *testing.T) {
3535
pg.Catalog{
3636
Schemas: map[string]pg.Schema{
3737
"public": {
38-
Enums: map[string]pg.Enum{
38+
Types: map[string]pg.Type{
3939
"status": pg.Enum{
4040
Name: "status",
4141
Vals: []string{"open", "closed"},
@@ -229,7 +229,7 @@ func TestUpdate(t *testing.T) {
229229
pg.Catalog{
230230
Schemas: map[string]pg.Schema{
231231
"public": {
232-
Enums: map[string]pg.Enum{
232+
Types: map[string]pg.Type{
233233
"status": pg.Enum{
234234
Name: "status",
235235
Vals: []string{"open", "closed"},
@@ -263,7 +263,7 @@ func TestUpdate(t *testing.T) {
263263
pg.Catalog{
264264
Schemas: map[string]pg.Schema{
265265
"public": {
266-
Enums: map[string]pg.Enum{},
266+
Types: map[string]pg.Type{},
267267
Tables: map[string]pg.Table{
268268
"arenas": pg.Table{
269269
Name: "arenas",
@@ -337,7 +337,7 @@ func TestUpdate(t *testing.T) {
337337
pg.Catalog{
338338
Schemas: map[string]pg.Schema{
339339
"public": {
340-
Enums: map[string]pg.Enum{},
340+
Types: map[string]pg.Type{},
341341
Tables: map[string]pg.Table{
342342
"venues": pg.Table{
343343
Name: "venues",
@@ -530,7 +530,7 @@ func TestUpdate(t *testing.T) {
530530
},
531531
},
532532
},
533-
Enums: map[string]pg.Enum{"bat": {Comment: "Enum comment", Name: "bat", Vals: []string{"bat"}}},
533+
Types: map[string]pg.Type{"bat": pg.Enum{Comment: "Enum comment", Name: "bat", Vals: []string{"bat"}}},
534534
Funcs: map[string][]pg.Function{},
535535
},
536536
},
@@ -561,7 +561,7 @@ func TestUpdate(t *testing.T) {
561561
},
562562
},
563563
},
564-
Enums: map[string]pg.Enum{"bat": {Comment: "Enum comment", Name: "bat", Vals: []string{"bat"}}},
564+
Types: map[string]pg.Type{"bat": pg.Enum{Comment: "Enum comment", Name: "bat", Vals: []string{"bat"}}},
565565
Funcs: map[string][]pg.Function{},
566566
},
567567
},

internal/dinosql/gen.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ func (r Result) Enums(settings CombinedSettings) []GoEnum {
495495
if name == "pg_catalog" {
496496
continue
497497
}
498-
for _, enum := range schema.Enums {
498+
for _, enum := range schema.Enums() {
499499
var enumName string
500500
if name == "public" {
501501
enumName = enum.Name
@@ -711,12 +711,20 @@ func (r Result) goInnerType(col core.Column, settings CombinedSettings) string {
711711
if name == "pg_catalog" {
712712
continue
713713
}
714-
for _, enum := range schema.Enums {
715-
if fqn.Rel == enum.Name && fqn.Schema == name {
716-
if name == "public" {
717-
return StructName(enum.Name, settings)
714+
for _, typ := range schema.Types {
715+
switch t := typ.(type) {
716+
case core.Enum:
717+
if fqn.Rel == t.Name && fqn.Schema == name {
718+
if name == "public" {
719+
return StructName(t.Name, settings)
720+
}
721+
return StructName(name+"_"+t.Name, settings)
722+
}
723+
case core.CompositeType:
724+
if notNull {
725+
return "string"
718726
}
719-
return StructName(name+"_"+enum.Name, settings)
727+
return "sql.NullString"
720728
}
721729
}
722730
}

internal/endtoend/testdata/composite_type/go/db.go

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

internal/endtoend/testdata/composite_type/go/models.go

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

internal/endtoend/testdata/composite_type/go/query.sql.go

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CREATE SCHEMA foo;
2+
3+
CREATE TYPE point_type AS (
4+
x integer,
5+
y integer
6+
);
7+
8+
CREATE TYPE foo.point_type AS (
9+
x integer,
10+
y integer
11+
);
12+
13+
CREATE TABLE foo.paths (
14+
point_one point_type,
15+
point_two foo.point_type
16+
);
17+
18+
-- name: ListPaths :many
19+
SELECT * FROM foo.paths;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"version": "1",
3+
"packages": [{
4+
"path": "go",
5+
"name": "querytest",
6+
"schema": "query.sql",
7+
"queries": "query.sql"
8+
}]
9+
}

internal/pg/catalog.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func NewCatalog() Catalog {
2121
func NewSchema() Schema {
2222
return Schema{
2323
Tables: map[string]Table{},
24-
Enums: map[string]Enum{},
24+
Types: map[string]Type{},
2525
Funcs: map[string][]Function{},
2626
}
2727
}
@@ -93,11 +93,21 @@ func (c Catalog) LookupFunctionN(fqn FQN, argn int) (Function, error) {
9393
type Schema struct {
9494
Name string
9595
Tables map[string]Table
96-
Enums map[string]Enum
96+
Types map[string]Type
9797
Funcs map[string][]Function
9898
Comment string
9999
}
100100

101+
func (s Schema) Enums() []Enum {
102+
var enums []Enum
103+
for _, typ := range s.Types {
104+
if enum, ok := typ.(Enum); ok {
105+
enums = append(enums, enum)
106+
}
107+
}
108+
return enums
109+
}
110+
101111
type Table struct {
102112
ID FQN
103113
Name string
@@ -117,12 +127,26 @@ type Column struct {
117127
Table FQN
118128
}
119129

130+
type Type interface {
131+
isType()
132+
}
133+
120134
type Enum struct {
121135
Name string
122136
Vals []string
123137
Comment string
124138
}
125139

140+
func (e Enum) isType() {
141+
}
142+
143+
type CompositeType struct {
144+
Name string
145+
}
146+
147+
func (e CompositeType) isType() {
148+
}
149+
126150
type Function struct {
127151
Name string
128152
ArgN int

0 commit comments

Comments
 (0)