You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

112 lines
2.7 KiB

package database
import (
"database/sql"
"fmt"
)
type upgradeFunc func(*sql.Tx, *DatabaseContainer) error
// Upgrades is a list of functions that will upgrade a database to the latest version.
//
// This may be of use if you want to manage the database fully manually, but in most cases you
// should just call DatabaseContainer.Upgrade to let the library handle everything.
var Upgrades = [...]upgradeFunc{upgradeV1}
const (
AppMigrationTable = "app_migration_version"
)
func (c *DatabaseContainer) getVersion() (int, error) {
_, err := c.db.Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (version INTEGER)", AppMigrationTable))
if err != nil {
return -1, err
}
version := 0
row := c.db.QueryRow(fmt.Sprintf("SELECT version FROM %s LIMIT 1", AppMigrationTable))
if row != nil {
_ = row.Scan(&version)
}
return version, nil
}
func (c *DatabaseContainer) setVersion(tx *sql.Tx, version int) error {
_, err := tx.Exec(fmt.Sprintf("DELETE FROM %s", AppMigrationTable))
if err != nil {
return err
}
_, err = tx.Exec(fmt.Sprintf("INSERT INTO %s (version) VALUES ($1)", AppMigrationTable), version)
return err
}
func (c *DatabaseContainer) Upgrade() error {
if c.dialect == "sqlite" {
var foreignKeysEnabled bool
err := c.db.QueryRow("PRAGMA foreign_keys").Scan(&foreignKeysEnabled)
if err != nil {
return fmt.Errorf("failed to check if foreign keys are enabled: %w", err)
} else if !foreignKeysEnabled {
return fmt.Errorf("foreign keys are not enabled")
}
}
version, err := c.getVersion()
if err != nil {
return err
}
for ; version < len(Upgrades); version++ {
var tx *sql.Tx
tx, err = c.db.Begin()
if err != nil {
return err
}
migrateFunc := Upgrades[version]
err = migrateFunc(tx, c)
if err != nil {
_ = tx.Rollback()
return err
}
if err = c.setVersion(tx, version+1); err != nil {
return err
}
if err = tx.Commit(); err != nil {
return err
}
}
return nil
}
func upgradeV1(tx *sql.Tx, c *DatabaseContainer) error {
var err error
postgresAppCallback := `CREATE TABLE app_callback_responses (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
callback_url TEXT NOT NULL,
status VARCHAR(50) NOT NULL,
response JSONB,
error_message TEXT,
timestamp TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);`
sqliteAppCallback := `CREATE TABLE app_callback_responses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
callback_url TEXT NOT NULL,
status TEXT NOT NULL,
response TEXT,
error_message TEXT,
timestamp TEXT DEFAULT CURRENT_TIMESTAMP
);`
if c.dialect == "postgres" {
_, err = tx.Exec(postgresAppCallback)
} else if c.dialect == "sqlite" {
_, err = tx.Exec(sqliteAppCallback)
}
if err != nil {
return err
}
return nil
}