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 }