use std::collections::BinaryHeap;
use std::cmp::Reverse;
type MigrationFn<E> = dyn Send + 'static + Fn(&rusqlite::Connection) -> Result<(), E>;
pub struct Migrations<E = rusqlite::Error> {
migrations: BinaryHeap<Reverse<Migration<E>>>
}
impl <E> Default for Migrations<E> {
fn default() -> Self {
Migrations::new()
}
}
impl <E> Migrations<E> {
pub fn new() -> Self {
Migrations {
migrations: Default::default()
}
}
pub fn add<F>(self, version: i32, migration: F) -> Self
where F: Fn(&rusqlite::Connection) -> Result<(), E> + Send + 'static
{
self.do_add_migration(version, true, migration)
}
pub fn add_non_transactionally<F>(self, version: i32, migration: F) -> Self
where F: Fn(&rusqlite::Connection) -> Result<(), E> + Send + 'static
{
self.do_add_migration(version, false, migration)
}
fn do_add_migration<F>(mut self, version: i32, perform_in_transaction: bool, migration: F) -> Self
where F: Fn(&rusqlite::Connection) -> Result<(), E> + Send + 'static
{
assert!(version > 0, "migration version must be greater than 0");
let migration = Box::new(migration);
self.migrations.push(Reverse(Migration {
version,
perform_in_transaction,
migration
}));
self
}
pub(crate) fn iter(&self) -> impl Iterator<Item = (i32, bool, &MigrationFn<E>)> {
self.migrations.iter().map(|Reverse(m)| (m.version, m.perform_in_transaction, &*m.migration))
}
}
struct Migration<E> {
version: i32,
perform_in_transaction: bool,
migration: Box<MigrationFn<E>>
}
impl <E> PartialEq for Migration<E> {
fn eq(&self, other: &Self) -> bool {
self.version == other.version
}
}
impl <E> Eq for Migration<E> {}
impl <E> Ord for Migration<E> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.version.cmp(&other.version)
}
}
impl <E> PartialOrd for Migration<E> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.version.partial_cmp(&other.version)
}
}