diff --git a/docs/howto/embedding.md b/docs/howto/embedding.md index 5ea8cbbc0a..7649c87481 100644 --- a/docs/howto/embedding.md +++ b/docs/howto/embedding.md @@ -58,4 +58,24 @@ type ScoreAndTestsRow struct { Student Student TestScore TestScore } -``` \ No newline at end of file +``` + +sqlc can generate structs with fields based on the alias inside the macro `sqlc.embed()` by adding the `emit_embed_alias` key to the configuration file as it shows on [configuration reference](../reference/config.md). + +```sql +-- name: ListUserLink :many +SELECT + sqlc.embed(owner), + sqlc.embed(consumer) +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id; +``` + +``` +type ListUserLinkRow struct { + Owner User + Consumer User +} +``` diff --git a/docs/reference/config.md b/docs/reference/config.md index 2629babf4b..03f4db36a1 100644 --- a/docs/reference/config.md +++ b/docs/reference/config.md @@ -163,6 +163,8 @@ The `gen` mapping supports the following keys: - `emit_all_enum_values`: - If true, emit a function per enum type that returns all valid enum values. +- `emit_embed_alias`: + - If true, use alias name inside `sqlc.embed()` macro instead of table name for field name. Defaults to `false`. - `emit_sql_as_comment`: - If true, emits the SQL statement as a code-block comment above the generated function, appending to any existing comments. Defaults to `false`. - `build_tags`: @@ -412,6 +414,7 @@ packages: emit_pointers_for_null_types: false emit_enum_valid_method: false emit_all_enum_values: false + emit_embed_alias: false build_tags: "some_tag" json_tags_case_style: "camel" omit_unused_structs: false @@ -467,6 +470,8 @@ Each mapping in the `packages` collection has the following keys: - `emit_all_enum_values`: - If true, emit a function per enum type that returns all valid enum values. +- `emit_embed_alias`: + - If true, use alias name inside `sqlc.embed()` macro instead of table name for field name. Defaults to `false`. - `build_tags`: - If set, add a `//go:build ` directive at the beginning of each generated Go file. - `json_tags_case_style`: diff --git a/internal/codegen/golang/gen.go b/internal/codegen/golang/gen.go index 5b7977f500..bb887d1a1e 100644 --- a/internal/codegen/golang/gen.go +++ b/internal/codegen/golang/gen.go @@ -37,6 +37,7 @@ type tmplCtx struct { EmitMethodsWithDBArgument bool EmitEnumValidMethod bool EmitAllEnumValues bool + EmitEmbedAlias bool UsesCopyFrom bool UsesBatch bool OmitSqlcVersion bool @@ -177,6 +178,7 @@ func generate(req *plugin.GenerateRequest, options *opts.Options, enums []Enum, EmitMethodsWithDBArgument: options.EmitMethodsWithDbArgument, EmitEnumValidMethod: options.EmitEnumValidMethod, EmitAllEnumValues: options.EmitAllEnumValues, + EmitEmbedAlias: options.EmitEmbedAlias, UsesCopyFrom: usesCopyFrom(queries), UsesBatch: usesBatch(queries), SQLDriver: parseDriver(options.SqlPackage), diff --git a/internal/codegen/golang/opts/options.go b/internal/codegen/golang/opts/options.go index 30a6c2246c..dfa2ad075f 100644 --- a/internal/codegen/golang/opts/options.go +++ b/internal/codegen/golang/opts/options.go @@ -24,6 +24,7 @@ type Options struct { EmitPointersForNullTypes bool `json:"emit_pointers_for_null_types" yaml:"emit_pointers_for_null_types"` EmitEnumValidMethod bool `json:"emit_enum_valid_method,omitempty" yaml:"emit_enum_valid_method"` EmitAllEnumValues bool `json:"emit_all_enum_values,omitempty" yaml:"emit_all_enum_values"` + EmitEmbedAlias bool `json:"emit_embed_alias,omitempty" yaml:"emit_embed_alias"` EmitSqlAsComment bool `json:"emit_sql_as_comment,omitempty" yaml:"emit_sql_as_comment"` JsonTagsCaseStyle string `json:"json_tags_case_style,omitempty" yaml:"json_tags_case_style"` Package string `json:"package" yaml:"package"` diff --git a/internal/codegen/golang/result.go b/internal/codegen/golang/result.go index 515d0a654f..e07fc82e7a 100644 --- a/internal/codegen/golang/result.go +++ b/internal/codegen/golang/result.go @@ -124,7 +124,7 @@ type goEmbed struct { // look through all the structs and attempt to find a matching one to embed // We need the name of the struct and its field names. -func newGoEmbed(embed *plugin.Identifier, structs []Struct, defaultSchema string) *goEmbed { +func newGoEmbed(options *opts.Options, columnName string, embed *plugin.Identifier, structs []Struct, defaultSchema string) *goEmbed { if embed == nil { return nil } @@ -141,13 +141,16 @@ func newGoEmbed(embed *plugin.Identifier, structs []Struct, defaultSchema string } fields := make([]Field, len(s.Fields)) - for i, f := range s.Fields { - fields[i] = f + copy(fields, s.Fields) + + structName := s.Name + if options.EmitEmbedAlias && s.Table.Name != columnName { + structName = columnName } return &goEmbed{ modelType: s.Name, - modelName: s.Name, + modelName: structName, fields: fields, } } @@ -306,7 +309,7 @@ func buildQueries(req *plugin.GenerateRequest, options *opts.Options, structs [] columns = append(columns, goColumn{ id: i, Column: c, - embed: newGoEmbed(c.EmbedTable, structs, req.Catalog.DefaultSchema), + embed: newGoEmbed(options, c.Name, c.EmbedTable, structs, req.Catalog.DefaultSchema), }) } var err error diff --git a/internal/compiler/output_columns.go b/internal/compiler/output_columns.go index dbdbe252b3..b02415c5ba 100644 --- a/internal/compiler/output_columns.go +++ b/internal/compiler/output_columns.go @@ -260,7 +260,7 @@ func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, er // add a column with a reference to an embedded table if embed, ok := qc.embeds.Find(n); ok { cols = append(cols, &Column{ - Name: embed.Table.Name, + Name: embed.Name(), EmbedTable: embed.Table, }) continue diff --git a/internal/config/v_one.go b/internal/config/v_one.go index 8efa9f42fc..f1625ba2e9 100644 --- a/internal/config/v_one.go +++ b/internal/config/v_one.go @@ -41,6 +41,7 @@ type v1PackageSettings struct { EmitPointersForNullTypes bool `json:"emit_pointers_for_null_types" yaml:"emit_pointers_for_null_types"` EmitEnumValidMethod bool `json:"emit_enum_valid_method,omitempty" yaml:"emit_enum_valid_method"` EmitAllEnumValues bool `json:"emit_all_enum_values,omitempty" yaml:"emit_all_enum_values"` + EmitEmbedAlias bool `json:"emit_embed_alias,omitempty" yaml:"emit_embed_alias"` EmitSqlAsComment bool `json:"emit_sql_as_comment,omitempty" yaml:"emit_sql_as_comment"` JSONTagsCaseStyle string `json:"json_tags_case_style,omitempty" yaml:"json_tags_case_style"` SQLPackage string `json:"sql_package" yaml:"sql_package"` @@ -151,6 +152,7 @@ func (c *V1GenerateSettings) Translate() Config { EmitPointersForNullTypes: pkg.EmitPointersForNullTypes, EmitEnumValidMethod: pkg.EmitEnumValidMethod, EmitAllEnumValues: pkg.EmitAllEnumValues, + EmitEmbedAlias: pkg.EmitEmbedAlias, EmitSqlAsComment: pkg.EmitSqlAsComment, Package: pkg.Name, Out: pkg.Path, diff --git a/internal/endtoend/testdata/sqlc_embed/mysql/go/models.go b/internal/endtoend/testdata/sqlc_embed/mysql/go/models.go index f10836dc65..8108dd0dde 100644 --- a/internal/endtoend/testdata/sqlc_embed/mysql/go/models.go +++ b/internal/endtoend/testdata/sqlc_embed/mysql/go/models.go @@ -23,3 +23,8 @@ type User struct { Name string Age sql.NullInt32 } + +type UserLink struct { + OwnerID int32 + ConsumerID int32 +} diff --git a/internal/endtoend/testdata/sqlc_embed/mysql/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed/mysql/go/query.sql.go index 1695fe345d..47c46e537b 100644 --- a/internal/endtoend/testdata/sqlc_embed/mysql/go/query.sql.go +++ b/internal/endtoend/testdata/sqlc_embed/mysql/go/query.sql.go @@ -56,6 +56,51 @@ func (q *Queries) Join(ctx context.Context) (JoinRow, error) { return i, err } +const listUserLink = `-- name: ListUserLink :many +SELECT + owner.id, owner.name, owner.age, + consumers.id, consumers.name, consumers.age +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumers ON consumers.id = user_links.consumer_id +` + +type ListUserLinkRow struct { + User User + User_2 User +} + +func (q *Queries) ListUserLink(ctx context.Context) ([]ListUserLinkRow, error) { + rows, err := q.db.QueryContext(ctx, listUserLink) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserLinkRow + for rows.Next() { + var i ListUserLinkRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ); 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 +} + const only = `-- name: Only :one SELECT users.id, users.name, users.age FROM users ` diff --git a/internal/endtoend/testdata/sqlc_embed/mysql/query.sql b/internal/endtoend/testdata/sqlc_embed/mysql/query.sql index 7822145508..c0d60038df 100644 --- a/internal/endtoend/testdata/sqlc_embed/mysql/query.sql +++ b/internal/endtoend/testdata/sqlc_embed/mysql/query.sql @@ -22,4 +22,13 @@ SELECT sqlc.embed(bu) FROM baz.users bu; -- name: WithCrossSchema :many SELECT sqlc.embed(users), sqlc.embed(bu) FROM users -INNER JOIN baz.users bu ON users.id = bu.id; \ No newline at end of file +INNER JOIN baz.users bu ON users.id = bu.id; + +-- name: ListUserLink :many +SELECT + sqlc.embed(owner), + sqlc.embed(consumers) +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumers ON consumers.id = user_links.consumer_id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed/mysql/schema.sql b/internal/endtoend/testdata/sqlc_embed/mysql/schema.sql index 28751aa16e..1fe4e5d97c 100644 --- a/internal/endtoend/testdata/sqlc_embed/mysql/schema.sql +++ b/internal/endtoend/testdata/sqlc_embed/mysql/schema.sql @@ -16,4 +16,8 @@ CREATE TABLE baz.users ( name varchar(255) NOT NULL ); - +CREATE TABLE user_links ( + owner_id integer NOT NULL, + consumer_id integer NOT NULL, + PRIMARY KEY (owner_id, consumer_id) +); diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/models.go b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/models.go index 5d38d329c2..4a08e5d047 100644 --- a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/models.go +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/models.go @@ -23,3 +23,8 @@ type User struct { Name string `db:"name" json:"name"` Age sql.NullInt32 `db:"age" json:"age"` } + +type UserLink struct { + OwnerID int32 `db:"owner_id" json:"owner_id"` + ConsumerID int32 `db:"consumer_id" json:"consumer_id"` +} diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/query.sql.go index 6da4f12a25..72f8351369 100644 --- a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/query.sql.go +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/go/query.sql.go @@ -56,6 +56,48 @@ func (q *Queries) Join(ctx context.Context) (JoinRow, error) { return i, err } +const listUserLink = `-- name: ListUserLink :many +SELECT + owner.id, owner.name, owner.age, + consumer.id, consumer.name, consumer.age +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id +` + +type ListUserLinkRow struct { + User User `db:"user" json:"user"` + User_2 User `db:"user_2" json:"user_2"` +} + +func (q *Queries) ListUserLink(ctx context.Context) ([]ListUserLinkRow, error) { + rows, err := q.db.Query(ctx, listUserLink) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserLinkRow + for rows.Next() { + var i ListUserLinkRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const only = `-- name: Only :one SELECT users.id, users.name, users.age FROM users ` diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/query.sql b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/query.sql index 7822145508..a35c345639 100644 --- a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/query.sql +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/query.sql @@ -22,4 +22,13 @@ SELECT sqlc.embed(bu) FROM baz.users bu; -- name: WithCrossSchema :many SELECT sqlc.embed(users), sqlc.embed(bu) FROM users -INNER JOIN baz.users bu ON users.id = bu.id; \ No newline at end of file +INNER JOIN baz.users bu ON users.id = bu.id; + +-- name: ListUserLink :many +SELECT + sqlc.embed(owner), + sqlc.embed(consumer) +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/schema.sql b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/schema.sql index 28751aa16e..1fe4e5d97c 100644 --- a/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/schema.sql +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/pgx/schema.sql @@ -16,4 +16,8 @@ CREATE TABLE baz.users ( name varchar(255) NOT NULL ); - +CREATE TABLE user_links ( + owner_id integer NOT NULL, + consumer_id integer NOT NULL, + PRIMARY KEY (owner_id, consumer_id) +); diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/models.go index 746747ed6f..e030275079 100644 --- a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/models.go +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/models.go @@ -24,3 +24,8 @@ type User struct { Name string Age sql.NullInt32 } + +type UserLink struct { + OwnerID int32 + ConsumerID int32 +} diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/query.sql.go index 96d89db67c..1df4ddfadd 100644 --- a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/query.sql.go +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/go/query.sql.go @@ -59,6 +59,51 @@ func (q *Queries) Join(ctx context.Context) (JoinRow, error) { return i, err } +const listUserLink = `-- name: ListUserLink :many +SELECT + owner.id, owner.name, owner.age, + consumer.id, consumer.name, consumer.age +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id +` + +type ListUserLinkRow struct { + User User + User_2 User +} + +func (q *Queries) ListUserLink(ctx context.Context) ([]ListUserLinkRow, error) { + rows, err := q.db.QueryContext(ctx, listUserLink) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserLinkRow + for rows.Next() { + var i ListUserLinkRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ); 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 +} + const only = `-- name: Only :one SELECT users.id, users.name, users.age FROM users ` diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/query.sql b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/query.sql index 7822145508..a35c345639 100644 --- a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/query.sql +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/query.sql @@ -22,4 +22,13 @@ SELECT sqlc.embed(bu) FROM baz.users bu; -- name: WithCrossSchema :many SELECT sqlc.embed(users), sqlc.embed(bu) FROM users -INNER JOIN baz.users bu ON users.id = bu.id; \ No newline at end of file +INNER JOIN baz.users bu ON users.id = bu.id; + +-- name: ListUserLink :many +SELECT + sqlc.embed(owner), + sqlc.embed(consumer) +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/schema.sql index 7a60bb1659..0307e3facb 100644 --- a/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/schema.sql +++ b/internal/endtoend/testdata/sqlc_embed/postgresql/stdlib/schema.sql @@ -17,4 +17,8 @@ CREATE TABLE baz.users ( name varchar(255) NOT NULL ); - +CREATE TABLE user_links ( + owner_id integer NOT NULL, + consumer_id integer NOT NULL, + PRIMARY KEY (owner_id, consumer_id) +); diff --git a/internal/endtoend/testdata/sqlc_embed/sqlite/go/models.go b/internal/endtoend/testdata/sqlc_embed/sqlite/go/models.go index f20fa48f63..3487a26518 100644 --- a/internal/endtoend/testdata/sqlc_embed/sqlite/go/models.go +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/go/models.go @@ -23,3 +23,8 @@ type User struct { Name string Age sql.NullInt64 } + +type UserLink struct { + OwnerID int64 + ConsumerID int64 +} diff --git a/internal/endtoend/testdata/sqlc_embed/sqlite/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed/sqlite/go/query.sql.go index 6ef5ba8d65..4712e496a0 100644 --- a/internal/endtoend/testdata/sqlc_embed/sqlite/go/query.sql.go +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/go/query.sql.go @@ -56,6 +56,51 @@ func (q *Queries) Join(ctx context.Context) (JoinRow, error) { return i, err } +const listUserLink = `-- name: ListUserLink :many +SELECT + owner.id, owner.name, owner.age, + consumer.id, consumer.name, consumer.age +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id +` + +type ListUserLinkRow struct { + User User + User_2 User +} + +func (q *Queries) ListUserLink(ctx context.Context) ([]ListUserLinkRow, error) { + rows, err := q.db.QueryContext(ctx, listUserLink) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserLinkRow + for rows.Next() { + var i ListUserLinkRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ); 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 +} + const only = `-- name: Only :one SELECT users.id, users.name, users.age FROM users ` diff --git a/internal/endtoend/testdata/sqlc_embed/sqlite/query.sql b/internal/endtoend/testdata/sqlc_embed/sqlite/query.sql index 4b999b5629..c377686010 100644 --- a/internal/endtoend/testdata/sqlc_embed/sqlite/query.sql +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/query.sql @@ -23,3 +23,12 @@ SELECT sqlc.embed(bu) FROM baz.users AS bu; -- name: WithCrossSchema :many SELECT sqlc.embed(u), sqlc.embed(bu) FROM users AS u INNER JOIN baz.users bu ON u.id = bu.id; + +-- name: ListUserLink :many +SELECT + sqlc.embed(owner), + sqlc.embed(consumer) +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed/sqlite/schema.sql b/internal/endtoend/testdata/sqlc_embed/sqlite/schema.sql index a67026ba33..472602b57b 100644 --- a/internal/endtoend/testdata/sqlc_embed/sqlite/schema.sql +++ b/internal/endtoend/testdata/sqlc_embed/sqlite/schema.sql @@ -17,3 +17,10 @@ CREATE TABLE baz.users ( ); +CREATE TABLE user_links ( + owner_id integer NOT NULL, + consumer_id integer NOT NULL, + PRIMARY KEY (owner_id, consumer_id) +); + + diff --git a/internal/endtoend/testdata/sqlc_embed_alias/mysql/go/db.go b/internal/endtoend/testdata/sqlc_embed_alias/mysql/go/db.go new file mode 100644 index 0000000000..0ea90b328a --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +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/sqlc_embed_alias/mysql/go/models.go b/internal/endtoend/testdata/sqlc_embed_alias/mysql/go/models.go new file mode 100644 index 0000000000..8108dd0dde --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/mysql/go/models.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +package querytest + +import ( + "database/sql" +) + +type BazUser struct { + ID int32 + Name string +} + +type Post struct { + ID int32 + UserID int32 +} + +type User struct { + ID int32 + Name string + Age sql.NullInt32 +} + +type UserLink struct { + OwnerID int32 + ConsumerID int32 +} diff --git a/internal/endtoend/testdata/sqlc_embed_alias/mysql/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed_alias/mysql/go/query.sql.go new file mode 100644 index 0000000000..6707a0a37e --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/mysql/go/query.sql.go @@ -0,0 +1,248 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const duplicate = `-- name: Duplicate :one +SELECT users.id, users.name, users.age, users.id, users.name, users.age FROM users +` + +type DuplicateRow struct { + User User + User_2 User +} + +func (q *Queries) Duplicate(ctx context.Context) (DuplicateRow, error) { + row := q.db.QueryRowContext(ctx, duplicate) + var i DuplicateRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ) + return i, err +} + +const join = `-- name: Join :one +SELECT users.id, users.name, users.age, posts.id, posts.user_id FROM posts +INNER JOIN users ON posts.user_id = users.id +` + +type JoinRow struct { + User User + Post Post +} + +func (q *Queries) Join(ctx context.Context) (JoinRow, error) { + row := q.db.QueryRowContext(ctx, join) + var i JoinRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Post.ID, + &i.Post.UserID, + ) + return i, err +} + +const listUserLink = `-- name: ListUserLink :many +SELECT + owner.id, owner.name, owner.age, + consumers.id, consumers.name, consumers.age +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumers ON consumers.id = user_links.consumer_id +` + +type ListUserLinkRow struct { + Owner User + Consumers User +} + +func (q *Queries) ListUserLink(ctx context.Context) ([]ListUserLinkRow, error) { + rows, err := q.db.QueryContext(ctx, listUserLink) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserLinkRow + for rows.Next() { + var i ListUserLinkRow + if err := rows.Scan( + &i.Owner.ID, + &i.Owner.Name, + &i.Owner.Age, + &i.Consumers.ID, + &i.Consumers.Name, + &i.Consumers.Age, + ); 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 +} + +const only = `-- name: Only :one +SELECT users.id, users.name, users.age FROM users +` + +type OnlyRow struct { + User User +} + +func (q *Queries) Only(ctx context.Context) (OnlyRow, error) { + row := q.db.QueryRowContext(ctx, only) + var i OnlyRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAlias = `-- name: WithAlias :one +SELECT u.id, u.name, u.age FROM users u +` + +type WithAliasRow struct { + U User +} + +func (q *Queries) WithAlias(ctx context.Context) (WithAliasRow, error) { + row := q.db.QueryRowContext(ctx, withAlias) + var i WithAliasRow + err := row.Scan(&i.U.ID, &i.U.Name, &i.U.Age) + return i, err +} + +const withAsterisk = `-- name: WithAsterisk :one +SELECT users.id, users.name, users.age, id, name, age FROM users +` + +type WithAsteriskRow struct { + User User + ID int32 + Name string + Age sql.NullInt32 +} + +func (q *Queries) WithAsterisk(ctx context.Context) (WithAsteriskRow, error) { + row := q.db.QueryRowContext(ctx, withAsterisk) + var i WithAsteriskRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.ID, + &i.Name, + &i.Age, + ) + return i, err +} + +const withCrossSchema = `-- name: WithCrossSchema :many +SELECT users.id, users.name, users.age, bu.id, bu.name FROM users +INNER JOIN baz.users bu ON users.id = bu.id +` + +type WithCrossSchemaRow struct { + User User + Bu BazUser +} + +func (q *Queries) WithCrossSchema(ctx context.Context) ([]WithCrossSchemaRow, error) { + rows, err := q.db.QueryContext(ctx, withCrossSchema) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithCrossSchemaRow + for rows.Next() { + var i WithCrossSchemaRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Bu.ID, + &i.Bu.Name, + ); 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 +} + +const withSchema = `-- name: WithSchema :one +SELECT bu.id, bu.name FROM baz.users bu +` + +type WithSchemaRow struct { + Bu BazUser +} + +func (q *Queries) WithSchema(ctx context.Context) (WithSchemaRow, error) { + row := q.db.QueryRowContext(ctx, withSchema) + var i WithSchemaRow + err := row.Scan(&i.Bu.ID, &i.Bu.Name) + return i, err +} + +const withSubquery = `-- name: WithSubquery :many +SELECT users.id, users.name, users.age, (SELECT count(*) FROM users) AS total_count FROM users +` + +type WithSubqueryRow struct { + User User + TotalCount int64 +} + +func (q *Queries) WithSubquery(ctx context.Context) ([]WithSubqueryRow, error) { + rows, err := q.db.QueryContext(ctx, withSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithSubqueryRow + for rows.Next() { + var i WithSubqueryRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.TotalCount, + ); 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/sqlc_embed_alias/mysql/query.sql b/internal/endtoend/testdata/sqlc_embed_alias/mysql/query.sql new file mode 100644 index 0000000000..c0d60038df --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/mysql/query.sql @@ -0,0 +1,34 @@ +-- name: Only :one +SELECT sqlc.embed(users) FROM users; + +-- name: WithAlias :one +SELECT sqlc.embed(u) FROM users u; + +-- name: WithSubquery :many +SELECT sqlc.embed(users), (SELECT count(*) FROM users) AS total_count FROM users; + +-- name: WithAsterisk :one +SELECT sqlc.embed(users), * FROM users; + +-- name: Duplicate :one +SELECT sqlc.embed(users), sqlc.embed(users) FROM users; + +-- name: Join :one +SELECT sqlc.embed(users), sqlc.embed(posts) FROM posts +INNER JOIN users ON posts.user_id = users.id; + +-- name: WithSchema :one +SELECT sqlc.embed(bu) FROM baz.users bu; + +-- name: WithCrossSchema :many +SELECT sqlc.embed(users), sqlc.embed(bu) FROM users +INNER JOIN baz.users bu ON users.id = bu.id; + +-- name: ListUserLink :many +SELECT + sqlc.embed(owner), + sqlc.embed(consumers) +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumers ON consumers.id = user_links.consumer_id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed_alias/mysql/schema.sql b/internal/endtoend/testdata/sqlc_embed_alias/mysql/schema.sql new file mode 100644 index 0000000000..1fe4e5d97c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/mysql/schema.sql @@ -0,0 +1,23 @@ +CREATE SCHEMA IF NOT EXISTS baz; + +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL, + age integer NULL +); + +CREATE TABLE posts ( + id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL +); + +CREATE TABLE baz.users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL +); + +CREATE TABLE user_links ( + owner_id integer NOT NULL, + consumer_id integer NOT NULL, + PRIMARY KEY (owner_id, consumer_id) +); diff --git a/internal/endtoend/testdata/sqlc_embed_alias/mysql/sqlc.json b/internal/endtoend/testdata/sqlc_embed_alias/mysql/sqlc.json new file mode 100644 index 0000000000..01d0043a5b --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/mysql/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_embed_alias": true + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/go/db.go b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/go/db.go new file mode 100644 index 0000000000..58779be81d --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/go/models.go b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/go/models.go new file mode 100644 index 0000000000..4a08e5d047 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/go/models.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +package querytest + +import ( + "database/sql" +) + +type BazUser struct { + ID int32 `db:"id" json:"id"` + Name string `db:"name" json:"name"` +} + +type Post struct { + ID int32 `db:"id" json:"id"` + UserID int32 `db:"user_id" json:"user_id"` +} + +type User struct { + ID int32 `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Age sql.NullInt32 `db:"age" json:"age"` +} + +type UserLink struct { + OwnerID int32 `db:"owner_id" json:"owner_id"` + ConsumerID int32 `db:"consumer_id" json:"consumer_id"` +} diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000000..9cdaafe84a --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/go/query.sql.go @@ -0,0 +1,239 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const duplicate = `-- name: Duplicate :one +SELECT users.id, users.name, users.age, users.id, users.name, users.age FROM users +` + +type DuplicateRow struct { + User User `db:"user" json:"user"` + User_2 User `db:"user_2" json:"user_2"` +} + +func (q *Queries) Duplicate(ctx context.Context) (DuplicateRow, error) { + row := q.db.QueryRow(ctx, duplicate) + var i DuplicateRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ) + return i, err +} + +const join = `-- name: Join :one +SELECT users.id, users.name, users.age, posts.id, posts.user_id FROM posts +INNER JOIN users ON posts.user_id = users.id +` + +type JoinRow struct { + User User `db:"user" json:"user"` + Post Post `db:"post" json:"post"` +} + +func (q *Queries) Join(ctx context.Context) (JoinRow, error) { + row := q.db.QueryRow(ctx, join) + var i JoinRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Post.ID, + &i.Post.UserID, + ) + return i, err +} + +const listUserLink = `-- name: ListUserLink :many +SELECT + owner.id, owner.name, owner.age, + consumer.id, consumer.name, consumer.age +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id +` + +type ListUserLinkRow struct { + Owner User `db:"owner" json:"owner"` + Consumer User `db:"consumer" json:"consumer"` +} + +func (q *Queries) ListUserLink(ctx context.Context) ([]ListUserLinkRow, error) { + rows, err := q.db.Query(ctx, listUserLink) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserLinkRow + for rows.Next() { + var i ListUserLinkRow + if err := rows.Scan( + &i.Owner.ID, + &i.Owner.Name, + &i.Owner.Age, + &i.Consumer.ID, + &i.Consumer.Name, + &i.Consumer.Age, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const only = `-- name: Only :one +SELECT users.id, users.name, users.age FROM users +` + +type OnlyRow struct { + User User `db:"user" json:"user"` +} + +func (q *Queries) Only(ctx context.Context) (OnlyRow, error) { + row := q.db.QueryRow(ctx, only) + var i OnlyRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAlias = `-- name: WithAlias :one +SELECT u.id, u.name, u.age FROM users u +` + +type WithAliasRow struct { + U User `db:"u" json:"u"` +} + +func (q *Queries) WithAlias(ctx context.Context) (WithAliasRow, error) { + row := q.db.QueryRow(ctx, withAlias) + var i WithAliasRow + err := row.Scan(&i.U.ID, &i.U.Name, &i.U.Age) + return i, err +} + +const withAsterisk = `-- name: WithAsterisk :one +SELECT users.id, users.name, users.age, id, name, age FROM users +` + +type WithAsteriskRow struct { + User User `db:"user" json:"user"` + ID int32 `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Age sql.NullInt32 `db:"age" json:"age"` +} + +func (q *Queries) WithAsterisk(ctx context.Context) (WithAsteriskRow, error) { + row := q.db.QueryRow(ctx, withAsterisk) + var i WithAsteriskRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.ID, + &i.Name, + &i.Age, + ) + return i, err +} + +const withCrossSchema = `-- name: WithCrossSchema :many +SELECT users.id, users.name, users.age, bu.id, bu.name FROM users +INNER JOIN baz.users bu ON users.id = bu.id +` + +type WithCrossSchemaRow struct { + User User `db:"user" json:"user"` + Bu BazUser `db:"bu" json:"bu"` +} + +func (q *Queries) WithCrossSchema(ctx context.Context) ([]WithCrossSchemaRow, error) { + rows, err := q.db.Query(ctx, withCrossSchema) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithCrossSchemaRow + for rows.Next() { + var i WithCrossSchemaRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Bu.ID, + &i.Bu.Name, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const withSchema = `-- name: WithSchema :one +SELECT bu.id, bu.name FROM baz.users bu +` + +type WithSchemaRow struct { + Bu BazUser `db:"bu" json:"bu"` +} + +func (q *Queries) WithSchema(ctx context.Context) (WithSchemaRow, error) { + row := q.db.QueryRow(ctx, withSchema) + var i WithSchemaRow + err := row.Scan(&i.Bu.ID, &i.Bu.Name) + return i, err +} + +const withSubquery = `-- name: WithSubquery :many +SELECT users.id, users.name, users.age, (SELECT count(*) FROM users) AS total_count FROM users +` + +type WithSubqueryRow struct { + User User `db:"user" json:"user"` + TotalCount int64 `db:"total_count" json:"total_count"` +} + +func (q *Queries) WithSubquery(ctx context.Context) ([]WithSubqueryRow, error) { + rows, err := q.db.Query(ctx, withSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithSubqueryRow + for rows.Next() { + var i WithSubqueryRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.TotalCount, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/query.sql b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/query.sql new file mode 100644 index 0000000000..a35c345639 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/query.sql @@ -0,0 +1,34 @@ +-- name: Only :one +SELECT sqlc.embed(users) FROM users; + +-- name: WithAlias :one +SELECT sqlc.embed(u) FROM users u; + +-- name: WithSubquery :many +SELECT sqlc.embed(users), (SELECT count(*) FROM users) AS total_count FROM users; + +-- name: WithAsterisk :one +SELECT sqlc.embed(users), * FROM users; + +-- name: Duplicate :one +SELECT sqlc.embed(users), sqlc.embed(users) FROM users; + +-- name: Join :one +SELECT sqlc.embed(users), sqlc.embed(posts) FROM posts +INNER JOIN users ON posts.user_id = users.id; + +-- name: WithSchema :one +SELECT sqlc.embed(bu) FROM baz.users bu; + +-- name: WithCrossSchema :many +SELECT sqlc.embed(users), sqlc.embed(bu) FROM users +INNER JOIN baz.users bu ON users.id = bu.id; + +-- name: ListUserLink :many +SELECT + sqlc.embed(owner), + sqlc.embed(consumer) +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/schema.sql b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/schema.sql new file mode 100644 index 0000000000..1fe4e5d97c --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/schema.sql @@ -0,0 +1,23 @@ +CREATE SCHEMA IF NOT EXISTS baz; + +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL, + age integer NULL +); + +CREATE TABLE posts ( + id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL +); + +CREATE TABLE baz.users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL +); + +CREATE TABLE user_links ( + owner_id integer NOT NULL, + consumer_id integer NOT NULL, + PRIMARY KEY (owner_id, consumer_id) +); diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/sqlc.json b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/sqlc.json new file mode 100644 index 0000000000..006bf524d6 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/pgx/sqlc.json @@ -0,0 +1,16 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_json_tags": true, + "emit_db_tags": true, + "emit_embed_alias": true + } + ] +} \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/go/db.go new file mode 100644 index 0000000000..0ea90b328a --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +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/sqlc_embed_alias/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/go/models.go new file mode 100644 index 0000000000..e030275079 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/go/models.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +package querytest + +import ( + "database/sql" +) + +type BazUser struct { + ID int32 + Name string +} + +type Post struct { + ID int32 + UserID int32 + Likes []int32 +} + +type User struct { + ID int32 + Name string + Age sql.NullInt32 +} + +type UserLink struct { + OwnerID int32 + ConsumerID int32 +} diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000000..6f7cc87a49 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,251 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" + + "github.com/lib/pq" +) + +const duplicate = `-- name: Duplicate :one +SELECT users.id, users.name, users.age, users.id, users.name, users.age FROM users +` + +type DuplicateRow struct { + User User + User_2 User +} + +func (q *Queries) Duplicate(ctx context.Context) (DuplicateRow, error) { + row := q.db.QueryRowContext(ctx, duplicate) + var i DuplicateRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ) + return i, err +} + +const join = `-- name: Join :one +SELECT users.id, users.name, users.age, posts.id, posts.user_id, posts.likes FROM posts +INNER JOIN users ON posts.user_id = users.id +` + +type JoinRow struct { + User User + Post Post +} + +func (q *Queries) Join(ctx context.Context) (JoinRow, error) { + row := q.db.QueryRowContext(ctx, join) + var i JoinRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Post.ID, + &i.Post.UserID, + pq.Array(&i.Post.Likes), + ) + return i, err +} + +const listUserLink = `-- name: ListUserLink :many +SELECT + owner.id, owner.name, owner.age, + consumer.id, consumer.name, consumer.age +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id +` + +type ListUserLinkRow struct { + Owner User + Consumer User +} + +func (q *Queries) ListUserLink(ctx context.Context) ([]ListUserLinkRow, error) { + rows, err := q.db.QueryContext(ctx, listUserLink) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserLinkRow + for rows.Next() { + var i ListUserLinkRow + if err := rows.Scan( + &i.Owner.ID, + &i.Owner.Name, + &i.Owner.Age, + &i.Consumer.ID, + &i.Consumer.Name, + &i.Consumer.Age, + ); 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 +} + +const only = `-- name: Only :one +SELECT users.id, users.name, users.age FROM users +` + +type OnlyRow struct { + User User +} + +func (q *Queries) Only(ctx context.Context) (OnlyRow, error) { + row := q.db.QueryRowContext(ctx, only) + var i OnlyRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAlias = `-- name: WithAlias :one +SELECT u.id, u.name, u.age FROM users u +` + +type WithAliasRow struct { + U User +} + +func (q *Queries) WithAlias(ctx context.Context) (WithAliasRow, error) { + row := q.db.QueryRowContext(ctx, withAlias) + var i WithAliasRow + err := row.Scan(&i.U.ID, &i.U.Name, &i.U.Age) + return i, err +} + +const withAsterisk = `-- name: WithAsterisk :one +SELECT users.id, users.name, users.age, id, name, age FROM users +` + +type WithAsteriskRow struct { + User User + ID int32 + Name string + Age sql.NullInt32 +} + +func (q *Queries) WithAsterisk(ctx context.Context) (WithAsteriskRow, error) { + row := q.db.QueryRowContext(ctx, withAsterisk) + var i WithAsteriskRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.ID, + &i.Name, + &i.Age, + ) + return i, err +} + +const withCrossSchema = `-- name: WithCrossSchema :many +SELECT users.id, users.name, users.age, bu.id, bu.name FROM users +INNER JOIN baz.users bu ON users.id = bu.id +` + +type WithCrossSchemaRow struct { + User User + Bu BazUser +} + +func (q *Queries) WithCrossSchema(ctx context.Context) ([]WithCrossSchemaRow, error) { + rows, err := q.db.QueryContext(ctx, withCrossSchema) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithCrossSchemaRow + for rows.Next() { + var i WithCrossSchemaRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.Bu.ID, + &i.Bu.Name, + ); 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 +} + +const withSchema = `-- name: WithSchema :one +SELECT bu.id, bu.name FROM baz.users bu +` + +type WithSchemaRow struct { + Bu BazUser +} + +func (q *Queries) WithSchema(ctx context.Context) (WithSchemaRow, error) { + row := q.db.QueryRowContext(ctx, withSchema) + var i WithSchemaRow + err := row.Scan(&i.Bu.ID, &i.Bu.Name) + return i, err +} + +const withSubquery = `-- name: WithSubquery :many +SELECT users.id, users.name, users.age, (SELECT count(*) FROM users) AS total_count FROM users +` + +type WithSubqueryRow struct { + User User + TotalCount int64 +} + +func (q *Queries) WithSubquery(ctx context.Context) ([]WithSubqueryRow, error) { + rows, err := q.db.QueryContext(ctx, withSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithSubqueryRow + for rows.Next() { + var i WithSubqueryRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.TotalCount, + ); 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/sqlc_embed_alias/postgresql/stdlib/query.sql b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/query.sql new file mode 100644 index 0000000000..a35c345639 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/query.sql @@ -0,0 +1,34 @@ +-- name: Only :one +SELECT sqlc.embed(users) FROM users; + +-- name: WithAlias :one +SELECT sqlc.embed(u) FROM users u; + +-- name: WithSubquery :many +SELECT sqlc.embed(users), (SELECT count(*) FROM users) AS total_count FROM users; + +-- name: WithAsterisk :one +SELECT sqlc.embed(users), * FROM users; + +-- name: Duplicate :one +SELECT sqlc.embed(users), sqlc.embed(users) FROM users; + +-- name: Join :one +SELECT sqlc.embed(users), sqlc.embed(posts) FROM posts +INNER JOIN users ON posts.user_id = users.id; + +-- name: WithSchema :one +SELECT sqlc.embed(bu) FROM baz.users bu; + +-- name: WithCrossSchema :many +SELECT sqlc.embed(users), sqlc.embed(bu) FROM users +INNER JOIN baz.users bu ON users.id = bu.id; + +-- name: ListUserLink :many +SELECT + sqlc.embed(owner), + sqlc.embed(consumer) +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/schema.sql new file mode 100644 index 0000000000..0307e3facb --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/schema.sql @@ -0,0 +1,24 @@ +CREATE SCHEMA IF NOT EXISTS baz; + +CREATE TABLE users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL, + age integer NULL +); + +CREATE TABLE posts ( + id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL, + likes integer[] NOT NULL +); + +CREATE TABLE baz.users ( + id integer NOT NULL PRIMARY KEY, + name varchar(255) NOT NULL +); + +CREATE TABLE user_links ( + owner_id integer NOT NULL, + consumer_id integer NOT NULL, + PRIMARY KEY (owner_id, consumer_id) +); diff --git a/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000000..dafdb980be --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_embed_alias": true + } + ] +} diff --git a/internal/endtoend/testdata/sqlc_embed_alias/sqlite/go/db.go b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/go/db.go new file mode 100644 index 0000000000..0ea90b328a --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +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/sqlc_embed_alias/sqlite/go/models.go b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/go/models.go new file mode 100644 index 0000000000..3487a26518 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/go/models.go @@ -0,0 +1,30 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +package querytest + +import ( + "database/sql" +) + +type BazUser struct { + ID int64 + Name string +} + +type Post struct { + ID int64 + UserID int64 +} + +type User struct { + ID int64 + Name string + Age sql.NullInt64 +} + +type UserLink struct { + OwnerID int64 + ConsumerID int64 +} diff --git a/internal/endtoend/testdata/sqlc_embed_alias/sqlite/go/query.sql.go b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/go/query.sql.go new file mode 100644 index 0000000000..486a34a3f3 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/go/query.sql.go @@ -0,0 +1,248 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 +// source: query.sql + +package querytest + +import ( + "context" + "database/sql" +) + +const duplicate = `-- name: Duplicate :one +SELECT users.id, users.name, users.age, users.id, users.name, users.age FROM users +` + +type DuplicateRow struct { + User User + User_2 User +} + +func (q *Queries) Duplicate(ctx context.Context) (DuplicateRow, error) { + row := q.db.QueryRowContext(ctx, duplicate) + var i DuplicateRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.User_2.ID, + &i.User_2.Name, + &i.User_2.Age, + ) + return i, err +} + +const join = `-- name: Join :one +SELECT u.id, u.name, u.age, p.id, p.user_id FROM posts AS p +INNER JOIN users AS u ON p.user_id = u.users.id +` + +type JoinRow struct { + U User + P Post +} + +func (q *Queries) Join(ctx context.Context) (JoinRow, error) { + row := q.db.QueryRowContext(ctx, join) + var i JoinRow + err := row.Scan( + &i.U.ID, + &i.U.Name, + &i.U.Age, + &i.P.ID, + &i.P.UserID, + ) + return i, err +} + +const listUserLink = `-- name: ListUserLink :many +SELECT + owner.id, owner.name, owner.age, + consumer.id, consumer.name, consumer.age +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id +` + +type ListUserLinkRow struct { + Owner User + Consumer User +} + +func (q *Queries) ListUserLink(ctx context.Context) ([]ListUserLinkRow, error) { + rows, err := q.db.QueryContext(ctx, listUserLink) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListUserLinkRow + for rows.Next() { + var i ListUserLinkRow + if err := rows.Scan( + &i.Owner.ID, + &i.Owner.Name, + &i.Owner.Age, + &i.Consumer.ID, + &i.Consumer.Name, + &i.Consumer.Age, + ); 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 +} + +const only = `-- name: Only :one +SELECT users.id, users.name, users.age FROM users +` + +type OnlyRow struct { + User User +} + +func (q *Queries) Only(ctx context.Context) (OnlyRow, error) { + row := q.db.QueryRowContext(ctx, only) + var i OnlyRow + err := row.Scan(&i.User.ID, &i.User.Name, &i.User.Age) + return i, err +} + +const withAlias = `-- name: WithAlias :one +SELECT u.id, u.name, u.age FROM users AS u +` + +type WithAliasRow struct { + U User +} + +func (q *Queries) WithAlias(ctx context.Context) (WithAliasRow, error) { + row := q.db.QueryRowContext(ctx, withAlias) + var i WithAliasRow + err := row.Scan(&i.U.ID, &i.U.Name, &i.U.Age) + return i, err +} + +const withAsterisk = `-- name: WithAsterisk :one +SELECT users.id, users.name, users.age, id, name, age FROM users +` + +type WithAsteriskRow struct { + User User + ID int64 + Name string + Age sql.NullInt64 +} + +func (q *Queries) WithAsterisk(ctx context.Context) (WithAsteriskRow, error) { + row := q.db.QueryRowContext(ctx, withAsterisk) + var i WithAsteriskRow + err := row.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.ID, + &i.Name, + &i.Age, + ) + return i, err +} + +const withCrossSchema = `-- name: WithCrossSchema :many +SELECT u.id, u.name, u.age, bu.id, bu.name FROM users AS u +INNER JOIN baz.users bu ON u.id = bu.id +` + +type WithCrossSchemaRow struct { + U User + Bu BazUser +} + +func (q *Queries) WithCrossSchema(ctx context.Context) ([]WithCrossSchemaRow, error) { + rows, err := q.db.QueryContext(ctx, withCrossSchema) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithCrossSchemaRow + for rows.Next() { + var i WithCrossSchemaRow + if err := rows.Scan( + &i.U.ID, + &i.U.Name, + &i.U.Age, + &i.Bu.ID, + &i.Bu.Name, + ); 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 +} + +const withSchema = `-- name: WithSchema :one +SELECT bu.id, bu.name FROM baz.users AS bu +` + +type WithSchemaRow struct { + Bu BazUser +} + +func (q *Queries) WithSchema(ctx context.Context) (WithSchemaRow, error) { + row := q.db.QueryRowContext(ctx, withSchema) + var i WithSchemaRow + err := row.Scan(&i.Bu.ID, &i.Bu.Name) + return i, err +} + +const withSubquery = `-- name: WithSubquery :many +SELECT users.id, users.name, users.age, (SELECT count(*) FROM users) AS total_count FROM users +` + +type WithSubqueryRow struct { + User User + TotalCount int64 +} + +func (q *Queries) WithSubquery(ctx context.Context) ([]WithSubqueryRow, error) { + rows, err := q.db.QueryContext(ctx, withSubquery) + if err != nil { + return nil, err + } + defer rows.Close() + var items []WithSubqueryRow + for rows.Next() { + var i WithSubqueryRow + if err := rows.Scan( + &i.User.ID, + &i.User.Name, + &i.User.Age, + &i.TotalCount, + ); 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/sqlc_embed_alias/sqlite/query.sql b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/query.sql new file mode 100644 index 0000000000..c377686010 --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/query.sql @@ -0,0 +1,34 @@ +-- name: Only :one +SELECT sqlc.embed(users) FROM users; + +-- name: WithAlias :one +SELECT sqlc.embed(u) FROM users AS u; + +-- name: WithSubquery :many +SELECT sqlc.embed(users), (SELECT count(*) FROM users) AS total_count FROM users; + +-- name: WithAsterisk :one +SELECT sqlc.embed(users), * FROM users; + +-- name: Duplicate :one +SELECT sqlc.embed(users), sqlc.embed(users) FROM users; + +-- name: Join :one +SELECT sqlc.embed(u), sqlc.embed(p) FROM posts AS p +INNER JOIN users AS u ON p.user_id = u.users.id; + +-- name: WithSchema :one +SELECT sqlc.embed(bu) FROM baz.users AS bu; + +-- name: WithCrossSchema :many +SELECT sqlc.embed(u), sqlc.embed(bu) FROM users AS u +INNER JOIN baz.users bu ON u.id = bu.id; + +-- name: ListUserLink :many +SELECT + sqlc.embed(owner), + sqlc.embed(consumer) +FROM + user_links + INNER JOIN users AS owner ON owner.id = user_links.owner_id + INNER JOIN users AS consumer ON consumer.id = user_links.consumer_id; \ No newline at end of file diff --git a/internal/endtoend/testdata/sqlc_embed_alias/sqlite/schema.sql b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/schema.sql new file mode 100644 index 0000000000..472602b57b --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/schema.sql @@ -0,0 +1,26 @@ +ATTACH 'baz.db' AS baz; + +CREATE TABLE users ( + id integer PRIMARY KEY, + name text NOT NULL, + age integer +); + +CREATE TABLE posts ( + id integer PRIMARY KEY, + user_id integer NOT NULL +); + +CREATE TABLE baz.users ( + id integer PRIMARY KEY, + name text NOT NULL +); + + +CREATE TABLE user_links ( + owner_id integer NOT NULL, + consumer_id integer NOT NULL, + PRIMARY KEY (owner_id, consumer_id) +); + + diff --git a/internal/endtoend/testdata/sqlc_embed_alias/sqlite/sqlc.json b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/sqlc.json new file mode 100644 index 0000000000..11f16ca5df --- /dev/null +++ b/internal/endtoend/testdata/sqlc_embed_alias/sqlite/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "sqlite", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql", + "emit_embed_alias": true + } + ] +} diff --git a/internal/sql/rewrite/embeds.go b/internal/sql/rewrite/embeds.go index 596c03be89..95d7a32e7f 100644 --- a/internal/sql/rewrite/embeds.go +++ b/internal/sql/rewrite/embeds.go @@ -14,6 +14,11 @@ type Embed struct { Node *ast.ColumnRef } +// Name name or scope of the embed +func (e Embed) Name() string { + return e.param +} + // Orig string to replace func (e Embed) Orig() string { return fmt.Sprintf("sqlc.embed(%s)", e.param)