Skip to content

Migration

Overview

Migration is a feature that allows you to evolve your database schema over time, REL provides DSL that allows you to write migration in Golang.

Defining Migration

Migration package usually located inside your-repo/db/migrations package. It's a standalone package that should not be imported by the rest of your application. Each migration file is named as number_name.go, and each migration file must define a pair of migration and rollback functions: MigrateName and RollbackName. Migrate and rollback function name is the camel cased file name without version.

Note

Sample project that demonstrate this setup can be found at go-rel/gin-example

// 20202806225100_create_todos.go

package migrations

import (
    "context"

    "github.com/go-rel/rel"
)

// MigrateCreateTodos definition
func MigrateCreateTodos(schema *rel.Schema) {
    schema.CreateTable("todos", func(t *rel.Table) {
        t.ID("id")
        t.DateTime("created_at")
        t.DateTime("updated_at")
        t.String("title")
        t.Bool("completed")
        t.Int("order")
    })

    schema.CreateIndex("todos", "order", []string{"order"})

    schema.Do(func(ctx context.Context, repo rel.Repository) error {
        // add seeds
        return repo.Insert(ctx, &Todo{Title: "Do homework"})
    })
}

// RollbackCreateTodos definition
func RollbackCreateTodos(schema *rel.Schema) {
    schema.DropTable("todos")
}

Running Migration

REL provides CLI that can be used to run your migration, it can be installed using homebrew, go get or downloaded from release page.

Install using homebrew:

brew tap go-rel/tap
brew install rel

Or, Install using go get:

go get github.com/go-rel/cmd/rel

Since Go 1.18 use go install:

go install github.com/go-rel/cmd/rel@latest

Verify installation:

rel -version

Migrate to the latest version:

rel migrate

Rollback one migration step:

rel rollback

Configuring Database Connection

By default, REL will try to use database connection info that available as environment variable.

Variable Description
DATABASE_URL Database connection string (Optional)
DATABASE_ADAPTER Adapter package (Required if DATABASE_URL specified)
DATABASE_DRIVER Driver package (Required if DATABASE_URL specified)
MYSQL_HOST MySQL host (Optional)
MYSQL_PORT MySQL port (Optional)
MYSQL_DATABASE MySQL database (Required, if MYSQL_HOST specified)
MYSQL_USERNAME MySQL host (Required, if MYSQL_HOST specified)
MYSQL_PASSWORD MySQL host (Optional)
POSTGRES_HOST PostgreSQL host (Optional)
POSTGRES_PORT PostgreSQL port (Optional)
POSTGRES_DATABASE PostgreSQL database (Required, if POSTGRES_HOST specified)
POSTGRES_USERNAME PostgreSQL username (Required, if POSTGRES_HOST specified)
POSTGRES_PASSWORD PostgreSQL password (Optional)
SQLITE3_DATABASE SQLite3 database (Optional)

Database connection info can also be specified using command line options: dsn, adapter and driver:

rel migrate -adapter=github.com/go-rel/rel/adapter/sqlite3 -driver=github.com/mattn/go-sqlite3 -dsn=:memory:

Migration API

If you need more flexibility, migration API can be used to manually execute migrations.

package main

import (
    "context"

    "github.com/go-rel/doc/examples/db/migrations"
    "github.com/go-rel/migration"
    "github.com/go-rel/mysql"
    "github.com/go-rel/rel"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    var (
        ctx  = context.TODO()
        repo = rel.New(mysql.MustOpen("root@(source:3306)/rel_test?charset=utf8&parseTime=True&loc=Local"))
        m    = migration.New(repo)
    )

    // Register migrations
    m.Register(20202806225100, migrations.MigrateCreateTodos, migrations.RollbackCreateTodos)

    // Run migrations
    m.Migrate(ctx)
    // OR:
    // m.Rollback(ctx)
}

Last update: 2024-03-28