migra/migra_cli/src/commands/upgrade.rs

75 lines
2.5 KiB
Rust

use crate::app::App;
use crate::database;
use crate::opts::UpgradeCommandOpt;
use migra::migration;
pub(crate) fn upgrade_pending_migrations(
app: &App,
opts: &UpgradeCommandOpt,
) -> migra::StdResult<()> {
let config = app.config()?;
let mut client = database::create_client_from_config(&config)?;
client.create_migrations_table()?;
let migrations_dir_path = config.migration_dir_path();
let applied_migration_names = client.get_applied_migrations()?;
let all_migrations = migra::fs::get_all_migrations(&migrations_dir_path)?;
let pending_migrations = all_migrations.exclude(&applied_migration_names);
if pending_migrations.is_empty() {
println!("Up to date");
return Ok(());
}
let migrations: migration::List = if let Some(migration_name) = opts.migration_name.clone() {
let target_migration = (*pending_migrations)
.clone()
.into_iter()
.find(|m| m.name() == &migration_name);
if let Some(migration) = target_migration {
vec![migration].into()
} else {
eprintln!(r#"Cannot find migration with "{}" name"#, migration_name);
return Ok(());
}
} else {
let upgrade_migrations_number = opts
.migrations_number
.unwrap_or_else(|| pending_migrations.len());
pending_migrations[..upgrade_migrations_number]
.to_vec()
.into()
};
let migrations_with_content = migrations
.iter()
.map(|migration| {
let migration_name = migration.name();
let migration_file_path = migrations_dir_path.join(migration_name).join("up.sql");
std::fs::read_to_string(migration_file_path).map(|content| (migration_name, content))
})
.collect::<Result<Vec<_>, _>>()?;
database::should_run_in_transaction(
&mut client,
opts.transaction_opts.single_transaction,
|client| {
migrations_with_content
.iter()
.try_for_each(|(migration_name, content)| {
println!("upgrade {}...", migration_name);
database::should_run_in_transaction(
client,
!opts.transaction_opts.single_transaction,
|client| client.run_upgrade_migration(migration_name, &content),
)
})
.map_err(From::from)
},
)?;
Ok(())
}