Files
upstream-mirror 0f4df23290
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
2026-09-16 02:17:34 +05:00

244 lines
9.8 KiB
Go

package opts
import (
"encoding/json"
"fmt"
"maps"
"path/filepath"
"github.com/sqlc-dev/sqlc/internal/plugin"
)
type Options struct {
EmitInterface bool `json:"emit_interface" yaml:"emit_interface"`
EmitJsonTags bool `json:"emit_json_tags" yaml:"emit_json_tags"`
JsonTagsIdUppercase bool `json:"json_tags_id_uppercase" yaml:"json_tags_id_uppercase"`
EmitDbTags bool `json:"emit_db_tags" yaml:"emit_db_tags"`
EmitPreparedQueries bool `json:"emit_prepared_queries" yaml:"emit_prepared_queries"`
EmitExactTableNames bool `json:"emit_exact_table_names,omitempty" yaml:"emit_exact_table_names"`
EmitEmptySlices bool `json:"emit_empty_slices,omitempty" yaml:"emit_empty_slices"`
EmitExportedQueries bool `json:"emit_exported_queries" yaml:"emit_exported_queries"`
EmitResultStructPointers bool `json:"emit_result_struct_pointers" yaml:"emit_result_struct_pointers"`
EmitParamsStructPointers bool `json:"emit_params_struct_pointers" yaml:"emit_params_struct_pointers"`
EmitMethodsWithDbArgument bool `json:"emit_methods_with_db_argument,omitempty" yaml:"emit_methods_with_db_argument"`
EmitPointersForNullTypes bool `json:"emit_pointers_for_null_types" yaml:"emit_pointers_for_null_types"`
// nil inherits EmitPointersForNullTypes; non-nil overrides for enums only.
EmitPointersForNullEnumTypes *bool `json:"emit_pointers_for_null_enum_types,omitempty" yaml:"emit_pointers_for_null_enum_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"`
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"`
Out string `json:"out" yaml:"out"`
Overrides []Override `json:"overrides,omitempty" yaml:"overrides"`
Rename map[string]string `json:"rename,omitempty" yaml:"rename"`
SqlPackage string `json:"sql_package" yaml:"sql_package"`
SqlDriver string `json:"sql_driver" yaml:"sql_driver"`
OutputBatchFileName string `json:"output_batch_file_name,omitempty" yaml:"output_batch_file_name"`
OutputDbFileName string `json:"output_db_file_name,omitempty" yaml:"output_db_file_name"`
OutputModelsFileName string `json:"output_models_file_name,omitempty" yaml:"output_models_file_name"`
OutputModelsPath string `json:"output_models_path,omitempty" yaml:"output_models_path"`
OutputModelsPackage string `json:"output_models_package,omitempty" yaml:"output_models_package"`
OutputModelsImport string `json:"output_models_import,omitempty" yaml:"output_models_import"`
OutputModelsEmit *bool `json:"output_models_emit,omitempty" yaml:"output_models_emit"`
OutputQuerierFileName string `json:"output_querier_file_name,omitempty" yaml:"output_querier_file_name"`
OutputCopyfromFileName string `json:"output_copyfrom_file_name,omitempty" yaml:"output_copyfrom_file_name"`
OutputFilesSuffix string `json:"output_files_suffix,omitempty" yaml:"output_files_suffix"`
InflectionExcludeTableNames []string `json:"inflection_exclude_table_names,omitempty" yaml:"inflection_exclude_table_names"`
WrapErrors bool `json:"wrap_errors,omitempty" yaml:"wrap_errors"`
QueryParameterLimit *int32 `json:"query_parameter_limit,omitempty" yaml:"query_parameter_limit"`
OmitSqlcVersion bool `json:"omit_sqlc_version,omitempty" yaml:"omit_sqlc_version"`
OmitUnusedStructs bool `json:"omit_unused_structs,omitempty" yaml:"omit_unused_structs"`
BuildTags string `json:"build_tags,omitempty" yaml:"build_tags"`
Initialisms *[]string `json:"initialisms,omitempty" yaml:"initialisms"`
InitialismsMap map[string]struct{} `json:"-" yaml:"-"`
}
type GlobalOptions struct {
Overrides []Override `json:"overrides,omitempty" yaml:"overrides"`
Rename map[string]string `json:"rename,omitempty" yaml:"rename"`
}
func Parse(req *plugin.GenerateRequest) (*Options, error) {
options, err := parseOpts(req)
if err != nil {
return nil, err
}
global, err := parseGlobalOpts(req)
if err != nil {
return nil, err
}
if len(global.Overrides) > 0 {
options.Overrides = append(global.Overrides, options.Overrides...)
}
if len(global.Rename) > 0 {
if options.Rename == nil {
options.Rename = map[string]string{}
}
maps.Copy(options.Rename, global.Rename)
}
return options, nil
}
func parseOpts(req *plugin.GenerateRequest) (*Options, error) {
var options Options
if len(req.PluginOptions) == 0 {
return &options, nil
}
if err := json.Unmarshal(req.PluginOptions, &options); err != nil {
return nil, fmt.Errorf("unmarshalling plugin options: %w", err)
}
if options.Package == "" {
if options.Out != "" {
options.Package = filepath.Base(options.Out)
} else {
return nil, fmt.Errorf("invalid options: missing package name")
}
}
// Default the models package name to the base of the models path. When
// the user only configures output_models_emit: false (no path), fall
// back to the base of the import path.
if options.OutputModelsPackage == "" {
if options.OutputModelsPath != "" {
options.OutputModelsPackage = filepath.Base(options.OutputModelsPath)
} else if options.OutputModelsImport != "" {
options.OutputModelsPackage = filepath.Base(options.OutputModelsImport)
}
}
for i := range options.Overrides {
if err := options.Overrides[i].parse(req); err != nil {
return nil, err
}
}
if options.SqlPackage != "" {
if err := validatePackage(options.SqlPackage); err != nil {
return nil, fmt.Errorf("invalid options: %s", err)
}
}
if options.SqlDriver != "" {
if err := validateDriver(options.SqlDriver); err != nil {
return nil, fmt.Errorf("invalid options: %s", err)
}
}
if options.QueryParameterLimit == nil {
options.QueryParameterLimit = new(int32)
*options.QueryParameterLimit = 1
}
if options.Initialisms == nil {
options.Initialisms = new([]string)
*options.Initialisms = []string{"id"}
}
options.InitialismsMap = map[string]struct{}{}
for _, initial := range *options.Initialisms {
options.InitialismsMap[initial] = struct{}{}
}
return &options, nil
}
func parseGlobalOpts(req *plugin.GenerateRequest) (*GlobalOptions, error) {
var options GlobalOptions
if len(req.GlobalOptions) == 0 {
return &options, nil
}
if err := json.Unmarshal(req.GlobalOptions, &options); err != nil {
return nil, fmt.Errorf("unmarshalling global options: %w", err)
}
for i := range options.Overrides {
if err := options.Overrides[i].parse(req); err != nil {
return nil, err
}
}
return &options, nil
}
func ValidateOpts(opts *Options) error {
if opts.EmitMethodsWithDbArgument && opts.EmitPreparedQueries {
return fmt.Errorf("invalid options: emit_methods_with_db_argument and emit_prepared_queries options are mutually exclusive")
}
if *opts.QueryParameterLimit < 0 {
return fmt.Errorf("invalid options: query parameter limit must not be negative")
}
if err := validateModelsOptions(opts); err != nil {
return err
}
return nil
}
// ModelsEmitEnabled reports whether this codegen block should write the
// models file. Defaults to true when the option is unset.
func (o *Options) ModelsEmitEnabled() bool {
if o.OutputModelsEmit == nil {
return true
}
return *o.OutputModelsEmit
}
// ModelsImportAlias is the fixed Go import alias used for the models
// package in query files. Using a constant alias keeps the type qualifier
// consistent regardless of how the user names the actual package.
const ModelsImportAlias = "models"
// ModelsPackage returns the Go package name to use in the models file
// itself (i.e. the `package X` declaration). When the caller has not
// configured a separate models package, this is the same as Package.
func (o *Options) ModelsPackage() string {
if o.OutputModelsPackage != "" {
return o.OutputModelsPackage
}
return o.Package
}
// ModelsAreExternal reports whether model types live in a different Go
// package than the queries package. When true, query files must import the
// models package and reference types as `models.Type`.
func (o *Options) ModelsAreExternal() bool {
return o.OutputModelsImport != ""
}
// ModelsTypeQualifier returns the prefix to use when referencing a model
// type from a query file ("models."). Empty string when no qualifier is
// needed.
func (o *Options) ModelsTypeQualifier() string {
if o.ModelsAreExternal() {
return ModelsImportAlias + "."
}
return ""
}
func validateModelsOptions(opts *Options) error {
hasAnyModelsOpt := opts.OutputModelsPath != "" ||
opts.OutputModelsPackage != "" ||
opts.OutputModelsImport != "" ||
opts.OutputModelsEmit != nil
if !hasAnyModelsOpt {
return nil
}
if opts.OutputModelsImport == "" {
return fmt.Errorf("invalid options: output_models_import is required when any output_models_* option is set")
}
if opts.ModelsEmitEnabled() && opts.OutputModelsPath == "" {
return fmt.Errorf("invalid options: output_models_path is required when emitting models to a separate package")
}
if opts.ModelsEmitEnabled() && opts.OutputModelsPath == opts.Out {
return fmt.Errorf("invalid options: output_models_path matches out; models would overwrite the queries package")
}
return nil
}