forked from rubenv/sql-migrate
-
Notifications
You must be signed in to change notification settings - Fork 0
Handle unknown migrations #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ericklaus-wf
wants to merge
4
commits into
master
Choose a base branch
from
handle-unknown
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -364,9 +364,8 @@ func PlanMigration(db *sql.DB, dialect string, m MigrationSource, dir MigrationD | |
| if len(existingMigrations) > 0 { | ||
| result = append(result, ToCatchup(migrations, existingMigrations, record)...) | ||
| } | ||
|
|
||
| // Figure out which migrations to apply | ||
| toApply := ToApply(migrations, record.Id, dir) | ||
| toApply := ToApply(migrations, existingMigrations, dir) | ||
| toApplyCount := len(toApply) | ||
| if max > 0 && max < toApplyCount { | ||
| toApplyCount = max | ||
|
|
@@ -379,6 +378,10 @@ func PlanMigration(db *sql.DB, dialect string, m MigrationSource, dir MigrationD | |
| Queries: v.Up, | ||
| }) | ||
| } else if dir == Down { | ||
| if v.Down == nil { | ||
| // This happens if we are trying to migrate down a migration unknown to us | ||
| return nil, nil, fmt.Errorf("Unable to undo unknown migration %q", v.Id) | ||
| } | ||
| result = append(result, &PlannedMigration{ | ||
| Migration: v, | ||
| Queries: v.Down, | ||
|
|
@@ -389,34 +392,86 @@ func PlanMigration(db *sql.DB, dialect string, m MigrationSource, dir MigrationD | |
| return result, dbMap, nil | ||
| } | ||
|
|
||
| // Filter a slice of migrations into ones that should be applied. | ||
| func ToApply(migrations []*Migration, current string, direction MigrationDirection) []*Migration { | ||
| var index = -1 | ||
| if current != "" { | ||
| for index < len(migrations)-1 { | ||
| index++ | ||
| if migrations[index].Id == current { | ||
| // Searches the arrays for the latest elements with common ids. | ||
| // Returns the indexes of the common id. | ||
| func lastCommonMigration(left []*Migration, right []*Migration) (int, int) { | ||
| const none = -1 | ||
| xIndexMatch := none | ||
| yIndexMatch := 0 | ||
| for i := 0; i < len(left); i++ { | ||
| existingId := left[i].Id | ||
| for j := yIndexMatch; j < len(right); j++ { | ||
| if right[j].Id == existingId { | ||
| xIndexMatch = i | ||
| yIndexMatch = j | ||
| break | ||
| } | ||
| } | ||
| } | ||
| if xIndexMatch == none { | ||
| // We never found a match; the arrays have nothing in common | ||
| return none, none | ||
| } | ||
| return xIndexMatch, yIndexMatch | ||
| } | ||
|
|
||
| // Filter a slice of migrations into ones that should be applied. | ||
| func ToApply(migrations, existingMigrations []*Migration, direction MigrationDirection) []*Migration { | ||
| if direction == Up { | ||
| return migrations[index+1:] | ||
| } else if direction == Down { | ||
| if index == -1 { | ||
| return []*Migration{} | ||
| } | ||
| return toApplyUp(migrations, existingMigrations) | ||
| } | ||
| if direction == Down { | ||
| return toApplyDown(migrations, existingMigrations) | ||
| } | ||
| panic("Unknown direction") | ||
| } | ||
|
|
||
| // Add in reverse order | ||
| toApply := make([]*Migration, index+1) | ||
| for i := 0; i < index+1; i++ { | ||
| toApply[index-i] = migrations[i] | ||
| } | ||
| return toApply | ||
| func toApplyUp(migrations, existingMigrations []*Migration) []*Migration { | ||
| if len(existingMigrations) == 0 { | ||
| return migrations | ||
| } | ||
| // All migrations after the last common migration need to be applied to the db. | ||
| // It's possible that there are some existingMigrations unknown to us-- | ||
| // we'll just ignore them and hope they don't matter. | ||
| _, index := lastCommonMigration(existingMigrations, migrations) | ||
| return migrations[index+1:] | ||
| } | ||
|
|
||
| func toApplyDown(migrations, existingMigrations []*Migration) []*Migration { | ||
| if len(existingMigrations) == 0 { | ||
| return []*Migration{} | ||
| } | ||
| allMigrations := mergeMigrations(existingMigrations, migrations) | ||
| _, index := lastCommonMigration(existingMigrations, allMigrations) | ||
| // Add in reverse order | ||
| toApply := make([]*Migration, index+1) | ||
| for i := 0; i < index+1; i++ { | ||
| toApply[index-i] = allMigrations[i] | ||
| } | ||
| return toApply | ||
| } | ||
|
|
||
| panic("Not possible") | ||
| // Returns a list of all migrations in either list, sorted by Id. | ||
| // Migrations present only in existingMigrations will not have Up or Down set. | ||
| func mergeMigrations(existingMigrations, migrations []*Migration) []*Migration { | ||
| migrationsMap := map[string]*Migration{} | ||
| for _, m := range existingMigrations { | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add note about the order of setting migrationsMap. It's important that we fill migrationsMap from existingMigrations first, then from migrations. |
||
| migrationsMap[m.Id] = m | ||
| } | ||
| // When a Migration appears in both existingMigrations and migrations, | ||
| // we want the Migration from migrations, since only that list has | ||
| // the Up and Down fields set | ||
| for _, m := range migrations { | ||
| migrationsMap[m.Id] = m | ||
| } | ||
|
|
||
| // Flatten our map back into a list that we can sort | ||
| allMigrations := make([]*Migration, 0, len(migrationsMap)) | ||
| for _, m := range migrationsMap { | ||
| allMigrations = append(allMigrations, m) | ||
| } | ||
| sort.Sort(byId(allMigrations)) | ||
| return allMigrations | ||
| } | ||
|
|
||
| func ToCatchup(migrations, existingMigrations []*Migration, lastRun *Migration) []*PlannedMigration { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a breaking change to a public method. It doesn't feel like the kind of method that library clients would actually use. However, when PRing upstream, I'll offer to rewrite this as
ToApplySafeor something similar and avoid breaking the signature ofToApply().