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>,
owner_id: Option<EntityId>,
index: i32,
old_tree_snapshot: Option<EntityTreeSnapshot>,
existing_child_ids: Vec<EntityId>,
displaced_children_snapshot: Option<EntityTreeSnapshot>,
previous_owner_relationship_ids: Option<Vec<EntityId>>,
}
impl<F: OwnedWriteUoWFactory> UndoableCreateUseCase<F> {
pub fn new(uow_factory: F, strategy: OwnerStrategy) -> Self {
UndoableCreateUseCase {
uow_factory,
strategy,
created_entities: Vec::new(),
owner_id: None,
index: -1,
old_tree_snapshot: None,
existing_child_ids: Vec::new(),
displaced_children_snapshot: None,
previous_owner_relationship_ids: 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()?;
self.owner_id = Some(owner_id);
self.index = index;
match self.strategy {
OwnerStrategy::Replacing => {
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)?);
}
}
OwnerStrategy::Appending => {
self.previous_owner_relationship_ids =
Some(uow.get_relationships_from_owner(&owner_id)?);
}
}
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 owner_id = self.owner_id.expect("owner_id not set");
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)?;
match self.strategy {
OwnerStrategy::Replacing => {
if let Some(ref snap) = self.displaced_children_snapshot {
uow.restore(snap)?;
uow.set_relationships_in_owner(&owner_id, &self.existing_child_ids)?;
} else {
uow.set_relationships_in_owner(&owner_id, &[])?;
}
}
OwnerStrategy::Appending => {
if let Some(ref prev_ids) = self.previous_owner_relationship_ids {
uow.set_relationships_in_owner(&owner_id, prev_ids)?;
}
}
}
uow.commit()?;
}
Ok(())
}
fn redo(&mut self) -> Result<()> {
if let Some(ref snapshot) = self.old_tree_snapshot {
let owner_id = self.owner_id.expect("owner_id not set");
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
match self.strategy {
OwnerStrategy::Replacing => {
if !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)?;
let created_ids: Vec<EntityId> =
self.created_entities.iter().map(|e| e.id()).collect();
uow.set_relationships_in_owner(&owner_id, &created_ids)?;
}
OwnerStrategy::Appending => {
uow.restore(snapshot)?;
if let Some(ref prev_ids) = self.previous_owner_relationship_ids {
let mut redo_junction = prev_ids.clone();
let created_ids: Vec<EntityId> =
self.created_entities.iter().map(|e| e.id()).collect();
if self.index >= 0 && (self.index as usize) < redo_junction.len() {
for (i, id) in created_ids.iter().enumerate() {
redo_junction.insert(self.index as usize + i, *id);
}
} else {
redo_junction.extend(created_ids.iter());
}
uow.set_relationships_in_owner(&owner_id, &redo_junction)?;
}
}
}
uow.commit()?;
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}