Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -638,15 +638,22 @@ root of the project.

Each of these connection details can be overriden by an `ENV` variable.

| Setting | Description | YAML variable | Environment variable (ENV) | Default |
| -------- | -------------------------------- | ------------- | -------------------------- | ----------- |
| Host | The database host | `host` | `APP_DATABASE_HOST` | `localhost` |
| Port | The database port | `port` | `APP_DATABASE_PORT` | `3306` |
| Database | The database name | `database` | `APP_DATABASE_DATABASE` | |
| Username | App user name | `username` | `APP_DATABASE_USERNAME` | |
| Password | App user password | `password` | `APP_DATABASE_PASSWORD` | |
| Pool | Connection pool size | `pool` | `APP_DATABASE_POOL` | `5` |
| Timeout | Connection timeout (in seconds) | `timeout` | `APP_DATABASE_TIMEOUT` | `1s` |
| Setting | Description | YAML variable | Environment variable (ENV) | Default |
|-------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|-------------------------------------------------|-------------|
| Host | The database host | `host` | `APP_DATABASE_HOST` | `localhost` |
| Port | The database port | `port` | `APP_DATABASE_PORT` | `3306` |
| Database | The database name | `database` | `APP_DATABASE_DATABASE` | |
| Username | App user name | `username` | `APP_DATABASE_USERNAME` | |
| Password | App user password | `password` | `APP_DATABASE_PASSWORD` | |
| Pool | Connection pool size | `pool` | `APP_DATABASE_POOL` | `5` |
| Timeout | Connection timeout (in seconds) | `timeout` | `APP_DATABASE_TIMEOUT` | `1s` |
| MaxOpenConnections | Sets the maximum number of open connections to the database. | `max_open_connections` | `APP_DATABASE_MAX_OPEN_CONNECTIONS` | `0` |
| ConnectionMaxIdleTime | Sets the maximum amount of time a connection may be idle. | `connection_max_idle_time` | `APP_DATABASE_CONNECTION_MAX_IDLE_TIME` | `0` |
| ConnectionMaxLifetime | Sets the maximum amount of time a connection may be reused | `connection_max_lifetime` | `APP_DATABASE_CONNECTION_MAX_LIFETIME` | `0s` |
| DisableDefaultGormTransaction | Disables default GORM transaction wrapper for write operations | `disable_default_gorm_transaction` | `APP_DATABASE_DISABLE_DEFAULT_GORM_TRANSACTION` | `false` |
| CachePreparedStatements | Enabled creating a prepared statement when executing any SQL and caches them to speed up future calls | `cache_prepared_statements` | `APP_DATABASE_CACHE_PREPARED_STATEMENTS` | `false` |
| MysqlInterpolateParams | If set to `true`, placeholders (?) in calls to db.Query() and db.Exec() are interpolated into a single query string with given parameters. | `mysql_interpolate_params` | `APP_DATABASE_MYSQL_INTERPOLATE_PARAMS` | `false` |


An example `database.yml`:

Expand Down
5 changes: 5 additions & 0 deletions pkg/database/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ type Config struct {
MaxOpenConnections int `mapstructure:"max_open_connections"`
ConnectionMaxIdleTime time.Duration `mapstructure:"connection_max_idle_time"`
ConnectionMaxLifetime time.Duration `mapstructure:"connection_max_lifetime"`

// Performance settings
DisableDefaultGormTransaction bool `mapstructure:"disable_default_gorm_transaction"`
CachePreparedStatements bool `mapstructure:"cache_prepared_statements"`
MysqlInterpolateParams bool `mapstructure:"mysql_interpolate_params"`
}

// NewConfig returns a new Config instance.
Expand Down
57 changes: 33 additions & 24 deletions pkg/database/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,38 @@ func TestNewConfig(t *testing.T) {
})

testCases := []struct {
name string
wantError bool
host string
port int
username string
password string
database string
timeout string
pool int
maxOpenConnections int
connectionMaxIdleTime time.Duration
connectionMaxLifetime time.Duration
name string
wantError bool
host string
port int
username string
password string
database string
timeout string
pool int
maxOpenConnections int
connectionMaxIdleTime time.Duration
connectionMaxLifetime time.Duration
disableDefaultGormTransaction bool
cachePreparedStatements bool
mysqlInterpolateParams bool
}{
{
name: "NewWithoutConfigFileFails",
wantError: true,
host: "",
port: 0,
username: "",
password: "",
database: "",
timeout: "",
pool: 0,
maxOpenConnections: 0,
connectionMaxIdleTime: 0,
connectionMaxLifetime: 0,
name: "NewWithoutConfigFileFails",
wantError: true,
host: "",
port: 0,
username: "",
password: "",
database: "",
timeout: "",
pool: 0,
maxOpenConnections: 0,
connectionMaxIdleTime: 0,
connectionMaxLifetime: 0,
disableDefaultGormTransaction: false,
cachePreparedStatements: false,
mysqlInterpolateParams: false,
},
}

