snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
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

This commit is contained in:
upstream-mirror
2026-09-16 02:17:34 +05:00
commit 0f4df23290
7340 changed files with 238743 additions and 0 deletions

239
internal/config/config.go Normal file
View File

@@ -0,0 +1,239 @@
package config
import (
"bytes"
"encoding/json"
"errors"
"io"
"gopkg.in/yaml.v3"
golang "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts"
)
type versionSetting struct {
Number string `json:"version" yaml:"version"`
}
type Engine string
type Paths []string
func (p *Paths) UnmarshalJSON(data []byte) error {
if string(data[0]) == `[` {
var out []string
if err := json.Unmarshal(data, &out); err != nil {
return nil
}
*p = Paths(out)
return nil
}
var out string
if err := json.Unmarshal(data, &out); err != nil {
return nil
}
*p = Paths([]string{out})
return nil
}
func (p *Paths) UnmarshalYAML(unmarshal func(any) error) error {
out := []string{}
if sliceErr := unmarshal(&out); sliceErr != nil {
var ele string
if strErr := unmarshal(&ele); strErr != nil {
return strErr
}
out = []string{ele}
}
*p = Paths(out)
return nil
}
const (
EngineMySQL Engine = "mysql"
EnginePostgreSQL Engine = "postgresql"
EngineSQLite Engine = "sqlite"
EngineClickHouse Engine = "clickhouse"
EngineGoogleSQL Engine = "googlesql"
EngineMSSQL Engine = "mssql"
EngineDuckDB Engine = "duckdb"
)
type Config struct {
Version string `json:"version" yaml:"version"`
Cloud Cloud `json:"cloud" yaml:"cloud"`
Servers []Server `json:"servers" yaml:"servers"`
SQL []SQL `json:"sql" yaml:"sql"`
Overrides Overrides `json:"overrides" yaml:"overrides"`
Plugins []Plugin `json:"plugins" yaml:"plugins"`
Rules []Rule `json:"rules" yaml:"rules"`
Options map[string]yaml.Node `json:"options" yaml:"options"`
}
type Server struct {
Name string `json:"name,omitempty" yaml:"name"`
Engine Engine `json:"engine,omitempty" yaml:"engine"`
URI string `json:"uri" yaml:"uri"`
}
type Database struct {
URI string `json:"uri" yaml:"uri"`
Managed bool `json:"managed" yaml:"managed"`
}
type Cloud struct {
Organization string `json:"organization" yaml:"organization"`
Project string `json:"project" yaml:"project"`
Hostname string `json:"hostname" yaml:"hostname"`
AuthToken string `json:"-" yaml:"-"`
}
type Plugin struct {
Name string `json:"name" yaml:"name"`
Env []string `json:"env" yaml:"env"`
Process *struct {
Cmd string `json:"cmd" yaml:"cmd"`
Format string `json:"format" yaml:"format"`
} `json:"process" yaml:"process"`
WASM *struct {
URL string `json:"url" yaml:"url"`
SHA256 string `json:"sha256" yaml:"sha256"`
} `json:"wasm" yaml:"wasm"`
}
type Rule struct {
Name string `json:"name" yaml:"name"`
Rule string `json:"rule" yaml:"rule"`
Msg string `json:"message" yaml:"message"`
}
type Overrides struct {
Go *golang.GlobalOptions `json:"go,omitempty" yaml:"go"`
}
type SQL struct {
Name string `json:"name" yaml:"name"`
Engine Engine `json:"engine,omitempty" yaml:"engine"`
Schema Paths `json:"schema" yaml:"schema"`
Queries Paths `json:"queries" yaml:"queries"`
Database *Database `json:"database" yaml:"database"`
StrictFunctionChecks bool `json:"strict_function_checks" yaml:"strict_function_checks"`
StrictOrderBy *bool `json:"strict_order_by" yaml:"strict_order_by"`
Gen SQLGen `json:"gen" yaml:"gen"`
Codegen []Codegen `json:"codegen" yaml:"codegen"`
Rules []string `json:"rules" yaml:"rules"`
Analyzer Analyzer `json:"analyzer" yaml:"analyzer"`
}
type Analyzer struct {
Database *bool `json:"database" yaml:"database"`
}
// TODO: Figure out a better name for this
type Codegen struct {
Out string `json:"out" yaml:"out"`
Plugin string `json:"plugin" yaml:"plugin"`
Options yaml.Node `json:"options" yaml:"options"`
}
type SQLGen struct {
Go *golang.Options `json:"go,omitempty" yaml:"go"`
JSON *SQLJSON `json:"json,omitempty" yaml:"json"`
}
type SQLJSON struct {
Out string `json:"out" yaml:"out"`
Indent string `json:"indent,omitempty" yaml:"indent"`
Filename string `json:"filename,omitempty" yaml:"filename"`
}
var ErrMissingEngine = errors.New("unknown engine")
var ErrMissingVersion = errors.New("no version number")
var ErrNoOutPath = errors.New("no output path")
var ErrNoPackagePath = errors.New("missing package path")
var ErrNoPackages = errors.New("no packages")
var ErrNoQuerierType = errors.New("no querier emit type enabled")
var ErrUnknownEngine = errors.New("invalid engine")
var ErrUnknownVersion = errors.New("invalid version number")
var ErrPluginBuiltin = errors.New("a built-in plugin with that name already exists")
var ErrPluginNoName = errors.New("missing plugin name")
var ErrPluginExists = errors.New("a plugin with that name already exists")
var ErrPluginNotFound = errors.New("no plugin found")
var ErrPluginNoType = errors.New("plugin: field `process` or `wasm` required")
var ErrPluginBothTypes = errors.New("plugin: `process` and `wasm` cannot both be defined")
var ErrPluginProcessNoCmd = errors.New("plugin: missing process command")
var ErrInvalidDatabase = errors.New("database must be managed or have a non-empty URI")
var ErrManagedDatabaseNoProject = errors.New(`managed databases require a cloud project
If you don't have a project, you can create one from the sqlc Cloud
dashboard at https://dashboard.sqlc.dev/. If you have a project, ensure
you've set its id as the value of the "project" field within the "cloud"
section of your sqlc configuration. The id will look similar to
"01HA8TWGMYPHK0V2GGMB3R2TP9".`)
var ErrManagedDatabaseNoAuthToken = errors.New(`managed databases require an auth token
If you don't have an auth token, you can create one from the sqlc Cloud
dashboard at https://dashboard.sqlc.dev/. If you have an auth token, ensure
you've set it as the value of the SQLC_AUTH_TOKEN environment variable.`)
func ParseConfig(rd io.Reader) (Config, error) {
var buf bytes.Buffer
var config Config
var version versionSetting
ver := io.TeeReader(rd, &buf)
dec := yaml.NewDecoder(ver)
if err := dec.Decode(&version); err != nil {
return config, err
}
if version.Number == "" {
return config, ErrMissingVersion
}
var err error
switch version.Number {
case "1":
config, err = v1ParseConfig(&buf)
if err != nil {
return config, err
}
case "2":
config, err = v2ParseConfig(&buf)
if err != nil {
return config, err
}
default:
return config, ErrUnknownVersion
}
err = config.addEnvVars()
if err != nil {
return config, err
}
return config, nil
}
type CombinedSettings struct {
Global Config
Package SQL
Go golang.Options
JSON SQLJSON
// TODO: Combine these into a more usable type
Codegen Codegen
}
func Combine(conf Config, pkg SQL) CombinedSettings {
cs := CombinedSettings{
Global: conf,
Package: pkg,
}
if pkg.Gen.Go != nil {
cs.Go = *pkg.Gen.Go
}
if pkg.Gen.JSON != nil {
cs.JSON = *pkg.Gen.JSON
}
return cs
}

