Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Commit

Permalink
Add code version used to upgrade database in the db_version table (cl…
Browse files Browse the repository at this point in the history
…oses #445) (#446)

* 1 - add basic test infrastructure to test database upgrades

* 2 - started TestUpgradeScripts with pending TODOs

* 3 - assert schema of db_versions table

* 4 - check entries of db_version table and set code_version_string in db_version
  • Loading branch information
nikhilsaraf authored Jul 9, 2020
1 parent 97327ef commit f394b46
Show file tree
Hide file tree
Showing 4 changed files with 335 additions and 14 deletions.
2 changes: 1 addition & 1 deletion cmd/trade.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ func runTradeCmd(options inputs) {
}

var e error
db, e = database.ConnectInitializedDatabase(botConfig.PostgresDbConfig, upgradeScripts)
db, e = database.ConnectInitializedDatabase(botConfig.PostgresDbConfig, upgradeScripts, version)
if e != nil {
logger.Fatal(l, fmt.Errorf("problem encountered while initializing the db: %s", e))
}
Expand Down
1 change: 1 addition & 0 deletions support/database/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
tables
*/
const SqlDbVersionTableCreate = "CREATE TABLE IF NOT EXISTS db_version (version INTEGER NOT NULL, date_completed_utc TIMESTAMP WITHOUT TIME ZONE NOT NULL, num_scripts INTEGER NOT NULL, time_elapsed_millis BIGINT NOT NULL, PRIMARY KEY (version))"
const SqlDbVersionTableAlter1 = "ALTER TABLE db_version ADD COLUMN code_version_string TEXT"

/*
queries
Expand Down
53 changes: 40 additions & 13 deletions support/database/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (
)

// sqlDbVersionTableInsertTemplate inserts into the db_version table
const sqlDbVersionTableInsertTemplate = "INSERT INTO db_version (version, date_completed_utc, num_scripts, time_elapsed_millis) VALUES (%d, '%s', %d, %d)"
const sqlDbVersionTableInsertTemplate1 = "INSERT INTO db_version (version, date_completed_utc, num_scripts, time_elapsed_millis) VALUES (%d, '%s', %d, %d)"
const sqlDbVersionTableInsertTemplate2 = "INSERT INTO db_version (version, date_completed_utc, num_scripts, time_elapsed_millis, code_version_string) VALUES (%d, '%s', %d, %d, '%s')"

// UpgradeScript encapsulates a script to be run to upgrade the database from one version to the next
type UpgradeScript struct {
Expand All @@ -31,8 +32,13 @@ func MakeUpgradeScript(version uint32, command string, moreCommands ...string) *
}
}

var UpgradeScripts = []*UpgradeScript{
MakeUpgradeScript(1, SqlDbVersionTableCreate),
MakeUpgradeScript(2, SqlDbVersionTableAlter1),
}

// ConnectInitializedDatabase creates a database with the required metadata tables
func ConnectInitializedDatabase(postgresDbConfig *postgresdb.Config, upgradeScripts []*UpgradeScript) (*sql.DB, error) {
func ConnectInitializedDatabase(postgresDbConfig *postgresdb.Config, upgradeScripts []*UpgradeScript, codeVersionString string) (*sql.DB, error) {
dbCreated, e := postgresdb.CreateDatabaseIfNotExists(postgresDbConfig)
if e != nil {
if strings.Contains(e.Error(), "connect: connection refused") {
Expand All @@ -53,7 +59,7 @@ func ConnectInitializedDatabase(postgresDbConfig *postgresdb.Config, upgradeScri
// don't defer db.Close() here becuase we want it open for the life of the application for now

log.Printf("creating db schema and running upgrade scripts ...\n")
e = runUpgradeScripts(db, upgradeScripts)
e = runUpgradeScripts(db, upgradeScripts, codeVersionString)
if e != nil {
return nil, fmt.Errorf("could not run upgrade scripts: %s", e)
}
Expand All @@ -62,16 +68,20 @@ func ConnectInitializedDatabase(postgresDbConfig *postgresdb.Config, upgradeScri
return db, nil
}

func runUpgradeScripts(db *sql.DB, scripts []*UpgradeScript) error {
currentDbVersion, e := QueryDbVersion(db)
if e != nil {
if !strings.Contains(e.Error(), "relation \"db_version\" does not exist") {
return fmt.Errorf("could not fetch current db version: %s", e)
}
currentDbVersion = 0
}
func runUpgradeScripts(db *sql.DB, scripts []*UpgradeScript, codeVersionString string) error {
// save feature flags for the db_version table here
hasCodeVersionString := false

for _, script := range scripts {
// fetch the db version inside the for loop because it constantly gets updated
currentDbVersion, e := QueryDbVersion(db)
if e != nil {
if !strings.Contains(e.Error(), "relation \"db_version\" does not exist") {
return fmt.Errorf("could not fetch current db version: %s", e)
}
currentDbVersion = 0
}

if script.version <= currentDbVersion {
log.Printf(" skipping upgrade script for version %d because current db version (%d) is equal or ahead\n", script.version, currentDbVersion)
continue
Expand All @@ -95,17 +105,34 @@ func runUpgradeScripts(db *sql.DB, scripts []*UpgradeScript) error {
endTimeMillis := time.Now().UnixNano() / int64(time.Millisecond)
elapsedMillis := endTimeMillis - startTimeMillis

// update feature flags here where required after running a script so we don't need to hard-code version numbers which can be different for different consumers of this API
for _, command := range script.commands {
if command == SqlDbVersionTableAlter1 {
// if we have run this alter table command it means the database version has the code_version_string feature
hasCodeVersionString = true
}
}

// add entry to db_version table
sqlInsertDbVersion := fmt.Sprintf(sqlDbVersionTableInsertTemplate,
sqlInsertDbVersion := fmt.Sprintf(sqlDbVersionTableInsertTemplate1,
script.version,
startTime.Format(postgresdb.TimestampFormatString),
len(script.commands),
elapsedMillis,
)
if hasCodeVersionString {
sqlInsertDbVersion = fmt.Sprintf(sqlDbVersionTableInsertTemplate2,
script.version,
startTime.Format(postgresdb.TimestampFormatString),
len(script.commands),
elapsedMillis,
codeVersionString,
)
}
_, e = db.Exec(sqlInsertDbVersion)
if e != nil {
// duplicate insert should return an error
return fmt.Errorf("could not execute sql insert values statement in db_version table for db version %d (%s): %s", script.version, sqlInsertDbVersion, e)
return fmt.Errorf("could not add an entry to the db_version table for upgrade script (db_version=%d) for current db version %d (%s): %s", script.version, currentDbVersion, sqlInsertDbVersion, e)
}

// commit transaction
Expand Down
Loading

0 comments on commit f394b46

Please sign in to comment.