use crate::exid::ExId;
use crate::patches::PatchLog;
use crate::ChangeHash;
use crate::{automerge::Automerge, AutomergeError};
use super::{CommitOptions, TransactionArgs, TransactionInner};
#[derive(Debug)]
pub struct Transaction<'a> {
inner: Option<TransactionInner>,
patch_log: PatchLog,
doc: &'a mut Automerge,
}
impl<'a> Transaction<'a> {
pub(crate) fn new(doc: &'a mut Automerge, args: TransactionArgs, patch_log: PatchLog) -> Self {
Self {
inner: Some(TransactionInner::new(args)),
doc,
patch_log,
}
}
pub fn hash_for_opid(&self, opid: &ExId) -> Option<ChangeHash> {
self.doc.hash_for_opid(opid)
}
}
impl<'a> Transaction<'a> {
pub(crate) fn empty(
doc: &'a mut Automerge,
args: TransactionArgs,
opts: CommitOptions,
) -> ChangeHash {
TransactionInner::empty(doc, args, opts.message, opts.time)
}
}
impl Transaction<'_> {
pub fn get_heads(&self) -> Vec<ChangeHash> {
self.doc.get_heads()
}
pub fn commit(mut self) -> (Option<ChangeHash>, PatchLog) {
let tx = self.inner.take().unwrap();
let hash = tx.commit(self.doc, None, None);
self.patch_log.finish_transaction(&self.doc.ops().actors);
(hash, self.patch_log.clone())
}
pub fn commit_with(mut self, options: CommitOptions) -> (Option<ChangeHash>, PatchLog) {
let tx = self.inner.take().unwrap();
let hash = tx.commit(self.doc, options.message, options.time);
self.patch_log.finish_transaction(&self.doc.ops().actors);
(hash, self.patch_log.clone())
}
pub fn rollback(mut self) -> usize {
self.patch_log.finish_transaction(&self.doc.ops().actors);
self.inner.take().unwrap().rollback(self.doc)
}
fn do_tx<F, O>(&mut self, f: F) -> O
where
F: FnOnce(&mut TransactionInner, &mut Automerge, &mut PatchLog) -> O,
{
let tx = self.inner.as_mut().unwrap();
f(tx, self.doc, &mut self.patch_log)
}
fn get_scope(&self, heads: Option<&[ChangeHash]>) -> Option<crate::types::Clock> {
if let Some(h) = heads {
Some(self.doc.clock_at(h))
} else {
self.inner.as_ref().and_then(|i| i.get_scope().clone())
}
}
pub(crate) fn batch_init_root_map(
&mut self,
value: &crate::hydrate::Map,
) -> Result<(), AutomergeError> {
self.do_tx(move |tx, doc, hist| tx.batch_init_root_map(doc, hist, value))
}
}
super::impl_read_doc_for_tx!(Transaction<'_>);
super::impl_transactable_for_tx!(Transaction<'_>);
impl Drop for Transaction<'_> {
fn drop(&mut self) {
if let Some(txn) = self.inner.take() {
txn.rollback(self.doc);
}
}
}