use super::traits::WriteRelUoWFactory;
use crate::types::{EntityId, Savepoint};
use crate::undo_redo::UndoRedoCommand;
use anyhow::Result;
use std::any::Any;
use std::collections::VecDeque;
pub struct SetRelationshipUseCase<RF, F: WriteRelUoWFactory<RF>> {
uow_factory: F,
_phantom: std::marker::PhantomData<RF>,
}
impl<RF, F: WriteRelUoWFactory<RF>> SetRelationshipUseCase<RF, F> {
pub fn new(uow_factory: F) -> Self {
SetRelationshipUseCase {
uow_factory,
_phantom: std::marker::PhantomData,
}
}
pub fn execute(&mut self, id: &EntityId, field: &RF, right_ids: &[EntityId]) -> Result<()> {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
uow.set_relationship(id, field, right_ids)?;
uow.commit()?;
Ok(())
}
}
pub struct UndoableSetRelationshipUseCase<RF: Clone, F: WriteRelUoWFactory<RF>> {
uow_factory: F,
undo_stack: VecDeque<Savepoint>,
redo_stack: VecDeque<(EntityId, RF, Vec<EntityId>)>,
}
impl<RF: Clone, F: WriteRelUoWFactory<RF>> UndoableSetRelationshipUseCase<RF, F> {
pub fn new(uow_factory: F) -> Self {
UndoableSetRelationshipUseCase {
uow_factory,
undo_stack: VecDeque::new(),
redo_stack: VecDeque::new(),
}
}
pub fn execute(&mut self, id: &EntityId, field: &RF, right_ids: &[EntityId]) -> Result<()> {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let savepoint = uow.create_savepoint()?;
uow.set_relationship(id, field, right_ids)?;
uow.commit()?;
self.undo_stack.push_back(savepoint);
self.redo_stack
.push_back((*id, field.clone(), right_ids.to_vec()));
Ok(())
}
}
impl<RF: Clone + Send + 'static, F: WriteRelUoWFactory<RF> + Send + 'static> UndoRedoCommand
for UndoableSetRelationshipUseCase<RF, F>
{
fn undo(&mut self) -> Result<()> {
if let Some(savepoint) = self.undo_stack.pop_back() {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
uow.restore_to_savepoint(savepoint)?;
uow.commit()?;
}
Ok(())
}
fn redo(&mut self) -> Result<()> {
if let Some((id, field, right_ids)) = self.redo_stack.pop_back() {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let savepoint = uow.create_savepoint()?;
uow.set_relationship(&id, &field, &right_ids)?;
uow.commit()?;
self.undo_stack.push_back(savepoint);
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}