Merge pull request 'database: add FormatDSN' (#278) from database-newv3 into v3

Reviewed-on: #278
This commit is contained in:
Василий Толстов 2023-11-02 01:35:25 +03:00
commit 0be09c8b3e
2 changed files with 62 additions and 3 deletions

View File

@ -15,7 +15,6 @@ var (
) )
type Config struct { type Config struct {
Params map[string]string
TLSConfig *tls.Config TLSConfig *tls.Config
Username string Username string
Password string Password string
@ -23,6 +22,50 @@ type Config struct {
Host string Host string
Port string Port string
Database string Database string
Params []string
}
func (cfg *Config) FormatDSN() string {
var s strings.Builder
if len(cfg.Scheme) > 0 {
s.WriteString(cfg.Scheme + "://")
}
// [username[:password]@]
if len(cfg.Username) > 0 {
s.WriteString(cfg.Username)
if len(cfg.Password) > 0 {
s.WriteByte(':')
s.WriteString(url.PathEscape(cfg.Password))
}
s.WriteByte('@')
}
// [host:port]
if len(cfg.Host) > 0 {
s.WriteString(cfg.Host)
if len(cfg.Port) > 0 {
s.WriteByte(':')
s.WriteString(cfg.Port)
}
}
// /dbname
s.WriteByte('/')
s.WriteString(url.PathEscape(cfg.Database))
for i := 0; i < len(cfg.Params); i += 2 {
if i == 0 {
s.WriteString("?")
} else {
s.WriteString("&")
}
s.WriteString(cfg.Params[i])
s.WriteString("=")
s.WriteString(cfg.Params[i+1])
}
return s.String()
} }
func ParseDSN(dsn string) (*Config, error) { func ParseDSN(dsn string) (*Config, error) {
@ -84,13 +127,13 @@ func ParseDSN(dsn string) (*Config, error) {
for j = i + 1; j < len(dsn); j++ { for j = i + 1; j < len(dsn); j++ {
if dsn[j] == '?' { if dsn[j] == '?' {
parts := strings.Split(dsn[j+1:], "&") parts := strings.Split(dsn[j+1:], "&")
cfg.Params = make(map[string]string, len(parts)) cfg.Params = make([]string, 0, len(parts)*2)
for _, p := range parts { for _, p := range parts {
k, v, found := strings.Cut(p, "=") k, v, found := strings.Cut(p, "=")
if !found { if !found {
continue continue
} }
cfg.Params[k] = v cfg.Params = append(cfg.Params, k, v)
} }
break break

View File

@ -1,6 +1,7 @@
package database package database
import ( import (
"net/url"
"testing" "testing"
) )
@ -13,3 +14,18 @@ func TestParseDSN(t *testing.T) {
t.Fatalf("parsing error") t.Fatalf("parsing error")
} }
} }
func TestFormatDSN(t *testing.T) {
src := "postgres://username:p@ssword#@host:12345/dbname?key1=val2&key2=val2"
cfg, err := ParseDSN(src)
if err != nil {
t.Fatal(err)
}
dst, err := url.PathUnescape(cfg.FormatDSN())
if err != nil {
t.Fatal(err)
}
if src != dst {
t.Fatalf("\n%s\n%s", src, dst)
}
}