use super::{Migration, MigrationStatus, exec::*};
use crate::{IntoSchemaManagerConnection, MigrationTrait, SchemaManager, seaql_migrations};
use sea_orm::sea_query::IntoIden;
use sea_orm::{ConnectionTrait, DbErr, DynIden};
use tracing::info;
#[async_trait::async_trait]
pub trait MigratorTraitSelf: Sized + Send + Sync {
fn migrations(&self) -> Vec<Box<dyn MigrationTrait>>;
fn migration_table_name(&self) -> DynIden {
seaql_migrations::Entity.into_iden()
}
fn get_migration_files(&self) -> Vec<Migration> {
self.migrations()
.into_iter()
.map(|migration| Migration {
migration,
status: MigrationStatus::Pending,
})
.collect()
}
async fn get_migration_models<C>(&self, db: &C) -> Result<Vec<seaql_migrations::Model>, DbErr>
where
C: ConnectionTrait,
{
self.install(db).await?;
get_migration_models(db, self.migration_table_name()).await
}
async fn get_migration_with_status<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
where
C: ConnectionTrait,
{
self.install(db).await?;
get_migration_with_status(
self.get_migration_files(),
self.get_migration_models(db).await?,
)
}
async fn get_pending_migrations<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
where
C: ConnectionTrait,
{
self.install(db).await?;
Ok(self
.get_migration_with_status(db)
.await?
.into_iter()
.filter(|file| file.status == MigrationStatus::Pending)
.collect())
}
async fn get_applied_migrations<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
where
C: ConnectionTrait,
{
self.install(db).await?;
Ok(self
.get_migration_with_status(db)
.await?
.into_iter()
.filter(|file| file.status == MigrationStatus::Applied)
.collect())
}
async fn install<C>(&self, db: &C) -> Result<(), DbErr>
where
C: ConnectionTrait,
{
install(db, self.migration_table_name()).await
}
async fn status<C>(&self, db: &C) -> Result<(), DbErr>
where
C: ConnectionTrait,
{
self.install(db).await?;
info!("Checking migration status");
for Migration { migration, status } in self.get_migration_with_status(db).await? {
info!("Migration '{}'... {}", migration.name(), status);
}
Ok(())
}
async fn fresh<'c, C>(&self, db: C) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
let db = db.into_database_executor();
let manager = SchemaManager::new(db);
exec_fresh(self, &manager).await
}
async fn refresh<'c, C>(&self, db: C) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
let db = db.into_database_executor();
let manager = SchemaManager::new(db);
exec_down(self, &manager, None).await?;
exec_up(self, &manager, None).await
}
async fn reset<'c, C>(&self, db: C) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
let db = db.into_database_executor();
let manager = SchemaManager::new(db);
exec_down(self, &manager, None).await?;
uninstall(&manager, self.migration_table_name()).await
}
async fn uninstall<'c, C>(&self, db: C) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
let db = db.into_database_executor();
let manager = SchemaManager::new(db);
uninstall(&manager, self.migration_table_name()).await
}
async fn up<'c, C>(&self, db: C, steps: Option<u32>) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
let db = db.into_database_executor();
let manager = SchemaManager::new(db);
exec_up(self, &manager, steps).await
}
async fn down<'c, C>(&self, db: C, steps: Option<u32>) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
let db = db.into_database_executor();
let manager = SchemaManager::new(db);
exec_down(self, &manager, steps).await
}
}
#[async_trait::async_trait]
impl<M> MigratorTraitSelf for M
where
M: super::MigratorTrait + Sized + Send + Sync,
{
fn migrations(&self) -> Vec<Box<dyn MigrationTrait>> {
M::migrations()
}
fn migration_table_name(&self) -> DynIden {
M::migration_table_name()
}
fn get_migration_files(&self) -> Vec<Migration> {
M::get_migration_files()
}
async fn get_migration_models<C>(&self, db: &C) -> Result<Vec<seaql_migrations::Model>, DbErr>
where
C: ConnectionTrait,
{
M::get_migration_models(db).await
}
async fn get_migration_with_status<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
where
C: ConnectionTrait,
{
M::get_migration_with_status(db).await
}
async fn get_pending_migrations<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
where
C: ConnectionTrait,
{
M::get_pending_migrations(db).await
}
async fn get_applied_migrations<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
where
C: ConnectionTrait,
{
M::get_applied_migrations(db).await
}
async fn install<C>(&self, db: &C) -> Result<(), DbErr>
where
C: ConnectionTrait,
{
M::install(db).await
}
async fn status<C>(&self, db: &C) -> Result<(), DbErr>
where
C: ConnectionTrait,
{
M::status(db).await
}
async fn fresh<'c, C>(&self, db: C) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
M::fresh(db).await
}
async fn refresh<'c, C>(&self, db: C) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
M::refresh(db).await
}
async fn reset<'c, C>(&self, db: C) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
M::reset(db).await
}
async fn uninstall<'c, C>(&self, db: C) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
M::uninstall(db).await
}
async fn up<'c, C>(&self, db: C, steps: Option<u32>) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
M::up(db, steps).await
}
async fn down<'c, C>(&self, db: C, steps: Option<u32>) -> Result<(), DbErr>
where
C: IntoSchemaManagerConnection<'c>,
{
M::down(db, steps).await
}
}
async fn exec_fresh<M>(migrator: &M, manager: &SchemaManager<'_>) -> Result<(), DbErr>
where
M: MigratorTraitSelf,
{
let db = manager.get_connection();
migrator.install(db).await?;
drop_everything(db).await?;
exec_up(migrator, manager, None).await
}
async fn exec_up<M>(
migrator: &M,
manager: &SchemaManager<'_>,
steps: Option<u32>,
) -> Result<(), DbErr>
where
M: MigratorTraitSelf,
{
let db = manager.get_connection();
migrator.install(db).await?;
exec_up_with(
manager,
steps,
migrator.get_pending_migrations(db).await?,
migrator.migration_table_name(),
)
.await
}
async fn exec_down<M>(
migrator: &M,
manager: &SchemaManager<'_>,
steps: Option<u32>,
) -> Result<(), DbErr>
where
M: MigratorTraitSelf,
{
let db = manager.get_connection();
migrator.install(db).await?;
exec_down_with(
manager,
steps,
migrator.get_applied_migrations(db).await?,
migrator.migration_table_name(),
)
.await
}