Repository: sqlc-dev/sqlc
Pull request #2899 (2023-10-22 22:34:11)

refactor(codegen): Removed deprecated code and improved speed
Just tiny change for single file:

* removed `strings.Title` cause this function is deprecated
* removed regexp, cause this expression easily converts to `strings.Map`
* replaced multiple `strings.Replace` to simple, fast and single line solution
* Added docs cuz why not? ¯\\\_(ツ)_/¯

Why this pr? I just probing how good contribution pipeline is for this repo, wanna make a lot of good improvements 😊


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f6eba6dcf..edef06cd6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,8 +10,6 @@ jobs:
     runs-on: windows-latest
     steps:
     - uses: actions/checkout@v4
-    # wasmtime can't be built with 12.2
-    - run: choco install mingw --version 11.2.0.07112021 --allow-downgrade
     - uses: actions/setup-go@v4
       with:
         go-version: '1.21.3'
diff --git a/go.mod b/go.mod
index 532b10ff9..06b9f4f09 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.21
 
 require (
 	github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1
-	github.com/bytecodealliance/wasmtime-go/v13 v13.0.0
+	github.com/bytecodealliance/wasmtime-go/v14 v14.0.0
 	github.com/cubicdaiya/gonp v1.0.4
 	github.com/davecgh/go-spew v1.1.1
 	github.com/go-sql-driver/mysql v1.7.1
diff --git a/go.sum b/go.sum
index a5e0c2934..4870a4694 100644
--- a/go.sum
+++ b/go.sum
@@ -5,8 +5,8 @@ github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1/g
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
 github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
-github.com/bytecodealliance/wasmtime-go/v13 v13.0.0 h1:o2PsUgSu6vMKr5S0+mz8EL3mZGQ0M8gHwS8/R0wY/wY=
-github.com/bytecodealliance/wasmtime-go/v13 v13.0.0/go.mod h1:KmsZLdjjzNH/E5wbfoRehqP70tHzKlfNOi730VCAR4E=
+github.com/bytecodealliance/wasmtime-go/v14 v14.0.0 h1:ur7S3P+PAeJmgllhSrKnGQOAmmtUbLQxb/nw2NZiaEM=
+github.com/bytecodealliance/wasmtime-go/v14 v14.0.0/go.mod h1:tqOVEUjnXY6aGpSfM9qdVRR6G//Yc513fFYUdzZb/DY=
 github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go
index 8d7a64c8d..9a6584b52 100644
--- a/internal/cmd/cmd.go
+++ b/internal/cmd/cmd.go
@@ -39,7 +39,6 @@ func Do(args []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) int
 	rootCmd.PersistentFlags().BoolP("experimental", "x", false, "DEPRECATED: enable experimental features (default: false)")
 	rootCmd.PersistentFlags().Bool("no-remote", false, "disable remote execution (default: false)")
 	rootCmd.PersistentFlags().Bool("remote", false, "enable remote execution (default: false)")
-	rootCmd.PersistentFlags().Bool("no-database", false, "disable database connections (default: false)")
 
 	rootCmd.AddCommand(checkCmd)
 	rootCmd.AddCommand(createDBCmd)
@@ -137,24 +136,21 @@ var initCmd = &cobra.Command{
 }
 
 type Env struct {
-	DryRun     bool
-	Debug      opts.Debug
-	Remote     bool
-	NoRemote   bool
-	NoDatabase bool
+	DryRun   bool
+	Debug    opts.Debug
+	Remote   bool
+	NoRemote bool
 }
 
 func ParseEnv(c *cobra.Command) Env {
 	dr := c.Flag("dry-run")
 	r := c.Flag("remote")
 	nr := c.Flag("no-remote")
-	nodb := c.Flag("no-database")
 	return Env{
-		DryRun:     dr != nil && dr.Changed,
-		Debug:      opts.DebugFromEnv(),
-		Remote:     r != nil && nr.Value.String() == "true",
-		NoRemote:   nr != nil && nr.Value.String() == "true",
-		NoDatabase: nodb != nil && nodb.Value.String() == "true",
+		DryRun:   dr != nil && dr.Changed,
+		Debug:    opts.DebugFromEnv(),
+		Remote:   r != nil && nr.Value.String() == "true",
+		NoRemote: nr != nil && nr.Value.String() == "true",
 	}
 }
 
diff --git a/internal/cmd/vet.go b/internal/cmd/vet.go
index bb56c7de3..2d3e1c24b 100644
--- a/internal/cmd/vet.go
+++ b/internal/cmd/vet.go
@@ -144,13 +144,13 @@ func Vet(ctx context.Context, dir, filename string, opts *Options) error {
 	}
 
 	c := checker{
-		Rules:      rules,
-		Conf:       conf,
-		Dir:        dir,
-		Env:        env,
-		Envmap:     map[string]string{},
-		Stderr:     stderr,
-		NoDatabase: e.NoDatabase,
+		Rules:         rules,
+		Conf:          conf,
+		Dir:           dir,
+		Env:           env,
+		Stderr:        stderr,
+		OnlyManagedDB: e.Debug.OnlyManagedDatabases,
+		Replacer:      shfmt.NewReplacer(nil),
 	}
 	errored := false
 	for _, sql := range conf.SQL {
@@ -379,14 +379,14 @@ type rule struct {
 }
 
 type checker struct {
-	Rules      map[string]rule
-	Conf       *config.Config
-	Dir        string
-	Env        *cel.Env
-	Envmap     map[string]string
-	Stderr     io.Writer
-	NoDatabase bool
-	Client     pb.QuickClient
+	Rules         map[string]rule
+	Conf          *config.Config
+	Dir           string
+	Env           *cel.Env
+	Stderr        io.Writer
+	OnlyManagedDB bool
+	Client        pb.QuickClient
+	Replacer      *shfmt.Replacer
 }
 
 func (c *checker) fetchDatabaseUri(ctx context.Context, s config.SQL) (string, func() error, error) {
@@ -448,14 +448,7 @@ func (c *checker) fetchDatabaseUri(ctx context.Context, s config.SQL) (string, f
 }
 
 func (c *checker) DSN(dsn string) (string, error) {
-	// Populate the environment variable map if it is empty
-	if len(c.Envmap) == 0 {
-		for _, e := range os.Environ() {
-			k, v, _ := strings.Cut(e, "=")
-			c.Envmap[k] = v
-		}
-	}
-	return shfmt.Replace(dsn, c.Envmap), nil
+	return c.Replacer.Replace(dsn), nil
 }
 
 func (c *checker) checkSQL(ctx context.Context, s config.SQL) error {
@@ -488,8 +481,8 @@ func (c *checker) checkSQL(ctx context.Context, s config.SQL) error {
 	var prep preparer
 	var expl explainer
 	if s.Database != nil { // TODO only set up a database connection if a rule evaluation requires it
-		if c.NoDatabase {
-			return fmt.Errorf("database: connections disabled via command line flag")
+		if s.Database.URI != "" && c.OnlyManagedDB {
+			return fmt.Errorf("database: connections disabled via SQLCDEBUG=databases=managed")
 		}
 		dburl, cleanup, err := c.fetchDatabaseUri(ctx, s)
 		if err != nil {
diff --git a/internal/codegen/golang/enum.go b/internal/codegen/golang/enum.go
index 75291d3ac..f429551f4 100644
--- a/internal/codegen/golang/enum.go
+++ b/internal/codegen/golang/enum.go
@@ -1,12 +1,10 @@
 package golang
 
 import (
-	"regexp"
 	"strings"
+	"unicode"
 )
 
-var IdentPattern = regexp.MustCompile("[^a-zA-Z0-9_]+")
-
 type Constant struct {
 	Name  string
 	Type  string
@@ -29,21 +27,38 @@ func (e Enum) ValidTag() string {
 	return TagsToString(e.ValidTags)
 }
 
+func enumReplacer(r rune) rune {
+	if strings.ContainsRune("-/:_", r) {
+		return '_'
+	} else if (r >= 'a' && r <= 'z') ||
+		(r >= 'A' && r <= 'Z') ||
+		(r >= '0' && r <= '9') {
+		return r
+	} else {
+		return -1
+	}
+}
+
+// EnumReplace removes all non ident symbols (all but letters, numbers and
+// underscore) and returns valid ident name for provided name.
 func EnumReplace(value string) string {
-	id := strings.Replace(value, "-", "_", -1)
-	id = strings.Replace(id, ":", "_", -1)
-	id = strings.Replace(id, "/", "_", -1)
-	return IdentPattern.ReplaceAllString(id, "")
+	return strings.Map(enumReplacer, value)
 }
 
+// EnumValueName removes all non ident symbols (all but letters, numbers and
+// underscore) and converts snake case ident to camel case.
 func EnumValueName(value string) string {
-	name := ""
-	id := strings.Replace(value, "-", "_", -1)
-	id = strings.Replace(id, ":", "_", -1)
-	id = strings.Replace(id, "/", "_", -1)
-	id = IdentPattern.ReplaceAllString(id, "")
-	for _, part := range strings.Split(id, "_") {
-		name += strings.Title(part)
+	parts := strings.Split(EnumReplace(value), "_")
+	for i, part := range parts {
+		parts[i] = titleFirst(part)
 	}
-	return name
+
+	return strings.Join(parts, "")
+}
+
+func titleFirst(s string) string {
+	r := []rune(s)
+	r[0] = unicode.ToUpper(r[0])
+
+	return string(r)
 }
diff --git a/internal/config/validate.go b/internal/config/validate.go
index dd17b2aa3..fadef4fb3 100644
--- a/internal/config/validate.go
+++ b/internal/config/validate.go
@@ -6,14 +6,6 @@ func Validate(c *Config) error {
 			if sql.Database.URI == "" && !sql.Database.Managed {
 				return ErrInvalidDatabase
 			}
-			if sql.Database.Managed {
-				if c.Cloud.Project == "" {
-					return ErrManagedDatabaseNoProject
-				}
-				if c.Cloud.AuthToken == "" {
-					return ErrManagedDatabaseNoAuthToken
-				}
-			}
 		}
 	}
 	return nil
diff --git a/internal/engine/postgresql/analyzer/analyze.go b/internal/engine/postgresql/analyzer/analyze.go
index 9c1e77f65..7a3a53892 100644
--- a/internal/engine/postgresql/analyzer/analyze.go
+++ b/internal/engine/postgresql/analyzer/analyze.go
@@ -13,26 +13,31 @@ import (
 
 	core "github.com/sqlc-dev/sqlc/internal/analysis"
 	"github.com/sqlc-dev/sqlc/internal/config"
+	"github.com/sqlc-dev/sqlc/internal/opts"
 	pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1"
+	"github.com/sqlc-dev/sqlc/internal/shfmt"
 	"github.com/sqlc-dev/sqlc/internal/sql/ast"
 	"github.com/sqlc-dev/sqlc/internal/sql/named"
 	"github.com/sqlc-dev/sqlc/internal/sql/sqlerr"
 )
 
 type Analyzer struct {
-	db     config.Database
-	client pb.QuickClient
-	pool   *pgxpool.Pool
-
-	formats sync.Map
-	columns sync.Map
-	tables  sync.Map
+	db       config.Database
+	client   pb.QuickClient
+	pool     *pgxpool.Pool
+	dbg      opts.Debug
+	replacer *shfmt.Replacer
+	formats  sync.Map
+	columns  sync.Map
+	tables   sync.Map
 }
 
 func New(client pb.QuickClient, db config.Database) *Analyzer {
 	return &Analyzer{
-		db:     db,
-		client: client,
+		db:       db,
+		dbg:      opts.DebugFromEnv(),
+		client:   client,
+		replacer: shfmt.NewReplacer(nil),
 	}
 }
 
@@ -204,8 +209,10 @@ func (a *Analyzer) Analyze(ctx context.Context, n ast.Node, query string, migrat
 				return nil, err
 			}
 			uri = edb.Uri
+		} else if a.dbg.OnlyManagedDatabases {
+			return nil, fmt.Errorf("database: connections disabled via SQLCDEBUG=databases=managed")
 		} else {
-			uri = a.db.URI
+			uri = a.replacer.Replace(a.db.URI)
 		}
 		conf, err := pgxpool.ParseConfig(uri)
 		if err != nil {
diff --git a/internal/ext/wasm/wasm.go b/internal/ext/wasm/wasm.go
index a06d86796..f626dbfd1 100644
--- a/internal/ext/wasm/wasm.go
+++ b/internal/ext/wasm/wasm.go
@@ -17,7 +17,7 @@ import (
 	"runtime/trace"
 	"strings"
 
-	wasmtime "github.com/bytecodealliance/wasmtime-go/v13"
+	wasmtime "github.com/bytecodealliance/wasmtime-go/v14"
 	"golang.org/x/sync/singleflight"
 
 	"github.com/sqlc-dev/sqlc/internal/cache"
@@ -26,7 +26,7 @@ import (
 )
 
 // This version must be updated whenever the wasmtime-go dependency is updated
-const wasmtimeVersion = `v13.0.0`
+const wasmtimeVersion = `v14.0.0`
 
 func cacheDir() (string, error) {
 	cache := os.Getenv("SQLCCACHE")
diff --git a/internal/opts/debug.go b/internal/opts/debug.go
index 94cda8786..b92cbd4ae 100644
--- a/internal/opts/debug.go
+++ b/internal/opts/debug.go
@@ -12,18 +12,20 @@ import (
 //     dumpcatalog: setting dumpcatalog=1 will print the parsed database schema
 //     trace: setting trace=<path> will output a trace
 //     processplugins: setting processplugins=0 will disable process-based plugins
+//     databases: setting databases=managed will disable connections to databases via URI
 //     dumpvetenv: setting dumpvetenv=1 will print the variables available to
 //         a vet rule during evaluation
 //     dumpexplain: setting dumpexplain=1 will print the JSON-formatted output
 //         from executing EXPLAIN ... on a query during vet rule evaluation
 
 type Debug struct {
-	DumpAST        bool
-	DumpCatalog    bool
-	Trace          string
-	ProcessPlugins bool
-	DumpVetEnv     bool
-	DumpExplain    bool
+	DumpAST              bool
+	DumpCatalog          bool
+	Trace                string
+	ProcessPlugins       bool
+	OnlyManagedDatabases bool
+	DumpVetEnv           bool
+	DumpExplain          bool
 }
 
 func DebugFromEnv() Debug {
@@ -53,6 +55,8 @@ func DebugFromString(val string) Debug {
 			}
 		case pair == "processplugins=0":
 			d.ProcessPlugins = false
+		case pair == "databases=managed":
+			d.OnlyManagedDatabases = true
 		case pair == "dumpvetenv=1":
 			d.DumpVetEnv = true
 		case pair == "dumpexplain=1":
diff --git a/internal/shfmt/shfmt.go b/internal/shfmt/shfmt.go
index a3f1c5bbf..88f3074b7 100644
--- a/internal/shfmt/shfmt.go
+++ b/internal/shfmt/shfmt.go
@@ -1,16 +1,38 @@
 package shfmt
 
 import (
+	"os"
 	"regexp"
 	"strings"
 )
 
 var pat = regexp.MustCompile(`\$\{[A-Z_]+\}`)
 
-func Replace(f string, vars map[string]string) string {
+type Replacer struct {
+	envmap map[string]string
+}
+
+func (r *Replacer) Replace(f string) string {
 	return pat.ReplaceAllStringFunc(f, func(s string) string {
 		s = strings.TrimPrefix(s, "${")
 		s = strings.TrimSuffix(s, "}")
-		return vars[s]
+		return r.envmap[s]
 	})
 }
+
+func NewReplacer(env []string) *Replacer {
+	r := Replacer{
+		envmap: map[string]string{},
+	}
+	if env == nil {
+		env = os.Environ()
+	}
+	for _, e := range env {
+		k, v, _ := strings.Cut(e, "=")
+		if k == "SQLC_AUTH_TOKEN" {
+			continue
+		}
+		r.envmap[k] = v
+	}
+	return &r
+}


Test patch:
diff --git a/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/sqlc.yaml
index 2f1271592..5dc63e3f9 100644
--- a/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/sqlc.yaml
+++ b/internal/endtoend/testdata/star_expansion_series/postgresql/pgx/sqlc.yaml
@@ -1,6 +1,4 @@
 version: "2"
-cloud:
-  project: "01HAQMMECEYQYKFJN8MP16QC41"
 sql:
   - engine: "postgresql"
     schema: "schema.sql"
@@ -10,5 +8,3 @@ sql:
         package: "querytest"
         out: "go"
         sql_package: "pgx/v5"
-    database:
-      managed: true
diff --git a/internal/shfmt/shfmt_test.go b/internal/shfmt/shfmt_test.go
index ce5c29ea5..cf99ed220 100644
--- a/internal/shfmt/shfmt_test.go
+++ b/internal/shfmt/shfmt_test.go
@@ -4,14 +4,14 @@ import "testing"
 
 func TestReplace(t *testing.T) {
 	s := "POSTGRES_SQL://${PG_USER}:${PG_PASSWORD}@${PG_HOST}:${PG_PORT}/AUTHORS"
-	env := map[string]string{
-		"PG_USER":     "user",
-		"PG_PASSWORD": "password",
-		"PG_HOST":     "host",
-		"PG_PORT":     "port",
-	}
+	r := NewReplacer([]string{
+		"PG_USER=user",
+		"PG_PASSWORD=password",
+		"PG_HOST=host",
+		"PG_PORT=port",
+	})
 	e := "POSTGRES_SQL://user:password@host:port/AUTHORS"
-	if v := Replace(s, env); v != e {
+	if v := r.Replace(s); v != e {
 		t.Errorf("%s != %s", v, e)
 	}
 }