refactor: remove mandatory use of collaboration

This commit is contained in:
zhuyasen
2025-09-06 18:46:19 +08:00
parent dac5582c59
commit d0af80b2ca

View File

@@ -8,122 +8,7 @@ import (
// AdaptiveMysqlDsn adaptation of various mysql format dsn address
func AdaptiveMysqlDsn(dsn string) string {
// remove optional scheme prefix
dsn = strings.ReplaceAll(dsn, "mysql://", "")
dsn = ensureNetworkAddress(dsn)
return ensureCharsetAndCollation(dsn)
}
// helper: ensure network/address section is valid for go-sql-driver/mysql
func ensureNetworkAddress(dsn string) string {
at := strings.Index(dsn, "@")
if at == -1 {
return dsn
}
afterAt := dsn[at+1:]
slashIdx := strings.Index(afterAt, "/")
if slashIdx == -1 {
return dsn
}
addrPart := afterAt[:slashIdx]
if addrPart == "" {
return dsn
}
if strings.HasPrefix(addrPart, "(") {
// missing protocol, add tcp
return strings.Replace(dsn, "@(", "@tcp(", 1)
}
if strings.HasPrefix(addrPart, "tcp(") || strings.HasPrefix(addrPart, "unix(") {
return dsn
}
// no parentheses and no protocol → wrap with tcp()
return strings.Replace(dsn, "@"+addrPart, "@tcp("+addrPart+")", 1)
}
// helper: ensure charset utf8mb4 and a reasonable collation are present
func ensureCharsetAndCollation(dsn string) string {
qIdx := strings.Index(dsn, "?")
if qIdx == -1 {
return dsn + "?charset=utf8mb4"
}
prefix := dsn[:qIdx]
queryStr := dsn[qIdx+1:]
parts := strings.Split(queryStr, "&")
hasCharset := false
hasCollation := false
for i, p := range parts {
if strings.HasPrefix(p, "charset=") {
hasCharset = true
parts[i] = "charset=" + normalizeCharsets(strings.TrimPrefix(p, "charset="))
break
}
if strings.HasPrefix(p, "collation=") {
hasCollation = true
}
}
if !hasCharset {
parts = append(parts, "charset=utf8mb4")
}
if !hasCollation {
parts = append(parts, "collation=utf8mb4_general_ci")
}
return prefix + "?" + strings.Join(parts, "&")
}
// normalizeCharsets deduplicates a comma-separated charset list and ensures utf8mb4 is first
func normalizeCharsets(val string) string {
pieces := strings.Split(val, ",")
seen := map[string]bool{}
ordered := []string{}
for _, cs := range pieces {
cs = strings.TrimSpace(cs)
if cs == "" {
continue
}
lower := strings.ToLower(cs)
if seen[lower] {
continue
}
seen[lower] = true
ordered = append(ordered, cs)
}
// ensure utf8mb4 is present and at the front (case-insensitive)
found := -1
for i, cs := range ordered {
if strings.EqualFold(cs, "utf8mb4") {
found = i
break
}
}
if found == -1 {
ordered = append([]string{"utf8mb4"}, ordered...)
} else if found != 0 {
// move to front
front := []string{"utf8mb4"}
for i, cs := range ordered {
if i == found {
continue
}
if strings.EqualFold(cs, "utf8mb4") {
continue
}
front = append(front, cs)
}
ordered = front
}
return strings.Join(ordered, ",")
return strings.ReplaceAll(dsn, "mysql://", "")
}
// AdaptivePostgresqlDsn convert postgres dsn to kv string