migrations snippets

How to run ActiveRecord migrations from the console

Tagged activerecord, console, migrations, schema  Languages ruby

There are multiple ways of running migrations from the console. This might be the easiest one to remember:

irb ActiveRecord::Schema
add_index :followers, [:leader_id, :follower_id], :unique => true

You can also paste the migration code into the console window:

class ModifyRating < ActiveRecord::Migration
  def self.up
    change_column :products, :rating, :decimal, :precision => 5, :scale => 3
  end

  def self.down
  end
end

Run the migration by typing ModifyRating.up.

Migrations for Golang

Tagged go, golang, migrations, migrate, sqitch  Languages go

Alternative 1: Code your own

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

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/