Migrations
Migrations help create your database and track how it evolves overtime. Here, we use GoMigrate to achieve this. Some added complexity is added to enable easy extendability and generate better logs throughout your development process.
Migrations go under pkg/db/migrations/<myNewMigration>.go
. Its implemention uses Go
's init()
function, which means they're added to the list in alphabetical order. They migrate in that order (top to bottom) and rollback in the reverse order (bottom up). For this, it is best to maintain the naming convention of YYYYMMDD[00-99]_migration_description
.
Here's a sample migration to get you started:
func init() {
m := &gormigrate.Migration{}
m.ID = "2022081801_create_cats_table"
m.Migrate = func(db *gorm.DB) error {
type Cat struct {
models.ModelBase
Name string `gorm:"size:255"`
Type string `gorm:"size:255"`
}
return AutoMigrateAndLog(db, &Cat{}, m.ID)
}
m.Rollback = func(db *gorm.DB) error {
if err := db.Migrator().DropTable("cats"); err != nil {
logFail(m.ID, err, true)
}
logSuccess(m.ID, true)
return nil
}
AddMigration(m)
}
The variable m
holds the migration details and is added to the list of migrations at the end. m.ID
is the identifier used by gomigrate
to keep track of the migrations that already ran. So, make sure to change that for every migration.
Every migration has 2 methods to be implemented, the Migrate()
and Rollback()
method as described above. Make sure you use the logSuccess
, logFail
and AutoMigrateAndLog()
functions to print the migrations that ran. This will come in very handy for remote deployments.
It's recommended to declare your models within each migration (separately from the models package) to keep track of the database schema change through time. You can add or delete columns, rename columns, and execute raw SQL in migrations.
A general good practice would be to flatten your migrations once your application achieves version 1, leaving only neat table creation in each migration.