• Stars
    star
    2,992
  • Rank 14,465 (Top 0.3 %)
  • Language
    Go
  • License
    MIT License
  • Created over 9 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

SQL schema migration tool for Go.

sql-migrate

SQL Schema migration tool for Go. Based on gorp and goose.

Test Go Reference

Features

  • Usable as a CLI tool or as a library
  • Supports SQLite, PostgreSQL, MySQL, MSSQL and Oracle databases (through gorp)
  • Can embed migrations into your application
  • Migrations are defined with SQL for full flexibility
  • Atomic migrations
  • Up/down migrations to allow rollback
  • Supports multiple database types in one project
  • Works great with other libraries such as sqlx
  • Supported on go1.13+

Installation

To install the library and command line program, use the following:

go get -v github.com/rubenv/sql-migrate/...

For Go version from 1.18, use:

go install github.com/rubenv/sql-migrate/...@latest

Usage

As a standalone tool

$ sql-migrate --help
usage: sql-migrate [--version] [--help] <command> [<args>]

Available commands are:
    down      Undo a database migration
    new       Create a new migration
    redo      Reapply the last migration
    status    Show migration status
    up        Migrates the database to the most recent version available

Each command requires a configuration file (which defaults to dbconfig.yml, but can be specified with the -config flag). This config file should specify one or more environments:

development:
  dialect: sqlite3
  datasource: test.db
  dir: migrations/sqlite3

production:
  dialect: postgres
  datasource: dbname=myapp sslmode=disable
  dir: migrations/postgres
  table: migrations

(See more examples for different set ups here)

Also one can obtain env variables in datasource field via os.ExpandEnv embedded call for the field. This may be useful if one doesn't want to store credentials in file:

production:
  dialect: postgres
  datasource: host=prodhost dbname=proddb user=${DB_USER} password=${DB_PASSWORD} sslmode=require
  dir: migrations
  table: migrations

The table setting is optional and will default to gorp_migrations.

The environment that will be used can be specified with the -env flag (defaults to development).

Use the --help flag in combination with any of the commands to get an overview of its usage:

$ sql-migrate up --help
Usage: sql-migrate up [options] ...

  Migrates the database to the most recent version available.

Options:

  -config=dbconfig.yml   Configuration file to use.
  -env="development"     Environment.
  -limit=0               Limit the number of migrations (0 = unlimited).
  -version               Run migrate up to a specific version, eg: the version number of migration 1_initial.sql is 1.
  -dryrun                Don't apply migrations, just print them.

The new command creates a new empty migration template using the following pattern <current time>-<name>.sql.

The up command applies all available migrations. By contrast, down will only apply one migration by default. This behavior can be changed for both by using the -limit parameter, and the -version parameter. Note -version has higher priority than -limit if you try to use them both.

The redo command will unapply the last migration and reapply it. This is useful during development, when you're writing migrations.

Use the status command to see the state of the applied migrations:

$ sql-migrate status
+---------------+-----------------------------------------+
|   MIGRATION   |                 APPLIED                 |
+---------------+-----------------------------------------+
| 1_initial.sql | 2014-09-13 08:19:06.788354925 +0000 UTC |
| 2_record.sql  | no                                      |
+---------------+-----------------------------------------+

Running Test Integrations

You can see how to run setups for different setups by executing the .sh files in test-integration

# Run mysql-env.sh example (you need to be in the project root directory)

./test-integration/mysql-env.sh

MySQL Caveat

If you are using MySQL, you must append ?parseTime=true to the datasource configuration. For example:

production:
  dialect: mysql
  datasource: root@/dbname?parseTime=true
  dir: migrations/mysql
  table: migrations

See here for more information.

Oracle (oci8)

Oracle Driver is oci8, it is not pure Go code and relies on Oracle Office Client (Instant Client), more detailed information is in the oci8 repo.

Install with Oracle support

To install the library and command line program, use the following:

go get -tags oracle -v github.com/rubenv/sql-migrate/...
development:
  dialect: oci8
  datasource: user/password@localhost:1521/sid
  dir: migrations/oracle
  table: migrations

