guesstimate/cmd/server/migration.go

146 lines
3.3 KiB
Go

package main
import (
"context"
"forge.cadoles.com/Cadoles/guesstimate/internal/model"
"forge.cadoles.com/Cadoles/guesstimate/internal/orm"
"github.com/jinzhu/gorm"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
"gitlab.com/wpetit/goweb/service"
)
const (
migrateUp = "up"
migrateLatest = "latest"
migrateDown = "down"
)
func applyMigration(ctx context.Context, ctn *service.Container) error {
orm, err := orm.From(ctn)
if err != nil {
return err
}
migr := orm.Migration()
// Register available migrations
migr.Register(
m000initialSchema(),
)
currentVersion, err := migr.CurrentVersion(ctx)
if err != nil {
return errors.Wrap(err, "could not retrieve current data schema version")
}
switch migrate {
case migrateUp:
if err := migr.Up(ctx); err != nil {
return errors.Wrap(err, "could not apply up migration")
}
case migrateLatest:
latestVersion, err := migr.LatestVersion()
if err != nil {
return errors.Wrap(err, "could not retrieve latest data schema version")
}
logger.Info(
ctx,
"migrating data schema to latest version",
logger.F("currentVersion", currentVersion),
logger.F("latestVersion", latestVersion),
)
// Execute migration to latest available version
if err := migr.Latest(ctx); err != nil {
return errors.Wrap(err, "could not migrate to latest data schema")
}
case migrateDown:
if err := migr.Down(ctx); err != nil {
return errors.Wrap(err, "could not apply down migration")
}
default:
return errors.Errorf("unknown migration command: '%s'", migrate)
}
logger.Info(
ctx,
"migration completed",
)
return nil
}
// nolint: gochecknoglobals
var initialModels = []interface{}{
&model.User{},
&model.Project{},
&model.Access{},
&model.TaskCategory{},
&model.Task{},
}
func m000initialSchema() orm.Migration {
return orm.NewDBMigration(
"00_initial_schema",
func(ctx context.Context, tx *gorm.DB) error {
for _, m := range initialModels {
if err := tx.AutoMigrate(m).Error; err != nil {
return errors.WithStack(err)
}
}
// Create foreign keys indexes
err := tx.Model(&model.Access{}).
AddForeignKey("user_id", "users(id)", "CASCADE", "CASCADE").Error
if err != nil {
return errors.WithStack(err)
}
err = tx.Model(&model.TaskCategory{}).
AddForeignKey("project_id", "projects(id)", "CASCADE", "CASCADE").Error
if err != nil {
return errors.WithStack(err)
}
err = tx.Model(&model.Access{}).
AddForeignKey("project_id", "projects(id)", "CASCADE", "CASCADE").Error
if err != nil {
return errors.WithStack(err)
}
err = tx.Model(&model.Access{}).
AddForeignKey("user_id", "users(id)", "CASCADE", "CASCADE").Error
if err != nil {
return errors.WithStack(err)
}
err = tx.Model(&model.Task{}).
AddForeignKey("category_id", "task_categories(id)", "CASCADE", "CASCADE").Error
if err != nil {
return errors.WithStack(err)
}
return nil
},
func(ctx context.Context, tx *gorm.DB) error {
for i := len(initialModels) - 1; i >= 0; i-- {
if err := tx.DropTableIfExists(initialModels[i]).Error; err != nil {
return errors.WithStack(err)
}
}
if err := tx.DropTableIfExists("sessions").Error; err != nil {
return errors.WithStack(err)
}
return nil
},
)
}