use crate::{RelError, RelationalBackend};
use std::fmt;
use std::future::Future;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Migration {
pub version: i64,
pub description: String,
pub sql: String,
}
impl Migration {
pub fn new(version: i64, description: impl Into<String>, sql: impl Into<String>) -> Self {
Migration {
version,
description: description.into(),
sql: sql.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum MigrateError {
ChecksumMismatch {
version: i64,
},
NewerThanProgram {
version: i64,
},
Dirty {
version: i64,
},
Failed {
version: i64,
error: RelError,
},
Backend(String),
}
impl fmt::Display for MigrateError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MigrateError::ChecksumMismatch { version } => {
write!(f, "migration {version} was applied and has been modified")
}
MigrateError::NewerThanProgram { version } => write!(
f,
"the database has applied migration {version}, which this program does not know"
),
MigrateError::Dirty { version } => {
write!(
f,
"migration {version} is partially applied; fix it by hand"
)
}
MigrateError::Failed { version, error } => {
write!(f, "migration {version} failed: {error}")
}
MigrateError::Backend(m) => write!(f, "migration: {m}"),
}
}
}
impl std::error::Error for MigrateError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MigrateReport {
pub applied: Vec<i64>,
pub already_applied: Vec<i64>,
pub checksums: Vec<(i64, Vec<u8>)>,
}
pub trait Migrates: RelationalBackend {
fn migrate(
&self,
migrations: &[Migration],
) -> impl Future<Output = Result<MigrateReport, MigrateError>> + Send;
fn applied_versions(&self) -> impl Future<Output = Result<Vec<i64>, MigrateError>> + Send;
}