From 67d36316d0f742d717b7ba8e44ba6e1a0793895e Mon Sep 17 00:00:00 2001 From: Andrew Benton Date: Mon, 26 Jun 2023 23:10:03 -0700 Subject: [PATCH 1/2] internal/codegen/golang: omit unused structs from output --- internal/cmd/shim.go | 1 + internal/codegen/golang/gen.go | 44 ++++ internal/config/config.go | 1 + internal/config/v_one.go | 2 + .../testdata/codegen_json/gen/codegen.json | 3 +- .../postgresql/stdlib/go/db.go | 31 +++ .../postgresql/stdlib/go/models.go | 225 ++++++++++++++++++ .../postgresql/stdlib/go/query.sql.go | 92 +++++++ .../postgresql/stdlib/query.sql | 14 ++ .../postgresql/stdlib/schema.sql | 52 ++++ .../postgresql/stdlib/sqlc.json | 13 + .../process_plugin_disabled/gen/codegen.json | 3 +- .../gen/codegen.json | 3 +- internal/plugin/codegen.pb.go | 15 +- internal/plugin/codegen_vtproto.pb.go | 51 ++++ protos/plugin/codegen.proto | 1 + 16 files changed, 546 insertions(+), 5 deletions(-) create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/sqlc.json diff --git a/internal/cmd/shim.go b/internal/cmd/shim.go index fae67ed1e9..de5bfb76cd 100644 --- a/internal/cmd/shim.go +++ b/internal/cmd/shim.go @@ -108,6 +108,7 @@ func pluginGoCode(s config.SQLGo) *plugin.GoCode { OutputFilesSuffix: s.OutputFilesSuffix, InflectionExcludeTableNames: s.InflectionExcludeTableNames, QueryParameterLimit: s.QueryParameterLimit, + OmitUnusedStructs: s.OmitUnusedStructs, } } diff --git a/internal/codegen/golang/gen.go b/internal/codegen/golang/gen.go index 58fb8a9c8c..68095d96d2 100644 --- a/internal/codegen/golang/gen.go +++ b/internal/codegen/golang/gen.go @@ -108,6 +108,11 @@ func Generate(ctx context.Context, req *plugin.CodeGenRequest) (*plugin.CodeGenR if err != nil { return nil, err } + + if req.Settings.Go.OmitUnusedStructs { + enums, structs = filterUnusedStructs(enums, structs, queries) + } + return generate(req, enums, structs, queries) } @@ -288,3 +293,42 @@ func usesBatch(queries []Query) bool { } return false } + +func filterUnusedStructs(enums []Enum, structs []Struct, queries []Query) ([]Enum, []Struct) { + keepTypes := make(map[string]struct{}) + + for _, query := range queries { + if !query.Arg.isEmpty() { + keepTypes[strings.TrimPrefix(query.Arg.Type(), "Null")] = struct{}{} + if query.Arg.IsStruct() { + for _, field := range query.Arg.Struct.Fields { + keepTypes[strings.TrimPrefix(field.Type, "Null")] = struct{}{} + } + } + } + if query.hasRetType() { + keepTypes[strings.TrimPrefix(query.Ret.Type(), "Null")] = struct{}{} + if query.Ret.IsStruct() { + for _, field := range query.Ret.Struct.Fields { + keepTypes[strings.TrimPrefix(field.Type, "Null")] = struct{}{} + } + } + } + } + + keepEnums := make([]Enum, 0, len(enums)) + for _, enum := range enums { + if _, ok := keepTypes[enum.Name]; ok { + keepEnums = append(keepEnums, enum) + } + } + + keepStructs := make([]Struct, 0, len(structs)) + for _, st := range structs { + if _, ok := keepTypes[st.Name]; ok { + keepStructs = append(keepStructs, st) + } + } + + return keepEnums, keepStructs +} diff --git a/internal/config/config.go b/internal/config/config.go index 86f03f4757..ba7035cbbc 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -145,6 +145,7 @@ type SQLGo struct { OutputFilesSuffix string `json:"output_files_suffix,omitempty" yaml:"output_files_suffix"` InflectionExcludeTableNames []string `json:"inflection_exclude_table_names,omitempty" yaml:"inflection_exclude_table_names"` QueryParameterLimit *int32 `json:"query_parameter_limit,omitempty" yaml:"query_parameter_limit"` + OmitUnusedStructs bool `json:"omit_unused_structs,omitempty" yaml:"omit_unused_structs"` } type SQLJSON struct { diff --git a/internal/config/v_one.go b/internal/config/v_one.go index 1d9a29b2df..273413aea4 100644 --- a/internal/config/v_one.go +++ b/internal/config/v_one.go @@ -49,6 +49,7 @@ type v1PackageSettings struct { StrictFunctionChecks bool `json:"strict_function_checks" yaml:"strict_function_checks"` StrictOrderBy *bool `json:"strict_order_by" yaml:"strict_order_by"` QueryParameterLimit *int32 `json:"query_parameter_limit,omitempty" yaml:"query_parameter_limit"` + OmitUnusedStructs bool `json:"omit_unused_structs,omitempty" yaml:"omit_unused_structs"` } func v1ParseConfig(rd io.Reader) (Config, error) { @@ -168,6 +169,7 @@ func (c *V1GenerateSettings) Translate() Config { OutputQuerierFileName: pkg.OutputQuerierFileName, OutputFilesSuffix: pkg.OutputFilesSuffix, QueryParameterLimit: pkg.QueryParameterLimit, + OmitUnusedStructs: pkg.OmitUnusedStructs, }, }, StrictFunctionChecks: pkg.StrictFunctionChecks, diff --git a/internal/endtoend/testdata/codegen_json/gen/codegen.json b/internal/endtoend/testdata/codegen_json/gen/codegen.json index 167a301cda..0afd9fa665 100644 --- a/internal/endtoend/testdata/codegen_json/gen/codegen.json +++ b/internal/endtoend/testdata/codegen_json/gen/codegen.json @@ -41,7 +41,8 @@ "emit_pointers_for_null_types": false, "query_parameter_limit": 1, "output_batch_file_name": "", - "json_tags_id_uppercase": false + "json_tags_id_uppercase": false, + "omit_unused_structs": false }, "json": { "out": "gen", diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/db.go new file mode 100644 index 0000000000..e0b5347fe3 --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 + +package db + +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/omit_unused_structs/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go new file mode 100644 index 0000000000..7ad77daeaa --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/models.go @@ -0,0 +1,225 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 + +package db + +import ( + "database/sql/driver" + "fmt" +) + +type QueryParamEnumTableEnum string + +const ( + QueryParamEnumTableEnumG QueryParamEnumTableEnum = "g" + QueryParamEnumTableEnumH QueryParamEnumTableEnum = "h" +) + +func (e *QueryParamEnumTableEnum) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = QueryParamEnumTableEnum(s) + case string: + *e = QueryParamEnumTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryParamEnumTableEnum: %T", src) + } + return nil +} + +type NullQueryParamEnumTableEnum struct { + QueryParamEnumTableEnum QueryParamEnumTableEnum + Valid bool // Valid is true if QueryParamEnumTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryParamEnumTableEnum) Scan(value interface{}) error { + if value == nil { + ns.QueryParamEnumTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryParamEnumTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryParamEnumTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryParamEnumTableEnum), nil +} + +type QueryParamStructEnumTableEnum string + +const ( + QueryParamStructEnumTableEnumI QueryParamStructEnumTableEnum = "i" + QueryParamStructEnumTableEnumJ QueryParamStructEnumTableEnum = "j" +) + +func (e *QueryParamStructEnumTableEnum) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = QueryParamStructEnumTableEnum(s) + case string: + *e = QueryParamStructEnumTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryParamStructEnumTableEnum: %T", src) + } + return nil +} + +type NullQueryParamStructEnumTableEnum struct { + QueryParamStructEnumTableEnum QueryParamStructEnumTableEnum + Valid bool // Valid is true if QueryParamStructEnumTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryParamStructEnumTableEnum) Scan(value interface{}) error { + if value == nil { + ns.QueryParamStructEnumTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryParamStructEnumTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryParamStructEnumTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryParamStructEnumTableEnum), nil +} + +type QueryReturnEnumTableEnum string + +const ( + QueryReturnEnumTableEnumK QueryReturnEnumTableEnum = "k" + QueryReturnEnumTableEnumL QueryReturnEnumTableEnum = "l" +) + +func (e *QueryReturnEnumTableEnum) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = QueryReturnEnumTableEnum(s) + case string: + *e = QueryReturnEnumTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryReturnEnumTableEnum: %T", src) + } + return nil +} + +type NullQueryReturnEnumTableEnum struct { + QueryReturnEnumTableEnum QueryReturnEnumTableEnum + Valid bool // Valid is true if QueryReturnEnumTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryReturnEnumTableEnum) Scan(value interface{}) error { + if value == nil { + ns.QueryReturnEnumTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryReturnEnumTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryReturnEnumTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryReturnEnumTableEnum), nil +} + +type QueryReturnFullTableEnum string + +const ( + QueryReturnFullTableEnumE QueryReturnFullTableEnum = "e" + QueryReturnFullTableEnumF QueryReturnFullTableEnum = "f" +) + +func (e *QueryReturnFullTableEnum) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = QueryReturnFullTableEnum(s) + case string: + *e = QueryReturnFullTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryReturnFullTableEnum: %T", src) + } + return nil +} + +type NullQueryReturnFullTableEnum struct { + QueryReturnFullTableEnum QueryReturnFullTableEnum + Valid bool // Valid is true if QueryReturnFullTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryReturnFullTableEnum) Scan(value interface{}) error { + if value == nil { + ns.QueryReturnFullTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryReturnFullTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryReturnFullTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryReturnFullTableEnum), nil +} + +type QueryReturnStructEnumTableEnum string + +const ( + QueryReturnStructEnumTableEnumK QueryReturnStructEnumTableEnum = "k" + QueryReturnStructEnumTableEnumL QueryReturnStructEnumTableEnum = "l" +) + +func (e *QueryReturnStructEnumTableEnum) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = QueryReturnStructEnumTableEnum(s) + case string: + *e = QueryReturnStructEnumTableEnum(s) + default: + return fmt.Errorf("unsupported scan type for QueryReturnStructEnumTableEnum: %T", src) + } + return nil +} + +type NullQueryReturnStructEnumTableEnum struct { + QueryReturnStructEnumTableEnum QueryReturnStructEnumTableEnum + Valid bool // Valid is true if QueryReturnStructEnumTableEnum is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullQueryReturnStructEnumTableEnum) Scan(value interface{}) error { + if value == nil { + ns.QueryReturnStructEnumTableEnum, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.QueryReturnStructEnumTableEnum.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullQueryReturnStructEnumTableEnum) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.QueryReturnStructEnumTableEnum), nil +} + +type QueryReturnFullTable struct { + ID int32 + Value NullQueryReturnFullTableEnum +} 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 new file mode 100644 index 0000000000..dc6bd31f79 --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,92 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.18.0 +// source: query.sql + +package db + +import ( + "context" + "database/sql" +) + +const query_param_enum_table = `-- name: query_param_enum_table :one +SELECT id FROM query_param_enum_table WHERE value = $1 +` + +func (q *Queries) query_param_enum_table(ctx context.Context, value NullQueryParamEnumTableEnum) (int32, error) { + row := q.db.QueryRowContext(ctx, query_param_enum_table, value) + var id int32 + err := row.Scan(&id) + return id, err +} + +const query_param_struct_enum_table = `-- name: query_param_struct_enum_table :one +SELECT id FROM query_param_struct_enum_table WHERE id = $1 AND value = $2 +` + +type query_param_struct_enum_tableParams struct { + ID int32 + Value NullQueryParamStructEnumTableEnum +} + +func (q *Queries) query_param_struct_enum_table(ctx context.Context, arg query_param_struct_enum_tableParams) (int32, error) { + row := q.db.QueryRowContext(ctx, query_param_struct_enum_table, arg.ID, arg.Value) + var id int32 + err := row.Scan(&id) + return id, err +} + +const query_return_enum_table = `-- name: query_return_enum_table :one +SELECT value FROM query_return_enum_table WHERE id = $1 +` + +func (q *Queries) query_return_enum_table(ctx context.Context, id int32) (NullQueryReturnEnumTableEnum, error) { + row := q.db.QueryRowContext(ctx, query_return_enum_table, id) + var value NullQueryReturnEnumTableEnum + err := row.Scan(&value) + return value, err +} + +const query_return_full_table = `-- name: query_return_full_table :many +SELECT id, value FROM query_return_full_table +` + +func (q *Queries) query_return_full_table(ctx context.Context) ([]QueryReturnFullTable, error) { + rows, err := q.db.QueryContext(ctx, query_return_full_table) + if err != nil { + return nil, err + } + defer rows.Close() + var items []QueryReturnFullTable + for rows.Next() { + var i QueryReturnFullTable + if err := rows.Scan(&i.ID, &i.Value); 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 query_return_struct_enum_table = `-- name: query_return_struct_enum_table :one +SELECT value, another FROM query_return_struct_enum_table WHERE id = $1 +` + +type query_return_struct_enum_tableRow struct { + Value NullQueryReturnStructEnumTableEnum + Another sql.NullInt32 +} + +func (q *Queries) query_return_struct_enum_table(ctx context.Context, id int32) (query_return_struct_enum_tableRow, error) { + row := q.db.QueryRowContext(ctx, query_return_struct_enum_table, id) + var i query_return_struct_enum_tableRow + err := row.Scan(&i.Value, &i.Another) + 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 new file mode 100644 index 0000000000..7105779d27 --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/query.sql @@ -0,0 +1,14 @@ +-- name: query_return_full_table :many +SELECT * FROM query_return_full_table; + +-- name: query_param_enum_table :one +SELECT id FROM query_param_enum_table WHERE value = $1; + +-- name: query_param_struct_enum_table :one +SELECT id FROM query_param_struct_enum_table WHERE id = $1 AND value = $2; + +-- name: query_return_enum_table :one +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 diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql new file mode 100644 index 0000000000..e51554f040 --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/schema.sql @@ -0,0 +1,52 @@ +CREATE TYPE unused_enum AS ENUM ( + 'a', 'b' +); + +CREATE TYPE unused_table_enum AS ENUM ( + 'c', 'd' +); +CREATE TABLE unused_table ( + id INTEGER PRIMARY KEY, + value unused_table_enum +); + +CREATE TYPE query_return_full_table_enum AS ENUM ( + 'e', 'f' +); +CREATE TABLE query_return_full_table ( + id INTEGER PRIMARY KEY, + value query_return_full_table_enum +); + +CREATE TYPE query_param_enum_table_enum AS ENUM ( + 'g', 'h' +); +CREATE TABLE query_param_enum_table ( + id INTEGER PRIMARY KEY, + value query_param_enum_table_enum +); + +CREATE TYPE query_param_struct_enum_table_enum AS ENUM ( + 'i', 'j' +); +CREATE TABLE query_param_struct_enum_table ( + id INTEGER PRIMARY KEY, + value query_param_struct_enum_table_enum +); + +CREATE TYPE query_return_enum_table_enum AS ENUM ( + 'k', 'l' +); +CREATE TABLE query_return_enum_table ( + id INTEGER PRIMARY KEY, + value query_return_enum_table_enum +); + +CREATE TYPE query_return_struct_enum_table_enum AS ENUM ( + 'k', 'l' +); +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 diff --git a/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000000..a48c4d4206 --- /dev/null +++ b/internal/endtoend/testdata/omit_unused_structs/postgresql/stdlib/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "name": "db", + "engine": "postgresql", + "schema": "schema.sql", + "queries": "query.sql", + "omit_unused_structs": true + } + ] +} diff --git a/internal/endtoend/testdata/process_plugin_disabled/gen/codegen.json b/internal/endtoend/testdata/process_plugin_disabled/gen/codegen.json index 9db04bec79..8aa57cc330 100644 --- a/internal/endtoend/testdata/process_plugin_disabled/gen/codegen.json +++ b/internal/endtoend/testdata/process_plugin_disabled/gen/codegen.json @@ -41,7 +41,8 @@ "emit_pointers_for_null_types": false, "query_parameter_limit": 1, "output_batch_file_name": "", - "json_tags_id_uppercase": false + "json_tags_id_uppercase": false, + "omit_unused_structs": false }, "json": { "out": "", diff --git a/internal/endtoend/testdata/process_plugin_sqlc_gen_json/gen/codegen.json b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/gen/codegen.json index 9db04bec79..8aa57cc330 100644 --- a/internal/endtoend/testdata/process_plugin_sqlc_gen_json/gen/codegen.json +++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_json/gen/codegen.json @@ -41,7 +41,8 @@ "emit_pointers_for_null_types": false, "query_parameter_limit": 1, "output_batch_file_name": "", - "json_tags_id_uppercase": false + "json_tags_id_uppercase": false, + "omit_unused_structs": false }, "json": { "out": "", diff --git a/internal/plugin/codegen.pb.go b/internal/plugin/codegen.pb.go index e66fca5ccf..03f16037b4 100644 --- a/internal/plugin/codegen.pb.go +++ b/internal/plugin/codegen.pb.go @@ -468,6 +468,7 @@ type GoCode struct { QueryParameterLimit *int32 `protobuf:"varint,23,opt,name=query_parameter_limit,json=queryParameterLimit,proto3,oneof" json:"query_parameter_limit,omitempty"` OutputBatchFileName string `protobuf:"bytes,24,opt,name=output_batch_file_name,json=outputBatchFileName,proto3" json:"output_batch_file_name,omitempty"` JsonTagsIdUppercase bool `protobuf:"varint,26,opt,name=json_tags_id_uppercase,json=jsonTagsIdUppercase,proto3" json:"json_tags_id_uppercase,omitempty"` + OmitUnusedStructs bool `protobuf:"varint,27,opt,name=omit_unused_structs,json=omitUnusedStructs,proto3" json:"omit_unused_structs,omitempty"` } func (x *GoCode) Reset() { @@ -684,6 +685,13 @@ func (x *GoCode) GetJsonTagsIdUppercase() bool { return false } +func (x *GoCode) GetOmitUnusedStructs() bool { + if x != nil { + return x.OmitUnusedStructs + } + return false +} + type JSONCode struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1657,7 +1665,7 @@ var file_plugin_codegen_proto_rawDesc = []byte{ 0x09, 0x52, 0x03, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x94, 0x0a, 0x0a, 0x06, 0x47, 0x6f, 0x43, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xc4, 0x0a, 0x0a, 0x06, 0x47, 0x6f, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6d, 0x69, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x65, 0x6d, 0x69, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x6d, @@ -1737,7 +1745,10 @@ var file_plugin_codegen_proto_rawDesc = []byte{ 0x12, 0x33, 0x0a, 0x16, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x5f, 0x69, 0x64, 0x5f, 0x75, 0x70, 0x70, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x6a, 0x73, 0x6f, 0x6e, 0x54, 0x61, 0x67, 0x73, 0x49, 0x64, 0x55, 0x70, 0x70, 0x65, - 0x72, 0x63, 0x61, 0x73, 0x65, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, + 0x72, 0x63, 0x61, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x6f, 0x6d, 0x69, 0x74, 0x5f, 0x75, 0x6e, + 0x75, 0x73, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x18, 0x1b, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x11, 0x6f, 0x6d, 0x69, 0x74, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x53, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x73, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x50, 0x0a, 0x08, 0x4a, 0x53, 0x4f, 0x4e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, diff --git a/internal/plugin/codegen_vtproto.pb.go b/internal/plugin/codegen_vtproto.pb.go index 2035e910f8..c2728bf8d5 100644 --- a/internal/plugin/codegen_vtproto.pb.go +++ b/internal/plugin/codegen_vtproto.pb.go @@ -194,6 +194,7 @@ func (m *GoCode) CloneVT() *GoCode { EmitPointersForNullTypes: m.EmitPointersForNullTypes, OutputBatchFileName: m.OutputBatchFileName, JsonTagsIdUppercase: m.JsonTagsIdUppercase, + OmitUnusedStructs: m.OmitUnusedStructs, } if rhs := m.InflectionExcludeTableNames; rhs != nil { tmpContainer := make([]string, len(rhs)) @@ -833,6 +834,9 @@ func (this *GoCode) EqualVT(that *GoCode) bool { if this.JsonTagsIdUppercase != that.JsonTagsIdUppercase { return false } + if this.OmitUnusedStructs != that.OmitUnusedStructs { + return false + } return string(this.unknownFields) == string(that.unknownFields) } @@ -1776,6 +1780,18 @@ func (m *GoCode) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.OmitUnusedStructs { + i-- + if m.OmitUnusedStructs { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xd8 + } if m.JsonTagsIdUppercase { i-- if m.JsonTagsIdUppercase { @@ -3340,6 +3356,18 @@ func (m *GoCode) MarshalToSizedBufferVTStrict(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.OmitUnusedStructs { + i-- + if m.OmitUnusedStructs { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xd8 + } if m.JsonTagsIdUppercase { i-- if m.JsonTagsIdUppercase { @@ -4718,6 +4746,9 @@ func (m *GoCode) SizeVT() (n int) { if m.JsonTagsIdUppercase { n += 3 } + if m.OmitUnusedStructs { + n += 3 + } n += len(m.unknownFields) return n } @@ -7058,6 +7089,26 @@ func (m *GoCode) UnmarshalVT(dAtA []byte) error { } } m.JsonTagsIdUppercase = bool(v != 0) + case 27: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OmitUnusedStructs", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.OmitUnusedStructs = bool(v != 0) default: iNdEx = preIndex skippy, err := skip(dAtA[iNdEx:]) diff --git a/protos/plugin/codegen.proto b/protos/plugin/codegen.proto index 79a64d06d5..cd4d4a040e 100644 --- a/protos/plugin/codegen.proto +++ b/protos/plugin/codegen.proto @@ -99,6 +99,7 @@ message GoCode optional int32 query_parameter_limit = 23; string output_batch_file_name = 24; bool json_tags_id_uppercase = 26; + bool omit_unused_structs = 27; } message JSONCode From 4ac6049692eb6bb985f6253f28fe4a55191799bc Mon Sep 17 00:00:00 2001 From: Andrew Benton Date: Tue, 27 Jun 2023 15:11:12 -0700 Subject: [PATCH 2/2] internal/codegen/golang: modify omit_unused_structs behavior to correctly handle nullable enum types --- internal/codegen/golang/gen.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/internal/codegen/golang/gen.go b/internal/codegen/golang/gen.go index 68095d96d2..9f1b6fe6b5 100644 --- a/internal/codegen/golang/gen.go +++ b/internal/codegen/golang/gen.go @@ -299,18 +299,18 @@ func filterUnusedStructs(enums []Enum, structs []Struct, queries []Query) ([]Enu for _, query := range queries { if !query.Arg.isEmpty() { - keepTypes[strings.TrimPrefix(query.Arg.Type(), "Null")] = struct{}{} + keepTypes[query.Arg.Type()] = struct{}{} if query.Arg.IsStruct() { for _, field := range query.Arg.Struct.Fields { - keepTypes[strings.TrimPrefix(field.Type, "Null")] = struct{}{} + keepTypes[field.Type] = struct{}{} } } } if query.hasRetType() { - keepTypes[strings.TrimPrefix(query.Ret.Type(), "Null")] = struct{}{} + keepTypes[query.Ret.Type()] = struct{}{} if query.Ret.IsStruct() { for _, field := range query.Ret.Struct.Fields { - keepTypes[strings.TrimPrefix(field.Type, "Null")] = struct{}{} + keepTypes[field.Type] = struct{}{} } } } @@ -321,6 +321,9 @@ func filterUnusedStructs(enums []Enum, structs []Struct, queries []Query) ([]Enu if _, ok := keepTypes[enum.Name]; ok { keepEnums = append(keepEnums, enum) } + if _, ok := keepTypes["Null"+enum.Name]; ok { + keepEnums = append(keepEnums, enum) + } } keepStructs := make([]Struct, 0, len(structs))