Repository: sqlc-dev/sqlc
Pull request #2868 (2023-10-17 05:00:31)

fix(codegen/go): Prevent filtering of embedded struct fields
Resolves https://github.com/sqlc-dev/sqlc/issues/2860


Patch:
diff --git a/internal/codegen/golang/gen.go b/internal/codegen/golang/gen.go
index c5f1956e0..ea3d8384c 100644
--- a/internal/codegen/golang/gen.go
+++ b/internal/codegen/golang/gen.go
@@ -345,6 +345,9 @@ func filterUnusedStructs(enums []Enum, structs []Struct, queries []Query) ([]Enu
 			if query.Ret.IsStruct() {
 				for _, field := range query.Ret.Struct.Fields {
 					keepTypes[field.Type] = struct{}{}
+					for _, embedField := range field.EmbedFields {
+						keepTypes[embedField.Type] = struct{}{}
+					}
 				}
 			}
 		}


Test patch:
diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go
index b1624997b..d918dc44c 100644
--- a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go
+++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go
@@ -219,6 +219,48 @@ func (ns NullQueryReturnStructEnumTableEnum) Value() (driver.Value, error) {
 	return string(ns.QueryReturnStructEnumTableEnum), nil
 }
 
+type QuerySqlcEmbedEnum string
+
+const (
+	QuerySqlcEmbedEnumM QuerySqlcEmbedEnum = "m"
+	QuerySqlcEmbedEnumN QuerySqlcEmbedEnum = "n"
+)
+
+func (e *QuerySqlcEmbedEnum) Scan(src interface{}) error {
+	switch s := src.(type) {
+	case []byte:
+		*e = QuerySqlcEmbedEnum(s)
+	case string:
+		*e = QuerySqlcEmbedEnum(s)
+	default:
+		return fmt.Errorf("unsupported scan type for QuerySqlcEmbedEnum: %T", src)
+	}
+	return nil
+}
+
+type NullQuerySqlcEmbedEnum struct {
+	QuerySqlcEmbedEnum QuerySqlcEmbedEnum
+	Valid              bool // Valid is true if QuerySqlcEmbedEnum is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (ns *NullQuerySqlcEmbedEnum) Scan(value interface{}) error {
+	if value == nil {
+		ns.QuerySqlcEmbedEnum, ns.Valid = "", false
+		return nil
+	}
+	ns.Valid = true
+	return ns.QuerySqlcEmbedEnum.Scan(value)
+}
+
+// Value implements the driver Valuer interface.
+func (ns NullQuerySqlcEmbedEnum) Value() (driver.Value, error) {
+	if !ns.Valid {
+		return nil, nil
+	}
+	return string(ns.QuerySqlcEmbedEnum), nil
+}
+
 type QueryParamEnumTable struct {
 	ID    int32
 	Other QueryParamEnumTableEnum
@@ -229,3 +271,8 @@ type QueryReturnFullTable struct {
 	ID    int32
 	Value NullQueryReturnFullTableEnum
 }
+
+type QuerySqlcEmbedTable struct {
+	ID    int32
+	Value NullQuerySqlcEmbedEnum
+}
diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go
index f65910269..91457e09a 100644
--- a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go
+++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go
@@ -90,3 +90,18 @@ func (q *Queries) query_return_struct_enum_table(ctx context.Context, id int32)
 	err := row.Scan(&i.Value, &i.Another)
 	return i, err
 }
+
+const query_sqlc_embed_table = `-- name: query_sqlc_embed_table :one
+SELECT query_sqlc_embed_table.id, query_sqlc_embed_table.value FROM query_sqlc_embed_table WHERE id = $1
+`
+
+type query_sqlc_embed_tableRow struct {
+	QuerySqlcEmbedTable QuerySqlcEmbedTable
+}
+
+func (q *Queries) query_sqlc_embed_table(ctx context.Context, id int32) (query_sqlc_embed_tableRow, error) {
+	row := q.db.QueryRowContext(ctx, query_sqlc_embed_table, id)
+	var i query_sqlc_embed_tableRow
+	err := row.Scan(&i.QuerySqlcEmbedTable.ID, &i.QuerySqlcEmbedTable.Value)
+	return i, err
+}
diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql
index 1420d869d..599a22748 100644
--- a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql
+++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql
@@ -11,4 +11,7 @@ SELECT id FROM query_param_struct_enum_table WHERE id = $1 AND value = $2;
 SELECT value FROM query_return_enum_table WHERE id = $1;
 
 -- name: query_return_struct_enum_table :one
-SELECT value, another FROM query_return_struct_enum_table WHERE id = $1;
\ No newline at end of file
+SELECT value, another FROM query_return_struct_enum_table WHERE id = $1;
+
+-- name: query_sqlc_embed_table :one
+SELECT sqlc.embed(query_sqlc_embed_table) FROM query_sqlc_embed_table WHERE id = $1;
diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql
index cc2ae14b2..486119c33 100644
--- a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql
+++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql
@@ -50,4 +50,12 @@ CREATE TABLE query_return_struct_enum_table (
     id      INTEGER PRIMARY KEY,
     value   query_return_struct_enum_table_enum,
     another INTEGER
-);
\ No newline at end of file
+);
+
+CREATE TYPE query_sqlc_embed_enum AS ENUM (
+    'm', 'n'
+);
+CREATE TABLE query_sqlc_embed_table (
+    id      INTEGER PRIMARY KEY,
+    value   query_sqlc_embed_enum
+)