text_document_direct_access/resource/
resource_controller.rs1use super::{
4 dtos::{CreateResourceDto, ResourceDto, UpdateResourceDto},
5 units_of_work::{ResourceReadUoWFactory, ResourceWriteUoWFactory},
6};
7use anyhow::{Ok, Result};
8use common::direct_access::use_cases;
9use common::undo_redo::UndoRedoManager;
10use common::{database::db_context::DbContext, event::EventHub, types::EntityId};
11use std::sync::Arc;
12
13pub fn create_orphan(
14 db_context: &DbContext,
15 event_hub: &Arc<EventHub>,
16 undo_redo_manager: &mut UndoRedoManager,
17 stack_id: Option<u64>,
18 entity: &CreateResourceDto,
19) -> Result<ResourceDto> {
20 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
21 let mut uc = use_cases::UndoableCreateOrphanUseCase::new(uow_factory);
22 let entity_in: common::entities::Resource = entity.into();
23 let result = uc.execute(&entity_in)?;
24 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
25 Ok(result.into())
26}
27
28pub fn create_orphan_multi(
29 db_context: &DbContext,
30 event_hub: &Arc<EventHub>,
31 undo_redo_manager: &mut UndoRedoManager,
32 stack_id: Option<u64>,
33 entities: &[CreateResourceDto],
34) -> Result<Vec<ResourceDto>> {
35 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
36 let entities_in: Vec<common::entities::Resource> =
37 entities.iter().map(|dto| dto.into()).collect();
38 let mut uc = use_cases::UndoableCreateOrphanUseCase::new(uow_factory);
39 let result = uc.execute_multi(&entities_in)?;
40 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
41 Ok(result.into_iter().map(|e| e.into()).collect())
42}
43
44pub fn create(
45 db_context: &DbContext,
46 event_hub: &Arc<EventHub>,
47 undo_redo_manager: &mut UndoRedoManager,
48 stack_id: Option<u64>,
49 entity: &CreateResourceDto,
50 owner_id: EntityId,
51 index: i32,
52) -> Result<ResourceDto> {
53 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
54 let entity_in: common::entities::Resource = entity.into();
55 let strategy = use_cases::OwnerStrategy::Appending;
56 let mut uc = use_cases::UndoableCreateUseCase::new(uow_factory, strategy);
57 let result = uc.execute(&entity_in, owner_id, index)?;
58 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
59 Ok(result.into())
60}
61
62pub fn create_multi(
63 db_context: &DbContext,
64 event_hub: &Arc<EventHub>,
65 undo_redo_manager: &mut UndoRedoManager,
66 stack_id: Option<u64>,
67 entities: &[CreateResourceDto],
68 owner_id: EntityId,
69 index: i32,
70) -> Result<Vec<ResourceDto>> {
71 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
72 let entities_in: Vec<common::entities::Resource> =
73 entities.iter().map(|dto| dto.into()).collect();
74 let strategy = use_cases::OwnerStrategy::Appending;
75 let mut uc = use_cases::UndoableCreateUseCase::new(uow_factory, strategy);
76 let result = uc.execute_multi(&entities_in, owner_id, index)?;
77 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
78 Ok(result.into_iter().map(|e| e.into()).collect())
79}
80
81pub fn get(db_context: &DbContext, id: &EntityId) -> Result<Option<ResourceDto>> {
82 let uow_factory = ResourceReadUoWFactory::new(db_context);
83 let uc = use_cases::GetUseCase::new(uow_factory);
84 Ok(uc.execute(id)?.map(|e| e.into()))
85}
86
87pub fn get_all(db_context: &DbContext) -> Result<Vec<ResourceDto>> {
88 let uow_factory = ResourceReadUoWFactory::new(db_context);
89 let uc = use_cases::GetUseCase::new(uow_factory);
90 Ok(uc.execute_all()?.into_iter().map(|e| e.into()).collect())
91}
92
93pub fn get_multi(db_context: &DbContext, ids: &[EntityId]) -> Result<Vec<Option<ResourceDto>>> {
94 let uow_factory = ResourceReadUoWFactory::new(db_context);
95 let uc = use_cases::GetUseCase::new(uow_factory);
96 Ok(uc
97 .execute_multi(ids)?
98 .into_iter()
99 .map(|o| o.map(|e| e.into()))
100 .collect())
101}
102
103pub fn update(
104 db_context: &DbContext,
105 event_hub: &Arc<EventHub>,
106 undo_redo_manager: &mut UndoRedoManager,
107 stack_id: Option<u64>,
108 entity: &UpdateResourceDto,
109) -> Result<ResourceDto> {
110 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
111 let entity_in: common::entities::Resource = entity.into();
112 let mut uc = use_cases::UndoableUpdateUseCase::new(uow_factory);
113 let result = uc.execute(&entity_in)?;
114 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
115 Ok(result.into())
116}
117
118pub fn update_multi(
119 db_context: &DbContext,
120 event_hub: &Arc<EventHub>,
121 undo_redo_manager: &mut UndoRedoManager,
122 stack_id: Option<u64>,
123 entities: &[UpdateResourceDto],
124) -> Result<Vec<ResourceDto>> {
125 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
126 let entities_in: Vec<common::entities::Resource> =
127 entities.iter().map(|dto| dto.into()).collect();
128 let mut uc = use_cases::UndoableUpdateUseCase::new(uow_factory);
129 let result = uc.execute_multi(&entities_in)?;
130 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
131 Ok(result.into_iter().map(|e| e.into()).collect())
132}
133
134pub fn update_with_relationships(
135 db_context: &DbContext,
136 event_hub: &Arc<EventHub>,
137 undo_redo_manager: &mut UndoRedoManager,
138 stack_id: Option<u64>,
139 entity: &ResourceDto,
140) -> Result<ResourceDto> {
141 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
142 let entity_in: common::entities::Resource = entity.into();
143 let mut uc = use_cases::UndoableUpdateWithRelationshipsUseCase::new(uow_factory);
144 let result = uc.execute(&entity_in)?;
145 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
146 Ok(result.into())
147}
148
149pub fn update_with_relationships_multi(
150 db_context: &DbContext,
151 event_hub: &Arc<EventHub>,
152 undo_redo_manager: &mut UndoRedoManager,
153 stack_id: Option<u64>,
154 entities: &[ResourceDto],
155) -> Result<Vec<ResourceDto>> {
156 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
157 let entities_in: Vec<common::entities::Resource> =
158 entities.iter().map(|dto| dto.into()).collect();
159 let mut uc = use_cases::UndoableUpdateWithRelationshipsUseCase::new(uow_factory);
160 let result = uc.execute_multi(&entities_in)?;
161 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
162 Ok(result.into_iter().map(|e| e.into()).collect())
163}
164
165pub fn remove(
166 db_context: &DbContext,
167 event_hub: &Arc<EventHub>,
168 undo_redo_manager: &mut UndoRedoManager,
169 stack_id: Option<u64>,
170 id: &EntityId,
171) -> Result<()> {
172 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
173 let mut uc = use_cases::UndoableRemoveUseCase::new(uow_factory);
174 uc.execute(id)?;
175 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
176 Ok(())
177}
178
179pub fn remove_multi(
180 db_context: &DbContext,
181 event_hub: &Arc<EventHub>,
182 undo_redo_manager: &mut UndoRedoManager,
183 stack_id: Option<u64>,
184 ids: &[EntityId],
185) -> Result<()> {
186 let uow_factory = ResourceWriteUoWFactory::new(db_context, event_hub);
187 let mut uc = use_cases::UndoableRemoveUseCase::new(uow_factory);
188 uc.execute_multi(ids)?;
189 undo_redo_manager.add_command_to_stack(Box::new(uc), stack_id)?;
190 Ok(())
191}
192
193#[cfg(test)]
194mod tests {
195 #![allow(dead_code)]
196 #![allow(unused_imports)]
197
198 use super::*;
199 use crate::document::document_controller;
200 use crate::document::dtos::CreateDocumentDto;
201 use crate::root::dtos::CreateRootDto;
202 use crate::root::root_controller;
203 use common::database::db_context::DbContext;
204 use common::event::EventHub;
205 use common::types::EntityId;
206 use common::undo_redo::UndoRedoManager;
207 use std::sync::Arc;
208
209 struct TestContext {
210 db: DbContext,
211 hub: Arc<EventHub>,
212 undo: UndoRedoManager,
213 }
214
215 impl TestContext {
216 fn new() -> Self {
217 let db = DbContext::new().expect("Failed to create in-memory DB");
218 let hub = Arc::new(EventHub::new());
219 let mut undo = UndoRedoManager::new();
220 undo.set_event_hub(&hub);
221 TestContext { db, hub, undo }
222 }
223 }
224
225 fn create_owner_chain(ctx: &mut TestContext) -> EntityId {
227 let root =
228 root_controller::create_orphan(&ctx.db, &ctx.hub, &CreateRootDto::default()).unwrap();
229 let document = document_controller::create(
230 &ctx.db,
231 &ctx.hub,
232 &mut ctx.undo,
233 None,
234 &CreateDocumentDto::default(),
235 root.id,
236 -1,
237 )
238 .unwrap();
239 document.id
240 }
241
242 fn create_one(ctx: &mut TestContext) -> ResourceDto {
244 create_orphan(
245 &ctx.db,
246 &ctx.hub,
247 &mut ctx.undo,
248 None,
249 &CreateResourceDto::default(),
250 )
251 .unwrap()
252 }
253
254 #[test]
259 fn test_create_orphan_and_get() {
260 let mut ctx = TestContext::new();
261 let created = create_one(&mut ctx);
262 assert!(created.id > 0);
263
264 let fetched = get(&ctx.db, &created.id).unwrap();
265 assert!(fetched.is_some());
266 assert_eq!(fetched.unwrap().id, created.id);
267 }
268
269 #[test]
274 fn test_get_nonexistent() {
275 let ctx = TestContext::new();
276 assert!(get(&ctx.db, &999999).unwrap().is_none());
277 }
278
279 #[test]
284 fn test_get_all() {
285 let mut ctx = TestContext::new();
286 create_one(&mut ctx);
287 let all = get_all(&ctx.db).unwrap();
288 assert!(!all.is_empty());
289 }
290
291 #[test]
296 fn test_get_multi() {
297 let mut ctx = TestContext::new();
298 let a = create_one(&mut ctx);
299 let results = get_multi(&ctx.db, &[a.id, 999999]).unwrap();
300 assert_eq!(results.len(), 2);
301 assert!(results[0].is_some());
302 assert!(results[1].is_none());
303 }
304
305 #[test]
310 fn test_update() {
311 let mut ctx = TestContext::new();
312 let created = create_one(&mut ctx);
313 let update_dto: UpdateResourceDto = created.into();
314 let updated = update(&ctx.db, &ctx.hub, &mut ctx.undo, None, &update_dto).unwrap();
315 assert_eq!(updated.id, update_dto.id);
316 }
317
318 #[test]
323 fn test_remove() {
324 let mut ctx = TestContext::new();
325 let created = create_one(&mut ctx);
326 remove(&ctx.db, &ctx.hub, &mut ctx.undo, None, &created.id).unwrap();
327 assert!(get(&ctx.db, &created.id).unwrap().is_none());
328 }
329
330 #[test]
335 fn test_remove_multi() {
336 let mut ctx = TestContext::new();
337 let a = create_one(&mut ctx);
338 remove_multi(&ctx.db, &ctx.hub, &mut ctx.undo, None, &[a.id]).unwrap();
339 assert!(get(&ctx.db, &a.id).unwrap().is_none());
340 }
341
342 #[test]
347 fn test_create_with_owner() {
348 let mut ctx = TestContext::new();
349 let owner_id = create_owner_chain(&mut ctx);
350 let created = create(
351 &ctx.db,
352 &ctx.hub,
353 &mut ctx.undo,
354 None,
355 &CreateResourceDto::default(),
356 owner_id,
357 -1,
358 )
359 .unwrap();
360 assert!(created.id > 0);
361 let fetched = get(&ctx.db, &created.id).unwrap();
362 assert!(fetched.is_some());
363 }
364
365 #[test]
370 fn test_create_orphan_undo() {
371 let mut ctx = TestContext::new();
372 let created = create_one(&mut ctx);
373 assert!(get(&ctx.db, &created.id).unwrap().is_some());
374 ctx.undo.undo(None).unwrap();
375 assert!(get(&ctx.db, &created.id).unwrap().is_none());
376 }
377
378 #[test]
383 fn test_remove_undo() {
384 let mut ctx = TestContext::new();
385 let created = create_one(&mut ctx);
386 remove(&ctx.db, &ctx.hub, &mut ctx.undo, None, &created.id).unwrap();
387 assert!(get(&ctx.db, &created.id).unwrap().is_none());
388 ctx.undo.undo(None).unwrap();
389 assert!(get(&ctx.db, &created.id).unwrap().is_some());
390 }
391}