Home

Awesome

<p align="center"><img src="https://github.com/lopezator/migrator/blob/master/logo.png" width="360"></p> <p align="center"> <a href="https://cloud.drone.io/lopezator/migrator"><img src="https://cloud.drone.io/api/badges/lopezator/migrator/status.svg?branch=master" alt="DroneCI" /></a> <a href="https://goreportcard.com/report/github.com/lopezator/migrator"><img src="https://goreportcard.com/badge/github.com/lopezator/migrator" alt="Go Report Card" /></a> <a href="https://codecov.io/gh/lopezator/migrator"><img src="https://codecov.io/gh/lopezator/migrator/branch/master/graph/badge.svg" alt="codecov" /></a> <a href="https://github.com/avelino/awesome-go#database"><img src="https://awesome.re/mentioned-badge.svg" alt="DroneCI" /></a> <a href="https://godoc.org/github.com/lopezator/migrator"><img src="https://godoc.org/github.com/lopezator/migrator/go?status.svg" alt="GoDoc" /></a> <a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License: Apache 2.0" /></a> </p>

migrator

Dead simple Go database migration library.

Features

Compatibility

Although any database supported by database/sql and one of its recommended drivers SQLDrivers should work OK, at the moment only PostgreSQL and MySQL are being explicitly tested.

If you find any issues with any of the databases included under the umbrella of database/sql, feel free to contribute by opening an issue or sending a pull request.

Usage

The following example assumes:

Customize this to your needs by changing the driver and/or connection settings.

QuickStart:

package main

import (
	"database/sql"
	"log"

	_ "github.com/jackc/pgx/v4/stdlib" // postgres driver
	"github.com/lopezator/migrator"
)

func main() {
    // Configure migrations
    m, err := migrator.New(
        migrator.Migrations(
            &migrator.Migration{
                Name: "Create table foo",
                Func: func(tx *sql.Tx) error {
                    if _, err := tx.Exec("CREATE TABLE foo (id INT PRIMARY KEY)"); err != nil {
                        return err
                    }
                    return nil
                },
            },
        ),
    )
    if err != nil {
        log.Fatal(err)
    }
   
    // Open database connection
    db, err := sql.Open("pgx", "postgres://postgres@localhost/foo?sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    
    // Migrate up
    if err := m.Migrate(db); err != nil {
        log.Fatal(err)
    }
}

Notes on examples above:

Logging

By default, migrator prints applying/applied migration info to stdout. If that's enough for you, you can skip this section.

If you need some special formatting or want to use a 3rd party logging library, this could be done by using WithLogger option as follows:

logger := migrator.WithLogger(migrator.LoggerFunc(func(msg string, args ...interface{}) {
	// Your code here 
})))

Then you will only need to pass the logger as an option to migrator.New.

Looking for more examples?

Just examine the migrator_test.go file.

But I don't want to write complex migrations in strings! 😥

You still can use your favorite embedding tool to write your migrations inside .sql files and load them into migrator!

I provide a simple example using //go:embed on the Using tx, one embedded query test here: migrator_test

Erm... Where are the ID's of the migrations to know their order? 🤔

In order to avoid problems with different identifiers, ID collisions, etc... the order of the migrations is just the order being passed to the migrator.

Wait... no down migrations? 😱

Adding the functionality to reverse a migration introduces complexity to the API, the code, and the risk of losing the synchrony between the defined list of migrations and current state of the database. In addition to this, depending on the case, not all the migrations are easily reversible, or they cannot be reversed.

We also think that it's a good idea to follow an "append-only" philosophy when coming to database migrations, so correcting a defective migration comes in the form of adding a new migration instead of reversing it.

e.g. After a CREATE TABLE foo we'll simply add a new DROP TABLE foo instead of reverting the first migration, so both states are reflected both in the code and the database.

Caveats

Motivation

Why another migration library?

These are not migrator objectives

Comparison with other tools

Contribute

Pull requests are welcome, this is an early implementation and work is needed in all areas: docs, examples, tests, ci...

The easiest way to contribute is by installing docker and docker-compose, and ensure you comply with code standards and pass all the tests before submitting a PR by running:

$> docker-compose up -d --build
$> docker-compose exec migrator make prepare
$> docker-compose exec migrator make sanity-check
$> docker-compose exec migrator make test
$> docker-compose down

Make sure you also provide relevant information in your PR as detailed in the pull request template.

Logo

The logo was taken from @ashleymcnamara's gophers repo. I've just applied slight modifications to it.