diff --git a/examples/booktest/mysql/models.go b/examples/booktest/mysql/models.go index d5fd9fc6df..b7b1cd05ba 100644 --- a/examples/booktest/mysql/models.go +++ b/examples/booktest/mysql/models.go @@ -3,9 +3,29 @@ package booktest import ( + "fmt" "time" ) +type BookType string + +const ( + BookTypeFICTION BookType = "FICTION" + BookTypeNONFICTION BookType = "NONFICTION" +) + +func (e *BookType) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = BookType(s) + case string: + *e = BookType(s) + default: + return fmt.Errorf("unsupported scan type for BookType: %T", src) + } + return nil +} + type Author struct { AuthorID int32 Name string @@ -15,7 +35,7 @@ type Book struct { BookID int32 AuthorID int32 Isbn string - BookType string + BookType BookType Title string Yr int32 Available time.Time diff --git a/examples/booktest/mysql/query.sql.go b/examples/booktest/mysql/query.sql.go index ab79aac754..e9f204a59a 100644 --- a/examples/booktest/mysql/query.sql.go +++ b/examples/booktest/mysql/query.sql.go @@ -131,7 +131,7 @@ INSERT INTO books ( type CreateBookParams struct { AuthorID int32 Isbn string - BookType string + BookType BookType Title string Yr int32 Available time.Time diff --git a/internal/codegen/golang/mysql_type.go b/internal/codegen/golang/mysql_type.go index 6149609304..4be59fc7f6 100644 --- a/internal/codegen/golang/mysql_type.go +++ b/internal/codegen/golang/mysql_type.go @@ -5,6 +5,8 @@ import ( "github.com/kyleconroy/sqlc/internal/compiler" "github.com/kyleconroy/sqlc/internal/config" + "github.com/kyleconroy/sqlc/internal/debug" + "github.com/kyleconroy/sqlc/internal/sql/catalog" ) func mysqlType(r *compiler.Result, col *compiler.Column, settings config.CombinedSettings) string { @@ -69,7 +71,22 @@ func mysqlType(r *compiler.Result, col *compiler.Column, settings config.Combine return "interface{}" default: - log.Printf("unknown MySQL type: %s\n", columnType) + for _, schema := range r.Catalog.Schemas { + for _, typ := range schema.Types { + switch t := typ.(type) { + case *catalog.Enum: + if t.Name == columnType { + if schema.Name == r.Catalog.DefaultSchema { + return StructName(t.Name, settings) + } + return StructName(schema.Name+"_"+t.Name, settings) + } + } + } + } + if debug.Active { + log.Printf("Unknown MySQL type: %s\n", columnType) + } return "interface{}" } diff --git a/internal/codegen/golang/postgresql_type.go b/internal/codegen/golang/postgresql_type.go index 5124d5cf8c..9c82bf3632 100644 --- a/internal/codegen/golang/postgresql_type.go +++ b/internal/codegen/golang/postgresql_type.go @@ -5,6 +5,7 @@ import ( "github.com/kyleconroy/sqlc/internal/compiler" "github.com/kyleconroy/sqlc/internal/config" + "github.com/kyleconroy/sqlc/internal/debug" "github.com/kyleconroy/sqlc/internal/sql/catalog" ) @@ -166,8 +167,9 @@ func postgresType(r *compiler.Result, col *compiler.Column, settings config.Comb } } } - - log.Printf("unknown PostgreSQL type: %s\n", columnType) + if debug.Active { + log.Printf("unknown PostgreSQL type: %s\n", columnType) + } return "interface{}" } } diff --git a/internal/endtoend/testdata/enums/go/db.go b/internal/endtoend/testdata/ddl_create_enum/mysql/go/db.go similarity index 96% rename from internal/endtoend/testdata/enums/go/db.go rename to internal/endtoend/testdata/ddl_create_enum/mysql/go/db.go index 6b476d86a6..6a99519302 100644 --- a/internal/endtoend/testdata/enums/go/db.go +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/go/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. -package enum +package querytest import ( "context" diff --git a/internal/endtoend/testdata/enums/go/models.go b/internal/endtoend/testdata/ddl_create_enum/mysql/go/models.go similarity index 90% rename from internal/endtoend/testdata/enums/go/models.go rename to internal/endtoend/testdata/ddl_create_enum/mysql/go/models.go index 469e833b9c..db124f1d88 100644 --- a/internal/endtoend/testdata/enums/go/models.go +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/go/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. -package enum +package querytest import ( "fmt" @@ -29,3 +29,7 @@ func (e *Foobar) Scan(src interface{}) error { } return nil } + +type Foo struct { + Foobar Foobar +} diff --git a/internal/endtoend/testdata/ddl_create_enum/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_create_enum/mysql/go/query.sql.go new file mode 100644 index 0000000000..1deedd495c --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/go/query.sql.go @@ -0,0 +1,35 @@ +// Code generated by sqlc. DO NOT EDIT. +// source: query.sql + +package querytest + +import ( + "context" +) + +const listFoo = `-- name: ListFoo :many +SELECT foobar FROM foo +` + +func (q *Queries) ListFoo(ctx context.Context) ([]Foobar, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foobar + for rows.Next() { + var foobar Foobar + if err := rows.Scan(&foobar); err != nil { + return nil, err + } + items = append(items, foobar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/ddl_create_enum/mysql/query.sql b/internal/endtoend/testdata/ddl_create_enum/mysql/query.sql new file mode 100644 index 0000000000..e120062b78 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: ListFoo :many */ +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/ddl_create_enum/mysql/schema.sql b/internal/endtoend/testdata/ddl_create_enum/mysql/schema.sql new file mode 100644 index 0000000000..98c2c56f06 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo ( + foobar ENUM ('foo-a', 'foo_b', 'foo:c', 'foo/d', 'foo@e', 'foo+f', 'foo!g') NOT NULL +); diff --git a/internal/endtoend/testdata/ddl_create_enum/mysql/sqlc.json b/internal/endtoend/testdata/ddl_create_enum/mysql/sqlc.json new file mode 100644 index 0000000000..60ef946c26 --- /dev/null +++ b/internal/endtoend/testdata/ddl_create_enum/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "mysql:beta", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/go/models.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/go/models.go index a3b9d24cda..d4423cdb40 100644 --- a/internal/endtoend/testdata/ddl_create_enum/postgresql/go/models.go +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/go/models.go @@ -6,21 +6,30 @@ import ( "fmt" ) -type Status string +type Foobar string const ( - StatusOpen Status = "open" - StatusClosed Status = "closed" + FoobarFooA Foobar = "foo-a" + FoobarFooB Foobar = "foo_b" + FoobarFooC Foobar = "foo:c" + FoobarFooD Foobar = "foo/d" + FoobarFooe Foobar = "foo@e" + FoobarFoof Foobar = "foo+f" + FoobarFoog Foobar = "foo!g" ) -func (e *Status) Scan(src interface{}) error { +func (e *Foobar) Scan(src interface{}) error { switch s := src.(type) { case []byte: - *e = Status(s) + *e = Foobar(s) case string: - *e = Status(s) + *e = Foobar(s) default: - return fmt.Errorf("unsupported scan type for Status: %T", src) + return fmt.Errorf("unsupported scan type for Foobar: %T", src) } return nil } + +type Foo struct { + Val Foobar +} diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/go/query.sql.go b/internal/endtoend/testdata/ddl_create_enum/postgresql/go/query.sql.go index 203f0fe62c..85347b0255 100644 --- a/internal/endtoend/testdata/ddl_create_enum/postgresql/go/query.sql.go +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/go/query.sql.go @@ -7,11 +7,29 @@ import ( "context" ) -const placeholder = `-- name: Placeholder :exec -SELECT 1 +const listFoo = `-- name: ListFoo :many +SELECT val FROM foo ` -func (q *Queries) Placeholder(ctx context.Context) error { - _, err := q.db.ExecContext(ctx, placeholder) - return err +func (q *Queries) ListFoo(ctx context.Context) ([]Foobar, error) { + rows, err := q.db.QueryContext(ctx, listFoo) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Foobar + for rows.Next() { + var val Foobar + if err := rows.Scan(&val); err != nil { + return nil, err + } + items = append(items, val) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil } diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/query.sql b/internal/endtoend/testdata/ddl_create_enum/postgresql/query.sql index 6520aef4b6..b475d29f5e 100644 --- a/internal/endtoend/testdata/ddl_create_enum/postgresql/query.sql +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/query.sql @@ -1,2 +1,2 @@ --- name: Placeholder :exec -SELECT 1; +-- name: ListFoo :many +SELECT * FROM foo; diff --git a/internal/endtoend/testdata/ddl_create_enum/postgresql/schema.sql b/internal/endtoend/testdata/ddl_create_enum/postgresql/schema.sql index bd57be2003..252f31dc93 100644 --- a/internal/endtoend/testdata/ddl_create_enum/postgresql/schema.sql +++ b/internal/endtoend/testdata/ddl_create_enum/postgresql/schema.sql @@ -1 +1,13 @@ -CREATE TYPE status AS ENUM ('open', 'closed'); \ No newline at end of file +CREATE TYPE foobar AS ENUM ( + -- Valid separators + 'foo-a', + 'foo_b', + 'foo:c', + 'foo/d', + -- Strip unknown characters + 'foo@e', + 'foo+f', + 'foo!g' +); + +CREATE TABLE foo (val foobar NOT NULL); diff --git a/internal/endtoend/testdata/enums/sql/enum.sql b/internal/endtoend/testdata/enums/sql/enum.sql deleted file mode 100644 index f1de033807..0000000000 --- a/internal/endtoend/testdata/enums/sql/enum.sql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE TYPE foobar AS ENUM ( - -- Valid separators - 'foo-a', - 'foo_b', - 'foo:c', - 'foo/d', - -- Strip unknown characters - 'foo@e', - 'foo+f', - 'foo!g' -); diff --git a/internal/endtoend/testdata/enums/sql/query.sql b/internal/endtoend/testdata/enums/sql/query.sql deleted file mode 100644 index e0ac49d1ec..0000000000 --- a/internal/endtoend/testdata/enums/sql/query.sql +++ /dev/null @@ -1 +0,0 @@ -SELECT 1; diff --git a/internal/endtoend/testdata/enums/sqlc.json b/internal/endtoend/testdata/enums/sqlc.json deleted file mode 100644 index cbe430a51f..0000000000 --- a/internal/endtoend/testdata/enums/sqlc.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "1", - "packages": [ - { - "path": "go", - "name": "enum", - "schema": "sql/", - "queries": "sql/" - } - ] -} diff --git a/internal/engine/dolphin/convert.go b/internal/engine/dolphin/convert.go index a106122d3a..50f64fe06e 100644 --- a/internal/engine/dolphin/convert.go +++ b/internal/engine/dolphin/convert.go @@ -2,6 +2,7 @@ package dolphin import ( "fmt" + "log" pcast "github.com/pingcap/parser/ast" "github.com/pingcap/parser/opcode" @@ -172,6 +173,7 @@ func (c *cc) convertCreateTableStmt(n *pcast.CreateTableStmt) ast.Node { TypeName: &ast.TypeName{Name: types.TypeStr(def.Tp.Tp)}, IsNotNull: isNotNull(def), Comment: comment, + Vals: vals, }) } for _, opt := range n.Options { @@ -492,7 +494,7 @@ func (c *cc) convert(node pcast.Node) ast.Node { default: if debug.Active { - fmt.Printf("dolphin.convert: Unknown node type %T\n", n) + log.Printf("dolphin.convert: Unknown node type %T\n", n) } return &ast.TODO{} } diff --git a/internal/sql/catalog/table.go b/internal/sql/catalog/table.go index aa2e1edbc3..d9276877b5 100644 --- a/internal/sql/catalog/table.go +++ b/internal/sql/catalog/table.go @@ -153,13 +153,24 @@ func (c *Catalog) createTable(stmt *ast.CreateTableStmt) error { } } else { for _, col := range stmt.Cols { - tbl.Columns = append(tbl.Columns, &Column{ + tc := &Column{ Name: col.Colname, Type: *col.TypeName, IsNotNull: col.IsNotNull, IsArray: col.IsArray, Comment: col.Comment, - }) + } + if col.Vals != nil { + typeName := ast.TypeName{ + Name: col.Colname, + } + s := &ast.CreateEnumStmt{TypeName: &typeName, Vals: col.Vals} + if err := c.createEnum(s); err != nil { + return err + } + tc.Type = typeName + } + tbl.Columns = append(tbl.Columns, tc) } } schema.Tables = append(schema.Tables, &tbl)