DSN: Align ParseDriver and detectDriver alias sets #5588

This commit is contained in:
Michael Mayer 2026-05-17 15:03:41 +00:00
parent c8390a2e8d
commit 18214b2494
4 changed files with 47 additions and 25 deletions

View file

@ -19,17 +19,14 @@ const (
)
// ParseDriver canonicalizes a user-supplied driver identifier to one of the
// DriverMySQL/DriverPostgres/DriverSQLite3/DriverTiDB constants. Comparison is
// case-insensitive and tolerates surrounding whitespace. "mariadb" collapses
// to DriverMySQL because both share the same wire protocol and GORM dialect.
// The aliases "sqlite", "test", "file" and the empty string normalize to
// DriverSQLite3. Unrecognized inputs return an empty string so callers can
// distinguish them from supported drivers in a switch.
// DriverMySQL/DriverPostgres/DriverSQLite3/DriverTiDB constants (case- and
// whitespace-insensitive). Aliases: "mariadb" → MySQL (shared GORM dialect),
// "postgresql" → Postgres, "sqlite"/"test"/"file"/"" → SQLite3; unknown → "".
func ParseDriver(s string) string {
switch strings.ToLower(strings.TrimSpace(s)) {
case DriverMySQL, DriverMariaDB:
return DriverMySQL
case DriverPostgres:
case DriverPostgres, "postgresql":
return DriverPostgres
case DriverSQLite3, "sqlite", "test", "file", "":
return DriverSQLite3

View file

@ -20,6 +20,9 @@ func TestParseDriver(t *testing.T) {
})
t.Run("Postgres", func(t *testing.T) {
assert.Equal(t, DriverPostgres, ParseDriver("postgres"))
// URI-style DSNs spell the driver "postgresql"; accept it as a Postgres alias.
assert.Equal(t, DriverPostgres, ParseDriver("postgresql"))
assert.Equal(t, DriverPostgres, ParseDriver("PostgreSQL"))
})
t.Run("SQLite3", func(t *testing.T) {
assert.Equal(t, DriverSQLite3, ParseDriver("sqlite3"))
@ -44,7 +47,6 @@ func TestParseDriver(t *testing.T) {
t.Run("Unknown", func(t *testing.T) {
// Unknown inputs return an empty string so the caller's `default` arm fires.
assert.Equal(t, "", ParseDriver("oracle"))
assert.Equal(t, "", ParseDriver("postgresql"))
assert.Equal(t, "", ParseDriver("garbage"))
})
}

View file

@ -365,24 +365,17 @@ func (d *DSN) splitKeyValue(input string) ([]string, bool) {
return tokens, true
}
// detectDriver infers the driver name from DSN contents when it is not explicitly specified.
// detectDriver infers the driver name from DSN contents. Explicit driver names
// flow through ParseDriver so both helpers share an alias set; unknown but
// non-empty names are kept (lowercased) rather than misclassified by the
// DSN-string heuristics below.
func (d *DSN) detectDriver() {
driver := strings.ToLower(d.Driver)
switch driver {
case "postgres", "postgresql":
d.Driver = DriverPostgres
return
case "mysql", "mariadb":
d.Driver = DriverMySQL
return
case "sqlite", "sqlite3", "file":
d.Driver = DriverSQLite3
return
}
if driver != "" {
d.Driver = driver
if d.Driver != "" {
if normalized := ParseDriver(d.Driver); normalized != "" {
d.Driver = normalized
return
}
d.Driver = strings.ToLower(d.Driver)
return
}

View file

@ -105,3 +105,33 @@ func TestParse(t *testing.T) {
})
}
}
// TestParse_DriverDetection exercises detectDriver via Parse: alias unification
// with ParseDriver and the preserve-unknown contract.
func TestParse_DriverDetection(t *testing.T) {
t.Run("PostgresqlAliasNormalizes", func(t *testing.T) {
got := Parse("postgresql://alice:s3cr3t@db.local:5432/app")
assert.Equal(t, DriverPostgres, got.Driver)
})
t.Run("PostgresqlAliasCaseInsensitive", func(t *testing.T) {
got := Parse("POSTGRESQL://alice:s3cr3t@db.local:5432/app")
assert.Equal(t, DriverPostgres, got.Driver)
})
t.Run("MariaDBAliasCollapsesToMySQL", func(t *testing.T) {
got := Parse("mariadb://user:secret@db.local:3306/app")
assert.Equal(t, DriverMySQL, got.Driver)
})
t.Run("SqliteAliasNormalizes", func(t *testing.T) {
got := Parse("sqlite:///data/index.db")
assert.Equal(t, DriverSQLite3, got.Driver)
})
t.Run("UnknownDriverPreserved", func(t *testing.T) {
// Unknown explicit drivers are kept instead of falling through to heuristics.
got := Parse("oracle://user:secret@db.local:1521/app")
assert.Equal(t, "oracle", got.Driver)
})
t.Run("UnknownDriverPreservedLowercased", func(t *testing.T) {
got := Parse("Snowflake://user:secret@account.region/db")
assert.Equal(t, "snowflake", got.Driver)
})
}