use super::traits::WriteUoWFactory;
use crate::types::HasId;
use crate::undo_redo::UndoRedoCommand;
use anyhow::{Ok, Result};
use std::any::Any;
use std::collections::VecDeque;
pub struct CreateOrphanUseCase<F: WriteUoWFactory> {
uow_factory: F,
}
impl<F: WriteUoWFactory> CreateOrphanUseCase<F> {
pub fn new(uow_factory: F) -> Self {
CreateOrphanUseCase { uow_factory }
}
pub fn execute(&mut self, entity: &F::Entity) -> Result<F::Entity> {
let results = self.execute_multi(std::slice::from_ref(entity))?;
results
.into_iter()
.next()
.ok_or_else(|| anyhow::anyhow!("Create orphan returned empty"))
}
pub fn execute_multi(&mut self, entities: &[F::Entity]) -> Result<Vec<F::Entity>> {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let created = uow.create_orphan_multi(entities)?;
uow.commit()?;
Ok(created)
}
}
pub struct UndoableCreateOrphanUseCase<F: WriteUoWFactory> {
uow_factory: F,
undo_stack: VecDeque<Vec<F::Entity>>,
redo_stack: VecDeque<Vec<F::Entity>>,
}
impl<F: WriteUoWFactory> UndoableCreateOrphanUseCase<F> {
pub fn new(uow_factory: F) -> Self {
UndoableCreateOrphanUseCase {
uow_factory,
undo_stack: VecDeque::new(),
redo_stack: VecDeque::new(),
}
}
pub fn execute(&mut self, entity: &F::Entity) -> Result<F::Entity> {
let results = self.execute_multi(std::slice::from_ref(entity))?;
results
.into_iter()
.next()
.ok_or_else(|| anyhow::anyhow!("Create orphan returned empty"))
}
pub fn execute_multi(&mut self, entities: &[F::Entity]) -> Result<Vec<F::Entity>> {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let created = uow.create_orphan_multi(entities)?;
uow.commit()?;
self.undo_stack.push_back(created.clone());
self.redo_stack.clear();
Ok(created)
}
}
impl<F: WriteUoWFactory + Send + 'static> UndoRedoCommand for UndoableCreateOrphanUseCase<F>
where
F::Entity: 'static,
{
fn undo(&mut self) -> Result<()> {
if let Some(last_entities) = self.undo_stack.pop_back() {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
uow.remove_multi(&last_entities.iter().map(|e| e.id()).collect::<Vec<_>>())?;
uow.commit()?;
self.redo_stack.push_back(last_entities);
}
Ok(())
}
fn redo(&mut self) -> Result<()> {
if let Some(last_entities) = self.redo_stack.pop_back() {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
uow.create_orphan_multi(&last_entities)?;
uow.commit()?;
self.undo_stack.push_back(last_entities);
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}