/
pgutil.go
100 lines (85 loc) · 2.35 KB
/
pgutil.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Package pgutil provides utilities for Postgres
package pgutil
import (
"fmt"
"net/url"
"strings"
"github.com/pkg/errors"
)
// ConnectionOptions represents the configurable options of a connection to a
// Postgres database
type ConnectionOptions struct {
Host string
Port string
User string
Password string
DBName string
SSLMode string
}
type Opts func(*ConnectionOptions)
// Supported SSL modes.
type sslMode string
const (
SSLBlank sslMode = ""
SSLDisable = "disable"
SSLAllow = "allow"
SSLPrefer = "prefer"
SSLRequire = "require"
SSLVerifyCa = "verify-ca"
SSLVerifyFull = "verify-full"
)
// WithSSL sets the sslmode parameter for postgresql. See the
// postgresql documentation at
// https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING
func WithSSL(requestedSslMode sslMode) Opts {
return func(c *ConnectionOptions) {
c.SSLMode = string(requestedSslMode)
}
}
// NewFromURL returns a ConnectionOptions from a given URL. This uses
// a format like `postgres://myuser:mypass@localhost/somedatabase`,
// which is commonly found on hosting platforms.
func NewFromURL(rawurl string, opts ...Opts) (ConnectionOptions, error) {
var c ConnectionOptions
parsed, err := url.Parse(rawurl)
if err != nil {
return c, errors.Wrap(err, "url parse")
}
c = ConnectionOptions{
Host: parsed.Host,
User: parsed.User.Username(),
DBName: strings.TrimPrefix(parsed.Path, "/"),
SSLMode: string(SSLRequire),
}
if pass, ok := parsed.User.Password(); ok {
c.Password = pass
}
// Split the URL host/port into parts
hostComponents := strings.Split(parsed.Host, ":")
switch len(hostComponents) {
case 1:
c.Host = hostComponents[0]
c.Port = "5432"
case 2:
c.Host = hostComponents[0]
c.Port = hostComponents[1]
default:
return c, errors.Errorf("Could not parse %s as host:port", parsed.Host)
}
for _, opt := range opts {
opt(&c)
}
return c, nil
}
// String implements the Stringer interface so that a pgutil.ConnectionOptions
// can be converted into a value key/value connection string
func (c ConnectionOptions) String() string {
s := fmt.Sprintf(
"host=%s port=%s dbname=%s sslmode=%s user=%s",
c.Host, c.Port, c.DBName, c.SSLMode, c.User,
)
if c.Password != "" {
s = fmt.Sprintf("%s password=%s", s, c.Password)
}
return s
}