From ee9840150f24e821bc8c3a46b57625087b4021fa Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Sat, 21 Nov 2020 13:53:11 -0800 Subject: [PATCH] dolphin: Add support for coalesce For some reason it's a special case in the AST Fixes #725 --- .../testdata/coalesce/{ => mysql}/go/db.go | 0 .../coalesce/{ => mysql}/go/models.go | 0 .../coalesce/{ => mysql}/go/query.sql.go | 0 .../testdata/coalesce/{ => mysql}/query.sql | 0 .../testdata/coalesce/{ => mysql}/sqlc.json | 1 + .../testdata/coalesce/postgresql/go/db.go | 29 ++++++++ .../testdata/coalesce/postgresql/go/models.go | 12 ++++ .../coalesce/postgresql/go/query.sql.go | 71 +++++++++++++++++++ .../testdata/coalesce/postgresql/query.sql | 9 +++ .../testdata/coalesce/postgresql/sqlc.json | 12 ++++ internal/engine/dolphin/convert.go | 35 +++++---- 11 files changed, 155 insertions(+), 14 deletions(-) rename internal/endtoend/testdata/coalesce/{ => mysql}/go/db.go (100%) rename internal/endtoend/testdata/coalesce/{ => mysql}/go/models.go (100%) rename internal/endtoend/testdata/coalesce/{ => mysql}/go/query.sql.go (100%) rename internal/endtoend/testdata/coalesce/{ => mysql}/query.sql (100%) rename internal/endtoend/testdata/coalesce/{ => mysql}/sqlc.json (86%) create mode 100644 internal/endtoend/testdata/coalesce/postgresql/go/db.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/go/models.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/go/query.sql.go create mode 100644 internal/endtoend/testdata/coalesce/postgresql/query.sql create mode 100644 internal/endtoend/testdata/coalesce/postgresql/sqlc.json diff --git a/internal/endtoend/testdata/coalesce/go/db.go b/internal/endtoend/testdata/coalesce/mysql/go/db.go similarity index 100% rename from internal/endtoend/testdata/coalesce/go/db.go rename to internal/endtoend/testdata/coalesce/mysql/go/db.go diff --git a/internal/endtoend/testdata/coalesce/go/models.go b/internal/endtoend/testdata/coalesce/mysql/go/models.go similarity index 100% rename from internal/endtoend/testdata/coalesce/go/models.go rename to internal/endtoend/testdata/coalesce/mysql/go/models.go diff --git a/internal/endtoend/testdata/coalesce/go/query.sql.go b/internal/endtoend/testdata/coalesce/mysql/go/query.sql.go similarity index 100% rename from internal/endtoend/testdata/coalesce/go/query.sql.go rename to internal/endtoend/testdata/coalesce/mysql/go/query.sql.go diff --git a/internal/endtoend/testdata/coalesce/query.sql b/internal/endtoend/testdata/coalesce/mysql/query.sql similarity index 100% rename from internal/endtoend/testdata/coalesce/query.sql rename to internal/endtoend/testdata/coalesce/mysql/query.sql diff --git a/internal/endtoend/testdata/coalesce/sqlc.json b/internal/endtoend/testdata/coalesce/mysql/sqlc.json similarity index 86% rename from internal/endtoend/testdata/coalesce/sqlc.json rename to internal/endtoend/testdata/coalesce/mysql/sqlc.json index ac7c2ed829..445bbd1589 100644 --- a/internal/endtoend/testdata/coalesce/sqlc.json +++ b/internal/endtoend/testdata/coalesce/mysql/sqlc.json @@ -3,6 +3,7 @@ "packages": [ { "path": "go", + "engine": "mysql", "name": "querytest", "schema": "query.sql", "queries": "query.sql" diff --git a/internal/endtoend/testdata/coalesce/postgresql/go/db.go b/internal/endtoend/testdata/coalesce/postgresql/go/db.go new file mode 100644 index 0000000000..6a99519302 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/go/db.go @@ -0,0 +1,29 @@ +// Code generated by sqlc. DO NOT EDIT. + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/coalesce/postgresql/go/models.go b/internal/endtoend/testdata/coalesce/postgresql/go/models.go new file mode 100644 index 0000000000..1ee813a39b --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/go/models.go @@ -0,0 +1,12 @@ +// Code generated by sqlc. DO NOT EDIT. + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullString + Bat string +} diff --git a/internal/endtoend/testdata/coalesce/postgresql/go/query.sql.go b/internal/endtoend/testdata/coalesce/postgresql/go/query.sql.go new file mode 100644 index 0000000000..3f69c6b692 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/go/query.sql.go @@ -0,0 +1,71 @@ +// Code generated by sqlc. DO NOT EDIT. +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const coalesce = `-- name: Coalesce :many +SELECT coalesce(bar, '') as login +FROM foo +` + +func (q *Queries) Coalesce(ctx context.Context) ([]string, error) { + rows, err := q.db.QueryContext(ctx, coalesce) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var login string + if err := rows.Scan(&login); err != nil { + return nil, err + } + items = append(items, login) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const coalesceColumns = `-- name: CoalesceColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo +` + +type CoalesceColumnsRow struct { + Bar sql.NullString + Bat string + Bar_2 string +} + +func (q *Queries) CoalesceColumns(ctx context.Context) ([]CoalesceColumnsRow, error) { + rows, err := q.db.QueryContext(ctx, coalesceColumns) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CoalesceColumnsRow + for rows.Next() { + var i CoalesceColumnsRow + if err := rows.Scan(&i.Bar, &i.Bat, &i.Bar_2); err != nil { + return nil, err + } + items = append(items, i) + } + 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/coalesce/postgresql/query.sql b/internal/endtoend/testdata/coalesce/postgresql/query.sql new file mode 100644 index 0000000000..022c1fb653 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/query.sql @@ -0,0 +1,9 @@ +CREATE TABLE foo (bar text, bat text not null); + +-- name: Coalesce :many +SELECT coalesce(bar, '') as login +FROM foo; + +-- name: CoalesceColumns :many +SELECT bar, bat, coalesce(bar, bat) +FROM foo; diff --git a/internal/endtoend/testdata/coalesce/postgresql/sqlc.json b/internal/endtoend/testdata/coalesce/postgresql/sqlc.json new file mode 100644 index 0000000000..c72b6132d5 --- /dev/null +++ b/internal/endtoend/testdata/coalesce/postgresql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/engine/dolphin/convert.go b/internal/engine/dolphin/convert.go index 99d684c74c..df857c4691 100644 --- a/internal/engine/dolphin/convert.go +++ b/internal/engine/dolphin/convert.go @@ -321,7 +321,7 @@ func (c *cc) convertFieldList(n *pcast.FieldList) *ast.List { return &ast.List{Items: fields} } -func (c *cc) convertFuncCallExpr(n *pcast.FuncCallExpr) *ast.FuncCall { +func (c *cc) convertFuncCallExpr(n *pcast.FuncCallExpr) ast.Node { schema := n.Schema.String() name := strings.ToLower(n.FnName.String()) @@ -332,21 +332,28 @@ func (c *cc) convertFuncCallExpr(n *pcast.FuncCallExpr) *ast.FuncCall { } items = append(items, &ast.String{Str: name}) - fn := &ast.FuncCall{ - Args: &ast.List{}, - Func: &ast.FuncName{ - Schema: schema, - Name: name, - }, - Funcname: &ast.List{ - Items: items, - }, - Location: n.OriginTextPosition(), - } + args := &ast.List{} for _, arg := range n.Args { - fn.Args.Items = append(fn.Args.Items, c.convert(arg)) + args.Items = append(args.Items, c.convert(arg)) + } + + if schema == "" && name == "coalesce" { + return &ast.CoalesceExpr{ + Args: args, + } + } else { + return &ast.FuncCall{ + Args: args, + Func: &ast.FuncName{ + Schema: schema, + Name: name, + }, + Funcname: &ast.List{ + Items: items, + }, + Location: n.OriginTextPosition(), + } } - return fn } func (c *cc) convertInsertStmt(n *pcast.InsertStmt) *ast.InsertStmt {