Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions internal/dbtest/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func TestMigrate(t *testing.T) {
tests := []Test{
{run: testMigrateUpAndDown},
{run: testMigrateUpError},
{run: testRunMigration},
}

testEachDB(t, func(t *testing.T, dbName string, db *bun.DB) {
Expand Down Expand Up @@ -180,6 +181,64 @@ func testMigrateUpError(t *testing.T, db *bun.DB) {
require.Equal(t, []string{"down2", "down1"}, history)
}

func testRunMigration(t *testing.T, db *bun.DB) {
ctx := context.Background()
cleanupMigrations(t, ctx, db)

var history []string

migrations := migrate.NewMigrations()
migrations.Add(migrate.Migration{
Name: "20060102150405",
Up: func(ctx context.Context, migrator *migrate.Migrator, migration *migrate.Migration) error {
history = append(history, "up1")
return nil
},
})
migrations.Add(migrate.Migration{
Name: "20060102160405",
Up: func(ctx context.Context, migrator *migrate.Migrator, migration *migrate.Migration) error {
history = append(history, "up2")
return nil
},
})

m := migrate.NewMigrator(db, migrations,
migrate.WithTableName(migrationsTable),
migrate.WithLocksTableName(migrationLocksTable),
)
require.NoError(t, m.Reset(ctx))

_, err := m.Migrate(ctx)
require.NoError(t, err)
require.Equal(t, []string{"up1", "up2"}, history)

appliedBefore, err := m.AppliedMigrations(ctx)
require.NoError(t, err)
migrationIDs := func(ms migrate.MigrationSlice) []int64 {
ids := make([]int64, len(ms))
for i := range ms {
ids[i] = ms[i].ID
}
return ids
}
migrationsWithStatus, err := m.MigrationsWithStatus(ctx)
require.NoError(t, err)
require.Len(t, migrationsWithStatus, 2)

targetID := migrationsWithStatus[0].ID
require.NotZero(t, targetID)

history = nil
err = m.RunMigration(ctx, targetID)
require.NoError(t, err)
require.Equal(t, []string{"up1"}, history)

appliedAfter, err := m.AppliedMigrations(ctx)
require.NoError(t, err)
require.ElementsMatch(t, migrationIDs(appliedBefore), migrationIDs(appliedAfter))
}

// newAutoMigratorOrSkip creates an AutoMigrator configured to use test migratins/locks
// tables and dedicated migrations directory. If an AutoMigrator cannob be created because
// the dialect doesn't support either schema inspections or migrations, the test will be *skipped*
Expand Down
41 changes: 40 additions & 1 deletion migrate/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,45 @@ func (m *Migrator) Migrate(ctx context.Context, opts ...MigrationOption) (*Migra
return group, nil
}

// RunMigration runs the up migration with the given ID without marking it as applied.
// It runs the migration even if it is already marked as applied.
func (m *Migrator) RunMigration(
ctx context.Context, migrationID int64, opts ...MigrationOption,
) error {
cfg := newMigrationConfig(opts)

if err := m.validate(); err != nil {
return err
}
if migrationID == 0 {
return errors.New("migrate: migration id must be greater than zero")
}

migrations, _, err := m.migrationsWithStatus(ctx)
if err != nil {
return err
}

var migration *Migration
for i := range migrations {
if migrations[i].ID == migrationID {
migration = &migrations[i]
break
}
}
if migration == nil {
return fmt.Errorf("migrate: migration with id %d not found", migrationID)
}
if migration.Up == nil {
return fmt.Errorf("migrate: migration %s does not have up migration", migration.Name)
}
if cfg.nop {
return nil
}

return migration.Up(ctx, m, migration)
}

func (m *Migrator) Rollback(ctx context.Context, opts ...MigrationOption) (*MigrationGroup, error) {
cfg := newMigrationConfig(opts)

Expand Down Expand Up @@ -418,7 +457,7 @@ func (m *Migrator) MissingMigrations(ctx context.Context) (MigrationSlice, error
return applied, nil
}

// AppliedMigrations selects applied (applied) migrations in descending order.
// AppliedMigrations returns applied (applied) migrations in descending order.
func (m *Migrator) AppliedMigrations(ctx context.Context) (MigrationSlice, error) {
var ms MigrationSlice
if err := m.db.NewSelect().
Expand Down
Loading