Skip to content

sandro/imigrate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

I Migrate

Interface-driven migrations for Go.

I Migrate is an interface-driven approach to managing database migrations. It was created out of a need for a migration tool that can be used in a Go project that doesn't conform to database/sql, and can execute migrations embedded in a single binary.

This project aims to fulfill the following needs:

  1. Migrations written in pure SQL, stored in flat files.
  2. CLI runner for up, down, redo, rollback, status, dry-run, etc.
  3. CLI template generator for timestamp-prefixed migrations.
  4. fs.FS support, allowing migration files to be embedded via //go:embed.
  5. Database driver agnostic via a sql Exec interface.
  6. No config files. (But config in code)
  7. All public API methods return errors (no panics).
  8. Dry-run mode to preview SQL without executing it.

Read the docs

Usage

Using the built-in *sql.DB adapter

For projects using database/sql, use the provided SQLDB adapter:

db, err := sql.Open("sqlite3", "db.sqlite3")
if err != nil {
  log.Fatal(err)
}
defer db.Close()

executor := imigrate.NewSQLDB(db)
migrator := imigrate.NewIMigrator(executor, os.DirFS("."))
imigrate.CLI(migrator)

With embedded migrations

//go:embed migrations
var migrationsFS embed.FS

func main() {
  db, _ := sql.Open("sqlite3", "app.db")
  executor := imigrate.NewSQLDB(db)
  migrator := imigrate.NewIMigrator(executor, migrationsFS)
  // WriteDirname tells Create where to write new files on disk,
  // since the embed.FS is read-only.
  migrator.WriteDirname = "internal/db/migrations"
  imigrate.CLI(migrator)
}

Custom executor (non-database/sql drivers)

If your database driver does not conform to database/sql, implement the Executor interface:

type Executor interface {
  Exec(query string, args ...interface{}) (sql.Result, error)
  GetVersions(query string, args ...interface{}) ([]int64, error)
}

Programmatic usage

All public API methods return errors:

// Run all pending migrations
err := migrator.Up(-1, 0)

// Run a specific number of migrations
err = migrator.Up(2, 0)

// Run a specific version
err = migrator.Up(-1, 1610069160)

// Roll back
err = migrator.Down(-1, 0)

// Preview what Up would do
err = migrator.DryRun(-1, 0)

CLI with args

Use CLIWithArgs when you need to control the argument parsing:

args := []string{"up", "-steps=1"}
err := imigrate.CLIWithArgs(migrator, args)

CLI(migrator) is a convenience wrapper that passes os.Args[1:].

Configuration

migrator := imigrate.NewIMigrator(executor, fsys)

// Set a separate directory for writing new migration files
migrator.WriteDirname = "internal/db/migrations"

// Silence migration output
migrator.Logger = imigrate.DiscardLogger

// Or provide your own logger
migrator.Logger = log.New(os.Stderr, "[migrate] ", log.LstdFlags)

CLI usage

Example CLI usage for a tool named "migrate":

migrate create create_users_table

migrate up
migrate up -steps=1
migrate up -version=1610069160

migrate down
migrate down -steps=1

migrate redo
migrate redo -steps=2

migrate rollback
migrate rollback -steps=3

migrate status

migrate dry-run
migrate dry-run -steps=2
migrate dry-run -version=1610069160

All commands accept a -silent flag to suppress output.

About

Interface-driven migrations in Go. A simple tool to run database migrations for sql drivers that don't conform to database/sql.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages