From 41d9eca65fee1b9417d54fa5af4e4fe269f2246f Mon Sep 17 00:00:00 2001 From: LudovicDebost <104353148+LudovicDebost@users.noreply.github.com> Date: Fri, 16 Jun 2023 12:06:16 +0200 Subject: [PATCH 1/2] fix: MySQL slice with database/sql type --- .../golang/templates/stdlib/queryCode.tmpl | 12 ++-- .../testdata/sqlc_slice/mysql/go/models.go | 5 +- .../testdata/sqlc_slice/mysql/go/query.sql.go | 71 ++++++++++++++----- .../testdata/sqlc_slice/mysql/query.sql | 6 +- .../testdata/sqlc_slice/sqlite/go/models.go | 5 +- .../sqlc_slice/sqlite/go/query.sql.go | 71 ++++++++++++++----- .../testdata/sqlc_slice/sqlite/query.sql | 6 +- 7 files changed, 134 insertions(+), 42 deletions(-) diff --git a/internal/codegen/golang/templates/stdlib/queryCode.tmpl b/internal/codegen/golang/templates/stdlib/queryCode.tmpl index 213477b15c..cde37d81ed 100644 --- a/internal/codegen/golang/templates/stdlib/queryCode.tmpl +++ b/internal/codegen/golang/templates/stdlib/queryCode.tmpl @@ -120,7 +120,7 @@ func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}} {{define "queryCodeStdExec"}} {{- if .Arg.HasSqlcSlices }} - sql := {{.ConstantName}} + query := {{.ConstantName}} var queryParams []interface{} {{- if .Arg.Struct }} {{- $arg := .Arg }} @@ -130,9 +130,9 @@ func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}} for _, v := range {{$arg.Name}}.{{.Name}} { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:{{.Column.Name}}*/?", strings.Repeat(",?", len({{$arg.Name}}.{{.Name}}))[1:], 1) + query = strings.Replace(query, "/*SLICE:{{.Column.Name}}*/?", strings.Repeat(",?", len({{$arg.Name}}.{{.Name}}))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:{{.Column.Name}}*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:{{.Column.Name}}*/?", "NULL", 1) } {{- else }} queryParams = append(queryParams, {{$arg.Name}}.{{.Name}}) @@ -147,12 +147,12 @@ func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}} for _, v := range {{.Arg.Name}} { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:{{.Arg.Column.Name}}*/?", strings.Repeat(",?", len({{.Arg.Name}}))[1:], 1) + query = strings.Replace(query, "/*SLICE:{{.Arg.Column.Name}}*/?", strings.Repeat(",?", len({{.Arg.Name}}))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:{{.Arg.Column.Name}}*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:{{.Arg.Column.Name}}*/?", "NULL", 1) } {{- end }} - {{ queryRetval . }} {{ queryMethod . }}(ctx, sql, queryParams...) + {{ queryRetval . }} {{ queryMethod . }}(ctx, query, queryParams...) {{- else if emitPreparedQueries }} {{- queryRetval . }} {{ queryMethod . }}(ctx, q.{{.FieldName}}, {{.ConstantName}}, {{.Arg.Params}}) {{- else}} diff --git a/internal/endtoend/testdata/sqlc_slice/mysql/go/models.go b/internal/endtoend/testdata/sqlc_slice/mysql/go/models.go index ecc6ffe82f..904f89e5ec 100644 --- a/internal/endtoend/testdata/sqlc_slice/mysql/go/models.go +++ b/internal/endtoend/testdata/sqlc_slice/mysql/go/models.go @@ -4,9 +4,12 @@ package querytest -import () +import ( + "database/sql" +) type Foo struct { ID int32 Name string + Bar sql.NullString } diff --git a/internal/endtoend/testdata/sqlc_slice/mysql/go/query.sql.go b/internal/endtoend/testdata/sqlc_slice/mysql/go/query.sql.go index e80c44fd41..90d9a0efb2 100644 --- a/internal/endtoend/testdata/sqlc_slice/mysql/go/query.sql.go +++ b/internal/endtoend/testdata/sqlc_slice/mysql/go/query.sql.go @@ -7,9 +7,48 @@ package querytest import ( "context" + "database/sql" "strings" ) +const funcNullable = `-- name: FuncNullable :many +SELECT bar FROM foo +WHERE id IN (/*SLICE:favourites*/?) +` + +func (q *Queries) FuncNullable(ctx context.Context, favourites []int32) ([]sql.NullString, error) { + query := funcNullable + var queryParams []interface{} + if len(favourites) > 0 { + for _, v := range favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const funcParamIdent = `-- name: FuncParamIdent :many SELECT name FROM foo WHERE name = ? @@ -22,18 +61,18 @@ type FuncParamIdentParams struct { } func (q *Queries) FuncParamIdent(ctx context.Context, arg FuncParamIdentParams) ([]string, error) { - sql := funcParamIdent + query := funcParamIdent var queryParams []interface{} queryParams = append(queryParams, arg.Slug) if len(arg.Favourites) > 0 { for _, v := range arg.Favourites { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:favourites*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) } - rows, err := q.db.QueryContext(ctx, sql, queryParams...) + rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err } @@ -61,17 +100,17 @@ WHERE id IN (/*SLICE:favourites*/?) ` func (q *Queries) FuncParamSoloArg(ctx context.Context, favourites []int32) ([]string, error) { - sql := funcParamSoloArg + query := funcParamSoloArg var queryParams []interface{} if len(favourites) > 0 { for _, v := range favourites { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:favourites*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) } - rows, err := q.db.QueryContext(ctx, sql, queryParams...) + rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err } @@ -105,18 +144,18 @@ type FuncParamStringParams struct { } func (q *Queries) FuncParamString(ctx context.Context, arg FuncParamStringParams) ([]string, error) { - sql := funcParamString + query := funcParamString var queryParams []interface{} queryParams = append(queryParams, arg.Slug) if len(arg.Favourites) > 0 { for _, v := range arg.Favourites { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:favourites*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) } - rows, err := q.db.QueryContext(ctx, sql, queryParams...) + rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err } @@ -149,17 +188,17 @@ type SliceExecParams struct { } func (q *Queries) SliceExec(ctx context.Context, arg SliceExecParams) error { - sql := sliceExec + query := sliceExec var queryParams []interface{} queryParams = append(queryParams, arg.Slug) if len(arg.Favourites) > 0 { for _, v := range arg.Favourites { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:favourites*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) } - _, err := q.db.ExecContext(ctx, sql, queryParams...) + _, err := q.db.ExecContext(ctx, query, queryParams...) return err } diff --git a/internal/endtoend/testdata/sqlc_slice/mysql/query.sql b/internal/endtoend/testdata/sqlc_slice/mysql/query.sql index 9168ed9456..e68046b0b4 100644 --- a/internal/endtoend/testdata/sqlc_slice/mysql/query.sql +++ b/internal/endtoend/testdata/sqlc_slice/mysql/query.sql @@ -1,4 +1,4 @@ -CREATE TABLE foo (id int not null, name text not null); +CREATE TABLE foo (id int not null, name text not null, bar text null); /* name: FuncParamIdent :many */ SELECT name FROM foo @@ -17,3 +17,7 @@ WHERE id IN (sqlc.slice('favourites')); /* name: SliceExec :exec */ UPDATE foo SET name = sqlc.arg(slug) WHERE id IN (sqlc.slice(favourites)); + +/* name: FuncNullable :many */ +SELECT bar FROM foo +WHERE id IN (sqlc.slice('favourites')); \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_slice/sqlite/go/models.go b/internal/endtoend/testdata/sqlc_slice/sqlite/go/models.go index ad4869d9e5..c5b5a0c6c4 100644 --- a/internal/endtoend/testdata/sqlc_slice/sqlite/go/models.go +++ b/internal/endtoend/testdata/sqlc_slice/sqlite/go/models.go @@ -4,9 +4,12 @@ package querytest -import () +import ( + "database/sql" +) type Foo struct { ID int64 Name string + Bar sql.NullString } diff --git a/internal/endtoend/testdata/sqlc_slice/sqlite/go/query.sql.go b/internal/endtoend/testdata/sqlc_slice/sqlite/go/query.sql.go index e14e1fe639..a66b6eb180 100644 --- a/internal/endtoend/testdata/sqlc_slice/sqlite/go/query.sql.go +++ b/internal/endtoend/testdata/sqlc_slice/sqlite/go/query.sql.go @@ -7,9 +7,48 @@ package querytest import ( "context" + "database/sql" "strings" ) +const funcNullable = `-- name: FuncNullable :many +SELECT bar FROM foo +WHERE id IN (/*SLICE:favourites*/?) +` + +func (q *Queries) FuncNullable(ctx context.Context, favourites []int64) ([]sql.NullString, error) { + query := funcNullable + var queryParams []interface{} + if len(favourites) > 0 { + for _, v := range favourites { + queryParams = append(queryParams, v) + } + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + } else { + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) + } + rows, err := q.db.QueryContext(ctx, query, queryParams...) + if err != nil { + return nil, err + } + defer rows.Close() + var items []sql.NullString + for rows.Next() { + var bar sql.NullString + if err := rows.Scan(&bar); err != nil { + return nil, err + } + items = append(items, bar) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const funcParamIdent = `-- name: FuncParamIdent :many SELECT name FROM foo WHERE name = ?1 @@ -22,18 +61,18 @@ type FuncParamIdentParams struct { } func (q *Queries) FuncParamIdent(ctx context.Context, arg FuncParamIdentParams) ([]string, error) { - sql := funcParamIdent + query := funcParamIdent var queryParams []interface{} queryParams = append(queryParams, arg.Slug) if len(arg.Favourites) > 0 { for _, v := range arg.Favourites { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:favourites*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) } - rows, err := q.db.QueryContext(ctx, sql, queryParams...) + rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err } @@ -61,17 +100,17 @@ WHERE id IN (/*SLICE:favourites*/?) ` func (q *Queries) FuncParamSoloArg(ctx context.Context, favourites []int64) ([]string, error) { - sql := funcParamSoloArg + query := funcParamSoloArg var queryParams []interface{} if len(favourites) > 0 { for _, v := range favourites { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(favourites))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:favourites*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) } - rows, err := q.db.QueryContext(ctx, sql, queryParams...) + rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err } @@ -105,18 +144,18 @@ type FuncParamStringParams struct { } func (q *Queries) FuncParamString(ctx context.Context, arg FuncParamStringParams) ([]string, error) { - sql := funcParamString + query := funcParamString var queryParams []interface{} queryParams = append(queryParams, arg.Slug) if len(arg.Favourites) > 0 { for _, v := range arg.Favourites { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:favourites*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) } - rows, err := q.db.QueryContext(ctx, sql, queryParams...) + rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err } @@ -149,17 +188,17 @@ type SliceExecParams struct { } func (q *Queries) SliceExec(ctx context.Context, arg SliceExecParams) error { - sql := sliceExec + query := sliceExec var queryParams []interface{} queryParams = append(queryParams, arg.Slug) if len(arg.Favourites) > 0 { for _, v := range arg.Favourites { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", strings.Repeat(",?", len(arg.Favourites))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:favourites*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:favourites*/?", "NULL", 1) } - _, err := q.db.ExecContext(ctx, sql, queryParams...) + _, err := q.db.ExecContext(ctx, query, queryParams...) return err } diff --git a/internal/endtoend/testdata/sqlc_slice/sqlite/query.sql b/internal/endtoend/testdata/sqlc_slice/sqlite/query.sql index 9168ed9456..3cb6c13fee 100644 --- a/internal/endtoend/testdata/sqlc_slice/sqlite/query.sql +++ b/internal/endtoend/testdata/sqlc_slice/sqlite/query.sql @@ -1,4 +1,4 @@ -CREATE TABLE foo (id int not null, name text not null); +CREATE TABLE foo (id int not null, name text not null, bar text); /* name: FuncParamIdent :many */ SELECT name FROM foo @@ -17,3 +17,7 @@ WHERE id IN (sqlc.slice('favourites')); /* name: SliceExec :exec */ UPDATE foo SET name = sqlc.arg(slug) WHERE id IN (sqlc.slice(favourites)); + +/* name: FuncNullable :many */ +SELECT bar FROM foo +WHERE id IN (sqlc.slice('favourites')); \ No newline at end of file From 551a16ce9b7bde766b887dc61f16c77214d5f3f2 Mon Sep 17 00:00:00 2001 From: LudovicDebost <104353148+LudovicDebost@users.noreply.github.com> Date: Tue, 20 Jun 2023 17:16:00 +0200 Subject: [PATCH 2/2] fixed examples --- examples/booktest/sqlite/query.sql.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/booktest/sqlite/query.sql.go b/examples/booktest/sqlite/query.sql.go index 340ba77920..500130c892 100644 --- a/examples/booktest/sqlite/query.sql.go +++ b/examples/booktest/sqlite/query.sql.go @@ -32,17 +32,17 @@ type BooksByTagsRow struct { } func (q *Queries) BooksByTags(ctx context.Context, tags []string) ([]BooksByTagsRow, error) { - sql := booksByTags + query := booksByTags var queryParams []interface{} if len(tags) > 0 { for _, v := range tags { queryParams = append(queryParams, v) } - sql = strings.Replace(sql, "/*SLICE:tags*/?", strings.Repeat(",?", len(tags))[1:], 1) + query = strings.Replace(query, "/*SLICE:tags*/?", strings.Repeat(",?", len(tags))[1:], 1) } else { - sql = strings.Replace(sql, "/*SLICE:tags*/?", "NULL", 1) + query = strings.Replace(query, "/*SLICE:tags*/?", "NULL", 1) } - rows, err := q.db.QueryContext(ctx, sql, queryParams...) + rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err }