use toolu_orm_connection::DbConnection;
use toolu_orm_core::dialect::Dialect;
use super::apply::{apply_migration, verify_hash};
use super::error::MigrateError;
use super::store::{ensure_migrations_table, get_applied_migrations};
pub struct EmbeddedMigration<'a> {
pub name: &'a str,
pub sql: &'a str,
pub hash: &'a str,
}
impl EmbeddedMigration<'_> {
pub fn verify_hash(&self) -> Result<(), MigrateError> {
verify_hash(self.name, self.sql, self.hash)
}
}
pub async fn run_migrate_embedded(
conn: &impl DbConnection,
migrations: &[EmbeddedMigration<'_>],
dialect: Dialect,
) -> Result<u32, MigrateError> {
reject_duplicate_names(migrations)?;
ensure_migrations_table(conn, dialect).await?;
let applied = get_applied_migrations(conn).await?;
let mut count: u32 = 0;
for migration in migrations {
if applied.iter().any(|name| name == migration.name) {
continue;
}
apply_migration(conn, migration.name, migration.sql, migration.hash, dialect).await?;
count += 1;
}
Ok(count)
}
fn reject_duplicate_names(migrations: &[EmbeddedMigration<'_>]) -> Result<(), MigrateError> {
let mut seen: Vec<&str> = Vec::with_capacity(migrations.len());
let mut duplicates: Vec<&str> = Vec::new();
for migration in migrations {
if seen.contains(&migration.name) {
if !duplicates.contains(&migration.name) {
duplicates.push(migration.name);
}
} else {
seen.push(migration.name);
}
}
if duplicates.is_empty() {
return Ok(());
}
Err(MigrateError::DuplicateMigration(duplicates.join(", ")))
}