51 lines
1.3 KiB
Go
51 lines
1.3 KiB
Go
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
|
|
|
|
// Title is an optional name for the migration.
|
|
Title string
|
|
|
|
// 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
|
|
}
|