Skip to content

Commit

Permalink
feat(database): add engine options (#886)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockopp authored Jun 20, 2023
1 parent 4e5d484 commit ef7d338
Show file tree
Hide file tree
Showing 13 changed files with 639 additions and 116 deletions.
4 changes: 2 additions & 2 deletions database/close.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ package database

// Close stops and terminates the connection to the database.
func (e *engine) Close() error {
e.Logger.Tracef("closing connection to the %s database", e.Driver())
e.logger.Tracef("closing connection to the %s database", e.Driver())

// capture database/sql database from gorm.io/gorm database
_sql, err := e.Database.DB()
_sql, err := e.client.DB()
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions database/close_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ func TestDatabase_Engine_Close(t *testing.T) {
name: "failure with invalid gorm database",
failure: true,
database: &engine{
Config: &Config{
config: &config{
Driver: "invalid",
},
Database: &gorm.DB{
client: &gorm.DB{
Config: &gorm.Config{
ConnPool: nil,
},
},
Logger: logrus.NewEntry(logrus.StandardLogger()),
logger: logrus.NewEntry(logrus.StandardLogger()),
},
},
}
Expand Down
20 changes: 10 additions & 10 deletions database/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ func ToContext(c Setter, d Interface) {
func FromCLIContext(c *cli.Context) (Interface, error) {
logrus.Debug("creating database engine from CLI configuration")

return New(&Config{
Address: c.String("database.addr"),
CompressionLevel: c.Int("database.compression.level"),
ConnectionLife: c.Duration("database.connection.life"),
ConnectionIdle: c.Int("database.connection.idle"),
ConnectionOpen: c.Int("database.connection.open"),
Driver: c.String("database.driver"),
EncryptionKey: c.String("database.encryption.key"),
SkipCreation: c.Bool("database.skip_creation"),
})
return New(
WithAddress(c.String("database.addr")),
WithCompressionLevel(c.Int("database.compression.level")),
WithConnectionLife(c.Duration("database.connection.life")),
WithConnectionIdle(c.Int("database.connection.idle")),
WithConnectionOpen(c.Int("database.connection.open")),
WithDriver(c.String("database.driver")),
WithEncryptionKey(c.String("database.encryption.key")),
WithSkipCreation(c.Bool("database.skip_creation")),
)
}
79 changes: 47 additions & 32 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import (
)

type (
// Config represents the settings required to create the engine that implements the Interface.
Config struct {
// config represents the settings required to create the engine that implements the Interface.
config struct {
// specifies the address to use for the database engine
Address string
// specifies the level of compression to use for the database engine
Expand All @@ -50,9 +50,12 @@ type (

// engine represents the functionality that implements the Interface.
engine struct {
Config *Config
Database *gorm.DB
Logger *logrus.Entry
// gorm.io/gorm database client used in database functions
client *gorm.DB
// engine configuration settings used in database functions
config *config
// sirupsen/logrus logger used in database functions
logger *logrus.Entry

build.BuildInterface
hook.HookInterface
Expand All @@ -74,52 +77,64 @@ type (
//
// * postgres
// * sqlite3
func New(c *Config) (Interface, error) {
func New(opts ...EngineOpt) (Interface, error) {
// create new database engine
e := new(engine)

// create new fields
e.client = new(gorm.DB)
e.config = new(config)
e.logger = new(logrus.Entry)

// apply all provided configuration options
for _, opt := range opts {
err := opt(e)
if err != nil {
return nil, err
}
}

// validate the configuration being provided
err := c.Validate()
err := e.config.Validate()
if err != nil {
return nil, err
}

// create new database engine
e := &engine{
Config: c,
Database: new(gorm.DB),
Logger: logrus.NewEntry(logrus.StandardLogger()).WithField("database", c.Driver),
}
// update the logger with additional metadata
e.logger = logrus.NewEntry(logrus.StandardLogger()).WithField("database", e.Driver())

e.Logger.Trace("creating database engine from configuration")
e.logger.Trace("creating database engine from configuration")
// process the database driver being provided
switch c.Driver {
switch e.config.Driver {
case constants.DriverPostgres:
// create the new Postgres database client
e.Database, err = gorm.Open(postgres.Open(e.Config.Address), &gorm.Config{})
e.client, err = gorm.Open(postgres.Open(e.config.Address), &gorm.Config{})
if err != nil {
return nil, err
}
case constants.DriverSqlite:
// create the new Sqlite database client
e.Database, err = gorm.Open(sqlite.Open(e.Config.Address), &gorm.Config{})
e.client, err = gorm.Open(sqlite.Open(e.config.Address), &gorm.Config{})
if err != nil {
return nil, err
}
default:
// handle an invalid database driver being provided
return nil, fmt.Errorf("invalid database driver provided: %s", c.Driver)
return nil, fmt.Errorf("invalid database driver provided: %s", e.Driver())
}

// capture database/sql database from gorm.io/gorm database
db, err := e.Database.DB()
db, err := e.client.DB()
if err != nil {
return nil, err
}

// set the maximum amount of time a connection may be reused
db.SetConnMaxLifetime(e.Config.ConnectionLife)
db.SetConnMaxLifetime(e.config.ConnectionLife)
// set the maximum number of connections in the idle connection pool
db.SetMaxIdleConns(e.Config.ConnectionIdle)
db.SetMaxIdleConns(e.config.ConnectionIdle)
// set the maximum number of open connections to the database
db.SetMaxOpenConns(e.Config.ConnectionOpen)
db.SetMaxOpenConns(e.config.ConnectionOpen)

// verify connection to the database
err = e.Ping()
Expand All @@ -140,14 +155,14 @@ func New(c *Config) (Interface, error) {
//
// This function is ONLY intended to be used for testing purposes.
func NewTest() (Interface, error) {
return New(&Config{
Address: "file::memory:?cache=shared",
CompressionLevel: 3,
ConnectionLife: 30 * time.Minute,
ConnectionIdle: 2,
ConnectionOpen: 0,
Driver: "sqlite3",
EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW",
SkipCreation: false,
})
return New(
WithAddress("file::memory:?cache=shared"),
WithCompressionLevel(3),
WithConnectionLife(30*time.Minute),
WithConnectionIdle(2),
WithConnectionOpen(0),
WithDriver("sqlite3"),
WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"),
WithSkipCreation(false),
)
}
35 changes: 22 additions & 13 deletions database/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ func TestDatabase_New(t *testing.T) {
tests := []struct {
failure bool
name string
config *Config
config *config
}{
{
name: "failure with postgres",
failure: true,
config: &Config{
config: &config{
Driver: "postgres",
Address: "postgres://foo:bar@localhost:5432/vela",
CompressionLevel: 3,
Expand All @@ -40,7 +40,7 @@ func TestDatabase_New(t *testing.T) {
{
name: "success with sqlite3",
failure: false,
config: &Config{
config: &config{
Driver: "sqlite3",
Address: "file::memory:?cache=shared",
CompressionLevel: 3,
Expand All @@ -54,7 +54,7 @@ func TestDatabase_New(t *testing.T) {
{
name: "failure with invalid config",
failure: true,
config: &Config{
config: &config{
Driver: "postgres",
Address: "",
CompressionLevel: 3,
Expand All @@ -68,7 +68,7 @@ func TestDatabase_New(t *testing.T) {
{
name: "failure with invalid driver",
failure: true,
config: &Config{
config: &config{
Driver: "mysql",
Address: "foo:bar@tcp(localhost:3306)/vela?charset=utf8mb4&parseTime=True&loc=Local",
CompressionLevel: 3,
Expand All @@ -84,7 +84,16 @@ func TestDatabase_New(t *testing.T) {
// run tests
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := New(test.config)
_, err := New(
WithAddress(test.config.Address),
WithCompressionLevel(test.config.CompressionLevel),
WithConnectionLife(test.config.ConnectionLife),
WithConnectionIdle(test.config.ConnectionIdle),
WithConnectionOpen(test.config.ConnectionOpen),
WithDriver(test.config.Driver),
WithEncryptionKey(test.config.EncryptionKey),
WithSkipCreation(test.config.SkipCreation),
)

if test.failure {
if err == nil {
Expand All @@ -105,7 +114,7 @@ func TestDatabase_New(t *testing.T) {
func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) {
// create the engine with test configuration
_engine := &engine{
Config: &Config{
config: &config{
CompressionLevel: 3,
ConnectionLife: 30 * time.Minute,
ConnectionIdle: 2,
Expand All @@ -114,7 +123,7 @@ func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) {
EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW",
SkipCreation: false,
},
Logger: logrus.NewEntry(logrus.StandardLogger()),
logger: logrus.NewEntry(logrus.StandardLogger()),
}

// create the new mock sql database
Expand All @@ -129,7 +138,7 @@ func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) {
_mock.ExpectPing()

// create the new mock Postgres database client
_engine.Database, err = gorm.Open(
_engine.client, err = gorm.Open(
postgres.New(postgres.Config{Conn: _sql}),
&gorm.Config{SkipDefaultTransaction: true},
)
Expand All @@ -146,7 +155,7 @@ func testSqlite(t *testing.T) *engine {

// create the engine with test configuration
_engine := &engine{
Config: &Config{
config: &config{
Address: "file::memory:?cache=shared",
CompressionLevel: 3,
ConnectionLife: 30 * time.Minute,
Expand All @@ -156,12 +165,12 @@ func testSqlite(t *testing.T) *engine {
EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW",
SkipCreation: false,
},
Logger: logrus.NewEntry(logrus.StandardLogger()),
logger: logrus.NewEntry(logrus.StandardLogger()),
}

// create the new mock Sqlite database client
_engine.Database, err = gorm.Open(
sqlite.Open(_engine.Config.Address),
_engine.client, err = gorm.Open(
sqlite.Open(_engine.config.Address),
&gorm.Config{SkipDefaultTransaction: true},
)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion database/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ package database

// Driver outputs the configured database driver.
func (e *engine) Driver() string {
return e.Config.Driver
return e.config.Driver
}
Loading

0 comments on commit ef7d338

Please sign in to comment.