use super::{ledger, migration_directories, CustomMigrationError};
use crate::database::{Database, DatabaseConnection};
use std::io;
use std::path::Path;
const MIGRATIONS_DIR: &str = "./config/database/migrations";
pub async fn create(connection: &DatabaseConnection) -> Result<Vec<String>, CustomMigrationError> {
record_ids(connection, &identities()?).await
}
pub async fn record_ids(
connection: &DatabaseConnection,
ids: &[String],
) -> Result<Vec<String>, CustomMigrationError> {
ledger::ensure_table(connection).await?;
let mut recorded = Vec::new();
for id in ids {
if ledger::is_applied(connection, id).await? {
continue;
}
let checksum =
ledger::file_checksum(&Path::new(MIGRATIONS_DIR).join(id).join("up.sql")).ok();
ledger::record_with_metadata(
connection,
id,
super::MigrationDirection::Up,
ledger::Provenance::Baselined,
checksum.as_deref(),
)
.await?;
recorded.push(id.clone());
}
Ok(recorded)
}
pub fn identities() -> Result<Vec<String>, CustomMigrationError> {
let root = Path::new(MIGRATIONS_DIR);
if !root.exists() {
return Err(CustomMigrationError::IoError(io::Error::new(
io::ErrorKind::NotFound,
format!("No migrations directory found at '{MIGRATIONS_DIR}'."),
)));
}
let mut directories = migration_directories(root).map_err(CustomMigrationError::IoError)?;
directories.sort();
Ok(directories
.iter()
.filter_map(|path| path.file_name()?.to_str().map(str::to_string))
.collect())
}
pub async fn connect() -> Result<DatabaseConnection, CustomMigrationError> {
let database = Database::get_database_from_rustyroad_toml().map_err(|error| {
CustomMigrationError::IoError(io::Error::other(format!(
"Couldn't parse the rustyroad.toml file: {error}"
)))
})?;
Database::create_database_connection(&database)
.await
.map_err(CustomMigrationError::SendError)
}