Skip to content

Commit 40c71de

Browse files
authored
internal/dinosql: Add COMMENT ON support (#191)
Comments are supported for SCHEMA, TABLE, COLUMN, and TYPE.
1 parent c869859 commit 40c71de

File tree

7 files changed

+215
-25
lines changed

7 files changed

+215
-25
lines changed

internal/catalog/build.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,105 @@ func Update(c *pg.Catalog, stmt nodes.Node) error {
370370
Arguments: args,
371371
ReturnType: join(n.ReturnType.Names, "."),
372372
})
373+
374+
case nodes.CommentStmt:
375+
switch n.Objtype {
376+
377+
case nodes.OBJECT_SCHEMA:
378+
name := n.Object.(nodes.String).Str
379+
schema, exists := c.Schemas[name]
380+
if !exists {
381+
return wrap(pg.ErrorSchemaDoesNotExist(name), raw.StmtLocation)
382+
}
383+
if n.Comment != nil {
384+
schema.Comment = *n.Comment
385+
} else {
386+
schema.Comment = ""
387+
}
388+
c.Schemas[name] = schema
389+
390+
case nodes.OBJECT_TABLE:
391+
fqn, err := ParseList(n.Object.(nodes.List))
392+
if err != nil {
393+
return err
394+
}
395+
schema, exists := c.Schemas[fqn.Schema]
396+
if !exists {
397+
return wrap(pg.ErrorSchemaDoesNotExist(fqn.Schema), raw.StmtLocation)
398+
}
399+
table, exists := schema.Tables[fqn.Rel]
400+
if !exists {
401+
return wrap(pg.ErrorRelationDoesNotExist(fqn.Rel), raw.StmtLocation)
402+
}
403+
if n.Comment != nil {
404+
table.Comment = *n.Comment
405+
} else {
406+
table.Comment = ""
407+
}
408+
schema.Tables[fqn.Rel] = table
409+
410+
case nodes.OBJECT_COLUMN:
411+
colParts := stringSlice(n.Object.(nodes.List))
412+
var fqn pg.FQN
413+
var col string
414+
switch len(colParts) {
415+
case 2:
416+
col = colParts[1]
417+
fqn = pg.FQN{Schema: "public", Rel: colParts[0]}
418+
case 3:
419+
col = colParts[2]
420+
fqn = pg.FQN{Schema: colParts[0], Rel: colParts[1]}
421+
case 4:
422+
col = colParts[3]
423+
fqn = pg.FQN{Catalog: colParts[0], Schema: colParts[1], Rel: colParts[2]}
424+
default:
425+
return fmt.Errorf("column specifier %q is not the proper format, expected '[catalog.][schema.]colname.tablename'", strings.Join(colParts, "."))
426+
}
427+
schema, exists := c.Schemas[fqn.Schema]
428+
if !exists {
429+
return wrap(pg.ErrorSchemaDoesNotExist(fqn.Schema), raw.StmtLocation)
430+
}
431+
table, exists := schema.Tables[fqn.Rel]
432+
if !exists {
433+
return wrap(pg.ErrorRelationDoesNotExist(fqn.Rel), raw.StmtLocation)
434+
}
435+
idx := -1
436+
for i, c := range table.Columns {
437+
if c.Name == col {
438+
idx = i
439+
}
440+
}
441+
if idx < 0 {
442+
return wrap(pg.ErrorColumnDoesNotExist(table.Name, col), raw.StmtLocation)
443+
}
444+
if n.Comment != nil {
445+
table.Columns[idx].Comment = *n.Comment
446+
} else {
447+
table.Columns[idx].Comment = ""
448+
}
449+
450+
case nodes.OBJECT_TYPE:
451+
fqn, err := ParseList(n.Object.(nodes.TypeName).Names)
452+
if err != nil {
453+
return err
454+
}
455+
schema, exists := c.Schemas[fqn.Schema]
456+
if !exists {
457+
return wrap(pg.ErrorSchemaDoesNotExist(fqn.Schema), raw.StmtLocation)
458+
}
459+
enum, exists := schema.Enums[fqn.Rel]
460+
if !exists {
461+
return wrap(pg.ErrorRelationDoesNotExist(fqn.Rel), raw.StmtLocation)
462+
}
463+
if n.Comment != nil {
464+
enum.Comment = *n.Comment
465+
} else {
466+
enum.Comment = ""
467+
}
468+
schema.Enums[fqn.Rel] = enum
469+
470+
}
471+
373472
}
374473
return nil
375474
}