Oracle (godror)

Oracle Driver is godror, it is not pure Go code and relies on Oracle Office Client (Instant Client), more detailed information is in the godror repository.

Install with Oracle support

To install the library and command line program, use the following:

  1. Install sql-migrate
go get -tags godror -v github.com/rubenv/sql-migrate/...
  1. Download Oracle Office Client(e.g. macos, click Instant Client if you are other system)
wget https://download.oracle.com/otn_software/mac/instantclient/193000/instantclient-basic-macos.x64-19.3.0.0.0dbru.zip
  1. Configure environment variables LD_LIBRARY_PATH
export LD_LIBRARY_PATH=your_oracle_office_path/instantclient_19_3
development:
  dialect: godror
  datasource: user/password@localhost:1521/sid
  dir: migrations/oracle
  table: migrations

As a library

Import sql-migrate into your application:

import "github.com/rubenv/sql-migrate"

Set up a source of migrations, this can be from memory, from a set of files, from bindata (more on that later), or from any library that implements http.FileSystem:

// Hardcoded strings in memory:
migrations := &migrate.MemoryMigrationSource{
    Migrations: []*migrate.Migration{
        &migrate.Migration{
            Id:   "123",
            Up:   []string{"CREATE TABLE people (id int)"},
            Down: []string{"DROP TABLE people"},
        },
    },
}

// OR: Read migrations from a folder:
migrations := &migrate.FileMigrationSource{
    Dir: "db/migrations",
}

// OR: Use migrations from a packr box
// Note: Packr is no longer supported, your best option these days is [embed](https://pkg.go.dev/embed)
migrations := &migrate.PackrMigrationSource{
    Box: packr.New("migrations", "./migrations"),
}

// OR: Use pkger which implements `http.FileSystem`
migrationSource := &migrate.HttpFileSystemMigrationSource{
    FileSystem: pkger.Dir("/db/migrations"),
}

// OR: Use migrations from bindata:
migrations := &migrate.AssetMigrationSource{
    Asset:    Asset,
    AssetDir: AssetDir,
    Dir:      "migrations",
}

// OR: Read migrations from a `http.FileSystem`
migrationSource := &migrate.HttpFileSystemMigrationSource{
    FileSystem: httpFS,
}

Then use the Exec function to upgrade your database:

db, err := sql.Open("sqlite3", filename)
if err != nil {
    // Handle errors!
}

n, err := migrate.Exec(db, "sqlite3", migrations, migrate.Up)
if err != nil {
    // Handle errors!
}
fmt.Printf("Applied %d migrations!\n", n)

Note that n can be greater than 0 even if there is an error: any migration that succeeded will remain applied even if a later one fails.

Check the GoDoc reference for the full documentation.

Writing migrations

Migrations are defined in SQL files, which contain a set of SQL statements. Special comments are used to distinguish up and down migrations.

-- +migrate Up
-- SQL in section 'Up' is executed when this migration is applied
CREATE TABLE people (id int);


-- +migrate Down
-- SQL section 'Down' is executed when this migration is rolled back
DROP TABLE people;

You can put multiple statements in each block, as long as you end them with a semicolon (;).

You can alternatively set up a separator string that matches an entire line by setting sqlparse.LineSeparator. This can be used to imitate, for example, MS SQL Query Analyzer functionality where commands can be separated by a line with contents of GO. If sqlparse.LineSeparator is matched, it will not be included in the resulting migration scripts.

If you have complex statements which contain semicolons, use StatementBegin and StatementEnd to indicate boundaries:

-- +migrate Up
CREATE TABLE people (id int);

-- +migrate StatementBegin
CREATE OR REPLACE FUNCTION do_something()
returns void AS $$
DECLARE
  create_query text;
BEGIN
  -- Do something here
END;
$$
language plpgsql;
-- +migrate StatementEnd

-- +migrate Down
DROP FUNCTION do_something();
DROP TABLE people;