Expand All @@ -62,6 +68,9 @@ func TestNewConfig(t *testing.T) {
assert.Equal(t, c.MaxOpenConnections, tc.maxOpenConnections)
assert.Equal(t, c.ConnectionMaxIdleTime, tc.connectionMaxIdleTime)
assert.Equal(t, c.ConnectionMaxLifetime, tc.connectionMaxLifetime)
assert.Equal(t, c.DisableDefaultGormTransaction, tc.disableDefaultGormTransaction)
assert.Equal(t, c.CachePreparedStatements, tc.cachePreparedStatements)
assert.Equal(t, c.MysqlInterpolateParams, tc.mysqlInterpolateParams)
})
}
}
41 changes: 23 additions & 18 deletions pkg/database/connection_details.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,31 @@ import (

// ConnectionDetails represents database connection details.
type ConnectionDetails struct {
Dialect string
Username string
Password string
Host string
Port int
Database string
Encoding string
Timeout string
Pool int
Dialect string
Username string
Password string
Host string
Port int
Database string
Encoding string
Timeout string
Pool int
MysqlInterpolateParams bool
}

// NewConnectionDetails creates a new ConnectionDetails struct from a DB configuration.
func NewConnectionDetails(config *Config) ConnectionDetails {
return ConnectionDetails{
Dialect: "mysql",
Username: config.Username,
Password: config.Password,
Host: config.Host,
Port: config.Port,
Database: config.Database,
Encoding: "utf8mb4_unicode_ci",
Timeout: config.Timeout,
Pool: config.Pool,
Dialect: "mysql",
Username: config.Username,
Password: config.Password,
Host: config.Host,
Port: config.Port,
Database: config.Database,
Encoding: "utf8mb4_unicode_ci",
Timeout: config.Timeout,
Pool: config.Pool,
MysqlInterpolateParams: config.MysqlInterpolateParams,
}
}

Expand Down Expand Up @@ -69,6 +71,9 @@ func (cd ConnectionDetails) opts() string {
"loc": "Local",
"timeout": cd.Timeout,
}
if cd.MysqlInterpolateParams {
options["interpolateParams"] = "true"
}

var opts []string

Expand Down
51 changes: 39 additions & 12 deletions pkg/database/connection_details_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func TestNewConnectionDetails(t *testing.T) {
assert.Equal(t, details.Encoding, "utf8mb4_unicode_ci")
assert.Equal(t, details.Timeout, config.Timeout)
assert.Equal(t, details.Pool, config.Pool)
assert.Equal(t, details.MysqlInterpolateParams, config.MysqlInterpolateParams)
}

func TestString(t *testing.T) {
Expand All @@ -34,12 +35,13 @@ func TestString(t *testing.T) {
{
name: "WithAllAttributesPresent",
config: &Config{
Host: "192.168.1.1",
Port: 8080,
Username: "john",
Password: "doe",
Database: "microlith",
Timeout: "10s",
Host: "192.168.1.1",
Port: 8080,
Username: "john",
Password: "doe",
Database: "microlith",
Timeout: "10s",
MysqlInterpolateParams: true,
},
connectionString: "john:doe@tcp(192.168.1.1:8080)/microlith",
optionsString: "timeout=10s",
Expand Down Expand Up @@ -118,12 +120,13 @@ func TestStringWithoutDB(t *testing.T) {

func TestOpts(t *testing.T) {
cases := []struct {
name string
details ConnectionDetails
timeout string
charset string
parseTime string
loc string
name string
details ConnectionDetails
timeout string
charset string
parseTime string
loc string
interpolateParams bool
}{
{
name: "WithPresentTimeout",
Expand All @@ -145,6 +148,24 @@ func TestOpts(t *testing.T) {
parseTime: "parseTime=True",
loc: "loc=Local",
},
{
name: "WithMysqlInterpolateParams",
timeout: "timeout=1s",
charset: "charset=utf8",
parseTime: "parseTime=True",
loc: "loc=Local",
details: ConnectionDetails{
MysqlInterpolateParams: true,
},
interpolateParams: true,
},
{
name: "WithNoMysqlInterpolateParams",
timeout: "timeout=1s",
charset: "charset=utf8",
parseTime: "parseTime=True",
loc: "loc=Local",
},
}

for _, c := range cases {
Expand All @@ -155,6 +176,12 @@ func TestOpts(t *testing.T) {
assert.Contains(t, got, c.charset)
assert.Contains(t, got, c.parseTime)
assert.Contains(t, got, c.loc)

if c.interpolateParams {
assert.Contains(t, got, "interpolateParams=true")
} else {
assert.NotContains(t, got, "interpolateParams=true")
}
})
}
}
11 changes: 10 additions & 1 deletion pkg/database/gorm.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,16 @@ func NewConnection(config *Config, environment, appName string) (*gorm.DB, error
databasePoolSettings(sqlDB, config)

dialector := mysql.New(mysql.Config{Conn: sqlDB})
db, err := gormtrace.Open(dialector, nil, gormtrace.WithServiceName(serviceName))

gormConfig := &gorm.Config{}
if config.DisableDefaultGormTransaction {
gormConfig.SkipDefaultTransaction = true
}
if config.CachePreparedStatements {
gormConfig.PrepareStmt = true
}

db, err := gormtrace.Open(dialector, gormConfig, gormtrace.WithServiceName(serviceName))
if err != nil {
return nil, err
}
Expand Down