diff --git a/docs/reference/query-annotations.md b/docs/reference/query-annotations.md index cb0b299310..024737594d 100644 --- a/docs/reference/query-annotations.md +++ b/docs/reference/query-annotations.md @@ -59,6 +59,24 @@ func (q *Queries) DeleteAllAuthors(ctx context.Context) (int64, error) { } ``` +## `:execlastid` + +The generated method will return the number generated by the database from the +[result](https://golang.org/pkg/database/sql/#Result) returned by +[ExecContext](https://golang.org/pkg/database/sql/#DB.ExecContext). + +```sql +-- name: InsertAuthor :execlastid +INSERT INTO authors (name) VALUES (?); +``` + +```go +func (q *Queries) InsertAuthor(ctx context.Context, name string) (int64, error) { + _, err := q.db.ExecContext(ctx, insertAuthor, name) + // ... +} +``` + ## `:many` The generated method will return a slice of records via diff --git a/internal/codegen/golang/templates/stdlib/interfaceCode.tmpl b/internal/codegen/golang/templates/stdlib/interfaceCode.tmpl index 3b59479801..3cbefe6df4 100644 --- a/internal/codegen/golang/templates/stdlib/interfaceCode.tmpl +++ b/internal/codegen/golang/templates/stdlib/interfaceCode.tmpl @@ -38,6 +38,15 @@ {{end -}} {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (int64, error) {{- end}} + {{- if and (eq .Cmd ":execlastid") ($dbtxParam) }} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (int64, error) + {{- else if eq .Cmd ":execlastid"}} + {{range .Comments}}//{{.}} + {{end -}} + {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (int64, error) + {{- end}} {{- if and (eq .Cmd ":execresult") ($dbtxParam) }} {{range .Comments}}//{{.}} {{end -}} diff --git a/internal/codegen/golang/templates/stdlib/queryCode.tmpl b/internal/codegen/golang/templates/stdlib/queryCode.tmpl index 421cf7958f..f496d8959e 100644 --- a/internal/codegen/golang/templates/stdlib/queryCode.tmpl +++ b/internal/codegen/golang/templates/stdlib/queryCode.tmpl @@ -124,6 +124,28 @@ func (q *Queries) {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (int64, er } {{end}} +{{if eq .Cmd ":execlastid"}} +{{range .Comments}}//{{.}} +{{end -}} +{{- if $.EmitMethodsWithDBArgument -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (int64, error) { +{{- else -}} +func (q *Queries) {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) (int64, error) { +{{- end -}} + {{- if $.EmitPreparedQueries}} + result, err := q.exec(ctx, q.{{.FieldName}}, {{.ConstantName}}, {{.Arg.Params}}) + {{- else if $.EmitMethodsWithDBArgument}} + result, err := db.ExecContext(ctx, {{.ConstantName}}, {{.Arg.Params}}) + {{- else}} + result, err := q.db.ExecContext(ctx, {{.ConstantName}}, {{.Arg.Params}}) + {{- end}} + if err != nil { + return 0, err + } + return result.LastInsertId() +} +{{end}} + {{if eq .Cmd ":execresult"}} {{range .Comments}}//{{.}} {{end -}} diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/db.go b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/db.go new file mode 100644 index 0000000000..6a99519302 --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/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/exec_lastid/go_postgresql_stdlib/go/models.go b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/models.go new file mode 100644 index 0000000000..7c3b98644d --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/models.go @@ -0,0 +1,9 @@ +// Code generated by sqlc. DO NOT EDIT. + +package querytest + +import () + +type Bar struct { + ID int32 +} diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/querier.go b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/querier.go new file mode 100644 index 0000000000..5c125e409e --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/querier.go @@ -0,0 +1,13 @@ +// Code generated by sqlc. DO NOT EDIT. + +package querytest + +import ( + "context" +) + +type Querier interface { + InsertBar(ctx context.Context) (int64, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/query.sql.go b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/query.sql.go new file mode 100644 index 0000000000..fd0d1ed903 --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/go/query.sql.go @@ -0,0 +1,20 @@ +// Code generated by sqlc. DO NOT EDIT. +// source: query.sql + +package querytest + +import ( + "context" +) + +const insertBar = `-- name: InsertBar :execlastid +INSERT INTO bar () VALUES () +` + +func (q *Queries) InsertBar(ctx context.Context) (int64, error) { + result, err := q.db.ExecContext(ctx, insertBar) + if err != nil { + return 0, err + } + return result.LastInsertId() +} diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/query.sql b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/query.sql new file mode 100644 index 0000000000..a8203f0a78 --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/query.sql @@ -0,0 +1,4 @@ +CREATE TABLE bar (id integer(10) NOT NULL AUTO_INCREMENT PRIMARY KEY); + +-- name: InsertBar :execlastid +INSERT INTO bar () VALUES (); \ No newline at end of file diff --git a/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/sqlc.json b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/sqlc.json new file mode 100644 index 0000000000..b199a32720 --- /dev/null +++ b/internal/endtoend/testdata/exec_lastid/go_postgresql_stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "querytest", + "engine": "mysql", + "schema": "query.sql", + "queries": "query.sql", + "emit_interface": true + } + ] +} \ No newline at end of file diff --git a/internal/metadata/meta.go b/internal/metadata/meta.go index 67a9e351c9..59a1add763 100644 --- a/internal/metadata/meta.go +++ b/internal/metadata/meta.go @@ -16,6 +16,7 @@ const ( CmdExec = ":exec" CmdExecResult = ":execresult" CmdExecRows = ":execrows" + CmdExecLastId = ":execlastid" CmdMany = ":many" CmdOne = ":one" CmdCopyFrom = ":copyfrom" @@ -83,7 +84,7 @@ func Parse(t string, commentStyle CommentSyntax) (string, string, error) { part = part[:len(part)-1] // removes the trailing "*/" element } if len(part) == 2 { - return "", "", fmt.Errorf("missing query type [':one', ':many', ':exec', ':execrows', ':execresult', ':copyfrom', 'batchexec', 'batchmany', 'batchone']: %s", line) + return "", "", fmt.Errorf("missing query type [':one', ':many', ':exec', ':execrows', ':execlastid', ':execresult', ':copyfrom', 'batchexec', 'batchmany', 'batchone']: %s", line) } if len(part) != 4 { return "", "", fmt.Errorf("invalid query comment: %s", line) @@ -91,7 +92,7 @@ func Parse(t string, commentStyle CommentSyntax) (string, string, error) { queryName := part[2] queryType := strings.TrimSpace(part[3]) switch queryType { - case CmdOne, CmdMany, CmdExec, CmdExecResult, CmdExecRows, CmdCopyFrom, CmdBatchExec, CmdBatchMany, CmdBatchOne: + case CmdOne, CmdMany, CmdExec, CmdExecResult, CmdExecRows, CmdExecLastId, CmdCopyFrom, CmdBatchExec, CmdBatchMany, CmdBatchOne: default: return "", "", fmt.Errorf("invalid query type: %s", queryType) }