use crate::{
BufferOpsContainer, Database, DatabaseEntry, DatabaseError, DeriveKey, Incrementable, Manifest,
Manifests, RecordKey, Repository, Storage, Unifier,
transaction::buffer::DatabaseTransactionBuffer, transaction::errors::TransactionError,
};
use core::marker::PhantomData;
pub struct DatabaseTransaction<Manifest, KU: Unifier, VU: Unifier, C: BufferOpsContainer> {
buffer: DatabaseTransactionBuffer<KU, VU, C>,
_marker: PhantomData<Manifest>,
}
impl<M: Manifest, KU: Unifier + Copy, VU: Unifier + Copy, C: BufferOpsContainer>
DatabaseTransaction<M, KU, VU, C>
{
pub fn new<S>(database: &Database<S, M>) -> Self
where
S: Storage<KeyUnifier = KU, ValueUnifier = VU, Container = C>,
{
Self {
buffer: DatabaseTransactionBuffer::new(
database.key_serializer,
database.value_serializer,
),
_marker: PhantomData,
}
}
#[must_use]
pub fn new_with_serializers(key_serializer: KU, value_serializer: VU) -> Self {
Self {
buffer: DatabaseTransactionBuffer::new(key_serializer, value_serializer),
_marker: PhantomData,
}
}
pub fn insert<K: RecordKey<Record = R>, R>(
&mut self,
record: R,
) -> Result<K, TransactionError<KU::SerError, VU::SerError>>
where
R: DeriveKey<Key = K> + DatabaseEntry<Key = K>,
M: Manifests<R>,
{
let original_key = R::key(&record);
self.buffer.prepare_writes::<R>(record, &original_key)?;
Ok(original_key)
}
pub fn put<S, R: DatabaseEntry>(
&mut self,
record: R,
database: &mut Database<S, M>,
) -> Result<R::Key, DatabaseError<S>>
where
S: Storage<KeyUnifier = KU, ValueUnifier = VU, Container = C>,
R::Key: RecordKey<Record = R> + Incrementable + Ord,
M: Manifests<R>,
{
let last_key = database.manifest.last();
let new_key = if let Some(k) = last_key {
k.next_id().ok_or(DatabaseError::FailedToIncrement)?
} else {
R::Key::default()
};
self.buffer
.prepare_writes::<R>(record, &new_key)
.map_err(DatabaseError::from_transaction_error)?;
last_key.replace(new_key.clone());
Ok(new_key)
}
pub fn remove<R: DatabaseEntry>(
&mut self,
key: &R::Key,
record: &R,
) -> Result<(), TransactionError<KU::SerError, VU::SerError>>
where
R::Key: RecordKey<Record = R>,
M: Manifests<R>,
{
self.buffer.prepare_deletes::<R>(record, key)
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
pub fn commit<S>(self, storage: &mut S) -> Result<(), DatabaseError<S>>
where
S: Storage<KeyUnifier = KU, ValueUnifier = VU, Container = C>,
{
if self.is_empty() {
return Ok(());
}
let iter = self.buffer.iter();
storage
.repository_mut()
.apply(iter)
.map_err(DatabaseError::Storage)
}
pub fn rollback(self) {
drop(self);
}
}