- Notifications
You must be signed in to change notification settings - Fork103
Minimalistic database migration helper for Gorm ORM
License
go-gormigrate/gormigrate
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Gormigrate is a minimalistic migration helper forGorm.Gorm already has usefulmigrate functions, just missesproper schema versioning and migration rollback support.
IMPORTANT: If you need support to Gorm v1 (which uses
github.com/jinzhu/gorm
as its import path), please import Gormigrate byusing thegopkg.in/gormigrate.v1
import path.The current Gorm version (v2) is supported by using the
github.com/go-gormigrate/gormigrate/v2
import path as described in thedocumentation below.
It supports any of thedatabases Gorm supports:
- MySQL
- MariaDB
- PostgreSQL
- SQLite
- Microsoft SQL Server
- TiDB
- Clickhouse
package mainimport ("log""github.com/go-gormigrate/gormigrate/v2""github.com/google/uuid""gorm.io/driver/sqlite""gorm.io/gorm""gorm.io/gorm/logger")funcmain() {db,err:=gorm.Open(sqlite.Open("./data.db"),&gorm.Config{Logger:logger.Default.LogMode(logger.Info),})iferr!=nil {log.Fatal(err)}m:=gormigrate.New(db,gormigrate.DefaultOptions, []*gormigrate.Migration{{// create `users` tableID:"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 timetypeuserstruct {ID uuid.UUID`gorm:"type:uuid;primaryKey;uniqueIndex"`Namestring}returntx.Migrator().CreateTable(&user{})},Rollback:func(tx*gorm.DB)error {returntx.Migrator().DropTable("users")},}, {// add `age` column to `users` tableID:"201608301415",Migrate:func(tx*gorm.DB)error {// when table already exists, define only columns that are about to changetypeuserstruct {Ageint}returntx.Migrator().AddColumn(&user{},"Age")},Rollback:func(tx*gorm.DB)error {typeuserstruct {Ageint}returndb.Migrator().DropColumn(&user{},"Age")},}, {// create `organizations` table where users belong toID:"201608301430",Migrate:func(tx*gorm.DB)error {typeorganizationstruct {ID uuid.UUID`gorm:"type:uuid;primaryKey;uniqueIndex"`NamestringAddressstring}iferr:=tx.Migrator().CreateTable(&organization{});err!=nil {returnerr}typeuserstruct {OrganizationID uuid.UUID`gorm:"type:uuid"`}returntx.Migrator().AddColumn(&user{},"OrganizationID")},Rollback:func(tx*gorm.DB)error {typeuserstruct {OrganizationID uuid.UUID`gorm:"type:uuid"`}iferr:=db.Migrator().DropColumn(&user{},"OrganizationID");err!=nil {returnerr}returntx.Migrator().DropTable("organizations")},}})iferr:=m.Migrate();err!=nil {log.Fatalf("Migration failed: %v",err)}log.Println("Migration did run successfully")}
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 runbefore (in a new clean database). Remember to create everything here, all tables,foreign keys and what more you need in your app.
typeOrganizationstruct {gorm.ModelNamestringAddressstring}typeUserstruct {gorm.ModelNamestringAgeintOrganizationIDuint}m:=gormigrate.New(db,gormigrate.DefaultOptions, []*gormigrate.Migration{// your migrations here})m.InitSchema(func(tx*gorm.DB)error {err:=tx.AutoMigrate(&Organization{},&User{},// all other tables of you app)iferr!=nil {returnerr}iferr:=tx.Exec("ALTER TABLE users ADD CONSTRAINT fk_users_organizations FOREIGN KEY (organization_id) REFERENCES organizations (id)").Error;err!=nil {returnerr}// all other constraints, indexes, etc...returnnil})
This is the options struct, in case you don't want the defaults:
typeOptionsstruct {// TableName is the migration table.TableNamestring// IDColumnName is the name of column where the migration id will be stored.IDColumnNamestring// IDColumnSize is the length of the migration id columnIDColumnSizeint// UseTransaction makes Gormigrate execute migrations inside a single transaction.// Keep in mind that not all databases support DDL commands inside transactions.UseTransactionbool// ValidateUnknownMigrations will cause migrate to fail if there's unknown migration// IDs in the databaseValidateUnknownMigrationsbool}
Gormigrate was born to be a simple and minimalistic migration tool for smallprojects that usesGorm. You may want to take a look at more advancedsolutions likegolang-migrate/migrateif you plan to scale.
Be aware that Gormigrate has no builtin lock mechanism, so if you're runningit automatically and have a distributed setup (i.e. more than one executablerunning at the same time), you might want to use adistributed lock/mutex mechanism toprevent race conditions while running migrations.
To run integration tests, some preparations are needed. Please ensure youhavetask anddocker installed.Then:
- Ensure target or all databases are available and ready to accept connections.You can start databases locally with
task docker:compose:up
- Copy
integration-test/.example.env
asintegration-test/.env
andadjust the database connection ports and credentials when needed. - Run integration test for single database or for all
# run test for MySQLtask test:mysql# run test for MariaDBtask test:mariadb# run test for PostgreSQLtask test:postgres# run test for SQLitetask test:sqlite# run test for Microsoft SQL Servertask test:sqlserver# run test for all databasestask test:all
Alternatively, you can run everything in one step:task docker:test
About
Minimalistic database migration helper for Gorm ORM