Skip to main content

text_document_common/direct_access/use_cases/
create.rs

1// Generated by Qleany v1.4.8 from common_da_use_cases_create.tera
2
3use super::traits::OwnedWriteUoWFactory;
4use crate::snapshot::EntityTreeSnapshot;
5use crate::types::{EntityId, HasId};
6use crate::undo_redo::UndoRedoCommand;
7use anyhow::{Ok, Result};
8use std::any::Any;
9
10/// Strategy for how the owner relationship is managed on create.
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub enum OwnerStrategy {
13    /// OneToOne / ManyToOne: new children replace existing children.
14    Replacing,
15    /// OrderedOneToMany / OneToMany / ManyToMany: new children are appended (or inserted at index).
16    Appending,
17}
18
19// ---------------------------------------------------------------------------
20// Non-undoable create (with owner)
21// ---------------------------------------------------------------------------
22
23pub struct CreateUseCase<F: OwnedWriteUoWFactory> {
24    uow_factory: F,
25}
26
27impl<F: OwnedWriteUoWFactory> CreateUseCase<F> {
28    pub fn new(uow_factory: F) -> Self {
29        CreateUseCase { uow_factory }
30    }
31
32    pub fn execute(
33        &mut self,
34        entity: &F::Entity,
35        owner_id: EntityId,
36        index: i32,
37    ) -> Result<F::Entity> {
38        let results = self.execute_multi(std::slice::from_ref(entity), owner_id, index)?;
39        results
40            .into_iter()
41            .next()
42            .ok_or_else(|| anyhow::anyhow!("Create returned empty"))
43    }
44
45    pub fn execute_multi(
46        &mut self,
47        entities: &[F::Entity],
48        owner_id: EntityId,
49        index: i32,
50    ) -> Result<Vec<F::Entity>> {
51        let mut uow = self.uow_factory.create();
52        uow.begin_transaction()?;
53        let created = uow.create_multi(entities, owner_id, index)?;
54        uow.commit()?;
55        Ok(created)
56    }
57}
58
59// ---------------------------------------------------------------------------
60// Undoable create (with owner)
61// ---------------------------------------------------------------------------
62
63pub struct UndoableCreateUseCase<F: OwnedWriteUoWFactory> {
64    uow_factory: F,
65    strategy: OwnerStrategy,
66    created_entities: Vec<F::Entity>,
67    owner_id: Option<EntityId>,
68    index: i32,
69    old_tree_snapshot: Option<EntityTreeSnapshot>,
70    // Replacing strategy fields
71    existing_child_ids: Vec<EntityId>,
72    displaced_children_snapshot: Option<EntityTreeSnapshot>,
73    // Appending strategy fields
74    previous_owner_relationship_ids: Option<Vec<EntityId>>,
75}
76
77impl<F: OwnedWriteUoWFactory> UndoableCreateUseCase<F> {
78    pub fn new(uow_factory: F, strategy: OwnerStrategy) -> Self {
79        UndoableCreateUseCase {
80            uow_factory,
81            strategy,
82            created_entities: Vec::new(),
83            owner_id: None,
84            index: -1,
85            old_tree_snapshot: None,
86            existing_child_ids: Vec::new(),
87            displaced_children_snapshot: None,
88            previous_owner_relationship_ids: None,
89        }
90    }
91
92    pub fn execute(
93        &mut self,
94        entity: &F::Entity,
95        owner_id: EntityId,
96        index: i32,
97    ) -> Result<F::Entity> {
98        let results = self.execute_multi(std::slice::from_ref(entity), owner_id, index)?;
99        results
100            .into_iter()
101            .next()
102            .ok_or_else(|| anyhow::anyhow!("Create returned empty"))
103    }
104
105    pub fn execute_multi(
106        &mut self,
107        entities: &[F::Entity],
108        owner_id: EntityId,
109        index: i32,
110    ) -> Result<Vec<F::Entity>> {
111        let mut uow = self.uow_factory.create();
112        uow.begin_transaction()?;
113
114        self.owner_id = Some(owner_id);
115        self.index = index;
116
117        match self.strategy {
118            OwnerStrategy::Replacing => {
119                self.existing_child_ids = uow.get_relationships_from_owner(&owner_id)?;
120                if !self.existing_child_ids.is_empty() {
121                    self.displaced_children_snapshot =
122                        Some(uow.snapshot(&self.existing_child_ids)?);
123                }
124            }
125            OwnerStrategy::Appending => {
126                self.previous_owner_relationship_ids =
127                    Some(uow.get_relationships_from_owner(&owner_id)?);
128            }
129        }
130
131        let created = uow.create_multi(entities, owner_id, index)?;
132        uow.commit()?;
133
134        self.created_entities = created.clone();
135        Ok(created)
136    }
137}
138
139impl<F: OwnedWriteUoWFactory + Send + 'static> UndoRedoCommand for UndoableCreateUseCase<F>
140where
141    F::Entity: 'static,
142{
143    fn undo(&mut self) -> Result<()> {
144        if !self.created_entities.is_empty() {
145            let owner_id = self.owner_id.expect("owner_id not set");
146            let ids_to_remove: Vec<EntityId> =
147                self.created_entities.iter().map(|e| e.id()).collect();
148            let mut uow = self.uow_factory.create();
149            uow.begin_transaction()?;
150
151            self.old_tree_snapshot = Some(uow.snapshot(&ids_to_remove)?);
152            uow.remove_multi(&ids_to_remove)?;
153
154            match self.strategy {
155                OwnerStrategy::Replacing => {
156                    if let Some(ref snap) = self.displaced_children_snapshot {
157                        uow.restore(snap)?;
158                        uow.set_relationships_in_owner(&owner_id, &self.existing_child_ids)?;
159                    } else {
160                        uow.set_relationships_in_owner(&owner_id, &[])?;
161                    }
162                }
163                OwnerStrategy::Appending => {
164                    if let Some(ref prev_ids) = self.previous_owner_relationship_ids {
165                        uow.set_relationships_in_owner(&owner_id, prev_ids)?;
166                    }
167                }
168            }
169
170            uow.commit()?;
171        }
172        Ok(())
173    }
174
175    fn redo(&mut self) -> Result<()> {
176        if let Some(ref snapshot) = self.old_tree_snapshot {
177            let owner_id = self.owner_id.expect("owner_id not set");
178            let mut uow = self.uow_factory.create();
179            uow.begin_transaction()?;
180
181            match self.strategy {
182                OwnerStrategy::Replacing => {
183                    if !self.existing_child_ids.is_empty() {
184                        self.displaced_children_snapshot =
185                            Some(uow.snapshot(&self.existing_child_ids)?);
186                        uow.remove_multi(&self.existing_child_ids)?;
187                    }
188                    uow.restore(snapshot)?;
189                    let created_ids: Vec<EntityId> =
190                        self.created_entities.iter().map(|e| e.id()).collect();
191                    uow.set_relationships_in_owner(&owner_id, &created_ids)?;
192                }
193                OwnerStrategy::Appending => {
194                    uow.restore(snapshot)?;
195                    if let Some(ref prev_ids) = self.previous_owner_relationship_ids {
196                        let mut redo_junction = prev_ids.clone();
197                        let created_ids: Vec<EntityId> =
198                            self.created_entities.iter().map(|e| e.id()).collect();
199                        if self.index >= 0 && (self.index as usize) < redo_junction.len() {
200                            for (i, id) in created_ids.iter().enumerate() {
201                                redo_junction.insert(self.index as usize + i, *id);
202                            }
203                        } else {
204                            redo_junction.extend(created_ids.iter());
205                        }
206                        uow.set_relationships_in_owner(&owner_id, &redo_junction)?;
207                    }
208                }
209            }
210
211            uow.commit()?;
212        }
213        Ok(())
214    }
215
216    fn as_any(&self) -> &dyn Any {
217        self
218    }
219}