From 159603831f1d1e8dced0f47f63f9ec3b509a1dc0 Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Thu, 19 Nov 2020 08:45:51 -0800 Subject: [PATCH 1/2] sql/catalog: Add support for variadic functions --- .../endtoend/testdata/json_build/go/db.go | 29 +++++++++ .../endtoend/testdata/json_build/go/models.go | 5 ++ .../testdata/json_build/go/query.sql.go | 63 +++++++++++++++++++ .../endtoend/testdata/json_build/query.sql | 13 ++++ .../endtoend/testdata/json_build/sqlc.json | 12 ++++ 5 files changed, 122 insertions(+) create mode 100644 internal/endtoend/testdata/json_build/go/db.go create mode 100644 internal/endtoend/testdata/json_build/go/models.go create mode 100644 internal/endtoend/testdata/json_build/go/query.sql.go create mode 100644 internal/endtoend/testdata/json_build/query.sql create mode 100644 internal/endtoend/testdata/json_build/sqlc.json diff --git a/internal/endtoend/testdata/json_build/go/db.go b/internal/endtoend/testdata/json_build/go/db.go new file mode 100644 index 0000000000..6a99519302 --- /dev/null +++ b/internal/endtoend/testdata/json_build/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/json_build/go/models.go b/internal/endtoend/testdata/json_build/go/models.go new file mode 100644 index 0000000000..4e2b892600 --- /dev/null +++ b/internal/endtoend/testdata/json_build/go/models.go @@ -0,0 +1,5 @@ +// Code generated by sqlc. DO NOT EDIT. + +package querytest + +import () diff --git a/internal/endtoend/testdata/json_build/go/query.sql.go b/internal/endtoend/testdata/json_build/go/query.sql.go new file mode 100644 index 0000000000..9444d909df --- /dev/null +++ b/internal/endtoend/testdata/json_build/go/query.sql.go @@ -0,0 +1,63 @@ +// Code generated by sqlc. DO NOT EDIT. +// source: query.sql + +package querytest + +import ( + "context" + "encoding/json" +) + +const selectJSONBuildArray = `-- name: SelectJSONBuildArray :one +SELECT + json_build_array(1), + json_build_array(1, 2), + json_build_array(1, 2, 'foo'), + json_build_array(1, 2, 'foo', 4) +` + +type SelectJSONBuildArrayRow struct { + JsonBuildArray json.RawMessage + JsonBuildArray_2 json.RawMessage + JsonBuildArray_3 json.RawMessage + JsonBuildArray_4 json.RawMessage +} + +func (q *Queries) SelectJSONBuildArray(ctx context.Context) (SelectJSONBuildArrayRow, error) { + row := q.db.QueryRowContext(ctx, selectJSONBuildArray) + var i SelectJSONBuildArrayRow + err := row.Scan( + &i.JsonBuildArray, + &i.JsonBuildArray_2, + &i.JsonBuildArray_3, + &i.JsonBuildArray_4, + ) + return i, err +} + +const selectJSONBuildObject = `-- name: SelectJSONBuildObject :one +SELECT + json_build_object('foo'), + json_build_object('foo', 1), + json_build_object('foo', 1, 2), + json_build_object('foo', 1, 2, 'bar') +` + +type SelectJSONBuildObjectRow struct { + JsonBuildObject json.RawMessage + JsonBuildObject_2 json.RawMessage + JsonBuildObject_3 json.RawMessage + JsonBuildObject_4 json.RawMessage +} + +func (q *Queries) SelectJSONBuildObject(ctx context.Context) (SelectJSONBuildObjectRow, error) { + row := q.db.QueryRowContext(ctx, selectJSONBuildObject) + var i SelectJSONBuildObjectRow + err := row.Scan( + &i.JsonBuildObject, + &i.JsonBuildObject_2, + &i.JsonBuildObject_3, + &i.JsonBuildObject_4, + ) + return i, err +} diff --git a/internal/endtoend/testdata/json_build/query.sql b/internal/endtoend/testdata/json_build/query.sql new file mode 100644 index 0000000000..eafb8477a7 --- /dev/null +++ b/internal/endtoend/testdata/json_build/query.sql @@ -0,0 +1,13 @@ +-- name: SelectJSONBuildObject :one +SELECT + json_build_object('foo'), + json_build_object('foo', 1), + json_build_object('foo', 1, 2), + json_build_object('foo', 1, 2, 'bar'); + +-- name: SelectJSONBuildArray :one +SELECT + json_build_array(1), + json_build_array(1, 2), + json_build_array(1, 2, 'foo'), + json_build_array(1, 2, 'foo', 4); diff --git a/internal/endtoend/testdata/json_build/sqlc.json b/internal/endtoend/testdata/json_build/sqlc.json new file mode 100644 index 0000000000..c72b6132d5 --- /dev/null +++ b/internal/endtoend/testdata/json_build/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "query.sql", + "queries": "query.sql" + } + ] +} From cb66d5271ad5af3f981e825dabd9b3e0e39544aa Mon Sep 17 00:00:00 2001 From: Kyle Conroy Date: Thu, 19 Nov 2020 08:49:53 -0800 Subject: [PATCH 2/2] oops --- internal/engine/postgresql/pg_catalog.go | 18 ++++++++++++++---- internal/sql/catalog/catalog.go | 1 + internal/sql/catalog/public.go | 22 +++++++++++++++++----- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/internal/engine/postgresql/pg_catalog.go b/internal/engine/postgresql/pg_catalog.go index 4868272f94..ba2652ba40 100644 --- a/internal/engine/postgresql/pg_catalog.go +++ b/internal/engine/postgresql/pg_catalog.go @@ -11646,13 +11646,23 @@ func genPGCatalog() *catalog.Schema { ReturnType: &ast.TypeName{Name: "integer"}, }, { - Name: "json_build_array", - Args: []*catalog.Argument{}, + Name: "json_build_array", + Args: []*catalog.Argument{ + { + Type: &ast.TypeName{Name: "any"}, + Variadic: true, + }, + }, ReturnType: &ast.TypeName{Name: "json"}, }, { - Name: "json_build_object", - Args: []*catalog.Argument{}, + Name: "json_build_object", + Args: []*catalog.Argument{ + { + Type: &ast.TypeName{Name: "any"}, + Variadic: true, + }, + }, ReturnType: &ast.TypeName{Name: "json"}, }, { diff --git a/internal/sql/catalog/catalog.go b/internal/sql/catalog/catalog.go index 38d93b6d60..403d82302e 100644 --- a/internal/sql/catalog/catalog.go +++ b/internal/sql/catalog/catalog.go @@ -251,6 +251,7 @@ type Argument struct { Name string Type *ast.TypeName HasDefault bool + Variadic bool Mode ast.FuncParamMode } diff --git a/internal/sql/catalog/public.go b/internal/sql/catalog/public.go index 883231ec59..864a6d29ea 100644 --- a/internal/sql/catalog/public.go +++ b/internal/sql/catalog/public.go @@ -66,20 +66,32 @@ func (c *Catalog) ResolveFuncCall(call *ast.FuncCall) (*Function, error) { for _, fun := range funs { args := fun.InArgs() var defaults int + var variadic bool known := map[string]struct{}{} for _, arg := range args { if arg.HasDefault { defaults += 1 } + if arg.Variadic { + variadic = true + } if arg.Name != "" { known[arg.Name] = struct{}{} } } - if (len(named) + len(positional)) > len(args) { - continue - } - if (len(named) + len(positional)) < (len(args) - defaults) { - continue + + if variadic { + // For now, assume variadic fucntions can't also have defaults + if (len(named) + len(positional)) < len(args) { + continue + } + } else { + if (len(named) + len(positional)) > len(args) { + continue + } + if (len(named) + len(positional)) < (len(args) - defaults) { + continue + } } // Validate that the provided named arguments exist in the function