refactor: make migration process more intelligent, add test coverage
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
"git.offline-twitter.com/offline-labs/gas-stack/pkg/must"
|
||||
"git.offline-twitter.com/offline-labs/gas-stack/pkg/textutils"
|
||||
)
|
||||
|
||||
type Migration struct {
|
||||
// ID is the version number that the schema will be at, after applying the migration.
|
||||
ID int
|
||||
@@ -10,3 +19,32 @@ type Migration struct {
|
||||
// SQL is the body of the migration that will be executed.
|
||||
SQL string
|
||||
}
|
||||
|
||||
// Apply runs the migration in a transaction. Foreign key checking is delayed until right before committing the transaction.
|
||||
func (m Migration) Apply(db *sqlx.DB) error {
|
||||
fmt.Print(textutils.ColorCyan)
|
||||
fmt.Println(m.SQL)
|
||||
fmt.Print(textutils.ColorReset)
|
||||
|
||||
// Temporarily suspend foreign keys until the migration is finished
|
||||
db.MustExec("pragma foreign_keys = off")
|
||||
defer db.MustExec("pragma foreign_keys = on")
|
||||
|
||||
tx := db.MustBegin()
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
// Sanity: should initially be on the previous version
|
||||
var prevVersion int
|
||||
must.Do(tx.Get(&prevVersion, `select version from db_version`))
|
||||
if prevVersion != m.ID-1 {
|
||||
return fmt.Errorf("%w: tried to apply migration %d on DB version %d", ErrMigrationOrder, m.ID, prevVersion)
|
||||
}
|
||||
|
||||
// Execute the migration
|
||||
tx.MustExec(m.SQL)
|
||||
tx.MustExec("update db_version set version = ?", m.ID)
|
||||
must.Do(PragmaForeignKeyCheck(tx))
|
||||
must.Do(tx.Commit())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user