use crate::{Fetch, FilterBuilder, Persistent, Ref, SRes, StructsyImpl, StructsyIter, StructsyQueryTx};
use persy::Transaction;
use std::{io::Cursor, marker::PhantomData, sync::Arc};
pub struct OwnedSytx {
pub(crate) structsy_impl: Arc<StructsyImpl>,
pub(crate) trans: Transaction,
}
impl OwnedSytx {
pub fn query<T: Persistent>(&mut self) -> StructsyQueryTx<T> {
StructsyQueryTx {
tx: self,
builder: FilterBuilder::new(),
}
}
pub fn into_iter<R: Fetch<T>, T>(&mut self, filter: R) -> StructsyIter<T> {
filter.fetch_tx(self)
}
pub(crate) fn reference(&mut self) -> RefSytx {
RefSytx {
trans: &mut self.trans,
structsy_impl: self.structsy_impl.clone(),
}
}
}
pub struct RefSytx<'a> {
pub(crate) structsy_impl: Arc<StructsyImpl>,
pub(crate) trans: &'a mut Transaction,
}
pub struct TxRef<'a> {
pub(crate) trans: &'a mut Transaction,
}
pub struct ImplRef {
pub(crate) structsy_impl: Arc<StructsyImpl>,
}
pub trait Sytx {
#[doc(hidden)]
fn tx(&mut self) -> TxRef;
#[doc(hidden)]
fn structsy(&self) -> ImplRef;
}
impl Sytx for OwnedSytx {
fn tx(&mut self) -> TxRef {
TxRef { trans: &mut self.trans }
}
fn structsy(&self) -> ImplRef {
ImplRef {
structsy_impl: self.structsy_impl.clone(),
}
}
}
impl StructsyTx for OwnedSytx {
fn commit(self) -> SRes<()> {
let prepared = self.trans.prepare()?;
prepared.commit()?;
Ok(())
}
fn prepare_commit(self) -> SRes<Prepared> {
Ok(Prepared {
prepared: self.trans.prepare()?,
})
}
}
impl<'a> Sytx for RefSytx<'a> {
fn tx(&mut self) -> TxRef {
TxRef { trans: self.trans }
}
fn structsy(&self) -> ImplRef {
ImplRef {
structsy_impl: self.structsy_impl.clone(),
}
}
}
impl<'a> StructsyTx for RefSytx<'a> {
fn commit(self) -> SRes<()> {
unreachable!();
}
fn prepare_commit(self) -> SRes<Prepared> {
unreachable!();
}
}
pub struct Prepared {
prepared: persy::TransactionFinalize,
}
impl Prepared {
pub fn commit(self) -> SRes<()> {
self.prepared.commit()?;
Ok(())
}
pub fn rollback(self) -> SRes<()> {
self.prepared.rollback()?;
Ok(())
}
}
pub trait StructsyTx: Sytx + Sized {
fn insert<T: Persistent>(&mut self, sct: &T) -> SRes<Ref<T>> {
let def = self.structsy().structsy_impl.check_defined::<T>()?;
let mut buff = Vec::new();
sct.write(&mut buff)?;
let id = self.tx().trans.insert(def.segment_name(), &buff)?;
let id_ref = Ref::new(id);
sct.put_indexes(self, &id_ref)?;
Ok(id_ref)
}
fn update<T: Persistent>(&mut self, sref: &Ref<T>, sct: &T) -> SRes<()> {
let def = self.structsy().structsy_impl.check_defined::<T>()?;
let mut buff = Vec::new();
sct.write(&mut buff)?;
let old = self.read::<T>(sref)?;
if let Some(old_rec) = old {
old_rec.remove_indexes(self, sref)?;
}
self.tx().trans.update(def.segment_name(), &sref.raw_id, &buff)?;
sct.put_indexes(self, sref)?;
Ok(())
}
fn delete<T: Persistent>(&mut self, sref: &Ref<T>) -> SRes<()> {
let def = self.structsy().structsy_impl.check_defined::<T>()?;
let old = self.read::<T>(sref)?;
if let Some(old_rec) = old {
old_rec.remove_indexes(self, sref)?;
}
self.tx().trans.delete(def.segment_name(), &sref.raw_id)?;
Ok(())
}
fn read<T: Persistent>(&mut self, sref: &Ref<T>) -> SRes<Option<T>> {
let def = self.structsy().structsy_impl.check_defined::<T>()?;
crate::structsy::tx_read(def.segment_name(), &mut self.tx().trans, &sref.raw_id)
}
fn scan<T: Persistent>(&mut self) -> SRes<TxRecordIter<T>> {
raw_tx_scan(self.structsy().structsy_impl, self.tx().trans)
}
fn commit(self) -> SRes<()>;
fn prepare_commit(self) -> SRes<Prepared>;
}
pub(crate) fn raw_tx_scan<'a, T: Persistent>(
structsy: Arc<StructsyImpl>,
trans: &'a mut Transaction,
) -> SRes<TxRecordIter<'a, T>> {
let def = structsy.check_defined::<T>()?;
let iter = trans.scan(def.segment_name())?;
Ok(TxRecordIter::new(iter, structsy))
}
pub trait TxIterator<'a>: Iterator {
fn tx(&mut self) -> RefSytx;
}
impl<'a, T: Persistent> TxIterator<'a> for TxRecordIter<'a, T> {
fn tx(&mut self) -> RefSytx {
self.tx()
}
}
pub struct TxRecordIter<'a, T> {
iter: persy::TxSegmentIter<'a>,
marker: PhantomData<T>,
structsy_impl: Arc<StructsyImpl>,
}
impl<'a, T> TxRecordIter<'a, T> {
fn new(iter: persy::TxSegmentIter<'a>, structsy_impl: Arc<StructsyImpl>) -> TxRecordIter<'a, T> {
TxRecordIter {
iter,
marker: PhantomData,
structsy_impl,
}
}
pub fn tx(&mut self) -> RefSytx {
RefSytx {
trans: self.iter.tx(),
structsy_impl: self.structsy_impl.clone(),
}
}
}
impl<'a, T: Persistent> TxRecordIter<'a, T> {
pub fn next_tx(&mut self) -> Option<(Ref<T>, T, RefSytx)> {
if let Some((id, buff, tx)) = self.iter.next_tx() {
if let Ok(x) = T::read(&mut Cursor::new(buff)) {
let stx = RefSytx {
trans: tx,
structsy_impl: self.structsy_impl.clone(),
};
Some((Ref::new(id), x, stx))
} else {
None
}
} else {
None
}
}
}
impl<'a, T: Persistent> Iterator for TxRecordIter<'a, T> {
type Item = (Ref<T>, T);
fn next(&mut self) -> Option<Self::Item> {
if let Some((id, buff)) = self.iter.next() {
if let Ok(x) = T::read(&mut Cursor::new(buff)) {
Some((Ref::new(id), x))
} else {
None
}
} else {
None
}
}
}