use alloc::boxed::Box;
+use crate::Merge;
+
+/// Represents a type that contains staged changes.
+pub trait Staged {
+ /// Type for staged changes.
+ type ChangeSet: Merge;
+
+ /// Get mutable reference of staged changes.
+ fn staged(&mut self) -> &mut Self::ChangeSet;
+}
+
/// Trait that persists the type with `Db`.
///
/// Methods of this trait should not be called directly.
-pub trait PersistWith<Db>: Sized {
+pub trait PersistWith<Db>: Staged + Sized {
/// Parameters for [`PersistWith::create`].
type CreateParams;
/// Parameters for [`PersistWith::load`].
/// Error type of [`PersistWith::persist`].
type PersistError;
- /// Create the type and initialize the `Db`.
+ /// Initialize the `Db` and create `Self`.
fn create(db: &mut Db, params: Self::CreateParams) -> Result<Self, Self::CreateError>;
- /// Load the type from the `Db`.
+ /// Initialize the `Db` and load a previously-persisted `Self`.
fn load(db: &mut Db, params: Self::LoadParams) -> Result<Option<Self>, Self::LoadError>;
- /// Persist staged changes into `Db`.
- fn persist(&mut self, db: &mut Db) -> Result<bool, Self::PersistError>;
+ /// Persist changes to the `Db`.
+ fn persist(
+ db: &mut Db,
+ changeset: &<Self as Staged>::ChangeSet,
+ ) -> Result<(), Self::PersistError>;
}
type FutureResult<'a, T, E> = Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'a>>;
/// Trait that persists the type with an async `Db`.
-pub trait PersistAsyncWith<Db>: Sized {
+pub trait PersistAsyncWith<Db>: Staged + Sized {
/// Parameters for [`PersistAsyncWith::create`].
type CreateParams;
/// Parameters for [`PersistAsyncWith::load`].
/// Error type of [`PersistAsyncWith::persist`].
type PersistError;
- /// Create the type and initialize the `Db`.
+ /// Initialize the `Db` and create `Self`.
fn create(db: &mut Db, params: Self::CreateParams) -> FutureResult<Self, Self::CreateError>;
- /// Load the type from `Db`.
+ /// Initialize the `Db` and load a previously-persisted `Self`.
fn load(db: &mut Db, params: Self::LoadParams) -> FutureResult<Option<Self>, Self::LoadError>;
- /// Persist staged changes into `Db`.
- fn persist<'a>(&'a mut self, db: &'a mut Db) -> FutureResult<'a, bool, Self::PersistError>;
+ /// Persist changes to the `Db`.
+ fn persist<'a>(
+ db: &'a mut Db,
+ changeset: &'a <Self as Staged>::ChangeSet,
+ ) -> FutureResult<'a, (), Self::PersistError>;
}
/// Represents a persisted `T`.
}
/// Persist staged changes of `T` into `Db`.
+ ///
+ /// If the database errors, the staged changes will not be cleared.
pub fn persist<Db>(&mut self, db: &mut Db) -> Result<bool, T::PersistError>
where
T: PersistWith<Db>,
{
- self.inner.persist(db)
+ let stage = T::staged(&mut self.inner);
+ if stage.is_empty() {
+ return Ok(false);
+ }
+ T::persist(db, &*stage)?;
+ stage.take();
+ Ok(true)
}
/// Persist staged changes of `T` into an async `Db`.
+ ///
+ /// If the database errors, the staged changes will not be cleared.
pub async fn persist_async<'a, Db>(
&'a mut self,
db: &'a mut Db,
where
T: PersistAsyncWith<Db>,
{
- self.inner.persist(db).await
+ let stage = T::staged(&mut self.inner);
+ if stage.is_empty() {
+ return Ok(false);
+ }
+ T::persist(db, &*stage).await?;
+ stage.take();
+ Ok(true)
}
}
}
fn persist(
- &mut self,
- conn: &mut bdk_chain::sqlite::Transaction,
- ) -> Result<bool, Self::PersistError> {
- if let Some(changeset) = self.take_staged() {
- changeset.persist_to_sqlite(conn)?;
- return Ok(true);
- }
- Ok(false)
+ db: &mut bdk_chain::sqlite::Transaction<'c>,
+ changeset: &<Self as chain::Staged>::ChangeSet,
+ ) -> Result<(), Self::PersistError> {
+ changeset.persist_to_sqlite(db)
}
}
}
fn persist(
- &mut self,
db: &mut bdk_chain::sqlite::Connection,
- ) -> Result<bool, Self::PersistError> {
- let mut db_tx = db.transaction()?;
- let has_changes = chain::PersistWith::persist(self, &mut db_tx)?;
- db_tx.commit()?;
- Ok(has_changes)
+ changeset: &<Self as chain::Staged>::ChangeSet,
+ ) -> Result<(), Self::PersistError> {
+ let db_tx = db.transaction()?;
+ changeset.persist_to_sqlite(&db_tx)?;
+ db_tx.commit()
}
}
}
fn persist(
- &mut self,
db: &mut bdk_file_store::Store<crate::ChangeSet>,
- ) -> Result<bool, Self::PersistError> {
- if let Some(changeset) = self.take_staged() {
- db.append_changeset(&changeset)?;
- return Ok(true);
- }
- Ok(false)
+ changeset: &<Self as chain::Staged>::ChangeSet,
+ ) -> Result<(), Self::PersistError> {
+ db.append_changeset(changeset)
}
}