The order in which migrations are applied is defined through the filename: sql-migrate will sort migrations based on their name. It's recommended to use an increasing version number or a timestamp as the first part of the filename.

Normally each migration is run within a transaction in order to guarantee that it is fully atomic. However some SQL commands (for example creating an index concurrently in PostgreSQL) cannot be executed inside a transaction. In order to execute such a command in a migration, the migration can be run using the notransaction option:

-- +migrate Up notransaction
CREATE UNIQUE INDEX CONCURRENTLY people_unique_id_idx ON people (id);

-- +migrate Down
DROP INDEX people_unique_id_idx;

Embedding migrations with embed

If you like your Go applications self-contained (that is: a single binary): use embed to embed the migration files.

Just write your migration files as usual, as a set of SQL files in a folder.

Import the embed package into your application and point it to your migrations:

import "embed"

//go:embed migrations/*
var dbMigrations embed.FS

Use the EmbedFileSystemMigrationSource in your application to find the migrations:

migrations := migrate.EmbedFileSystemMigrationSource{
	FileSystem: dbMigrations,
	Root:       "migrations",
}

Other options such as packr or go-bindata are no longer recommended.

Embedding migrations with libraries that implement http.FileSystem

You can also embed migrations with any library that implements http.FileSystem, like vfsgen, parcello, or go-resources.

migrationSource := &migrate.HttpFileSystemMigrationSource{
    FileSystem: httpFS,
}

Extending

Adding a new migration source means implementing MigrationSource.

type MigrationSource interface {
    FindMigrations() ([]*Migration, error)
}

The resulting slice of migrations will be executed in the given order, so it should usually be sorted by the Id field.

Usage with sqlx

This library is compatible with sqlx. When calling migrate just dereference the DB from your *sqlx.DB:

n, err := migrate.Exec(db.DB, "sqlite3", migrations, migrate.Up)
                    //   ^^^ <-- Here db is a *sqlx.DB, the db.DB field is the plain sql.DB
if err != nil {
    // Handle errors!
}

Questions or Feedback?

You can use Github Issues for feedback or questions.

License

This library is distributed under the MIT license.

More Repositories

1

angular-gettext

Gettext support for Angular.js
JavaScript
651
star
2

grunt-git

Git commands for grunt.
JavaScript
227
star
3

node-systemd

Support for running node.js as a socket-activated service under systemd
JavaScript
133
star
4

point-in-svg-polygon

Determine if an point is inside a polygon
JavaScript
79
star
5

node-apk-parser

Extract Android Manifest info from an APK file.
JavaScript
76
star
6

pofile

Parse and serialize Gettext PO files.
JavaScript
63
star
7

angular-select2

Select2 directive for Angular.js
JavaScript
62
star
8

angular-gettext-example

TodoMVC with angular-gettext added to it.
JavaScript
46
star
9

angular-debounce

Tiny debouncing function for Angular.JS.
JavaScript
42
star
10

angular-gettext-tools

Tools for extracting/compiling angular-gettext strings.
JavaScript
39
star
11

grunt-angular-gettext

Tasks for extracting/compiling angular-gettext strings.
JavaScript
38
star
12

pgtest

PostgreSQL test helper for Go
Go
37
star
13

zipper

Insanely simple zipfile creator for node.js.
C++
33
star
14

broadcaster

Websocket server for broadcasting Redis pub/sub messages to web clients.
Go
33
star
15

node-autoquit

Automatically quit node.js servers when inactive.
JavaScript
33
star
16

node-xlsx-writer

Simple XLSX writer for Node.js.
CoffeeScript
29
star
17

angular-tiny-eventemitter

Tiny event emitter for Angular.JS.
JavaScript
24
star
18

angular-rt-popup

A better version of the Bootstrap popover, for Angular.JS
JavaScript
22
star
19

node-broadcast-hub

WebSockets backed by Redis pubsub.
CoffeeScript
18
star
20

angular-encode-uri

Encode URIs through a filter.
CoffeeScript
17
star
21

