-
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
base: master
Are you sure you want to change the base?
Conversation
|
Perhaps we could add a column to the |
migrate.go
Outdated
| if migrations[index].Id == current { | ||
| // Searches the arrays for the latest elements with common ids. | ||
| // Returns the indexes of the common id. | ||
| func lastCommon(x []*Migration, y []*Migration) (int, int) { |
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.
Rename x and y to left and right to avoid unreadable array accesses like x[i] and y[j].
| return []*Migration{} | ||
| } | ||
| migrationsMap := map[string]*Migration{} | ||
| for _, m := range existingMigrations { |
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.
Add note about the order of setting migrationsMap. It's important that we fill migrationsMap from existingMigrations first, then from migrations. migrations is the only array with Up and Down set, and we want those values if possible.
| } | ||
|
|
||
| // Filter a slice of migrations into ones that should be applied. | ||
| func ToApply(migrations, existingMigrations []*Migration, direction MigrationDirection) []*Migration { |
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 ToApplySafe or something similar and avoid breaking the signature of ToApply().
6fff946 to
e03d678
Compare
migrate.go
Outdated
| // Figure out which migrations to apply | ||
| toApply := ToApply(migrations, record.Id, dir) | ||
| toApply := ToApply(migrations, existingMigrations, dir) | ||
| if err != nil { |
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.
I'm confused by this err check.
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.
Oops. At one point, I made ToApply() return an error, but changed my mind. I never took out the error check.
migrate.go
Outdated
| } | ||
| } | ||
| if xIndexMatch == -1 { | ||
| return -1, -1 // We never found a match; the arrays have nothing in common |
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.
Could use const none = -1 if you wanted
migrate.go
Outdated
| } | ||
|
|
||
| func toApplyDown(migrations, existingMigrations []*Migration) []*Migration { | ||
| if len(existingMigrations) == -1 { |
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.
Should this be == 0?
migrate.go
Outdated
| } | ||
| // 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. |
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.
Would this comment make more sense if it were on the second loop, which does the overwriting you describe?
|
Otherwise looks good. Thanks for taking care of this! |
migrate.go
Outdated
| if len(existingMigrations) == 0 { | ||
| return migrations | ||
| } | ||
| _, index := lastCommon(existingMigrations, migrations) |
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.
If I didn't know what bug this was fixing, I'd wonder why it is being done. Could you add some comments about it?
|
Can there be an unknown, unapplied migration? such as when you |
|
Going ahead and applying a new migration on top of a database that has an unknown, unapplied migration seems safe, but if the unknown migration was applied, that seems like it could leave the db in a state incompatible with the new migration. |
|
@johnlockwood-wf Are you saying, if the database has had an unknown migration applied, when we apply our known migration, we may leave the db in an incompatible state? |
|
@ericklaus-wf an applied, unknown migration may change the db into a state incompatible with the new, known migration. |
|
the unknown migration applied may make the db incompatible with a new known migration
|
|
That's true, but the problem already exists. Consider this: a database has migrations 1 and 2 applied and these migrations are the master branch. Branch A adds migration 3. Branch B adds migration 4. Branch B is merged to master and deployed. Migration 4 is applied. The database is now in state "1, 2, 4". Branch A is merged to master and deployed. Migration 3 is applied. The database is now in state "1, 2, 3, 4". This change does expand the area where this can happen though. It will now be possible for branch A to be deployed without merging to master and have migration 3 applied against the database. |
|
If I was going to PR this back to the main fork, I might add a flag for the new behavior and without the flag, an unknown migration would cause the program to exit with a non-0 code. I'd consider an interactive mode, where the user was prompted for a choice of whether to go ahead with applying a migration after an unknown had been applied. |
|
To me, this is behavior that I expect, so I'd be annoyed by having this behind a flag. But I think I see your point. It would be a little complicated to put this behind a flag. sql-migrate is both a library and a command line tool. Propagating the flag through would be a bit messy but possible. |
3181ab1 to
8f48137
Compare
Fixes bad behavior when some migrations in the db table are unknown to the current sql-migrate instance. That might happen when one branch applies some migrations and a branch lacking those migrations tries to add some of its own.
Fixed behaviors:
sql-migrate statuspanicsSome weirdness remains:
sql-migrate redoreports "nothing to do"sql-migrate statusinclude the fact of unknown statuses in the table it prints, rather than as separate warnings. I want to get some UX feedback on how that might look. Currently, the printout looks like: