tycho-storage 0.3.7

Tycho storage context.
Documentation
use std::future::Future;
use std::path::Path;

use tycho_util::sync::CancellationFlag;
use weedb::{MigrationError, Semver, Tables, VersionProvider, WeeDb, WeeDbBuilder};

pub trait NamedTables: Tables + Sized {
    const NAME: &'static str;
}

pub trait WeeDbExt<T: Tables>: Sized {
    fn builder_prepared<P: AsRef<Path>>(path: P, context: T::Context) -> WeeDbBuilder<T>;
}

impl<T: NamedTables + 'static> WeeDbExt<T> for WeeDb<T> {
    fn builder_prepared<P: AsRef<Path>>(
        path: P,
        context: <T as Tables>::Context,
    ) -> WeeDbBuilder<T> {
        WeeDbBuilder::new(path, context).with_name(T::NAME)
    }
}

pub trait ApplyMigrations {
    fn apply_migrations(&self) -> impl Future<Output = Result<(), MigrationError>> + Send;
}

impl<T> ApplyMigrations for WeeDb<T>
where
    T: NamedTables + WithMigrations + 'static,
{
    #[tracing::instrument(skip_all, fields(db = T::NAME))]
    async fn apply_migrations(&self) -> Result<(), MigrationError> {
        let cancelled = CancellationFlag::new();

        tracing::info!("started");
        scopeguard::defer! {
            cancelled.cancel();
        }

        let span = tracing::Span::current();

        let this = self.clone();
        let cancelled = cancelled.clone();
        tokio::task::spawn_blocking(move || {
            let _span = span.enter();

            let guard = scopeguard::guard((), |_| {
                tracing::warn!("cancelled");
            });

            let mut migrations = weedb::Migrations::with_target_version_and_provider(
                T::VERSION,
                T::new_version_provider(),
            );
            T::register_migrations(&mut migrations, cancelled)?;
            this.apply(migrations)?;

            scopeguard::ScopeGuard::into_inner(guard);
            tracing::info!("finished");
            Ok(())
        })
        .await
        .map_err(|e| MigrationError::Custom(e.into()))?
    }
}

pub trait WithMigrations: Tables + Sized {
    const VERSION: Semver;

    type VersionProvider: VersionProvider;

    fn new_version_provider() -> Self::VersionProvider;

    fn register_migrations(
        migrations: &mut Migrations<Self::VersionProvider, Self>,
        cancelled: CancellationFlag,
    ) -> Result<(), MigrationError>;
}

pub type Migrations<P, T> = weedb::Migrations<P, WeeDb<T>>;