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 }, ) }