Initial commit
This commit is contained in:
commit
358fed43ea
4 changed files with 177 additions and 0 deletions
92
migrate.go
Normal file
92
migrate.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Package migrate allows you to update your database from your application
|
||||
package migrate
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Options contains all settings
|
||||
type Options struct {
|
||||
TableName string // Name used for version info table; defaults to DefaultTableName if not set
|
||||
Schema string // Schema used for version info table; For PostgreSQL, ignored if not set
|
||||
AssetPrefix string
|
||||
}
|
||||
|
||||
// DefaultTableName is the name used when no TableName is specified in Options
|
||||
const DefaultTableName = `version`
|
||||
|
||||
// ErrUpdatesMissing indicates an update is missing, making it impossible to execute the migration
|
||||
var ErrUpdatesMissing = errors.New(`Missing migration files`)
|
||||
|
||||
// ErrDatabaseNewer indicates that the database version is newer than the requested version. We throw an error because downgrades might cause dataloss
|
||||
var ErrDatabaseNewer = errors.New(`Current version is newer than the requested version`)
|
||||
|
||||
const fileFormat = `%04d.sql`
|
||||
|
||||
// AssetFunc is a function that returns the data for the given name
|
||||
type AssetFunc func(string) ([]byte, error)
|
||||
|
||||
// Migrate executes
|
||||
func Migrate(db *sql.DB, version int, o Options, asset AssetFunc) error {
|
||||
if o.TableName == `` {
|
||||
o.TableName = DefaultTableName
|
||||
}
|
||||
|
||||
table := o.TableName
|
||||
if o.Schema != `` {
|
||||
table = o.Schema + `.` + table
|
||||
}
|
||||
|
||||
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS ` + table + ` (Version integer NOT NULL PRIMARY KEY)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
row := db.QueryRow(`SELECT Version FROM ` + table + ` ORDER BY Version DESC`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var v int
|
||||
err = row.Scan(&v)
|
||||
if err != sql.ErrNoRows && err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v > version {
|
||||
return ErrDatabaseNewer
|
||||
}
|
||||
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
for i := v + 1; i <= version; i++ {
|
||||
asset, err := asset(fmt.Sprintf(o.AssetPrefix+fileFormat, version))
|
||||
if err != nil {
|
||||
return ErrUpdatesMissing
|
||||
}
|
||||
|
||||
_, err = tx.Exec(string(asset))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(`INSERT INTO ` + table + ` VALUES (` + strconv.Itoa(i) + `)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue