Gormigrate
Gormigrate is a minimalistic migration helper for Gorm. Gorm already has useful migrate functions, just misses proper schema versioning and migration rollback support.
Supported databases
It supports any of the databases Gorm supports:
- PostgreSQL
- MySQL
- SQLite
- Microsoft SQL Server
Installing
go get -u gopkg.in/gormigrate.v1
Usage
package main
import (
"log"
"gopkg.in/gormigrate.v1"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
func main() {
db, err := gorm.Open("sqlite3", "mydb.sqlite3")
if err != nil {
log.Fatal(err)
}
db.LogMode(true)
m := gormigrate.New(db, gormigrate.DefaultOptions, []*gormigrate.Migration{
// create persons table
{
ID: "201608301400",
Migrate: func(tx *gorm.DB) error {
// it's a good pratice to copy the struct inside the function,
// so side effects are prevented if the original struct changes during the time
type Person struct {
gorm.Model
Name string
}
return tx.AutoMigrate(&Person{}).Error
},
Rollback: func(tx *gorm.DB) error {
return tx.DropTable("people").Error
},
},
// add age column to persons
{
ID: "201608301415",
Migrate: func(tx *gorm.DB) error {
// when table already exists, it just adds fields as columns
type Person struct {
Age int
}
return tx.AutoMigrate(&Person{}).Error
},
Rollback: func(tx *gorm.DB) error {
return tx.Table("people").DropColumn("age").Error
},
},
// add pets table
{
ID: "201608301430",
Migrate: func(tx *gorm.DB) error {
type Pet struct {
gorm.Model
Name string
PersonID int
}
return tx.AutoMigrate(&Pet{}).Error
},
Rollback: func(tx *gorm.DB) error {
return tx.DropTable("pets").Error
},
},
})
if err = m.Migrate(); err != nil {
log.Fatalf("Could not migrate: %v", err)
}
log.Printf("Migration did run successfully")
}
Having a separated function for initializing the schema
If you have a lot of migrations, it can be a pain to run all them, as example, when you are deploying a new instance of the app, in a clean database. To prevent this, you can set a function that will run if no migration was run before (in a new clean database). Remember to create everything here, all tables, foreign keys and what more you need in your app.
type Person struct {
gorm.Model
Name string
Age int
}
type Pet struct {
gorm.Model
Name string
PersonID int
}
m := gormigrate.New(db, gormigrate.DefaultOptions, []*gormigrate.Migration{
// you migrations here
})
m.InitSchema(func(tx *gorm.DB) error {
err := tx.AutoMigrate(
&Person{},
&Pet{},
// all other tables of you app
).Error
if err != nil {
return err
}
if err := tx.Model(Pet{}).AddForeignKey("person_id", "people (id)", "RESTRICT", "RESTRICT").Error; err != nil {
return err
}
// all other foreign keys...
return nil
})
Options
This is the options struct, in case you don't want the defaults:
type Options struct {
// TableName is the migration table.
TableName string
// IDColumnName is the name of column where the migration id will be stored.
IDColumnName string
// IDColumnSize is the length of the migration id column
IDColumnSize int
// UseTransaction makes Gormigrate execute migrations inside a single transaction.
// Keep in mind that not all databases support DDL commands inside transactions.
UseTransaction bool
// ValidateUnknownMigrations will cause migrate to fail if there's unknown migration
// IDs in the database
ValidateUnknownMigrations bool
}
Contributing
To run tests, first copy .sample.env
as sample.env
and edit the connection
string of the database you want to run tests against. Then, run tests like
below:
# running tests for PostgreSQL
go test -tags postgresql
# running test for MySQL
go test -tags mysql
# running tests for SQLite
go test -tags sqlite
# running tests for SQL Server
go test -tags sqlserver
# running test for multiple databases at once
go test -tags 'sqlite postgresql mysql'
Or altenatively, you could use Docker to easily run tests on all databases at once. To do that, make sure Docker is installed and running in your machine and then run:
task docker