Migrations for Golang

## Alternative 1: Code your own ```go package main import ( "database/sql" "fmt" _ "github.com/lib/pq" // Postgres "io/ioutil" "os" "regexp" "sort" "strconv" "strings" ) type Migration struct { Name string File string Version int } type Migrations []Migration func (slice Migrations) Len() int { return len(slice) } func (slice Migrations) Less(i, j int) bool { return slice[i].Version < slice[j].Version } func (slice Migrations) Swap(i, j int) { slice[i], slice[j] = slice[j], slice[i] } func migrate() { tx, err := db.Begin() dirname := "db/migrate/" // Find migration files d, err := os.Open(dirname) check(err) defer d.Close() fi, err := d.Readdir(-1) check(err) migrations := Migrations{} for _, file := range fi { if file.Mode().IsRegular() && strings.HasSuffix(file.Name(), ".sql") { // Find version number from file name 01_name.sql re := regexp.MustCompile("^[0-9]+") version, err := strconv.Atoi(re.FindString(file.Name())) if err != nil { panic("not a valid migration filename: " + file.Name()) } migrations = append(migrations, Migration{Name: file.Name(), Version: version, File: file.Name()}) } } // Process all migrations sort.Sort(migrations) for _, migration := range migrations { // Check if migration has been run var exists bool err = tx.QueryRow("select exists (select 1 from versions where id = $1)", migration.Version).Scan(&exists) if err != nil && err != sql.ErrNoRows { check(err) } // Run migration if exists == false { bytes, err := ioutil.ReadFile(dirname + migration.File) check(err) sql := string(bytes) // Split migration file at ; because some drivers can't handle multiple // statements This is not fool proof, but should work for most // migrations. count := strings.Count(sql, ";") statements := strings.SplitN(string(sql), ";", count) fmt.Println("RUN", "-", migration.Name) for _, statement := range statements { _, err = tx.Exec(statement) check(err) } _, err = tx.Exec("INSERT INTO versions VALUES ($1)", migration.Version) check(err) } else { fmt.Println("OK ", "-", migration.Name) } } check(tx.Commit()) } ``` ## Alternative 2: sql/migrate ```go package main import ( "github.com/rubenv/sql-migrate" "gitlab.com/christianhellsten/a15/domains" "log" "os" ) func main() { migrations := &migrate.FileMigrationSource{ Dir: "db/migrations", } var dir migrate.MigrationDirection switch os.Args[1] { case "up": dir = migrate.Up case "down": dir = migrate.Down default: dir = migrate.Up } n, err := migrate.Exec(domains.DBI, "postgres", migrations, dir) if err != nil { log.Fatalln(err) } log.Printf("Applied %d migrations %s!\n", n, os.Args[1]) } ``` ## Alternative 3: Sqitch http://sqitch.org/