connect-body-rewrite

Rewrite request bodies.
JavaScript
16
star
22

grunt-mkdir

Create directories with Grunt.
JavaScript
16
star
23

modl-migrate

SQL Schema migration tool for Go, using modl.
Go
15
star
24

topojson

TopoJSON implementation in Go
Go
11
star
25

jupyter-octave

Jupyter lab with an Octave kernel
Dockerfile
10
star
26

dupefinder

Detect duplicate files across different machines
Go
9
star
27

pygmentize

Go wrapper for pygments
Go
9
star
28

mod_rewrite-to-nginx

Apache mod_rewrite rule to nginx rewrite rule convertor
JavaScript
9
star
29

docker-ttrss-plugins

Tiny Tiny RSS feed reader as a docker image, with plugins.
PHP
8
star
30

1pif-to-kdbx

Quick hack to export a 1pif (1Password export) to kdbx (KeePass).
Python
8
star
31

ec2-disable-source-dest

Disable the EC2 source/dest check from within an instance.
Go
8
star
32

concourse-sentry-releases-resource

Concourse Resource for Sentry releases
Shell
7
star
33

grunt-unknown-css

Detect undeclared CSS classes in your HTML.
CoffeeScript
5
star
34

tripod

Top secret Banshee-based photo app project! Playground for new ideas that will land in F-Spot.
C#
5
star
35

angular-optimistic-cache

Optimistically use cached data before a request finishes.
JavaScript
5
star
36

opencagedata

Go bindings for OpenCage Geocoder
Go
4
star
37

vimrc

VIM configuration
Vim Script
4
star
38

belgium-zipcodes

Zipcodes and NIS codes for Belgium.
CoffeeScript
4
star
39

angular-optimistic-model

Optimistically cached models for Angular.JS.
JavaScript
4
star
40

angular-async-series

Apply an action to a set of data serially.
JavaScript
4
star
41

deploy-to

Git deployment utility script.
Shell
3
star
42

gorocksdb

gorocksdb is a Go wrapper for RocksDB, embedded by default
Go
3
star
43

ergast-mrd

Mirror of the Ergast.com database images
3
star
44

kube-appdeploy

Go
3
star
45

nvimrc

NeoVIM configuration
Vim Script
2
star
46

broadcaster-client

JavaScript client for broadcaster (https://github.com/rubenv/broadcaster)
JavaScript
2
star
47

helm-cert-manager-issuers-letsencrypt

2
star
48

js-validate

JSHint wrapper + validation profiles
JavaScript
2
star
49

backbone_test

Toying around with Node.js and Backbone.js
JavaScript
2
star
50

fastyaml

Super fast YAML parser generator for Go
Go
1
star
51

angular-resize

Window.resize hooks for Angular.JS.
JavaScript
1
star
52

goose

Database migration tool for Go.
Go
1
star
53

mapbox-dist

Compiled version of Mapbox.js.
JavaScript
1
star
54

deuac

Bootable ISO image to disable UAC on Windows machines.
Shell
1
star
55

mobile-monkeypatches

A collection of workarounds and hacks to make life a bit easier when developing mobile web apps.
JavaScript
1
star
56

gettext_sample

Sample showing a bug in the gettext for rails gem.
Ruby
1
star
57

osmtopo

OpenStreetMap topology extraction tools
Go
1
star
58

rrpubsub

More reliable Redis PubSub for Go
Go
1
star
59

angular-import-scope

Import a scope from another ui-view.
JavaScript
1
star
60

stash-go-import

Go import path support for Atlassian Stash
Go
1
star
61

query

Go SQL query builder
Go
1
star
62

connect-strip-manifest

Remove html5 app cache through connect middleware.
JavaScript
1
star
63

utf8mapper

Go
1
star
64

grunt-usemin-uglifynew

Usemin uglify task that reuses existing .min files.
JavaScript
1
star
65

prometheus-jira-api-exporter

Jira exporter for Prometheus that uses the API to fetch data
Go
1
star