Skip to content

Commit ef401a0

Browse files
committed
Merge pull request #16 from pschyska/master
Account for "holes" in the existing migrations in PlanMigration
2 parents 0ab1fcf + 1aa4565 commit ef401a0

File tree

2 files changed

+107
-10
lines changed

2 files changed

+107
-10
lines changed

migrate.go

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -323,23 +323,32 @@ func PlanMigration(db *sql.DB, dialect string, m MigrationSource, dir MigrationD
323323
record = existingMigrations[len(existingMigrations)-1]
324324
}
325325

326-
// Figure out which of the supplied migrations has been applied.
326+
result := make([]*PlannedMigration, 0)
327+
328+
// Add missing migrations up to the last run migration.
329+
// This can happen for example when merges happened.
330+
if len(existingMigrations) > 0 {
331+
result = append(result, ToCatchup(migrations, existingMigrations, record)...)
332+
}
333+
334+
// Figure out which migrations to apply
327335
toApply := ToApply(migrations, record.Id, dir)
328336
toApplyCount := len(toApply)
329337
if max > 0 && max < toApplyCount {
330338
toApplyCount = max
331339
}
332-
333-
result := make([]*PlannedMigration, toApplyCount)
334-
for k, v := range toApply[0:toApplyCount] {
335-
result[k] = &PlannedMigration{
336-
Migration: v,
337-
}
340+
for _, v := range toApply[0:toApplyCount] {
338341

339342
if dir == Up {
340-
result[k].Queries = v.Up
343+
result = append(result, &PlannedMigration{
344+
Migration: v,
345+
Queries: v.Up,
346+
})
341347
} else if dir == Down {
342-
result[k].Queries = v.Down
348+
result = append(result, &PlannedMigration{
349+
Migration: v,
350+
Queries: v.Down,
351+
})
343352
}
344353
}
345354

@@ -376,6 +385,23 @@ func ToApply(migrations []*Migration, current string, direction MigrationDirecti
376385
panic("Not possible")
377386
}
378387

388+
func ToCatchup(migrations, existingMigrations []*Migration, lastRun *Migration) []*PlannedMigration {
389+
missing := make([]*PlannedMigration, 0)
390+
for _, migration := range migrations {
391+
found := false
392+
for _, existing := range existingMigrations {
393+
if existing.Id == migration.Id {
394+
found = true
395+
break
396+
}
397+
}
398+
if !found && migration.Less(lastRun) {
399+
missing = append(missing, &PlannedMigration{Migration: migration, Queries: migration.Up})
400+
}
401+
}
402+
return missing
403+
}
404+
379405
func GetMigrationRecords(db *sql.DB, dialect string) ([]*MigrationRecord, error) {
380406
dbMap, err := getMigrationDbMap(db, dialect)
381407
if err != nil {

migrate_test.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import (
44
"database/sql"
55
"os"
66

7+
"github.com/go-gorp/gorp"
78
_ "github.com/mattn/go-sqlite3"
8-
"github.com/rubenv/gorp"
99
. "gopkg.in/check.v1"
1010
)
1111

@@ -284,3 +284,74 @@ func (s *SqliteMigrateSuite) TestPlanMigration(c *C) {
284284
c.Assert(plannedMigrations[1].Migration, Equals, migrations.Migrations[1])
285285
c.Assert(plannedMigrations[2].Migration, Equals, migrations.Migrations[0])
286286
}
287+
288+
func (s *SqliteMigrateSuite) TestPlanMigrationWithHoles(c *C) {
289+
up := "SELECT 0"
290+
down := "SELECT 1"
291+
migrations := &MemoryMigrationSource{
292+
Migrations: []*Migration{
293+
&Migration{
294+
Id: "1",
295+
Up: []string{up},
296+
Down: []string{down},
297+
},
298+
&Migration{
299+
Id: "3",
300+
Up: []string{up},
301+
Down: []string{down},
302+
},
303+
},
304+
}
305+
n, err := Exec(s.Db, "sqlite3", migrations, Up)
306+
c.Assert(err, IsNil)
307+
c.Assert(n, Equals, 2)
308+
309+
migrations.Migrations = append(migrations.Migrations, &Migration{
310+
Id: "2",
311+
Up: []string{up},
312+
Down: []string{down},
313+
})
314+
315+
migrations.Migrations = append(migrations.Migrations, &Migration{
316+
Id: "4",
317+
Up: []string{up},
318+
Down: []string{down},
319+
})
320+
321+
migrations.Migrations = append(migrations.Migrations, &Migration{
322+
Id: "5",
323+
Up: []string{up},
324+
Down: []string{down},
325+
})
326+
327+
// apply all the missing migrations
328+
plannedMigrations, _, err := PlanMigration(s.Db, "sqlite3", migrations, Up, 0)
329+
c.Assert(err, IsNil)
330+
c.Assert(plannedMigrations, HasLen, 3)
331+
c.Assert(plannedMigrations[0].Migration.Id, Equals, "2")
332+
c.Assert(plannedMigrations[0].Queries[0], Equals, up)
333+
c.Assert(plannedMigrations[1].Migration.Id, Equals, "4")
334+
c.Assert(plannedMigrations[1].Queries[0], Equals, up)
335+
c.Assert(plannedMigrations[2].Migration.Id, Equals, "5")
336+
c.Assert(plannedMigrations[2].Queries[0], Equals, up)
337+
338+
// first catch up to current target state 123, then migrate down 1 step to 12
339+
plannedMigrations, _, err = PlanMigration(s.Db, "sqlite3", migrations, Down, 1)
340+
c.Assert(err, IsNil)
341+
c.Assert(plannedMigrations, HasLen, 2)
342+
c.Assert(plannedMigrations[0].Migration.Id, Equals, "2")
343+
c.Assert(plannedMigrations[0].Queries[0], Equals, up)
344+
c.Assert(plannedMigrations[1].Migration.Id, Equals, "3")
345+
c.Assert(plannedMigrations[1].Queries[0], Equals, down)
346+
347+
// first catch up to current target state 123, then migrate down 2 steps to 1
348+
plannedMigrations, _, err = PlanMigration(s.Db, "sqlite3", migrations, Down, 2)
349+
c.Assert(err, IsNil)
350+
c.Assert(plannedMigrations, HasLen, 3)
351+
c.Assert(plannedMigrations[0].Migration.Id, Equals, "2")
352+
c.Assert(plannedMigrations[0].Queries[0], Equals, up)
353+
c.Assert(plannedMigrations[1].Migration.Id, Equals, "3")
354+
c.Assert(plannedMigrations[1].Queries[0], Equals, down)
355+
c.Assert(plannedMigrations[2].Migration.Id, Equals, "2")
356+
c.Assert(plannedMigrations[2].Queries[0], Equals, down)
357+
}

0 commit comments

Comments
 (0)