internal/catalog/build_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,71 @@ func TestUpdate(t *testing.T) {
502502
},
503503
},
504504
},
505+
{
506+
`
507+
CREATE SCHEMA foo;
508+
CREATE TABLE foo.bar (baz text);
509+
CREATE TYPE foo.bat AS ENUM ('bat');
510+
COMMENT ON SCHEMA foo IS 'Schema comment';
511+
COMMENT ON TABLE foo.bar IS 'Table comment';
512+
COMMENT ON COLUMN foo.bar.baz IS 'Column comment';
513+
COMMENT ON TYPE foo.bat IS 'Enum comment';
514+
`,
515+
pg.Catalog{
516+
Schemas: map[string]pg.Schema{
517+
"foo": {
518+
Comment: "Schema comment",
519+
Tables: map[string]pg.Table{
520+
"bar": {
521+
Comment: "Table comment",
522+
Name: "bar",
523+
Columns: []pg.Column{
524+
{
525+
Name: "baz",
526+
DataType: "text",
527+
Table: pg.FQN{Schema: "foo", Rel: "bar"},
528+
Comment: "Column comment",
529+
},
530+
},
531+
},
532+
},
533+
Enums: map[string]pg.Enum{"bat": {Comment: "Enum comment", Name: "bat", Vals: []string{"bat"}}},
534+
Funcs: map[string][]pg.Function{},
535+
},
536+
},
537+
},
538+
},
539+
{
540+
`
541+
CREATE TABLE bar (baz text);
542+
CREATE TYPE bat AS ENUM ('bat');
543+
COMMENT ON TABLE bar IS 'Table comment';
544+
COMMENT ON COLUMN bar.baz IS 'Column comment';
545+
COMMENT ON TYPE bat IS 'Enum comment';
546+
`,
547+
pg.Catalog{
548+
Schemas: map[string]pg.Schema{
549+
"public": {
550+
Tables: map[string]pg.Table{
551+
"bar": {
552+
Comment: "Table comment",
553+
Name: "bar",
554+
Columns: []pg.Column{
555+
{
556+
Name: "baz",
557+
DataType: "text",
558+
Table: pg.FQN{Schema: "public", Rel: "bar"},
559+
Comment: "Column comment",
560+
},
561+
},
562+
},
563+
},
564+
Enums: map[string]pg.Enum{"bat": {Comment: "Enum comment", Name: "bat", Vals: []string{"bat"}}},
565+
Funcs: map[string][]pg.Function{},
566+
},
567+
},
568+
},
569+
},
505570
} {
506571
test := tc
507572
t.Run(strconv.Itoa(i), func(t *testing.T) {

internal/dinosql/gen.go

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ type GoConstant struct {
2525

2626
type GoEnum struct {
2727
Name string
28+
Comment string
2829
Constants []GoConstant
2930
}
3031

3132
type GoField struct {
32-
Name string
33-
Type string
34-
Tags map[string]string
33+
Name string
34+
Type string
35+
Tags map[string]string
36+
Comment string
3537
}
3638

3739
func (gf GoField) Tag() string {
@@ -47,9 +49,10 @@ func (gf GoField) Tag() string {
4749
}
4850

4951
type GoStruct struct {
50-
Table *core.FQN
51-
Name string
52-
Fields []GoField
52+
Table *core.FQN
53+
Name string
54+
Fields []GoField
55+
Comment string
5356
}
5457

5558
// TODO: Terrible name
@@ -396,7 +399,8 @@ func (r Result) Enums() []GoEnum {
396399
enumName = name + "_" + enum.Name
397400
}
398401
e := GoEnum{
399-
Name: r.structName(enumName),
402+
Name: r.structName(enumName),
403+
Comment: enum.Comment,
400404
}
401405
for _, v := range enum.Vals {
402406
name := ""
@@ -447,14 +451,16 @@ func (r Result) Structs() []GoStruct {
447451
tableName = name + "_" + table.Name
448452
}
449453
s := GoStruct{
450-
Table: &core.FQN{Schema: name, Rel: table.Name},
451-
Name: inflection.Singular(r.structName(tableName)),
454+
Table: &core.FQN{Schema: name, Rel: table.Name},
455+
Name: inflection.Singular(r.structName(tableName)),
456+
Comment: table.Comment,
452457
}
453458
for _, column := range table.Columns {
454459
s.Fields = append(s.Fields, GoField{
455-
Name: r.structName(column.Name),
456-
Type: r.goType(column),
457-
Tags: map[string]string{"json:": column.Name},
460+
Name: r.structName(column.Name),
461+
Type: r.goType(column),
462+
Tags: map[string]string{"json:": column.Name},
463+
Comment: column.Comment,
458464
})
459465
}
460466
structs = append(structs, s)
@@ -860,6 +866,7 @@ import (
860866
)
861867
862868
{{range .Enums}}
869+
{{if .Comment}}// {{.Comment}}{{end}}
863870
type {{.Name}} string
864871
865872
const (
@@ -875,7 +882,11 @@ func (e *{{.Name}}) Scan(src interface{}) error {
875882
{{end}}
876883
877884
{{range .Structs}}
885+
{{if .Comment}}// {{.Comment}}{{end}}
878886
type {{.Name}} struct { {{- range .Fields}}
887+
{{- if .Comment}}
888+
// {{.Comment}}{{else}}
889+
{{- end}}
879890
{{.Name}} {{.Type}} {{if $.EmitJSONTags}}{{$.Q}}{{.Tag}}{{$.Q}}{{end}}
880891
{{- end}}
881892
}

internal/dinosql/testdata/ondeck/models.go

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

internal/dinosql/testdata/ondeck/prepared/models.go

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

internal/dinosql/testdata/ondeck/schema/0002_venue.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CREATE TYPE status AS ENUM ('open', 'closed');
2+
COMMENT ON TYPE status IS 'Venues can be either open or closed';
23

34
CREATE TABLE venues (
45
id SERIAL primary key,
@@ -11,4 +12,7 @@ CREATE TABLE venues (
1112
spotify_playlist varchar not null,
1213
songkick_id text,
1314
tags text[]
14-
)
15+
);
16+
COMMENT ON TABLE venues IS 'Venues are places where muisc happens';
17+
COMMENT ON COLUMN venues.slug IS 'This value appears in public URLs';
18+

internal/pg/catalog.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,39 +91,44 @@ func (c Catalog) LookupFunctionN(fqn FQN, argn int) (Function, error) {
9191
}
9292

9393
type Schema struct {
94-
Name string
95-
Tables map[string]Table
96-
Enums map[string]Enum
97-
Funcs map[string][]Function
94+
Name string
95+
Tables map[string]Table
96+
Enums map[string]Enum
97+
Funcs map[string][]Function
98+
Comment string
9899
}
99100

100101
type Table struct {
101102
ID FQN
102103
Name string
103104
Columns []Column
105+
Comment string
104106
}
105107

106108
type Column struct {
107109
Name string
108110
DataType string
109111
NotNull bool
110112
IsArray bool
113+
Comment string
111114

112115
// XXX: Figure out what PostgreSQL calls `foo.id`
113116
Scope string
114117
Table FQN
115118
}
116119

117120
type Enum struct {
118-
Name string
119-
Vals []string
121+
Name string
122+
Vals []string
123+
Comment string
120124
}
121125

122126
type Function struct {
123127
Name string
124128
ArgN int
125129
Arguments []Argument // not recorded for builtins
126130
ReturnType string
131+
Comment string
127132
}
128133

129134
type Argument struct {

0 commit comments

Comments
 (0)