use async_trait::async_trait;
use chrono::Utc;
use crate::migration::entity::{CrashOrmMigrationRecord, CrashOrmMigrationRecordColumn};
use crate::migration::migration::Migration;
use crate::prelude::{CrashOrmDatabaseConnection, CrashOrmMigrationRecordCreate, CreateEntity, Entity, EqualQueryColumn, OrderDirection, Schema};
#[async_trait]
pub trait CrashOrmMigrationManager: Sync + Send + 'static {
fn get_migrations() -> Vec<Box<dyn Migration>>;
async fn migrate_up(conn: &CrashOrmDatabaseConnection) -> crate::Result<()> {
CrashOrmMigrationRecord::create_table_if_not_exists(conn).await?;
let local_migrations = Self::get_migrations();
for local_migration in local_migrations {
let name = local_migration.get_name();
let migration_in_db = CrashOrmMigrationRecord::query()
.condition(CrashOrmMigrationRecordColumn::NAME.equals(name))
.fetch(conn)
.await?;
if migration_in_db.is_empty() {
local_migration.up(conn).await?;
let migration_entry = CrashOrmMigrationRecordCreate {
name: name.to_string(),
executed_at: Utc::now(),
};
migration_entry.insert(conn).await?;
}
}
Ok(())
}
async fn migrate_down_to(conn: &CrashOrmDatabaseConnection, name: &str) -> crate::Result<()> {
let mut local_migrations = Self::get_migrations();
local_migrations.reverse();
let latest = CrashOrmMigrationRecord::query()
.order(&CrashOrmMigrationRecordColumn::ID, OrderDirection::DESC)
.fetch_single(conn).await?;
let mut started = false;
for migration in local_migrations {
if !started && migration.get_name() == latest.name {
started = true;
}
if started {
migration.down(conn).await?;
CrashOrmMigrationRecord::delete()
.condition(CrashOrmMigrationRecordColumn::NAME.equals(migration.get_name()))
.execute(conn).await?;
}
if migration.get_name() == name {
break;
}
}
Ok(())
}
async fn migrate_down_prev(conn: &CrashOrmDatabaseConnection) -> crate::Result<()> {
let local_migrations = Self::get_migrations();
let latest = CrashOrmMigrationRecord::query()
.order(&CrashOrmMigrationRecordColumn::ID, OrderDirection::DESC)
.fetch_single(conn).await?;
let Some(local_migration) = local_migrations.iter().find(|m| m.get_name() == latest.name) else {
return Err(crate::Error::from_str(&*format!("The previous migration {} was not found in local migrations", latest.name)));
};
local_migration.down(conn).await?;
latest.remove(conn).await?;
Ok(())
}
}