Skip to content

Commit 74a4ee5

Browse files
authored
Merge pull request #300 from pieceofsoul/add-variadic-options-to-postgres
Added variadic ConfigOptions to postgres ConnectionPool function
2 parents e640e1e + d2711c7 commit 74a4ee5

File tree

3 files changed

+354
-1
lines changed

3 files changed

+354
-1
lines changed

backend/postgres/options.go

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// Copyright © 2022 by PACE Telematics GmbH. All rights reserved.
2+
// Created at 2022/03/09 by Sascha Voth
3+
4+
package postgres
5+
6+
import (
7+
"time"
8+
)
9+
10+
type ConfigOption func(cfg *Config)
11+
12+
// WithPort - customize the db port
13+
func WithPort(port int) ConfigOption {
14+
return func(cfg *Config) {
15+
cfg.Port = port
16+
}
17+
}
18+
19+
// WithHost - customise the db host
20+
func WithHost(host string) ConfigOption {
21+
return func(cfg *Config) {
22+
cfg.Host = host
23+
}
24+
}
25+
26+
// WithPassword - customise the db password
27+
func WithPassword(password string) ConfigOption {
28+
return func(cfg *Config) {
29+
cfg.Password = password
30+
}
31+
}
32+
33+
// WithUser - customise the db user
34+
func WithUser(user string) ConfigOption {
35+
return func(cfg *Config) {
36+
cfg.User = user
37+
}
38+
}
39+
40+
// WithDatabase - customise the db name
41+
func WithDatabase(database string) ConfigOption {
42+
return func(cfg *Config) {
43+
cfg.Database = database
44+
}
45+
}
46+
47+
// WithApplicationName -ApplicationName is the application name. Used in logs on Pg side.
48+
// Only available from pg-9.0.
49+
func WithApplicationName(applicationName string) ConfigOption {
50+
return func(cfg *Config) {
51+
cfg.ApplicationName = applicationName
52+
}
53+
}
54+
55+
// WithMaxRetries - Maximum number of retries before giving up.
56+
func WithMaxRetries(maxRetries int) ConfigOption {
57+
return func(cfg *Config) {
58+
cfg.MaxRetries = maxRetries
59+
}
60+
}
61+
62+
// WithRetryStatementTimeout - Whether to retry queries cancelled because of statement_timeout.
63+
func WithRetryStatementTimeout(retryStatementTimeout bool) ConfigOption {
64+
return func(cfg *Config) {
65+
cfg.RetryStatementTimeout = retryStatementTimeout
66+
}
67+
}
68+
69+
// WithMinRetryBackoff - Minimum backoff between each retry.
70+
// -1 disables backoff.
71+
func WithMinRetryBackoff(minRetryBackoff time.Duration) ConfigOption {
72+
return func(cfg *Config) {
73+
cfg.MinRetryBackoff = minRetryBackoff
74+
}
75+
}
76+
77+
// WithMaxRetryBackoff - Maximum backoff between each retry.
78+
// -1 disables backoff.
79+
func WithMaxRetryBackoff(maxRetryBackoff time.Duration) ConfigOption {
80+
return func(cfg *Config) {
81+
cfg.MaxRetryBackoff = maxRetryBackoff
82+
}
83+
}
84+
85+
// WithDialTimeout - Dial timeout for establishing new connections.
86+
func WithDialTimeout(dialTimeout time.Duration) ConfigOption {
87+
return func(cfg *Config) {
88+
cfg.DialTimeout = dialTimeout
89+
}
90+
}
91+
92+
// WithReadTimeout - Timeout for socket reads. If reached, commands will fail
93+
// with a timeout instead of blocking.
94+
func WithReadTimeout(readTimeout time.Duration) ConfigOption {
95+
return func(cfg *Config) {
96+
cfg.ReadTimeout = readTimeout
97+
}
98+
}
99+
100+
// WithWriteTimeout - Timeout for socket writes. If reached, commands will fail
101+
// with a timeout instead of blocking.
102+
func WithWriteTimeout(writeTimeout time.Duration) ConfigOption {
103+
return func(cfg *Config) {
104+
cfg.WriteTimeout = writeTimeout
105+
}
106+
}
107+
108+
// WithPoolSize - Maximum number of socket connections.
109+
func WithPoolSize(poolSize int) ConfigOption {
110+
return func(cfg *Config) {
111+
cfg.PoolSize = poolSize
112+
}
113+
}
114+
115+
// WithMinIdleConns - Minimum number of idle connections which is useful when establishing
116+
// new connection is slow.
117+
func WithMinIdleConns(minIdleConns int) ConfigOption {
118+
return func(cfg *Config) {
119+
cfg.MinIdleConns = minIdleConns
120+
}
121+
}
122+
123+
// WithMaxConnAge - Connection age at which client retires (closes) the connection.
124+
// It is useful with proxies like PgBouncer and HAProxy.
125+
func WithMaxConnAge(maxConnAge time.Duration) ConfigOption {
126+
return func(cfg *Config) {
127+
cfg.MaxConnAge = maxConnAge
128+
}
129+
}
130+
131+
// WithPoolTimeout - Time for which client waits for free connection if all
132+
// connections are busy before returning an error.
133+
func WithPoolTimeout(poolTimeout time.Duration) ConfigOption {
134+
return func(cfg *Config) {
135+
cfg.PoolTimeout = poolTimeout
136+
}
137+
}
138+
139+
// WithIdleTimeout - Amount of time after which client closes idle connections.
140+
// Should be less than server's timeout.
141+
// -1 disables idle timeout check.
142+
func WithIdleTimeout(idleTimeout time.Duration) ConfigOption {
143+
return func(cfg *Config) {
144+
cfg.IdleTimeout = idleTimeout
145+
}
146+
}
147+
148+
// WithIdleCheckFrequency - Frequency of idle checks made by idle connection's reaper.
149+
// -1 disables idle connection's reaper,
150+
// but idle connections are still discarded by the client
151+
// if IdleTimeout is set.
152+
func WithIdleCheckFrequency(idleCheckFrequency time.Duration) ConfigOption {
153+
return func(cfg *Config) {
154+
cfg.IdleCheckFrequency = idleCheckFrequency
155+
}
156+
}
157+
158+
// WithHealthCheckTableName - Name of the Table that is created to try if database is writeable
159+
func WithHealthCheckTableName(healthCheckTableName string) ConfigOption {
160+
return func(cfg *Config) {
161+
cfg.HealthCheckTableName = healthCheckTableName
162+
}
163+
}
164+
165+
// WithHealthCheckResultTTL - Amount of time to cache the last health check result
166+
func WithHealthCheckResultTTL(healthCheckResultTTL time.Duration) ConfigOption {
167+
return func(cfg *Config) {
168+
cfg.HealthCheckResultTTL = healthCheckResultTTL
169+
}
170+
}

