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 MoveRelationshipUseCase<RF, F: WriteRelUoWFactory<RF>> {
uow_factory: F,
_phantom: std::marker::PhantomData<RF>,
}
impl<RF, F: WriteRelUoWFactory<RF>> MoveRelationshipUseCase<RF, F> {
pub fn new(uow_factory: F) -> Self {
MoveRelationshipUseCase {
uow_factory,
_phantom: std::marker::PhantomData,
}
}
pub fn execute(
&mut self,
id: &EntityId,
field: &RF,
ids_to_move: &[EntityId],
new_index: i32,
) -> Result<Vec<EntityId>> {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let result = uow.move_relationship(id, field, ids_to_move, new_index)?;
uow.commit()?;
Ok(result)
}
}
pub struct UndoableMoveRelationshipUseCase<RF: Clone, F: WriteRelUoWFactory<RF>> {
uow_factory: F,
undo_stack: VecDeque<Savepoint>,
redo_stack: VecDeque<(EntityId, RF, Vec<EntityId>, i32)>,
}
impl<RF: Clone, F: WriteRelUoWFactory<RF>> UndoableMoveRelationshipUseCase<RF, F> {
pub fn new(uow_factory: F) -> Self {
UndoableMoveRelationshipUseCase {
uow_factory,
undo_stack: VecDeque::new(),
redo_stack: VecDeque::new(),
}
}
pub fn execute(
&mut self,
id: &EntityId,
field: &RF,
ids_to_move: &[EntityId],
new_index: i32,
) -> Result<Vec<EntityId>> {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let savepoint = uow.create_savepoint()?;
let result = uow.move_relationship(id, field, ids_to_move, new_index)?;
uow.commit()?;
self.undo_stack.push_back(savepoint);
self.redo_stack
.push_back((*id, field.clone(), ids_to_move.to_vec(), new_index));
Ok(result)
}
}
impl<RF: Clone + Send + 'static, F: WriteRelUoWFactory<RF> + Send + 'static> UndoRedoCommand
for UndoableMoveRelationshipUseCase<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, ids_to_move, new_index)) = self.redo_stack.pop_back() {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let savepoint = uow.create_savepoint()?;
uow.move_relationship(&id, &field, &ids_to_move, new_index)?;
uow.commit()?;
self.undo_stack.push_back(savepoint);
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}