func sortMigrations(dir MigrationDirection, migrations []Migration) []Migration {
	var m ByID
	for _, migration := range migrations {
		m = append(m, migration)
	}
	switch dir {
	case Up:
		sort.Sort(ByID(m))
	default:
		sort.Sort(sort.Reverse(ByID(m)))
	}
	return m
}
sortMigrations sorts the migrations by id.

When the direction is "Up", the migrations will be sorted by ID ascending.
When the direction is "Down", the migrations will be sorted by ID descending.
package migrate
import (
	"database/sql"
	"fmt"
	"hash/crc32"
	"sort"
	"sync"
)
type MigrationDirection int
const (
	Up MigrationDirection = iota
	Down
)
type TransactionMode int
const (
	IndividualTransactions TransactionMode = iota
	SingleTransaction
)
type MigrationError struct {
	Migration
	Err error
}
func (e *MigrationError) Error() string {
	return fmt.Sprintf("migration %d failed: %v", e.ID, e.Err)
}
const DefaultTable = "schema_migrations"
type Migration struct {
	ID int
	Up func(tx *sql.Tx) error
	Down func(tx *sql.Tx) error
}
type ByID []Migration
func (m ByID) Len() int           { return len(m) }
func (m ByID) Less(i, j int) bool { return m[i].ID < m[j].ID }
func (m ByID) Swap(i, j int)      { m[i], m[j] = m[j], m[i] }
type Migrator struct {
	Table string
	sync.Locker
	TransactionMode TransactionMode
	db *sql.DB
}
type postgresLocker struct {
	key uint32
	db  *sql.DB
}
func newPostgresLocker(db *sql.DB) sync.Locker {
	key := crc32.ChecksumIEEE([]byte("migrations"))
	return &postgresLocker{
		key: key,
		db:  db,
	}
}
func (l *postgresLocker) Lock() {
	l.do("lock")
}
func (l *postgresLocker) Unlock() {
	l.do("unlock")
}
func (l *postgresLocker) do(m string) {
	_, err := l.db.Exec(fmt.Sprintf("SELECT pg_advisory_%s(%d)", m, l.key))
	if err != nil {
		panic(fmt.Sprintf("migrate: %v", err))
	}
}
func NewMigrator(db *sql.DB) *Migrator {
	return &Migrator{
		db:     db,
		Locker: new(sync.Mutex),
	}
}
func NewPostgresMigrator(db *sql.DB) *Migrator {
	m := NewMigrator(db)
	m.Locker = newPostgresLocker(db)
	return m
}
func (m *Migrator) Exec(dir MigrationDirection, migrations ...Migration) error {
	m.Lock()
	defer m.Unlock()
	_, err := m.db.Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (version integer primary key not null)", m.table()))
	if err != nil {
		return err
	}
	var tx *sql.Tx
	if m.TransactionMode == SingleTransaction {
		tx, err = m.db.Begin()
		if err != nil {
			return err
		}
	}
	for _, migration := range sortMigrations(dir, migrations) {
		if m.TransactionMode == IndividualTransactions {
			tx, err = m.db.Begin()
			if err != nil {
				return err
			}
		}
		if err := m.runMigration(tx, dir, migration); err != nil {
			tx.Rollback()
			return err
		}
		if m.TransactionMode == IndividualTransactions {
			if err := tx.Commit(); err != nil {
				return err
			}
		}
	}
	if m.TransactionMode == SingleTransaction {
		if err := tx.Commit(); err != nil {
			return err
		}
	}
	return nil
}
func (m *Migrator) runMigration(tx *sql.Tx, dir MigrationDirection, migration Migration) error {
	shouldMigrate, err := m.shouldMigrate(tx, migration.ID, dir)
	if err != nil {
		return err
	}
	if !shouldMigrate {
		return nil
	}
	var migrate func(tx *sql.Tx) error
	switch dir {
	case Up:
		migrate = migration.Up
	default:
		migrate = migration.Down
	}
	if err := migrate(tx); err != nil {
		return &MigrationError{Migration: migration, Err: err}
	}
	var query string
	switch dir {
	case Up:
		query = fmt.Sprintf("INSERT INTO %s (version) VALUES (%d)", m.table(), migration.ID)
	default:
		query = fmt.Sprintf("DELETE FROM %s WHERE version = %d", m.table(), migration.ID)
	}
	_, err = tx.Exec(query)
	return err
}
func (m *Migrator) shouldMigrate(tx *sql.Tx, id int, dir MigrationDirection) (bool, error) {
	var _id int
	err := tx.QueryRow(fmt.Sprintf("SELECT version FROM %s WHERE version = %d", m.table(), id)).Scan(&_id)
	if err != nil && err != sql.ErrNoRows {
		return false, err
	}
	switch dir {
	case Up:
		return err == sql.ErrNoRows, nil
	default:
		return err != sql.ErrNoRows, nil
	}
}
func (m *Migrator) table() string {
	if m.Table == "" {
		return DefaultTable
	}
	return m.Table
}
func Exec(db *sql.DB, dir MigrationDirection, migrations ...Migration) error {
	return NewMigrator(db).Exec(dir, migrations...)
}
func Queries(queries []string) func(*sql.Tx) error {
	return func(tx *sql.Tx) error {
		for _, query := range queries {
			if _, err := tx.Exec(query); err != nil {
				return err
			}
		}
		return nil
	}
}