breaking change: version id is now int64 to accommodate larger date-based version id schemes

pull/2/head
Liam Staskawicz 2013-01-04 19:22:03 -10:00
parent 9140de5045
commit 517e1701e2
7 changed files with 38 additions and 31 deletions

View File

@ -28,8 +28,8 @@ func statusRun(cmd *Command, args ...string) {
} }
// collect all migrations // collect all migrations
min := 0 min := int64(0)
max := (1 << 31) - 1 max := int64((1 << 63) - 1)
mm, e := collectMigrations(conf.MigrationsDir, min, max) mm, e := collectMigrations(conf.MigrationsDir, min, max)
if e != nil { if e != nil {
log.Fatal(e) log.Fatal(e)
@ -54,7 +54,7 @@ func statusRun(cmd *Command, args ...string) {
} }
} }
func printMigrationStatus(db *sql.DB, version int, script string) { func printMigrationStatus(db *sql.DB, version int64, script string) {
var row MigrationRecord var row MigrationRecord
q := fmt.Sprintf("SELECT tstamp, is_applied FROM goose_db_version WHERE version_id=%d ORDER BY tstamp DESC LIMIT 1", version) q := fmt.Sprintf("SELECT tstamp, is_applied FROM goose_db_version WHERE version_id=%d ORDER BY tstamp DESC LIMIT 1", version)
e := db.QueryRow(q).Scan(&row.TStamp, &row.IsApplied) e := db.QueryRow(q).Scan(&row.TStamp, &row.IsApplied)

View File

@ -38,7 +38,7 @@ func downRun(cmd *Command, args ...string) {
runMigrations(conf, conf.MigrationsDir, previous) runMigrations(conf, conf.MigrationsDir, previous)
} }
func getPreviousVersion(dirpath string, version int) (previous, earliest int) { func getPreviousVersion(dirpath string, version int64) (previous, earliest int64) {
previous = -1 previous = -1
earliest = (1 << 31) - 1 earliest = (1 << 31) - 1

View File

@ -16,24 +16,31 @@ import (
) )
type MigrationRecord struct { type MigrationRecord struct {
VersionId int VersionId int64
TStamp time.Time TStamp time.Time
IsApplied bool // was this a result of up() or down() IsApplied bool // was this a result of up() or down()
} }
type Migration struct { type Migration struct {
Next int // next version, or -1 if none Next int64 // next version, or -1 if none
Previous int // previous version, -1 if none Previous int64 // previous version, -1 if none
Source string // .go or .sql script Source string // .go or .sql script
} }
type MigrationVersions []int64
// helpers so we can use pkg sort
func (s MigrationVersions) Len() int { return len(s) }
func (s MigrationVersions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s MigrationVersions) Less(i, j int) bool { return s[i] < s[j] }
type MigrationMap struct { type MigrationMap struct {
Versions []int // sorted slice of version keys Versions MigrationVersions // sorted slice of version keys
Migrations map[int]Migration // sources (.sql or .go) keyed by version Migrations map[int64]Migration // sources (.sql or .go) keyed by version
Direction bool // sort direction: true -> Up, false -> Down Direction bool // sort direction: true -> Up, false -> Down
} }
func runMigrations(conf *DBConf, migrationsDir string, target int) { func runMigrations(conf *DBConf, migrationsDir string, target int64) {
db, err := sql.Open(conf.Driver, conf.OpenStr) db, err := sql.Open(conf.Driver, conf.OpenStr)
if err != nil { if err != nil {
@ -85,10 +92,10 @@ func runMigrations(conf *DBConf, migrationsDir string, target int) {
// collect all the valid looking migration scripts in the // collect all the valid looking migration scripts in the
// migrations folder, and key them by version // migrations folder, and key them by version
func collectMigrations(dirpath string, current, target int) (mm *MigrationMap, err error) { func collectMigrations(dirpath string, current, target int64) (mm *MigrationMap, err error) {
mm = &MigrationMap{ mm = &MigrationMap{
Migrations: make(map[int]Migration), Migrations: make(map[int64]Migration),
} }
// extract the numeric component of each migration, // extract the numeric component of each migration,
@ -114,7 +121,7 @@ func collectMigrations(dirpath string, current, target int) (mm *MigrationMap, e
return mm, nil return mm, nil
} }
func versionFilter(v, current, target int) bool { func versionFilter(v, current, target int64) bool {
// special case - default target value // special case - default target value
if target < 0 { if target < 0 {
@ -132,7 +139,7 @@ func versionFilter(v, current, target int) bool {
return false return false
} }
func (m *MigrationMap) Append(v int, source string) { func (m *MigrationMap) Append(v int64, source string) {
m.Versions = append(m.Versions, v) m.Versions = append(m.Versions, v)
m.Migrations[v] = Migration{ m.Migrations[v] = Migration{
Next: -1, Next: -1,
@ -142,7 +149,7 @@ func (m *MigrationMap) Append(v int, source string) {
} }
func (m *MigrationMap) Sort(direction bool) { func (m *MigrationMap) Sort(direction bool) {
sort.Ints(m.Versions) sort.Sort(m.Versions)
// set direction, and reverse order if need be // set direction, and reverse order if need be
m.Direction = direction m.Direction = direction
@ -156,7 +163,7 @@ func (m *MigrationMap) Sort(direction bool) {
// populate next and previous for each migration // populate next and previous for each migration
// //
// work around http://code.google.com/p/go/issues/detail?id=3117 // work around http://code.google.com/p/go/issues/detail?id=3117
previousV := -1 previousV := int64(-1)
for _, v := range m.Versions { for _, v := range m.Versions {
cur := m.Migrations[v] cur := m.Migrations[v]
cur.Previous = previousV cur.Previous = previousV
@ -176,7 +183,7 @@ func (m *MigrationMap) Sort(direction bool) {
// XXX_descriptivename.ext // XXX_descriptivename.ext
// where XXX specifies the version number // where XXX specifies the version number
// and ext specifies the type of migration // and ext specifies the type of migration
func numericComponent(name string) (int, error) { func numericComponent(name string) (int64, error) {
base := path.Base(name) base := path.Base(name)
@ -189,7 +196,7 @@ func numericComponent(name string) (int, error) {
return 0, errors.New("no separator found") return 0, errors.New("no separator found")
} }
n, e := strconv.Atoi(base[:idx]) n, e := strconv.ParseInt(base[:idx], 10, 64)
if e == nil && n == 0 { if e == nil && n == 0 {
return 0, errors.New("0 is not a valid migration ID") return 0, errors.New("0 is not a valid migration ID")
} }
@ -199,7 +206,7 @@ func numericComponent(name string) (int, error) {
// retrieve the current version for this DB. // retrieve the current version for this DB.
// Create and initialize the DB version table if it doesn't exist. // Create and initialize the DB version table if it doesn't exist.
func ensureDBVersion(db *sql.DB) (int, error) { func ensureDBVersion(db *sql.DB) (int64, error) {
rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY tstamp DESC;") rows, err := db.Query("SELECT version_id, is_applied from goose_db_version ORDER BY tstamp DESC;")
if err != nil { if err != nil {
@ -212,7 +219,7 @@ func ensureDBVersion(db *sql.DB) (int, error) {
// whether it has been applied or rolled back. // whether it has been applied or rolled back.
// The first version we find that has been applied is the current version. // The first version we find that has been applied is the current version.
toSkip := make([]int, 0) toSkip := make([]int64, 0)
for rows.Next() { for rows.Next() {
var row MigrationRecord var row MigrationRecord
@ -252,7 +259,7 @@ func createVersionTable(db *sql.DB) error {
// create the table and insert an initial value of 0 // create the table and insert an initial value of 0
create := `CREATE TABLE goose_db_version ( create := `CREATE TABLE goose_db_version (
version_id int NOT NULL, version_id bigint NOT NULL,
is_applied boolean NOT NULL, is_applied boolean NOT NULL,
tstamp timestamp NULL default now(), tstamp timestamp NULL default now(),
PRIMARY KEY(tstamp) PRIMARY KEY(tstamp)
@ -271,7 +278,7 @@ func createVersionTable(db *sql.DB) error {
// wrapper for ensureDBVersion for callers that don't already have // wrapper for ensureDBVersion for callers that don't already have
// their own DB instance // their own DB instance
func getDBVersion(conf *DBConf) int { func getDBVersion(conf *DBConf) int64 {
db, err := sql.Open(conf.Driver, conf.OpenStr) db, err := sql.Open(conf.Driver, conf.OpenStr)
if err != nil { if err != nil {

View File

@ -21,7 +21,7 @@ const (
) )
type TemplateData struct { type TemplateData struct {
Version int Version int64
DBDriver string DBDriver string
DBOpen string DBOpen string
Direction string Direction string
@ -41,7 +41,7 @@ func directionStr(direction bool) string {
// original .go migration, and execute it via `go run` along // original .go migration, and execute it via `go run` along
// with a main() of our own creation. // with a main() of our own creation.
// //
func runGoMigration(conf *DBConf, path string, version int, direction bool) (int, error) { func runGoMigration(conf *DBConf, path string, version int64, direction bool) (int, error) {
// everything gets written to a temp dir, and zapped afterwards // everything gets written to a temp dir, and zapped afterwards
d, e := ioutil.TempDir("", "goose") d, e := ioutil.TempDir("", "goose")
@ -83,7 +83,7 @@ func runGoMigration(conf *DBConf, path string, version int, direction bool) (int
// * namespace the Up() and Down() funcs so we can compile several // * namespace the Up() and Down() funcs so we can compile several
// .go migrations into the same binary for execution // .go migrations into the same binary for execution
// //
func writeSubstituted(inpath, outpath string, version int) error { func writeSubstituted(inpath, outpath string, version int64) error {
fin, e := os.Open(inpath) fin, e := os.Open(inpath)
if e != nil { if e != nil {

View File

@ -17,7 +17,7 @@ import (
// //
// All statements following an Up or Down directive are grouped together // All statements following an Up or Down directive are grouped together
// until another direction directive is found. // until another direction directive is found.
func runSQLMigration(db *sql.DB, script string, v int, direction bool) (count int, err error) { func runSQLMigration(db *sql.DB, script string, v int64, direction bool) (count int, err error) {
txn, err := db.Begin() txn, err := db.Begin()
if err != nil { if err != nil {
@ -70,7 +70,7 @@ func runSQLMigration(db *sql.DB, script string, v int, direction bool) (count in
// Update the version table for the given migration, // Update the version table for the given migration,
// and finalize the transaction. // and finalize the transaction.
func finalizeMigration(txn *sql.Tx, direction bool, v int) error { func finalizeMigration(txn *sql.Tx, direction bool, v int64) error {
// XXX: drop goose_db_version table on some minimum version number? // XXX: drop goose_db_version table on some minimum version number?
versionStmt := fmt.Sprintf("INSERT INTO goose_db_version (version_id, is_applied) VALUES (%d, %t);", v, direction) versionStmt := fmt.Sprintf("INSERT INTO goose_db_version (version_id, is_applied) VALUES (%d, %t);", v, direction)

View File

@ -37,7 +37,7 @@ func pendingRun(cmd *Command, args ...string) {
} }
// collect all migrations that specify a version later than our current version // collect all migrations that specify a version later than our current version
func collectPendingMigrations(dirpath string, current int) []string { func collectPendingMigrations(dirpath string, current int64) []string {
var pendingScripts []string var pendingScripts []string

4
up.go
View File

@ -26,9 +26,9 @@ func upRun(cmd *Command, args ...string) {
// helper to identify the most recent possible version // helper to identify the most recent possible version
// within a folder of migration scripts // within a folder of migration scripts
func mostRecentVersionAvailable(dirpath string) int { func mostRecentVersionAvailable(dirpath string) int64 {
mostRecent := -1 mostRecent := int64(-1)
filepath.Walk(dirpath, func(name string, info os.FileInfo, err error) error { filepath.Walk(dirpath, func(name string, info os.FileInfo, err error) error {