use super::traits::OwnedWriteUoWFactory;
use crate::snapshot::EntityTreeSnapshot;
use crate::types::{EntityId, HasId};
use crate::undo_redo::UndoRedoCommand;
use anyhow::{Ok, Result};
use std::any::Any;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OwnerStrategy {
Replacing,
Appending,
}
pub struct CreateUseCase<F: OwnedWriteUoWFactory> {
uow_factory: F,
}
impl<F: OwnedWriteUoWFactory> CreateUseCase<F> {
pub fn new(uow_factory: F) -> Self {
CreateUseCase { uow_factory }
}
pub fn execute(
&mut self,
entity: &F::Entity,
owner_id: EntityId,
index: i32,
) -> Result<F::Entity> {
let results = self.execute_multi(std::slice::from_ref(entity), owner_id, index)?;
results
.into_iter()
.next()
.ok_or_else(|| anyhow::anyhow!("Create returned empty"))
}
pub fn execute_multi(
&mut self,
entities: &[F::Entity],
owner_id: EntityId,
index: i32,
) -> Result<Vec<F::Entity>> {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let created = uow.create_multi(entities, owner_id, index)?;
uow.commit()?;
Ok(created)
}
}
pub struct UndoableCreateUseCase<F: OwnedWriteUoWFactory> {
uow_factory: F,
strategy: OwnerStrategy,
created_entities: Vec<F::Entity>,
old_tree_snapshot: Option<EntityTreeSnapshot>,
existing_child_ids: Vec<EntityId>,
displaced_children_snapshot: Option<EntityTreeSnapshot>,
}
impl<F: OwnedWriteUoWFactory> UndoableCreateUseCase<F> {
pub fn new(uow_factory: F, strategy: OwnerStrategy) -> Self {
UndoableCreateUseCase {
uow_factory,
strategy,
created_entities: Vec::new(),
old_tree_snapshot: None,
existing_child_ids: Vec::new(),
displaced_children_snapshot: None,
}
}
pub fn execute(
&mut self,
entity: &F::Entity,
owner_id: EntityId,
index: i32,
) -> Result<F::Entity> {
let results = self.execute_multi(std::slice::from_ref(entity), owner_id, index)?;
results
.into_iter()
.next()
.ok_or_else(|| anyhow::anyhow!("Create returned empty"))
}
pub fn execute_multi(
&mut self,
entities: &[F::Entity],
owner_id: EntityId,
index: i32,
) -> Result<Vec<F::Entity>> {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
if let OwnerStrategy::Replacing = self.strategy {
self.existing_child_ids = uow.get_relationships_from_owner(&owner_id)?;
if !self.existing_child_ids.is_empty() {
self.displaced_children_snapshot = Some(uow.snapshot(&self.existing_child_ids)?);
}
}
let created = uow.create_multi(entities, owner_id, index)?;
uow.commit()?;
self.created_entities = created.clone();
Ok(created)
}
}
impl<F: OwnedWriteUoWFactory + Send + 'static> UndoRedoCommand for UndoableCreateUseCase<F>
where
F::Entity: 'static,
{
fn undo(&mut self) -> Result<()> {
if !self.created_entities.is_empty() {
let ids_to_remove: Vec<EntityId> =
self.created_entities.iter().map(|e| e.id()).collect();
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
self.old_tree_snapshot = Some(uow.snapshot(&ids_to_remove)?);
uow.remove_multi(&ids_to_remove)?;
if let OwnerStrategy::Replacing = self.strategy
&& let Some(ref snap) = self.displaced_children_snapshot
{
uow.restore(snap)?;
}
uow.commit()?;
}
Ok(())
}
fn redo(&mut self) -> Result<()> {
if let Some(ref snapshot) = self.old_tree_snapshot {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
if let OwnerStrategy::Replacing = self.strategy
&& !self.existing_child_ids.is_empty()
{
self.displaced_children_snapshot = Some(uow.snapshot(&self.existing_child_ids)?);
uow.remove_multi(&self.existing_child_ids)?;
}
uow.restore(snapshot)?;
uow.commit()?;
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}