Skip to content

Commit 2c8d3a7

Browse files
cmoogkyleconroy
authored andcommitted
MySQL support improvements
- adds support for unqualified column names in join expressions - adds support for more mysql datatypes and function return types - adds logic to reuse structs when all fields are selected from a table
1 parent 0276143 commit 2c8d3a7

File tree

9 files changed

+179
-193
lines changed

9 files changed

+179
-193
lines changed

examples/booktest/mysql/query.sql.go

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

internal/dinosql/gen.go

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (gf GoField) Tag() string {
5252
}
5353

5454
type GoStruct struct {
55-
Table Comparable
55+
Table core.FQN
5656
Name string
5757
Fields []GoField
5858
Comment string
@@ -65,28 +65,6 @@ type GoQueryValue struct {
6565
Typ string
6666
}
6767

68-
// TODO: consider making this deep equality from stdlib?
69-
type Comparable interface {
70-
EqualTo(b interface{}) bool
71-
}
72-
73-
type FQNAlias core.FQN
74-
75-
// Check whether tables are equal
76-
func (a *FQNAlias) EqualTo(other interface{}) bool {
77-
b, ok := other.(*core.FQN)
78-
if !ok {
79-
panic("Unknown ")
80-
}
81-
if a == nil && b == nil {
82-
return true
83-
}
84-
if a == nil || b == nil {
85-
return false
86-
}
87-
return a.Catalog == b.Catalog && a.Schema == b.Schema && a.Rel == b.Rel
88-
}
89-
9068
func (v GoQueryValue) EmitStruct() bool {
9169
return v.Emit
9270
}
@@ -490,7 +468,7 @@ func (r Result) Structs(settings GenerateSettings) []GoStruct {
490468
tableName = name + "_" + table.Name
491469
}
492470
s := GoStruct{
493-
Table: &FQNAlias{Schema: name, Rel: table.Name},
471+
Table: core.FQN{Schema: name, Rel: table.Name},
494472
Name: inflection.Singular(StructName(tableName, settings)),
495473
Comment: table.Comment,
496474
}
@@ -785,9 +763,8 @@ func (r Result) GoQueries(settings GenerateSettings) []GoQuery {
785763
c := query.Columns[i]
786764
sameName := f.Name == StructName(columnName(c, i), settings)
787765
sameType := f.Type == r.goType(c, settings)
766+
sameTable := s.Table.Catalog == c.Table.Catalog && s.Table.Schema == c.Table.Schema && s.Table.Rel == c.Table.Rel
788767

789-
// TODO: clean this up!!
790-
sameTable := s.Table.EqualTo(&c.Table)
791768
if !sameName || !sameType || !sameTable {
792769
same = false
793770
}

internal/mysql/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# MySQL Support
1+
# Experimental MySQL Support
22

33
## Missing Features
44

internal/mysql/functions.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ import (
77
// converts MySQL function name to MySQL return type
88
func functionReturnType(f string) string {
99
switch f {
10-
case "avg", "count", "instr", "sum", "min", "max", "length", "char_length":
10+
case "avg", "count", "instr", "sum", "min", "max", "length", "char_length",
11+
"ceil", "floor", "mod":
1112
return "int"
1213
case "concat", "left", "replace", "substring", "trim", "find_in_set", "format", "group_concat":
1314
return "varchar"
15+
case "abs", "round", "truncate":
16+
return "decimal"
1417
default:
1518
panic(fmt.Sprintf("unknown mysql function type [%v]", f))
1619
}

internal/mysql/gen.go

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/jinzhu/inflection"
1010
"github.com/kyleconroy/sqlc/internal/dinosql"
11+
core "github.com/kyleconroy/sqlc/internal/pg"
1112
"vitess.io/vitess/go/vt/sqlparser"
1213
)
1314

@@ -67,7 +68,8 @@ func (r *Result) Structs(settings dinosql.GenerateSettings) []dinosql.GoStruct {
6768
var structs []dinosql.GoStruct
6869
for tableName, cols := range r.Schema.tables {
6970
s := dinosql.GoStruct{
70-
Name: inflection.Singular(dinosql.StructName(tableName, settings)),
71+
Name: inflection.Singular(dinosql.StructName(tableName, settings)),
72+
Table: core.FQN{tableName, "", ""}, // TODO: Complete hack. Only need for equality check to see if struct can be reused between queries
7173
}
7274

7375
for _, col := range cols {
@@ -136,8 +138,8 @@ func (r *Result) GoQueries(settings dinosql.GenerateSettings) []dinosql.GoQuery
136138
if len(query.Columns) == 1 {
137139
c := query.Columns[0]
138140
gq.Ret = dinosql.GoQueryValue{
139-
Name: columnName(c, 0),
140-
Typ: goTypeCol(c, settings),
141+
Name: columnName(c.ColumnDefinition, 0),
142+
Typ: goTypeCol(c.ColumnDefinition, settings),
141143
}
142144
} else if len(query.Columns) > 1 {
143145
var gs *dinosql.GoStruct
@@ -150,11 +152,13 @@ func (r *Result) GoQueries(settings dinosql.GenerateSettings) []dinosql.GoQuery
150152
same := true
151153
for i, f := range s.Fields {
152154
c := query.Columns[i]
153-
sameName := f.Name == dinosql.StructName(columnName(c, i), settings)
154-
sameType := f.Type == goTypeCol(c, settings)
155-
// TODO: consider making this deep equality from stdlib?
156-
// sameFQN := s.Table.EqualTo(&c.Table)
157-
if !sameName || !sameType || true { // !sameFQN
155+
sameName := f.Name == dinosql.StructName(columnName(c.ColumnDefinition, i), settings)
156+
sameType := f.Type == goTypeCol(c.ColumnDefinition, settings)
157+
158+
hackedFQN := core.FQN{c.Table, "", ""} // TODO: only check needed here is equality to see if struct can be reused, this type should be removed or properly used
159+
sameTable := s.Table.Catalog == hackedFQN.Catalog && s.Table.Schema == hackedFQN.Schema && s.Table.Rel == hackedFQN.Rel
160+
161+
if !sameName || !sameType || !sameTable {
158162
same = false
159163
}
160164
}
@@ -169,7 +173,7 @@ func (r *Result) GoQueries(settings dinosql.GenerateSettings) []dinosql.GoQuery
169173
for i := range query.Columns {
170174
structInfo[i] = structParams{
171175
originalName: query.Columns[i].Name.String(),
172-
goType: goTypeCol(query.Columns[i], settings),
176+
goType: goTypeCol(query.Columns[i].ColumnDefinition, settings),
173177
}
174178
}
175179
gs = r.columnsToStruct(gq.MethodName+"Row", structInfo, settings)
@@ -219,30 +223,38 @@ func (r *Result) columnsToStruct(name string, items []structParams, settings din
219223

220224
func goTypeCol(col *sqlparser.ColumnDefinition, settings dinosql.GenerateSettings) string {
221225
switch t := col.Type.Type; {
222-
case "varchar" == t, "text" == t:
226+
case "varchar" == t, "text" == t, "char" == t,
227+
"tinytext" == t, "mediumtext" == t, "longtext" == t:
223228
if col.Type.NotNull {
224229
return "string"
225230
}
226231
return "sql.NullString"
227-
case "int" == t, "integer" == t:
232+
case "int" == t, "integer" == t, t == "smallint",
233+
t == "tinyint", "mediumint" == t, "bigint" == t, "year" == t:
228234
if col.Type.NotNull {
229235
return "int"
230236
}
231237
return "sql.NullInt64"
238+
case "blob" == t, "binary" == t, "varbinary" == t, "tinyblob" == t,
239+
"mediumblob" == t, "longblob" == t:
240+
return "[]byte"
232241
case "float" == t, strings.HasPrefix(strings.ToLower(t), "decimal"):
233242
if col.Type.NotNull {
234243
return "float64"
235244
}
236245
return "sql.NullFloat64"
237246
case "enum" == t:
238247
return enumNameFromColDef(col, settings)
239-
case "date" == t, "timestamp" == t, "datetime" == t:
248+
case "date" == t, "timestamp" == t, "datetime" == t, "time" == t:
240249
if col.Type.NotNull {
241250
return "time.Time"
242251
}
243252
return "sql.NullTime"
244253
case "boolean" == t:
245-
return "bool"
254+
if col.Type.NotNull {
255+
return "bool"
256+
}
257+
return "sql.NullBool"
246258
default:
247259
log.Printf("unknown MySQL type: %s\n", t)
248260
return "interface{}"

internal/mysql/param_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func TestSelectParamSearcher(t *testing.T) {
8383
}
8484
selectStm, ok := tree.(*sqlparser.Select)
8585

86-
tableAliasMap, err := parseFrom(selectStm.From, false)
86+
tableAliasMap, _, err := parseFrom(selectStm.From, false)
8787
if err != nil {
8888
t.Errorf("Failed to parse table name alias's: %v", err)
8989
}

0 commit comments

Comments
 (0)