lunar-lib 0.9.0

Common utilities for lunar applications
Documentation
use std::sync::Arc;

use crate::database::{
    CompareAndSwapTransaction, Createable, CustomTransactionError, DatabaseEntry, DbHandle,
    Deleteable, EntryId, Mergeable, TransactionError, caching::Cacheable, db_transaction,
};

pub trait EntryExtensions: DatabaseEntry {
    /// Upserts an entry from the database
    ///
    /// # Database Safety
    ///
    /// This function will upsert an item from the database plainly. It does not care to check if it points to other items that don't point back, as it does not know.
    /// Make sure any item you are upserting is fully linked
    ///
    /// For a safe version, see [`EntryExtensions::db_create()`] for types that implement [`Createable`]
    ///
    /// # Errors
    ///
    /// Errors if `sled` fails to open the entry's tree
    fn db_upsert(self, db: DbHandle<Self::Db>) -> Result<(), TransactionError> {
        db_transaction(
            |cas_tx| {
                cas_tx.tx_upsert(self.clone())?;
                Ok(())
            },
            db,
            false,
        )?;
        Ok(())
    }

    /// Inserts an entry from the database
    ///
    /// # Database Safety
    ///
    /// This function will insert an item from the database plainly. It does not care to check if it points to other items that don't point back, as it does not know.
    /// Make sure any item you are upserting is fully linked
    ///
    /// For a safe version, see [`EntryExtensions::db_create()`] for types that implement [`Createable`]
    ///
    /// # Errors
    ///
    /// - Errors with [`TransactionError::AlreadyInDatabase`] if the item already exists
    /// - Errors if [`EntryExtensions::db_upsert()`] errors
    fn db_insert(self, db: DbHandle<Self::Db>) -> Result<(), TransactionError> {
        db_transaction(
            |cas_tx| {
                cas_tx.tx_upsert(self.clone())?;
                Ok(())
            },
            db,
            false,
        )?;
        Ok(())
    }

    fn db_merge(self, from: Self, db: DbHandle<Self::Db>) -> Result<Self, TransactionError>
    where
        Self: Mergeable,
    {
        let new = db_transaction(
            |cas_tx| {
                let item = cas_tx.tx_merge(self.clone(), from.clone())?;
                Ok(item)
            },
            db,
            false,
        )?;
        Ok(new)
    }

    /// Attempts to merge the input entry into the existing entry. Upserts if the entry is not found
    ///
    /// # Database Safety
    ///
    /// See [`EntryExtensions::db_upsert()`]
    ///
    /// # Errors
    ///
    /// Errors if `sled` fails to open the entry's tree
    fn db_patch(self, db: DbHandle<Self::Db>) -> Result<Self, TransactionError>
    where
        Self: Mergeable,
    {
        let new = db_transaction(
            |cas_tx| {
                let item = cas_tx.tx_patch(self.clone())?;
                Ok(item)
            },
            db,
            false,
        )?;
        Ok(new)
    }

    fn db_merge_batch(
        self,
        from: impl IntoIterator<Item = Self> + Clone,
        db: DbHandle<Self::Db>,
    ) -> Result<Self, TransactionError>
    where
        Self: Mergeable,
    {
        let new = db_transaction(
            |cas_tx| {
                let item = cas_tx.tx_merge_batch(self.clone(), from.clone())?;
                Ok(item)
            },
            db,
            false,
        )?;
        Ok(new)
    }

    fn db_delete(&mut self, item: Self, db: DbHandle<Self::Db>) -> Result<(), TransactionError>
    where
        Self: Deleteable,
    {
        db_transaction(
            |cas_tx| {
                cas_tx.tx_delete(item.clone())?;
                Ok(())
            },
            db,
            false,
        )?;
        Ok(())
    }

    fn db_delete_id<Id>(id: Self::Id, db: DbHandle<Self::Db>) -> Result<(), TransactionError>
    where
        Self: Deleteable,
    {
        db_transaction(
            |cas_tx| {
                cas_tx.tx_delete_id(id)?;
                Ok(())
            },
            db,
            false,
        )?;
        Ok(())
    }

    fn db_create(
        args: <Self as Createable>::CreateArgs,
        db: DbHandle<Self::Db>,
    ) -> Result<Self, CustomTransactionError<<Self as Createable>::Err>>
    where
        Self: Createable,
    {
        let new = db_transaction(|cas_tx| cas_tx.tx_create(args.clone()), db, false)?;
        Ok(new)
    }
}

impl<T: DatabaseEntry> EntryExtensions for T {}

pub trait EntryIdExt: EntryId
where
    Self::Entry: DatabaseEntry<Id = Self, Db = Self::IdDb>,
{
    fn db_get(self, db: &Self::IdDb) -> Result<Option<Self::Entry>, TransactionError> {
        Self::Entry::db_get(self, db)
    }

    fn tx_get(
        self,
        cas_tx: &CompareAndSwapTransaction<Self::IdDb>,
    ) -> Result<Option<Self::Entry>, TransactionError> {
        cas_tx.tx_get(self)
    }

    fn cache_get(self, db: &Self::IdDb) -> Result<Option<Arc<Self::Entry>>, TransactionError>
    where
        Self::Entry: Cacheable,
    {
        Self::Entry::cache_get(self, db)
    }
}

impl<T: EntryId> EntryIdExt for T where Self::Entry: DatabaseEntry<Id = Self, Db = Self::IdDb> {}

pub trait EntryIdIteratorExt<Id: EntryId>: IntoIterator<Item = Id> + Sized
where
    Id::Entry: DatabaseEntry<Db = Id::IdDb, Id = Id>,
{
    fn db_get_batch(self, db: &Id::IdDb) -> Result<Vec<Id::Entry>, TransactionError> {
        Id::Entry::db_get_batch(self, db)
    }

    fn tx_get_batch(
        self,
        cas_tx: &CompareAndSwapTransaction<Id::IdDb>,
    ) -> Result<Vec<Id::Entry>, TransactionError> {
        cas_tx.tx_get_batch(self)
    }

    fn cache_get_batch(self, db: &Id::IdDb) -> Result<Vec<Arc<Id::Entry>>, TransactionError>
    where
        Id::Entry: Cacheable,
    {
        Id::Entry::cache_get_batch(self, db)
    }
}

impl<Id: EntryId, T: IntoIterator<Item = Id>> EntryIdIteratorExt<Id> for T where
    Id::Entry: DatabaseEntry<Db = Id::IdDb, Id = Id>
{
}