Better handling of multiple migrations (#1747)
* add migration tests that catch the bug * make multiple migrations more robust * clean up migrations ordering * update comment [ci skip] * remove explicit iter
This commit is contained in:
parent
6b1e722a6b
commit
30ba10e10c
@ -180,12 +180,11 @@ impl Manager {
|
|||||||
|
|
||||||
/// Adds new migration rules.
|
/// Adds new migration rules.
|
||||||
pub fn add_migration<T>(&mut self, migration: T) -> Result<(), Error> where T: Migration {
|
pub fn add_migration<T>(&mut self, migration: T) -> Result<(), Error> where T: Migration {
|
||||||
let version_match = match self.migrations.last() {
|
let is_new = match self.migrations.last() {
|
||||||
Some(last) => last.version() + 1 == migration.version(),
|
Some(last) => migration.version() > last.version(),
|
||||||
None => true,
|
None => true,
|
||||||
};
|
};
|
||||||
|
match is_new {
|
||||||
match version_match {
|
|
||||||
true => Ok(self.migrations.push(Box::new(migration))),
|
true => Ok(self.migrations.push(Box::new(migration))),
|
||||||
false => Err(Error::CannotAddMigration),
|
false => Err(Error::CannotAddMigration),
|
||||||
}
|
}
|
||||||
@ -195,7 +194,8 @@ impl Manager {
|
|||||||
/// and producing a path where the final migration lives.
|
/// and producing a path where the final migration lives.
|
||||||
pub fn execute(&mut self, old_path: &Path, version: u32) -> Result<PathBuf, Error> {
|
pub fn execute(&mut self, old_path: &Path, version: u32) -> Result<PathBuf, Error> {
|
||||||
let config = self.config.clone();
|
let config = self.config.clone();
|
||||||
let migrations = try!(self.migrations_from(version).ok_or(Error::MigrationImpossible));
|
let mut migrations = self.migrations_from(version);
|
||||||
|
if migrations.is_empty() { return Err(Error::MigrationImpossible) };
|
||||||
let db_config = DatabaseConfig {
|
let db_config = DatabaseConfig {
|
||||||
max_open_files: 64,
|
max_open_files: 64,
|
||||||
cache_size: None,
|
cache_size: None,
|
||||||
@ -235,10 +235,9 @@ impl Manager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn migrations_from(&mut self, version: u32) -> Option<&mut [Box<Migration>]> {
|
/// Find all needed migrations.
|
||||||
// index of the first required migration
|
fn migrations_from(&mut self, version: u32) -> Vec<&mut Box<Migration>> {
|
||||||
let position = self.migrations.iter().position(|m| m.version() == version + 1);
|
self.migrations.iter_mut().filter(|m| m.version() > version).collect()
|
||||||
position.map(move |p| &mut self.migrations[p..])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +109,18 @@ fn no_migration_needed() {
|
|||||||
manager.execute(&db_path, 1).unwrap();
|
manager.execute(&db_path, 1).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn wrong_adding_order() {
|
||||||
|
let dir = RandomTempPath::create_dir();
|
||||||
|
let db_path = db_path(dir.as_path());
|
||||||
|
let mut manager = Manager::new(Config::default());
|
||||||
|
make_db(&db_path, map![vec![] => vec![], vec![1] => vec![1]]);
|
||||||
|
|
||||||
|
manager.add_migration(Migration1).unwrap();
|
||||||
|
manager.add_migration(Migration0).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multiple_migrations() {
|
fn multiple_migrations() {
|
||||||
let dir = RandomTempPath::create_dir();
|
let dir = RandomTempPath::create_dir();
|
||||||
@ -139,6 +151,34 @@ fn second_migration() {
|
|||||||
verify_migration(&end_path, expected);
|
verify_migration(&end_path, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn first_and_noop_migration() {
|
||||||
|
let dir = RandomTempPath::create_dir();
|
||||||
|
let db_path = db_path(dir.as_path());
|
||||||
|
let mut manager = Manager::new(Config::default());
|
||||||
|
make_db(&db_path, map![vec![] => vec![], vec![1] => vec![1]]);
|
||||||
|
let expected = map![vec![0x11] => vec![0x22], vec![1, 0x11] => vec![1, 0x22]];
|
||||||
|
|
||||||
|
manager.add_migration(Migration0).unwrap();
|
||||||
|
let end_path = manager.execute(&db_path, 0).unwrap();
|
||||||
|
|
||||||
|
verify_migration(&end_path, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn noop_and_second_migration() {
|
||||||
|
let dir = RandomTempPath::create_dir();
|
||||||
|
let db_path = db_path(dir.as_path());
|
||||||
|
let mut manager = Manager::new(Config::default());
|
||||||
|
make_db(&db_path, map![vec![] => vec![], vec![1] => vec![1]]);
|
||||||
|
let expected = map![vec![] => vec![], vec![1] => vec![]];
|
||||||
|
|
||||||
|
manager.add_migration(Migration1).unwrap();
|
||||||
|
let end_path = manager.execute(&db_path, 0).unwrap();
|
||||||
|
|
||||||
|
verify_migration(&end_path, expected);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn is_migration_needed() {
|
fn is_migration_needed() {
|
||||||
let mut manager = Manager::new(Config::default());
|
let mut manager = Manager::new(Config::default());
|
||||||
|
Loading…
Reference in New Issue
Block a user