Skip to content

Commit ed42c09

Browse files
authored
gen: Pick correct struct to return for queries (#107)
When two tables have identical columns, pick the correct struct to return.
1 parent 894c71b commit ed42c09

5 files changed

Lines changed: 98 additions & 45 deletions

File tree

internal/dinosql/gen.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func (gf GoField) Tag() string {
4747
}
4848

4949
type GoStruct struct {
50+
Table *core.FQN
5051
Name string
5152
Fields []GoField
5253
}
@@ -406,7 +407,10 @@ func (r Result) Structs() []GoStruct {
406407
} else {
407408
tableName = name + "_" + table.Name
408409
}
409-
s := GoStruct{Name: inflection.Singular(r.structName(tableName))}
410+
s := GoStruct{
411+
Table: &core.FQN{Schema: name, Rel: table.Name},
412+
Name: inflection.Singular(r.structName(tableName)),
413+
}
410414
for _, column := range table.Columns {
411415
s.Fields = append(s.Fields, GoField{
412416
Name: r.structName(column.Name),
@@ -566,6 +570,16 @@ func columnName(c core.Column, pos int) string {
566570
return fmt.Sprintf("column_%d", pos+1)
567571
}
568572

573+
func compareFQN(a *core.FQN, b *core.FQN) bool {
574+
if a == nil && b == nil {
575+
return true
576+
}
577+
if a == nil || b == nil {
578+
return false
579+
}
580+
return a.Catalog == b.Catalog && a.Schema == b.Schema && a.Rel == b.Rel
581+
}
582+
569583
func (r Result) GoQueries() []GoQuery {
570584
structs := r.Structs()
571585

@@ -643,7 +657,8 @@ func (r Result) GoQueries() []GoQuery {
643657
c := query.Columns[i]
644658
sameName := f.Name == r.structName(columnName(c, i))
645659
sameType := f.Type == r.goType(c)
646-
if !sameName || !sameType {
660+
sameFQN := compareFQN(s.Table, &c.Table)
661+
if !sameName || !sameType || !sameFQN {
647662
same = false
648663
}
649664
}

internal/dinosql/parser.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ func (qc QueryCatalog) GetTable(fqn core.FQN) (core.Table, *core.Error) {
385385
err := core.ErrorRelationDoesNotExist(fqn.Rel)
386386
return core.Table{}, &err
387387
}
388+
table.ID = fqn
388389
return table, nil
389390
}
390391

@@ -524,6 +525,7 @@ func outputColumns(c core.Catalog, node nodes.Node) ([]core.Column, error) {
524525
cname = *res.Name
525526
}
526527
cols = append(cols, core.Column{
528+
Table: t.ID,
527529
Name: cname,
528530
Scope: scope,
529531
DataType: c.DataType,
@@ -606,6 +608,7 @@ func outputColumnRefs(res nodes.ResTarget, tables []core.Table, node nodes.Colum
606608
cname = *res.Name
607609
}
608610
cols = append(cols, core.Column{
611+
Table: t.ID,
609612
Name: cname,
610613
DataType: c.DataType,
611614
NotNull: c.NotNull,

internal/dinosql/query_test.go

Lines changed: 75 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ CREATE TABLE venue (
5151
);
5252
`
5353

54+
func public(rel string) core.FQN {
55+
return core.FQN{
56+
Catalog: "",
57+
Schema: "public",
58+
Rel: rel,
59+
}
60+
}
61+
5462
func TestQueries(t *testing.T) {
5563
for _, tc := range []struct {
5664
name string
@@ -65,8 +73,8 @@ func TestQueries(t *testing.T) {
6573
`,
6674
Query{
6775
Columns: []core.Column{
68-
{Name: "slug", DataType: "text", NotNull: true},
69-
{Name: "name", DataType: "text", NotNull: true},
76+
{Table: public("city"), Name: "slug", DataType: "text", NotNull: true},
77+
{Table: public("city"), Name: "name", DataType: "text", NotNull: true},
7078
},
7179
},
7280
},
@@ -80,8 +88,8 @@ func TestQueries(t *testing.T) {
8088
{1, core.Column{Name: "slug", DataType: "text", NotNull: true}},
8189
},
8290
Columns: []core.Column{
83-
{Name: "slug", DataType: "text", NotNull: true},
84-
{Name: "name", DataType: "text", NotNull: true},
91+
{Table: public("city"), Name: "slug", DataType: "text", NotNull: true},
92+
{Table: public("city"), Name: "name", DataType: "text", NotNull: true},
8593
},
8694
},
8795
},
@@ -102,8 +110,8 @@ func TestQueries(t *testing.T) {
102110
{2, core.Column{Name: "slug", DataType: "text", NotNull: true}},
103111
},
104112
Columns: []core.Column{
105-
{Name: "slug", DataType: "text", NotNull: true},
106-
{Name: "name", DataType: "text", NotNull: true},
113+
{Table: public("city"), Name: "slug", DataType: "text", NotNull: true},
114+
{Table: public("city"), Name: "name", DataType: "text", NotNull: true},
107115
},
108116
},
109117
},
@@ -129,14 +137,14 @@ func TestQueries(t *testing.T) {
129137
`,
130138
Query{
131139
Columns: []core.Column{
132-
{Name: "id", DataType: "serial", NotNull: true},
133-
{Name: "create_at", DataType: "pg_catalog.timestamp", NotNull: true},
134-
{Name: "status", DataType: "status", NotNull: true},
135-
{Name: "slug", DataType: "text", NotNull: true},
136-
{Name: "name", DataType: "pg_catalog.varchar", NotNull: true},
137-
{Name: "city", DataType: "text", NotNull: true},
138-
{Name: "spotify_playlist", DataType: "pg_catalog.varchar", NotNull: true},
139-
{Name: "songkick_id", DataType: "text"},
140+
{Table: public("venue"), Name: "id", DataType: "serial", NotNull: true},
141+
{Table: public("venue"), Name: "create_at", DataType: "pg_catalog.timestamp", NotNull: true},
142+
{Table: public("venue"), Name: "status", DataType: "status", NotNull: true},
143+
{Table: public("venue"), Name: "slug", DataType: "text", NotNull: true},
144+
{Table: public("venue"), Name: "name", DataType: "pg_catalog.varchar", NotNull: true},
145+
{Table: public("venue"), Name: "city", DataType: "text", NotNull: true},
146+
{Table: public("venue"), Name: "spotify_playlist", DataType: "pg_catalog.varchar", NotNull: true},
147+
{Table: public("venue"), Name: "songkick_id", DataType: "text"},
140148
},
141149
Params: []Parameter{
142150
{1, core.Column{Name: "city", DataType: "text", NotNull: true}},
@@ -164,14 +172,14 @@ func TestQueries(t *testing.T) {
164172
`,
165173
Query{
166174
Columns: []core.Column{
167-
{Name: "id", DataType: "serial", NotNull: true},
168-
{Name: "create_at", DataType: "pg_catalog.timestamp", NotNull: true},
169-
{Name: "status", DataType: "status", NotNull: true},
170-
{Name: "slug", DataType: "text", NotNull: true},
171-
{Name: "name", DataType: "pg_catalog.varchar", NotNull: true},
172-
{Name: "city", DataType: "text", NotNull: true},
173-
{Name: "spotify_playlist", DataType: "pg_catalog.varchar", NotNull: true},
174-
{Name: "songkick_id", DataType: "text"},
175+
{Table: public("venue"), Name: "id", DataType: "serial", NotNull: true},
176+
{Table: public("venue"), Name: "create_at", DataType: "pg_catalog.timestamp", NotNull: true},
177+
{Table: public("venue"), Name: "status", DataType: "status", NotNull: true},
178+
{Table: public("venue"), Name: "slug", DataType: "text", NotNull: true},
179+
{Table: public("venue"), Name: "name", DataType: "pg_catalog.varchar", NotNull: true},
180+
{Table: public("venue"), Name: "city", DataType: "text", NotNull: true},
181+
{Table: public("venue"), Name: "spotify_playlist", DataType: "pg_catalog.varchar", NotNull: true},
182+
{Table: public("venue"), Name: "songkick_id", DataType: "text"},
175183
},
176184
Params: []Parameter{
177185
{1, core.Column{Name: "slug", DataType: "text", NotNull: true}},
@@ -200,7 +208,7 @@ func TestQueries(t *testing.T) {
200208
`,
201209
Query{
202210
Columns: []core.Column{
203-
{Name: "id", DataType: "serial", NotNull: true},
211+
{Table: public("venue"), Name: "id", DataType: "serial", NotNull: true},
204212
},
205213
Params: []Parameter{
206214
{1, core.Column{NotNull: true, DataType: "text", Name: "slug"}},
@@ -221,7 +229,7 @@ func TestQueries(t *testing.T) {
221229
`,
222230
Query{
223231
Columns: []core.Column{
224-
{Name: "id", DataType: "serial", NotNull: true},
232+
{Table: public("venue"), Name: "id", DataType: "serial", NotNull: true},
225233
},
226234
Params: []Parameter{
227235
{1, core.Column{DataType: "text", Name: "slug", NotNull: true}},
@@ -239,7 +247,7 @@ func TestQueries(t *testing.T) {
239247
`,
240248
Query{
241249
Columns: []core.Column{
242-
{Name: "city", DataType: "text", NotNull: true},
250+
{Table: public("venue"), Name: "city", DataType: "text", NotNull: true},
243251
{Name: "count", DataType: "bigint", NotNull: true},
244252
},
245253
},
@@ -270,7 +278,7 @@ func TestQueries(t *testing.T) {
270278
`,
271279
Query{
272280
Columns: []core.Column{
273-
{Name: "id", DataType: "serial", NotNull: true},
281+
{Table: public("foo"), Name: "id", DataType: "serial", NotNull: true},
274282
},
275283
Params: []Parameter{
276284
{1, core.Column{Name: "id", DataType: "serial", NotNull: true}},
@@ -287,8 +295,8 @@ func TestQueries(t *testing.T) {
287295
`,
288296
Query{
289297
Columns: []core.Column{
290-
{Name: "bid", DataType: "serial", NotNull: true},
291-
{Name: "fid", DataType: "serial", NotNull: true},
298+
{Table: public("bar"), Name: "bid", DataType: "serial", NotNull: true},
299+
{Table: public("foo"), Name: "fid", DataType: "serial", NotNull: true},
292300
},
293301
},
294302
},
@@ -380,7 +388,7 @@ func TestQueries(t *testing.T) {
380388
`,
381389
Query{
382390
Columns: []core.Column{
383-
{Name: "other_name", DataType: "text", NotNull: true},
391+
{Table: public("foo"), Name: "other_name", DataType: "text", NotNull: true},
384392
},
385393
},
386394
},
@@ -392,7 +400,7 @@ func TestQueries(t *testing.T) {
392400
`,
393401
Query{
394402
Columns: []core.Column{
395-
{Name: "tags", DataType: "text", IsArray: true, NotNull: true},
403+
{Table: public("bar"), Name: "tags", DataType: "text", IsArray: true, NotNull: true},
396404
},
397405
},
398406
},
@@ -430,7 +438,7 @@ func TestQueries(t *testing.T) {
430438
`,
431439
Query{
432440
Columns: []core.Column{
433-
{Name: "bar", DataType: "bool", NotNull: true},
441+
{Table: public("foo"), Name: "bar", DataType: "bool", NotNull: true},
434442
},
435443
Params: []Parameter{
436444
{1, core.Column{Name: "limit", DataType: "integer", NotNull: true}},
@@ -446,7 +454,7 @@ func TestQueries(t *testing.T) {
446454
`,
447455
Query{
448456
Columns: []core.Column{
449-
{Name: "email", DataType: "text", NotNull: true},
457+
{Table: public("foo"), Name: "email", DataType: "text", NotNull: true},
450458
},
451459
Params: []Parameter{
452460
{1, core.Column{Name: "login", DataType: "text", NotNull: true}},
@@ -461,7 +469,7 @@ func TestQueries(t *testing.T) {
461469
`,
462470
Query{
463471
Columns: []core.Column{
464-
{Name: "id", DataType: "text", NotNull: true},
472+
{Table: public("foo"), Name: "id", DataType: "text", NotNull: true},
465473
},
466474
},
467475
},
@@ -478,7 +486,7 @@ func TestQueries(t *testing.T) {
478486
`,
479487
Query{
480488
Columns: []core.Column{
481-
{Name: "barid", DataType: "serial", NotNull: true, Scope: "foo"},
489+
{Table: public("foo"), Name: "barid", DataType: "serial", NotNull: true, Scope: "foo"},
482490
},
483491
Params: []Parameter{
484492
{1, core.Column{Name: "owner", DataType: "text", NotNull: true}},
@@ -499,8 +507,8 @@ func TestQueries(t *testing.T) {
499507
`,
500508
Query{
501509
Columns: []core.Column{
502-
{Name: "bar_id", DataType: "serial", NotNull: true, Scope: "foo"},
503-
{Name: "baz_id", DataType: "serial", NotNull: true, Scope: "foo"},
510+
{Table: public("foo"), Name: "bar_id", DataType: "serial", NotNull: true, Scope: "foo"},
511+
{Table: public("foo"), Name: "baz_id", DataType: "serial", NotNull: true, Scope: "foo"},
504512
},
505513
},
506514
},
@@ -514,7 +522,7 @@ func TestQueries(t *testing.T) {
514522
`,
515523
Query{
516524
Columns: []core.Column{
517-
{Name: "login", DataType: "text", NotNull: true},
525+
{Table: public("foo"), Name: "login", DataType: "text", NotNull: true},
518526
},
519527
},
520528
},
@@ -543,7 +551,7 @@ func TestQueries(t *testing.T) {
543551
`,
544552
Query{
545553
Columns: []core.Column{
546-
{Name: "id", DataType: "serial", NotNull: true},
554+
{Table: public("bar"), Name: "id", DataType: "serial", NotNull: true},
547555
},
548556
Params: []Parameter{
549557
{1, core.Column{Name: "id", DataType: "serial", NotNull: true}},
@@ -562,7 +570,7 @@ func TestQueries(t *testing.T) {
562570
`,
563571
Query{
564572
Columns: []core.Column{
565-
{Name: "id", DataType: "bigserial", NotNull: true},
573+
{Table: public("bar"), Name: "id", DataType: "bigserial", NotNull: true},
566574
},
567575
Params: []Parameter{
568576
{1, core.Column{Name: "", DataType: "bigserial", NotNull: true, IsArray: true}},
@@ -578,7 +586,10 @@ func TestQueries(t *testing.T) {
578586
`,
579587
Query{
580588
Columns: []core.Column{
581-
{Name: "id", DataType: "serial", NotNull: true},
589+
{
590+
Table: core.FQN{Schema: "foo", Rel: "bar"},
591+
Name: "id", DataType: "serial", NotNull: true,
592+
},
582593
},
583594
},
584595
},
@@ -591,7 +602,12 @@ func TestQueries(t *testing.T) {
591602
`,
592603
Query{
593604
Columns: []core.Column{
594-
{Name: "id", DataType: "serial", NotNull: true},
605+
{
606+
Table: core.FQN{Schema: "foo", Rel: "bar"},
607+
Name: "id",
608+
DataType: "serial",
609+
NotNull: true,
610+
},
595611
},
596612
Params: []Parameter{
597613
{1, core.Column{Name: "id", DataType: "serial", NotNull: true}},
@@ -607,7 +623,10 @@ func TestQueries(t *testing.T) {
607623
`,
608624
Query{
609625
Columns: []core.Column{
610-
{Name: "id", DataType: "serial", NotNull: true},
626+
{
627+
Table: core.FQN{Schema: "foo", Rel: "bar"},
628+
Name: "id", DataType: "serial", NotNull: true,
629+
},
611630
},
612631
Params: []Parameter{
613632
{1, core.Column{Name: "id", DataType: "serial", NotNull: true}},
@@ -650,14 +669,27 @@ func TestQueries(t *testing.T) {
650669
`,
651670
Query{
652671
Columns: []core.Column{
653-
{Name: "bar", DataType: "text", NotNull: true},
672+
{Table: public("foo"), Name: "bar", DataType: "text", NotNull: true},
654673
},
655674
Params: []Parameter{
656675
{1, core.Column{Name: "bar", DataType: "text", NotNull: true}},
657676
{2, core.Column{Name: "bat", DataType: "text", NotNull: true}},
658677
},
659678
},
660679
},
680+
{
681+
"identical-tables",
682+
`
683+
CREATE TABLE foo (id text not null);
684+
CREATE TABLE bar (id text not null);
685+
SELECT * FROM foo;
686+
`,
687+
Query{
688+
Columns: []core.Column{
689+
{Table: public("foo"), Name: "id", DataType: "text", NotNull: true},
690+
},
691+
},
692+
},
661693
} {
662694
test := tc
663695
t.Run(test.name, func(t *testing.T) {

internal/pg/catalog.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ type Schema struct {
8989
}
9090

9191
type Table struct {
92+
ID FQN
9293
Name string
9394
Columns []Column
9495
}
@@ -101,6 +102,7 @@ type Column struct {
101102

102103
// XXX: Figure out what PostgreSQL calls `foo.id`
103104
Scope string
105+
Table FQN
104106
}
105107

106108
type Enum struct {

internal/postgres/schema.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type Table struct {
4444
}
4545

4646
type Column struct {
47+
Table string
4748
GoName string
4849
GoType string
4950
Name string

0 commit comments

Comments
 (0)