text-document-common 1.4.1

Shared entities, database, events, and undo/redo infrastructure for text-document
Documentation
// Generated by Qleany v1.5.1 from common_da_use_cases_update.tera

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;

// ---------------------------------------------------------------------------
// Non-undoable update
// ---------------------------------------------------------------------------

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()?;
        // existence check
        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)
    }
}

// ---------------------------------------------------------------------------
// Undoable update
// ---------------------------------------------------------------------------

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()?;
        // existence check
        for entity in entities {
            if uow.get(&entity.id())?.is_none() {
                return Err(anyhow::anyhow!(
                    "Entity with id {} does not exist",
                    entity.id()
                ));
            }
        }
        // fetch old entities for undo
        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()?;
            // Capture current state before restoring, for redo
            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()?;
            // Capture current state before restoring, for undo
            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
    }
}

// ---------------------------------------------------------------------------
// Non-undoable update with relationships
// ---------------------------------------------------------------------------

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()?;
        // existence check
        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)
    }
}

// ---------------------------------------------------------------------------
// Undoable update with relationships
// ---------------------------------------------------------------------------

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()?;
        // existence check
        for entity in entities {
            if uow.get(&entity.id())?.is_none() {
                return Err(anyhow::anyhow!(
                    "Entity with id {} does not exist",
                    entity.id()
                ));
            }
        }
        // fetch old entities for undo
        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()?;
            // Capture current state before restoring, for redo
            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()?;
            // Capture current state before restoring, for undo
            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
    }
}