backend/postgres/options_test.go

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package postgres
2+
3+
import (
4+
"github.com/stretchr/testify/require"
5+
"testing"
6+
"time"
7+
)
8+
9+
func TestWithApplicationName(t *testing.T) {
10+
param := "ApplicationName"
11+
var conf Config
12+
f := WithApplicationName(param)
13+
f(&conf)
14+
require.Equal(t, conf.ApplicationName, param)
15+
}
16+
17+
func TestWithDatabase(t *testing.T) {
18+
param := "Database"
19+
var conf Config
20+
f := WithDatabase(param)
21+
f(&conf)
22+
require.Equal(t, conf.Database, param)
23+
}
24+
25+
func TestWithDialTimeout(t *testing.T) {
26+
param := 5 * time.Second
27+
var conf Config
28+
f := WithDialTimeout(param)
29+
f(&conf)
30+
require.Equal(t, conf.DialTimeout, param)
31+
}
32+
33+
func TestWithHealthCheckResultTTL(t *testing.T) {
34+
param := 5 * time.Second
35+
var conf Config
36+
f := WithHealthCheckResultTTL(param)
37+
f(&conf)
38+
require.Equal(t, conf.HealthCheckResultTTL, param)
39+
}
40+
41+
func TestWithHealthCheckTableName(t *testing.T) {
42+
param := "HealthCheckTableName"
43+
var conf Config
44+
f := WithHealthCheckTableName(param)
45+
f(&conf)
46+
require.Equal(t, conf.HealthCheckTableName, param)
47+
}
48+
49+
func TestWithHost(t *testing.T) {
50+
param := "Host"
51+
var conf Config
52+
f := WithHost(param)
53+
f(&conf)
54+
require.Equal(t, conf.Host, param)
55+
}
56+
57+
func TestWithIdleCheckFrequency(t *testing.T) {
58+
param := 5 * time.Second
59+
var conf Config
60+
f := WithIdleCheckFrequency(param)
61+
f(&conf)
62+
require.Equal(t, conf.IdleCheckFrequency, param)
63+
}
64+
65+
func TestWithIdleTimeout(t *testing.T) {
66+
param := 5 * time.Second
67+
var conf Config
68+
f := WithIdleTimeout(param)
69+
f(&conf)
70+
require.Equal(t, conf.IdleTimeout, param)
71+
}
72+
73+
func TestWithMaxConnAge(t *testing.T) {
74+
param := 5 * time.Second
75+
var conf Config
76+
f := WithMaxConnAge(param)
77+
f(&conf)
78+
require.Equal(t, conf.MaxConnAge, param)
79+
}
80+
81+
func TestWithMaxRetries(t *testing.T) {
82+
param := 42
83+
var conf Config
84+
f := WithMaxRetries(param)
85+
f(&conf)
86+
require.Equal(t, conf.MaxRetries, param)
87+
}
88+
89+
func TestWithMaxRetryBackoff(t *testing.T) {
90+
param := 5 * time.Second
91+
var conf Config
92+
f := WithMaxRetryBackoff(param)
93+
f(&conf)
94+
require.Equal(t, conf.MaxRetryBackoff, param)
95+
}
96+
97+
func TestWithMinIdleConns(t *testing.T) {
98+
param := 42
99+
var conf Config
100+
f := WithMinIdleConns(param)
101+
f(&conf)
102+
require.Equal(t, conf.MinIdleConns, param)
103+
}
104+
105+
func TestWithMinRetryBackoff(t *testing.T) {
106+
param := 5 * time.Second
107+
var conf Config
108+
f := WithMinRetryBackoff(param)
109+
f(&conf)
110+
require.Equal(t, conf.MinRetryBackoff, param)
111+
}
112+
113+
func TestWithPassword(t *testing.T) {
114+
param := "Password"
115+
var conf Config
116+
f := WithPassword(param)
117+
f(&conf)
118+
require.Equal(t, conf.Password, param)
119+
}
120+
121+
func TestWithPoolSize(t *testing.T) {
122+
param := 42
123+
var conf Config
124+
f := WithPoolSize(param)
125+
f(&conf)
126+
require.Equal(t, conf.PoolSize, param)
127+
}
128+
129+
func TestWithPoolTimeout(t *testing.T) {
130+
param := 5 * time.Second
131+
var conf Config
132+
f := WithPoolTimeout(param)
133+
f(&conf)
134+
require.Equal(t, conf.PoolTimeout, param)
135+
}
136+
137+
func TestWithPort(t *testing.T) {
138+
param := 42
139+
var conf Config
140+
f := WithPort(param)
141+
f(&conf)
142+
require.Equal(t, conf.Port, param)
143+
}
144+
145+
func TestWithReadTimeout(t *testing.T) {
146+
param := 5 * time.Second
147+
var conf Config
148+
f := WithReadTimeout(param)
149+
f(&conf)
150+
require.Equal(t, conf.ReadTimeout, param)
151+
}
152+
153+
func TestWithRetryStatementTimeout(t *testing.T) {
154+
param := true
155+
var conf Config
156+
f := WithRetryStatementTimeout(param)
157+
f(&conf)
158+
require.Equal(t, conf.RetryStatementTimeout, param)
159+
}
160+
161+
func TestWithUser(t *testing.T) {
162+
param := "User"
163+
var conf Config
164+
f := WithUser(param)
165+
f(&conf)
166+
require.Equal(t, conf.User, param)
167+
}
168+
169+
func TestWithWriteTimeout(t *testing.T) {
170+
param := 5 * time.Second
171+
var conf Config
172+
f := WithWriteTimeout(param)
173+
f(&conf)
174+
require.Equal(t, conf.WriteTimeout, param)
175+
}

backend/postgres/postgres.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,15 @@ func DefaultConnectionPool() *pg.DB {
183183
// ConnectionPool returns a new database connection pool
184184
// that is already configured with the correct credentials and
185185
// instrumented with tracing and logging
186-
func ConnectionPool() *pg.DB {
186+
// Used Config is taken from the env and it's default values. These
187+
// values can be overwritten by the use of ConfigOption.
188+
func ConnectionPool(opts ...ConfigOption) *pg.DB {
189+
190+
// apply functional options if given to overwrite the default config / env config
191+
for _, f := range opts {
192+
f(&cfg)
193+
}
194+
187195
return CustomConnectionPool(&pg.Options{
188196
Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
189197
User: cfg.User,

0 commit comments

Comments
 (0)