2
0

Require Config to be created by ParseConfig

This commit is contained in:
Jack Christensen
2019-08-24 09:28:44 -05:00
parent 1558987979
commit 760dd75542
3 changed files with 24 additions and 18 deletions
+10 -5
View File
@@ -26,7 +26,8 @@ import (
type AfterConnectFunc func(ctx context.Context, pgconn *PgConn) error type AfterConnectFunc func(ctx context.Context, pgconn *PgConn) error
type ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error type ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error
// Config is the settings used to establish a connection to a PostgreSQL server. // Config is the settings used to establish a connection to a PostgreSQL server. It must be created by ParseConfig and
// then it can be modified. A manually initialized Config will cause ConnectConfig to panic.
type Config struct { type Config struct {
Host string // host (e.g. localhost) or path to unix domain socket directory (e.g. /private/tmp) Host string // host (e.g. localhost) or path to unix domain socket directory (e.g. /private/tmp)
Port uint16 Port uint16
@@ -55,6 +56,8 @@ type Config struct {
// OnNotification is a callback function called when a notification from the LISTEN/NOTIFY system is received. // OnNotification is a callback function called when a notification from the LISTEN/NOTIFY system is received.
OnNotification NotificationHandler OnNotification NotificationHandler
createdByParseConfig bool // Used to enforce created by ParseConfig rule.
} }
// FallbackConfig is additional settings to attempt a connection with when the primary Config fails to establish a // FallbackConfig is additional settings to attempt a connection with when the primary Config fails to establish a
@@ -157,10 +160,12 @@ func ParseConfig(connString string) (*Config, error) {
} }
config := &Config{ config := &Config{
Database: settings["database"], createdByParseConfig: true,
User: settings["user"], Database: settings["database"],
Password: settings["password"], User: settings["user"],
RuntimeParams: make(map[string]string), Password: settings["password"],
RuntimeParams: make(map[string]string),
BuildFrontendFunc: makeDefaultBuildFrontendFunc(),
} }
if connectTimeout, present := settings["connect_timeout"]; present { if connectTimeout, present := settings["connect_timeout"]; present {
+6 -13
View File
@@ -99,25 +99,18 @@ func Connect(ctx context.Context, connString string) (*PgConn, error) {
return ConnectConfig(ctx, config) return ConnectConfig(ctx, config)
} }
// Connect establishes a connection to a PostgreSQL server using config. ctx can be used to cancel a connect attempt. // Connect establishes a connection to a PostgreSQL server using config. config must have been constructed with
// ParseConfig. ctx can be used to cancel a connect attempt.
// //
// If config.Fallbacks are present they will sequentially be tried in case of error establishing network connection. An // If config.Fallbacks are present they will sequentially be tried in case of error establishing network connection. An
// authentication error will terminate the chain of attempts (like libpq: // authentication error will terminate the chain of attempts (like libpq:
// https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS) and be returned as the error. Otherwise, // https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS) and be returned as the error. Otherwise,
// if all attempts fail the last error is returned. // if all attempts fail the last error is returned.
func ConnectConfig(ctx context.Context, config *Config) (pgConn *PgConn, err error) { func ConnectConfig(ctx context.Context, config *Config) (pgConn *PgConn, err error) {
// For convenience set a few defaults if not already set. This makes it simpler to directly construct a config. // Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from
if config.Port == 0 { // zero values.
config.Port = 5432 if !config.createdByParseConfig {
} panic("config must be created by ParseConfig")
if config.DialFunc == nil {
config.DialFunc = makeDefaultDialer().DialContext
}
if config.BuildFrontendFunc == nil {
config.BuildFrontendFunc = makeDefaultBuildFrontendFunc()
}
if config.RuntimeParams == nil {
config.RuntimeParams = make(map[string]string)
} }
// Simplify usage by treating primary config and fallbacks the same. // Simplify usage by treating primary config and fallbacks the same.
+8
View File
@@ -263,6 +263,14 @@ func TestConnectWithAfterConnect(t *testing.T) {
assert.Equal(t, []byte("foobar"), results[0].Rows[0][0]) assert.Equal(t, []byte("foobar"), results[0].Rows[0][0])
} }
func TestConnectConfigRequiresConfigFromParseConfig(t *testing.T) {
t.Parallel()
config := &pgconn.Config{}
require.PanicsWithValue(t, "config must be created by ParseConfig", func() { pgconn.ConnectConfig(context.Background(), config) })
}
func TestConnPrepareSyntaxError(t *testing.T) { func TestConnPrepareSyntaxError(t *testing.T) {
t.Parallel() t.Parallel()