View File

@@ -0,0 +1,91 @@
package config
import (
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
const missingVersion = `{
}`
const missingPackages = `{
"version": "1"
}`
const unknownVersion = `{
"version": "foo"
}`
const unknownFields = `{
"version": "1",
"foo": "bar"
}`
func TestBadConfigs(t *testing.T) {
for _, test := range []struct {
name string
err string
json string
}{
{
"missing version",
"no version number",
missingVersion,
},
{
"missing packages",
"no packages",
missingPackages,
},
{
"unknown version",
"invalid version number",
unknownVersion,
},
{
"unknown fields",
`yaml: unmarshal errors:
line 3: field foo not found in type config.V1GenerateSettings`,
unknownFields,
},
} {
tt := test
t.Run(tt.name, func(t *testing.T) {
_, err := ParseConfig(strings.NewReader(tt.json))
if err == nil {
t.Fatalf("expected err; got nil")
}
if diff := cmp.Diff(err.Error(), tt.err); diff != "" {
t.Errorf("differed (-want +got):\n%s", diff)
}
})
}
}
const validConfigOne = `{
"version": "1"
"packages": []
}`
func FuzzConfig(f *testing.F) {
f.Add(validConfigOne)
f.Fuzz(func(t *testing.T, orig string) {
ParseConfig(strings.NewReader(orig))
})
}
func TestInvalidConfig(t *testing.T) {
err := Validate(&Config{
SQL: []SQL{{
Database: &Database{
URI: "",
Managed: false,
},
}},
})
if err == nil {
t.Errorf("expected err; got nil")
}
}

View File

@@ -0,0 +1,84 @@
package convert
import (
"encoding/json"
"fmt"
"strconv"
"gopkg.in/yaml.v3"
)
func gen(n *yaml.Node) (any, error) {
switch n.Kind {
case yaml.MappingNode:
nn := map[string]any{}
for i, _ := range n.Content {
if i%2 == 0 {
k := n.Content[i]
v, err := gen(n.Content[i+1])
if err != nil {
return nil, err
}
nn[k.Value] = v
}
}
return nn, nil
case yaml.SequenceNode:
nn := []any{}
for i, _ := range n.Content {
v, err := gen(n.Content[i])
if err != nil {
return nil, err
}
nn = append(nn, v)
}
return nn, nil
case yaml.ScalarNode:
switch n.Tag {
case "!!bool":
return strconv.ParseBool(n.Value)
case "!!float":
return strconv.ParseFloat(n.Value, 64)
case "!!int":
return strconv.Atoi(n.Value)
case "!!null":
return nil, nil
case "!!str":
return n.Value, nil
default:
return n.Value, nil
}
case yaml.AliasNode:
return gen(n.Alias)
default:
return nil, fmt.Errorf("unknown yaml value: %s (%s)", n.Value, n.Tag)
}
}
func YAMLtoJSON(n yaml.Node) ([]byte, error) {
if n.Kind == 0 {
return []byte{}, nil
}
iface, err := gen(&n)
if err != nil {
return nil, err
}
blob, err := json.Marshal(iface)
if err != nil {
return nil, err
}
return blob, nil
}

View File

@@ -0,0 +1,47 @@
package convert
import (
"testing"
"gopkg.in/yaml.v3"
)
const anchor = `
sql:
- schema: query.sql
queries: query.sql
engine: postgresql
codegen:
- out: gateway/src/gateway/services/organization
plugin: py
options: &base-options
query_parameter_limit: 1
package: gateway
output_models_file_name: null
emit_module: true
emit_generators: false
emit_async: true
- schema: query.sql
queries: query.sql
engine: postgresql
codegen:
- out: gateway/src/gateway/services/project
plugin: py
options: *base-options
`
type config struct {
SQL yaml.Node `yaml:"sql"`
}
func TestAlias(t *testing.T) {
var a config
err := yaml.Unmarshal([]byte(anchor), &a)
if err != nil {
t.Fatal(err)
}
if _, err := gen(&a.SQL); err != nil {
t.Fatal(err)
}
}

17
internal/config/env.go Normal file
View File

@@ -0,0 +1,17 @@
package config
import (
"fmt"
"os"
"strings"
)
func (c *Config) addEnvVars() error {
authToken := os.Getenv("SQLC_AUTH_TOKEN")
if authToken != "" && !strings.HasPrefix(authToken, "sqlc_") {
return fmt.Errorf("$SQLC_AUTH_TOKEN doesn't start with \"sqlc_\"")
}
c.Cloud.AuthToken = authToken
return nil
}

196
internal/config/v_one.go Normal file
View File

@@ -0,0 +1,196 @@
package config
import (
"fmt"
"io"
"path/filepath"
yaml "gopkg.in/yaml.v3"
golang "github.com/sqlc-dev/sqlc/internal/codegen/golang/opts"
)
type V1GenerateSettings struct {
Version string `json:"version" yaml:"version"`
Cloud Cloud `json:"cloud" yaml:"cloud"`
Packages []v1PackageSettings `json:"packages" yaml:"packages"`
Overrides []golang.Override `json:"overrides,omitempty" yaml:"overrides,omitempty"`
Rename map[string]string `json:"rename,omitempty" yaml:"rename,omitempty"`
Rules []Rule `json:"rules" yaml:"rules"`
}
type v1PackageSettings struct {
Name string `json:"name" yaml:"name"`
Engine Engine `json:"engine,omitempty" yaml:"engine"`
Database *Database `json:"database,omitempty" yaml:"database"`
Analyzer Analyzer `json:"analyzer" yaml:"analyzer"`
Path string `json:"path" yaml:"path"`
Schema Paths `json:"schema" yaml:"schema"`
Queries Paths `json:"queries" yaml:"queries"`
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,omitempty" 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" yaml:"emit_methods_with_db_argument"`
EmitPointersForNullTypes bool `json:"emit_pointers_for_null_types" yaml:"emit_pointers_for_null_types"`
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"`
SQLPackage string `json:"sql_package" yaml:"sql_package"`
SQLDriver string `json:"sql_driver" yaml:"sql_driver"`
Overrides []golang.Override `json:"overrides" yaml:"overrides"`
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"`
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"`
OmitSqlcVersion bool `json:"omit_sqlc_version,omitempty" yaml:"omit_sqlc_version"`
OmitUnusedStructs bool `json:"omit_unused_structs,omitempty" yaml:"omit_unused_structs"`
Rules []string `json:"rules" yaml:"rules"`
BuildTags string `json:"build_tags,omitempty" yaml:"build_tags"`
}
func v1ParseConfig(rd io.Reader) (Config, error) {
dec := yaml.NewDecoder(rd)
dec.KnownFields(true)
var settings V1GenerateSettings
var config Config
if err := dec.Decode(&settings); err != nil {
return config, err
}
if settings.Version == "" {
return config, ErrMissingVersion
}
if settings.Version != "1" {
return config, ErrUnknownVersion
}
if len(settings.Packages) == 0 {
return config, ErrNoPackages
}
if err := settings.ValidateGlobalOverrides(); err != nil {
return config, err
}
for j := range settings.Packages {
if settings.Packages[j].Path == "" {
return config, ErrNoPackagePath
}
if settings.Packages[j].Name == "" {
settings.Packages[j].Name = filepath.Base(settings.Packages[j].Path)
}
if settings.Packages[j].Engine == "" {
settings.Packages[j].Engine = EnginePostgreSQL
}
}
return settings.Translate(), nil
}
func (c *V1GenerateSettings) ValidateGlobalOverrides() error {
engines := map[Engine]struct{}{}
for _, pkg := range c.Packages {
if _, ok := engines[pkg.Engine]; !ok {
engines[pkg.Engine] = struct{}{}
}
}
usesMultipleEngines := len(engines) > 1
for _, oride := range c.Overrides {
if usesMultipleEngines && oride.Engine == "" {
return fmt.Errorf(`the "engine" field is required for global type overrides because your configuration uses multiple database engines`)
}
}
return nil
}
func (c *V1GenerateSettings) Translate() Config {
conf := Config{
Version: c.Version,
Cloud: c.Cloud,
Rules: c.Rules,
}
for _, pkg := range c.Packages {
if pkg.StrictOrderBy == nil {
defaultValue := true
pkg.StrictOrderBy = &defaultValue
}
conf.SQL = append(conf.SQL, SQL{
Name: pkg.Name,
Engine: pkg.Engine,
Database: pkg.Database,
Schema: pkg.Schema,
Queries: pkg.Queries,
Rules: pkg.Rules,
Analyzer: pkg.Analyzer,
Gen: SQLGen{
Go: &golang.Options{
EmitInterface: pkg.EmitInterface,
EmitJsonTags: pkg.EmitJSONTags,
JsonTagsIdUppercase: pkg.JsonTagsIDUppercase,
EmitDbTags: pkg.EmitDBTags,
EmitPreparedQueries: pkg.EmitPreparedQueries,
EmitExactTableNames: pkg.EmitExactTableNames,
EmitEmptySlices: pkg.EmitEmptySlices,
EmitExportedQueries: pkg.EmitExportedQueries,
EmitResultStructPointers: pkg.EmitResultStructPointers,
EmitParamsStructPointers: pkg.EmitParamsStructPointers,
EmitMethodsWithDbArgument: pkg.EmitMethodsWithDBArgument,
EmitPointersForNullTypes: pkg.EmitPointersForNullTypes,
EmitPointersForNullEnumTypes: pkg.EmitPointersForNullEnumTypes,
EmitEnumValidMethod: pkg.EmitEnumValidMethod,
EmitAllEnumValues: pkg.EmitAllEnumValues,
EmitSqlAsComment: pkg.EmitSqlAsComment,
Package: pkg.Name,
Out: pkg.Path,
SqlPackage: pkg.SQLPackage,
SqlDriver: pkg.SQLDriver,
Overrides: pkg.Overrides,
JsonTagsCaseStyle: pkg.JSONTagsCaseStyle,
OutputBatchFileName: pkg.OutputBatchFileName,
OutputDbFileName: pkg.OutputDBFileName,
OutputModelsFileName: pkg.OutputModelsFileName,
OutputModelsPath: pkg.OutputModelsPath,
OutputModelsPackage: pkg.OutputModelsPackage,
OutputModelsImport: pkg.OutputModelsImport,
OutputModelsEmit: pkg.OutputModelsEmit,
OutputQuerierFileName: pkg.OutputQuerierFileName,
OutputCopyfromFileName: pkg.OutputCopyFromFileName,
OutputFilesSuffix: pkg.OutputFilesSuffix,
QueryParameterLimit: pkg.QueryParameterLimit,
OmitSqlcVersion: pkg.OmitSqlcVersion,
OmitUnusedStructs: pkg.OmitUnusedStructs,
BuildTags: pkg.BuildTags,
},
},
StrictFunctionChecks: pkg.StrictFunctionChecks,
StrictOrderBy: pkg.StrictOrderBy,
})
}
if len(c.Overrides) > 0 || len(c.Rename) > 0 {
conf.Overrides.Go = &golang.GlobalOptions{
Overrides: c.Overrides,
Rename: c.Rename,
}
}
return conf
}

361
internal/config/v_one.json Normal file
View File

@@ -0,0 +1,361 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"required": [
"version"
],
"properties": {
"version": {
"const": "1"
},
"cloud": {
"type": "object",
"properties": {
"organization": {
"type": "string"
},
"project": {
"type": "string"
},
"hostname": {
"type": "string"
}
}
},
"packages": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": [
"engine"
],
"properties": {
"engine": {
"enum": [
"postgresql",
"mysql",
"sqlite"
]
},
"schema": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"queries": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"database": {
"type": "object",
"properties": {
"uri": {
"type": "string"
},
"managed": {
"type": "boolean"
}
}
},
"analyzer": {
"type": "object",
"properties": {
"database": {
"type": "boolean"
}
}
},
"strict_function_checks": {
"type": "boolean"
},
"strict_order_by": {
"type": "boolean"
},
"emit_interface": {
"type": "boolean"
},
"emit_json_tags": {
"type": "boolean"
},
"json_tags_id_uppercase": {
"type": "boolean"
},
"emit_db_tags": {
"type": "boolean"
},
"emit_prepared_queries": {
"type": "boolean"
},
"emit_exact_table_names": {
"type": "boolean"
},
"emit_empty_slices": {
"type": "boolean"
},
"emit_exported_queries": {
"type": "boolean"
},
"emit_result_struct_pointers": {
"type": "boolean"
},
"emit_params_struct_pointers": {
"type": "boolean"
},
"emit_methods_with_db_argument": {
"type": "boolean"
},
"emit_pointers_for_null_types": {
"type": "boolean"
},
"emit_pointers_for_null_enum_types": {
"type": "boolean"
},
"emit_enum_valid_method": {
"type": "boolean"
},
"emit_all_enum_values": {
"type": "boolean"
},
"emit_sql_as_comment": {
"type": "boolean"
},
"build_tags": {
"type": "string"
},
"json_tags_case_style": {
"type": "string"
},
"package": {
"type": "string"
},
"out": {
"type": "string"
},
"overrides": {
"type": "array",
"items": {
"type": "object",
"properties": {
"go_type": {
"oneOf": [
{
"type": "object",
"properties": {
"import": {
"type": "string"
},
"package": {
"type": "string"
},
"type": {
"type": "string"
},
"pointer": {
"type": "boolean"
},
"slice": {
"type": "boolean"
},
"spec": {
"type": "string"
},
"builtin": {
"type": "boolean"
}
}
},
{
"type": "string"
}
]
},
"go_struct_tag": {
"type": "string"
},
"db_type": {
"type": "string"
},
"engine": {
"enum": [
"postgresql",
"mysql",
"sqlite"
]
},
"nullable": {
"type": "boolean"
},
"unsigned": {
"type": "boolean"
},
"column": {
"type": "string"
}
}
}
},
"sql_package": {
"type": "string"
},
"sql_driver": {
"type": "string"
},
"output_batch_file_name": {
"type": "string"
},
"output_db_file_name": {
"type": "string"
},
"output_models_file_name": {
"type": "string"
},
"output_models_path": {
"type": "string"
},
"output_models_package": {
"type": "string"
},
"output_models_import": {
"type": "string"
},
"output_models_emit": {
"type": "boolean"
},
"output_querier_file_name": {
"type": "string"
},
"output_copyfrom_file_name": {
"type": "string"
},
"output_files_suffix": {
"type": "string"
},
"inflection_exclude_table_names": {
"type": "array",
"items": {
"type": "string"
}
},
"query_parameter_limit": {
"type": "integer"
},
"omit_unused_structs": {
"type": "boolean"
},
"rules": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"overrides": {
"type": "array",
"items": {
"type": "object",
"properties": {
"go_type": {
"oneOf": [
{
"type": "object",
"properties": {
"import": {
"type": "string"
},
"package": {
"type": "string"
},
"type": {
"type": "string"
},
"pointer": {
"type": "boolean"
},
"slice": {
"type": "boolean"
},
"spec": {
"type": "string"
},
"builtin": {
"type": "boolean"
}
}
},
{
"type": "string"
}
]
},
"go_struct_tag": {
"type": "string"
},
"db_type": {
"type": "string"
},
"engine": {
"enum": [
"postgresql",
"mysql",
"sqlite"
]
},
"nullable": {
"type": "boolean"
},
"unsigned": {
"type": "boolean"
},
"column": {
"type": "string"
}
}
}
}
},
"rename": {
"type": "object",
"patternProperties": {
".*": {
"type": "string"
}
}
},
"rules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"rule": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}

109
internal/config/v_two.go Normal file
View File

@@ -0,0 +1,109 @@
package config
import (
"fmt"
"io"
yaml "gopkg.in/yaml.v3"
)
func v2ParseConfig(rd io.Reader) (Config, error) {
dec := yaml.NewDecoder(rd)
dec.KnownFields(true)
var conf Config
if err := dec.Decode(&conf); err != nil {
return conf, err
}
if conf.Version == "" {
return conf, ErrMissingVersion
}
if conf.Version != "2" {
return conf, ErrUnknownVersion
}
if len(conf.SQL) == 0 {
return conf, ErrNoPackages
}
if err := conf.validateGlobalOverrides(); err != nil {
return conf, err
}
// TODO: Store built-in plugins somewhere else
builtins := map[string]struct{}{
"go": {},
"json": {},
}
plugins := map[string]struct{}{}
for i := range conf.Plugins {
if conf.Plugins[i].Name == "" {
return conf, ErrPluginNoName
}
if _, ok := builtins[conf.Plugins[i].Name]; ok {
return conf, ErrPluginBuiltin
}
if _, ok := plugins[conf.Plugins[i].Name]; ok {
return conf, ErrPluginExists
}
if conf.Plugins[i].Process == nil && conf.Plugins[i].WASM == nil {
return conf, ErrPluginNoType
}
if conf.Plugins[i].Process != nil && conf.Plugins[i].WASM != nil {
return conf, ErrPluginBothTypes
}
if conf.Plugins[i].Process != nil {
if conf.Plugins[i].Process.Cmd == "" {
return conf, ErrPluginProcessNoCmd
}
}
plugins[conf.Plugins[i].Name] = struct{}{}
}
for j := range conf.SQL {
if conf.SQL[j].Engine == "" {
return conf, ErrMissingEngine
}
if conf.SQL[j].Gen.Go != nil {
if conf.SQL[j].Gen.Go.Out == "" {
return conf, ErrNoPackagePath
}
}
if conf.SQL[j].Gen.JSON != nil {
if conf.SQL[j].Gen.JSON.Out == "" {
return conf, ErrNoOutPath
}
}
for _, cg := range conf.SQL[j].Codegen {
if cg.Plugin == "" {
return conf, ErrPluginNoName
}
if cg.Out == "" {
return conf, ErrNoOutPath
}
// TODO: Allow the use of built-in codegen from here
if _, ok := plugins[cg.Plugin]; !ok {
return conf, ErrPluginNotFound
}
}
if conf.SQL[j].StrictOrderBy == nil {
defaultValidate := true
conf.SQL[j].StrictOrderBy = &defaultValidate
}
}
return conf, nil
}
func (c *Config) validateGlobalOverrides() error {
engines := map[Engine]struct{}{}
for _, pkg := range c.SQL {
if _, ok := engines[pkg.Engine]; !ok {
engines[pkg.Engine] = struct{}{}
}
}
if c.Overrides.Go == nil {
return nil
}
usesMultipleEngines := len(engines) > 1
for _, oride := range c.Overrides.Go.Overrides {
if usesMultipleEngines && oride.Engine == "" {
return fmt.Errorf(`the "engine" field is required for global type overrides because your configuration uses multiple database engines`)
}
}
return nil
}

463
internal/config/v_two.json Normal file
View File

@@ -0,0 +1,463 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"required": [
"version"
],
"properties": {
"version": {
"const": "2"
},
"cloud": {
"type": "object",
"properties": {
"organization": {
"type": "string"
},
"project": {
"type": "string"
},
"hostname": {
"type": "string"
}
}
},
"sql": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": [
"engine"
],
"properties": {
"name": {
"type": "string"
},
"engine": {
"enum": [
"postgresql",
"mysql",
"sqlite"
]
},
"schema": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"queries": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"database": {
"type": "object",
"properties": {
"uri": {
"type": "string"
},
"managed": {
"type": "boolean"
}
}
},
"analyzer": {
"type": "object",
"properties": {
"database": {
"type": "boolean"
}
}
},
"strict_function_checks": {
"type": "boolean"
},
"strict_order_by": {
"type": "boolean"
},
"gen": {
"type": "object",
"properties": {
"go": {
"type": "object",
"properties": {
"emit_interface": {
"type": "boolean"
},
"emit_json_tags": {
"type": "boolean"
},
"json_tags_id_uppercase": {
"type": "boolean"
},
"emit_db_tags": {
"type": "boolean"
},
"emit_prepared_queries": {
"type": "boolean"
},
"emit_exact_table_names": {
"type": "boolean"
},
"emit_empty_slices": {
"type": "boolean"
},
"emit_exported_queries": {
"type": "boolean"
},
"emit_result_struct_pointers": {
"type": "boolean"
},
"emit_params_struct_pointers": {
"type": "boolean"
},
"emit_methods_with_db_argument": {
"type": "boolean"
},
"emit_pointers_for_null_types": {
"type": "boolean"
},
"emit_pointers_for_null_enum_types": {
"type": "boolean"
},
"emit_enum_valid_method": {
"type": "boolean"
},
"emit_all_enum_values": {
"type": "boolean"
},
"emit_sql_as_comment": {
"type": "boolean"
},
"build_tags": {
"type": "string"
},
"json_tags_case_style": {
"type": "string"
},
"package": {
"type": "string"
},
"out": {
"type": "string"
},
"overrides": {
"type": "array",
"items": {
"type": "object",
"properties": {
"go_type": {
"oneOf": [
{
"type": "object",
"properties": {
"import": {
"type": "string"
},
"package": {
"type": "string"
},
"type": {
"type": "string"
},
"pointer": {
"type": "boolean"
},
"slice": {
"type": "boolean"
},
"spec": {
"type": "string"
},
"builtin": {
"type": "boolean"
}
}
},
{
"type": "string"
}
]
},
"go_struct_tag": {
"type": "string"
},
"db_type": {
"type": "string"
},
"engine": {
"enum": [
"postgresql",
"mysql",
"sqlite"
]
},
"nullable": {
"type": "boolean"
},
"unsigned": {
"type": "boolean"
},
"column": {
"type": "string"
}
}
}
}
},
"rename": {
"type": "object",
"patternProperties": {
".*": {
"type": "string"
}
}
},
"sql_package": {
"type": "string"
},
"sql_driver": {
"type": "string"
},
"output_batch_file_name": {
"type": "string"
},
"output_db_file_name": {
"type": "string"
},
"output_models_file_name": {
"type": "string"
},
"output_models_path": {
"type": "string"
},
"output_models_package": {
"type": "string"
},
"output_models_import": {
"type": "string"
},
"output_models_emit": {
"type": "boolean"
},
"output_querier_file_name": {
"type": "string"
},
"output_copyfrom_file_name": {
"type": "string"
},
"output_files_suffix": {
"type": "string"
},
"inflection_exclude_table_names": {
"type": "array",
"items": {
"type": "string"
}
},
"query_parameter_limit": {
"type": "integer"
},
"omit_unused_structs": {
"type": "boolean"
}
},
"json": {
"type": "object",
"properties": {
"out": {
"type": "string"
},
"indent": {
"type": "string"
},
"filename": {
"type": "string"
}
}
}
}
},
"codegen": {
"type": "array",
"items": {
"type": "object",
"properties": {
"out": {
"type": "string"
},
"plugin": {
"type": "string"
},
"options": {
"type": "object"
}
}
}
},
"rules": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"overrides": {
"type": "object",
"properties": {
"go": {
"type": "object",
"properties": {
"overrides": {
"type": "array",
"items": {
"type": "object",
"properties": {
"go_type": {
"oneOf": [
{
"type": "object",
"properties": {
"import": {
"type": "string"
},
"package": {
"type": "string"
},
"type": {
"type": "string"
},
"pointer": {
"type": "boolean"
},
"slice": {
"type": "boolean"
},
"spec": {
"type": "string"
},
"builtin": {
"type": "boolean"
}
}
},
{
"type": "string"
}
]
},
"go_struct_tag": {
"type": "string"
},
"db_type": {
"type": "string"
},
"engine": {
"enum": [
"postgresql",
"mysql",
"sqlite"
]
},
"nullable": {
"type": "boolean"
},
"unsigned": {
"type": "boolean"
},
"column": {
"type": "string"
}
}
}
},
"rename": {
"type": "object",
"patternProperties": {
".*": {
"type": "string"
}
}
}
}
}
}
},
"plugins": {
"type": "array",
"items": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"env": {
"type": "array",
"items": {
"type": "string"
}
},
"process": {
"type": "object",
"properties": {
"cmd": {
"type": "string"
}
}
},
"wasm": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"sha256": {
"type": "string"
}
}
}
}
}
},
"rules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"rule": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
package config
func Validate(c *Config) error {
for _, sql := range c.SQL {
if sql.Database != nil {
if sql.Database.URI == "" && !sql.Database.Managed {
return ErrInvalidDatabase
}
}
}
return nil
}