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 UpdateUseCase<F: WriteUoWFactory> {
uow_factory: F,
}
impl<F: WriteUoWFactory> UpdateUseCase<F> {
pub fn new(uow_factory: F) -> Self {
UpdateUseCase { 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!("Update 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()?;
for entity in entities {
if uow.get(&entity.id())?.is_none() {
return Err(anyhow::anyhow!(
"Entity with id {} does not exist",
entity.id()
));
}
}
let updated = uow.update_multi(entities)?;
uow.commit()?;
Ok(updated)
}
}
pub struct UndoableUpdateUseCase<F: WriteUoWFactory> {
uow_factory: F,
undo_stack: VecDeque<Vec<F::Entity>>,
redo_stack: VecDeque<Vec<F::Entity>>,
}
impl<F: WriteUoWFactory> UndoableUpdateUseCase<F> {
pub fn new(uow_factory: F) -> Self {
UndoableUpdateUseCase {
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!("Update 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()?;
for entity in entities {
if uow.get(&entity.id())?.is_none() {
return Err(anyhow::anyhow!(
"Entity with id {} does not exist",
entity.id()
));
}
}
let ids: Vec<_> = entities.iter().map(|e| e.id()).collect();
let old_entities: Vec<F::Entity> = uow.get_multi(&ids)?.into_iter().flatten().collect();
let updated = uow.update_multi(entities)?;
uow.commit()?;
self.undo_stack.push_back(old_entities);
self.redo_stack.clear();
Ok(updated)
}
}
impl<F: WriteUoWFactory + Send + 'static> UndoRedoCommand for UndoableUpdateUseCase<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()?;
let ids: Vec<_> = last_entities.iter().map(|e| e.id()).collect();
let current: Vec<F::Entity> = uow.get_multi(&ids)?.into_iter().flatten().collect();
uow.update_multi(&last_entities)?;
uow.commit()?;
self.redo_stack.push_back(current);
}
Ok(())
}
fn redo(&mut self) -> Result<()> {
if let Some(entities) = self.redo_stack.pop_back() {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let ids: Vec<_> = entities.iter().map(|e| e.id()).collect();
let current: Vec<F::Entity> = uow.get_multi(&ids)?.into_iter().flatten().collect();
uow.update_multi(&entities)?;
uow.commit()?;
self.undo_stack.push_back(current);
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct UpdateWithRelationshipsUseCase<F: WriteUoWFactory> {
uow_factory: F,
}
impl<F: WriteUoWFactory> UpdateWithRelationshipsUseCase<F> {
pub fn new(uow_factory: F) -> Self {
UpdateWithRelationshipsUseCase { 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!("Update 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()?;
for entity in entities {
if uow.get(&entity.id())?.is_none() {
return Err(anyhow::anyhow!(
"Entity with id {} does not exist",
entity.id()
));
}
}
let updated = uow.update_with_relationships_multi(entities)?;
uow.commit()?;
Ok(updated)
}
}
pub struct UndoableUpdateWithRelationshipsUseCase<F: WriteUoWFactory> {
uow_factory: F,
undo_stack: VecDeque<Vec<F::Entity>>,
redo_stack: VecDeque<Vec<F::Entity>>,
}
impl<F: WriteUoWFactory> UndoableUpdateWithRelationshipsUseCase<F> {
pub fn new(uow_factory: F) -> Self {
UndoableUpdateWithRelationshipsUseCase {
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!("Update 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()?;
for entity in entities {
if uow.get(&entity.id())?.is_none() {
return Err(anyhow::anyhow!(
"Entity with id {} does not exist",
entity.id()
));
}
}
let ids: Vec<_> = entities.iter().map(|e| e.id()).collect();
let old_entities: Vec<F::Entity> = uow.get_multi(&ids)?.into_iter().flatten().collect();
let updated = uow.update_with_relationships_multi(entities)?;
uow.commit()?;
self.undo_stack.push_back(old_entities);
self.redo_stack.clear();
Ok(updated)
}
}
impl<F: WriteUoWFactory + Send + 'static> UndoRedoCommand
for UndoableUpdateWithRelationshipsUseCase<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()?;
let ids: Vec<_> = last_entities.iter().map(|e| e.id()).collect();
let current: Vec<F::Entity> = uow.get_multi(&ids)?.into_iter().flatten().collect();
uow.update_with_relationships_multi(&last_entities)?;
uow.commit()?;
self.redo_stack.push_back(current);
}
Ok(())
}
fn redo(&mut self) -> Result<()> {
if let Some(entities) = self.redo_stack.pop_back() {
let mut uow = self.uow_factory.create();
uow.begin_transaction()?;
let ids: Vec<_> = entities.iter().map(|e| e.id()).collect();
let current: Vec<F::Entity> = uow.get_multi(&ids)?.into_iter().flatten().collect();
uow.update_with_relationships_multi(&entities)?;
uow.commit()?;
self.undo_stack.push_back(current);
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}