1use std::fmt::Display;
4
5use crate::{
6 database::transactions::Transaction,
7 direct_access::repository_factory,
8 entities::Feature,
9 event::{DirectAccessEntity, EntityEvent, Event, EventBuffer, Origin},
10 snapshot::EntityTreeSnapshot,
11 types::EntityId,
12};
13
14use crate::direct_access::workspace::WorkspaceRelationshipField;
15use crate::error::RepositoryError;
16use serde::{Deserialize, Serialize};
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub enum FeatureRelationshipField {
20 UseCases,
21}
22
23impl Display for FeatureRelationshipField {
24 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25 write!(f, "{:?}", self)
26 }
27}
28
29pub trait FeatureTable {
30 fn create(&mut self, entity: &Feature) -> Result<Feature, RepositoryError>;
31 fn create_multi(&mut self, entities: &[Feature]) -> Result<Vec<Feature>, RepositoryError>;
32 fn get(&self, id: &EntityId) -> Result<Option<Feature>, RepositoryError>;
33 fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Feature>>, RepositoryError>;
34 fn get_all(&self) -> Result<Vec<Feature>, RepositoryError>;
35 fn update(&mut self, entity: &Feature) -> Result<Feature, RepositoryError>;
36 fn update_multi(&mut self, entities: &[Feature]) -> Result<Vec<Feature>, RepositoryError>;
37 fn update_with_relationships(&mut self, entity: &Feature) -> Result<Feature, RepositoryError>;
38 fn update_with_relationships_multi(
39 &mut self,
40 entities: &[Feature],
41 ) -> Result<Vec<Feature>, RepositoryError>;
42 fn remove(&mut self, id: &EntityId) -> Result<(), RepositoryError>;
43 fn remove_multi(&mut self, ids: &[EntityId]) -> Result<(), RepositoryError>;
44 fn get_relationship(
45 &self,
46 id: &EntityId,
47 field: &FeatureRelationshipField,
48 ) -> Result<Vec<EntityId>, RepositoryError>;
49 fn get_relationship_many(
50 &self,
51 ids: &[EntityId],
52 field: &FeatureRelationshipField,
53 ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError>;
54 fn get_relationship_count(
55 &self,
56 id: &EntityId,
57 field: &FeatureRelationshipField,
58 ) -> Result<usize, RepositoryError>;
59 fn get_relationship_in_range(
60 &self,
61 id: &EntityId,
62 field: &FeatureRelationshipField,
63 offset: usize,
64 limit: usize,
65 ) -> Result<Vec<EntityId>, RepositoryError>;
66 fn get_relationships_from_right_ids(
67 &self,
68 field: &FeatureRelationshipField,
69 right_ids: &[EntityId],
70 ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError>;
71 fn set_relationship_multi(
72 &mut self,
73 field: &FeatureRelationshipField,
74 relationships: Vec<(EntityId, Vec<EntityId>)>,
75 ) -> Result<(), RepositoryError>;
76 fn set_relationship(
77 &mut self,
78 id: &EntityId,
79 field: &FeatureRelationshipField,
80 right_ids: &[EntityId],
81 ) -> Result<(), RepositoryError>;
82 fn move_relationship_ids(
83 &mut self,
84 id: &EntityId,
85 field: &FeatureRelationshipField,
86 ids_to_move: &[EntityId],
87 new_index: i32,
88 ) -> Result<Vec<EntityId>, RepositoryError>;
89}
90
91pub trait FeatureTableRO {
92 fn get(&self, id: &EntityId) -> Result<Option<Feature>, RepositoryError>;
93 fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Feature>>, RepositoryError>;
94 fn get_all(&self) -> Result<Vec<Feature>, RepositoryError>;
95 fn get_relationship(
96 &self,
97 id: &EntityId,
98 field: &FeatureRelationshipField,
99 ) -> Result<Vec<EntityId>, RepositoryError>;
100 fn get_relationship_many(
101 &self,
102 ids: &[EntityId],
103 field: &FeatureRelationshipField,
104 ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError>;
105 fn get_relationship_count(
106 &self,
107 id: &EntityId,
108 field: &FeatureRelationshipField,
109 ) -> Result<usize, RepositoryError>;
110 fn get_relationship_in_range(
111 &self,
112 id: &EntityId,
113 field: &FeatureRelationshipField,
114 offset: usize,
115 limit: usize,
116 ) -> Result<Vec<EntityId>, RepositoryError>;
117 fn get_relationships_from_right_ids(
118 &self,
119 field: &FeatureRelationshipField,
120 right_ids: &[EntityId],
121 ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError>;
122}
123
124pub struct FeatureRepository<'a> {
125 table: Box<dyn FeatureTable + 'a>,
126 transaction: &'a Transaction,
127}
128
129impl<'a> FeatureRepository<'a> {
130 pub fn new(table: Box<dyn FeatureTable + 'a>, transaction: &'a Transaction) -> Self {
131 FeatureRepository { table, transaction }
132 }
133
134 pub fn create_orphan(
135 &mut self,
136 event_buffer: &mut EventBuffer,
137 entity: &Feature,
138 ) -> Result<Feature, RepositoryError> {
139 let new = self.table.create(entity)?;
140 event_buffer.push(Event {
141 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Created)),
142 ids: vec![new.id],
143 data: None,
144 });
145 Ok(new)
146 }
147
148 pub fn create_orphan_multi(
149 &mut self,
150 event_buffer: &mut EventBuffer,
151 entities: &[Feature],
152 ) -> Result<Vec<Feature>, RepositoryError> {
153 let new_entities = self.table.create_multi(entities)?;
154 event_buffer.push(Event {
155 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Created)),
156 ids: new_entities.iter().map(|e| e.id).collect(),
157 data: None,
158 });
159 Ok(new_entities)
160 }
161 pub fn create(
162 &mut self,
163 event_buffer: &mut EventBuffer,
164 entity: &Feature,
165 owner_id: EntityId,
166 index: i32,
167 ) -> Result<Feature, RepositoryError> {
168 let new = self.table.create(entity)?;
169 let created_id = new.id;
170
171 let mut relationship_ids = self.get_relationships_from_owner(&owner_id)?;
172 if index >= 0 && (index as usize) < relationship_ids.len() {
174 relationship_ids.insert(index as usize, created_id);
175 } else {
176 relationship_ids.push(created_id);
177 }
178
179 self.set_relationships_in_owner(event_buffer, &owner_id, &relationship_ids)?;
180 event_buffer.push(Event {
181 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Created)),
182 ids: vec![created_id],
183 data: None,
184 });
185 Ok(new)
186 }
187
188 pub fn create_multi(
189 &mut self,
190 event_buffer: &mut EventBuffer,
191 entities: &[Feature],
192 owner_id: EntityId,
193 index: i32,
194 ) -> Result<Vec<Feature>, RepositoryError> {
195 let new_entities = self.table.create_multi(entities)?;
196 let created_ids: Vec<EntityId> = new_entities.iter().map(|e| e.id).collect();
197
198 let mut relationship_ids = self.get_relationships_from_owner(&owner_id)?;
199 if index >= 0 && (index as usize) < relationship_ids.len() {
200 for (i, id) in created_ids.iter().enumerate() {
201 relationship_ids.insert(index as usize + i, *id);
202 }
203 } else {
204 relationship_ids.extend(created_ids.iter());
205 }
206
207 self.set_relationships_in_owner(event_buffer, &owner_id, &relationship_ids)?;
208 event_buffer.push(Event {
209 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Created)),
210 ids: created_ids,
211 data: None,
212 });
213 Ok(new_entities)
214 }
215
216 pub fn get(&self, id: &EntityId) -> Result<Option<Feature>, RepositoryError> {
217 self.table.get(id)
218 }
219 pub fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Feature>>, RepositoryError> {
220 self.table.get_multi(ids)
221 }
222 pub fn get_all(&self) -> Result<Vec<Feature>, RepositoryError> {
223 self.table.get_all()
224 }
225
226 pub fn update(
227 &mut self,
228 event_buffer: &mut EventBuffer,
229 entity: &Feature,
230 ) -> Result<Feature, RepositoryError> {
231 let updated = self.table.update(entity)?;
232 event_buffer.push(Event {
233 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
234 ids: vec![updated.id],
235 data: None,
236 });
237 Ok(updated)
238 }
239
240 pub fn update_multi(
241 &mut self,
242 event_buffer: &mut EventBuffer,
243 entities: &[Feature],
244 ) -> Result<Vec<Feature>, RepositoryError> {
245 let updated = self.table.update_multi(entities)?;
246 event_buffer.push(Event {
247 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
248 ids: updated.iter().map(|e| e.id).collect(),
249 data: None,
250 });
251 Ok(updated)
252 }
253
254 pub fn update_with_relationships(
255 &mut self,
256 event_buffer: &mut EventBuffer,
257 entity: &Feature,
258 ) -> Result<Feature, RepositoryError> {
259 let updated = self.table.update_with_relationships(entity)?;
260 event_buffer.push(Event {
261 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
262 ids: vec![updated.id],
263 data: None,
264 });
265 Ok(updated)
266 }
267
268 pub fn update_with_relationships_multi(
269 &mut self,
270 event_buffer: &mut EventBuffer,
271 entities: &[Feature],
272 ) -> Result<Vec<Feature>, RepositoryError> {
273 let updated = self.table.update_with_relationships_multi(entities)?;
274 event_buffer.push(Event {
275 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
276 ids: updated.iter().map(|e| e.id).collect(),
277 data: None,
278 });
279 Ok(updated)
280 }
281
282 pub fn remove(
283 &mut self,
284 event_buffer: &mut EventBuffer,
285 id: &EntityId,
286 ) -> Result<(), RepositoryError> {
287 let entity = match self.table.get(id)? {
288 Some(e) => e,
289 None => return Ok(()),
290 };
291 let use_cases = entity.use_cases.clone();
294
295 repository_factory::write::create_use_case_repository(self.transaction)?
298 .remove_multi(event_buffer, &use_cases)?;
299 let affected_owner_ids: Vec<EntityId> = {
301 let owner_repo =
302 repository_factory::write::create_workspace_repository(self.transaction)?;
303 owner_repo
304 .get_relationships_from_right_ids(&WorkspaceRelationshipField::Features, &[*id])?
305 .into_iter()
306 .map(|(owner_id, _)| owner_id)
307 .collect()
308 };
309 let mut owner_rel_before: std::collections::HashMap<EntityId, Vec<EntityId>> =
311 std::collections::HashMap::new();
312 for owner_id in &affected_owner_ids {
313 owner_rel_before.insert(*owner_id, self.get_relationships_from_owner(owner_id)?);
314 }
315
316 self.table.remove(id)?;
318 event_buffer.push(Event {
319 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Removed)),
320 ids: vec![*id],
321 data: None,
322 });
323 for owner_id in &affected_owner_ids {
325 if let Some(rel_ids) = owner_rel_before.get(owner_id) {
326 let updated: Vec<EntityId> =
327 rel_ids.iter().copied().filter(|rid| *rid != *id).collect();
328 self.set_relationships_in_owner(event_buffer, owner_id, &updated)?;
329 }
330 }
331
332 Ok(())
333 }
334
335 pub fn remove_multi(
336 &mut self,
337 event_buffer: &mut EventBuffer,
338 ids: &[EntityId],
339 ) -> Result<(), RepositoryError> {
340 let entities = self.table.get_multi(ids)?;
341 if entities.is_empty() || entities.iter().all(|e| e.is_none()) {
342 return Ok(());
343 }
344
345 let mut use_cases_ids: Vec<EntityId> = entities
348 .iter()
349 .flat_map(|entity| entity.as_ref().map(|entity| entity.use_cases.clone()))
350 .flatten()
351 .collect();
352 use_cases_ids.sort();
354 use_cases_ids.dedup();
355
356 repository_factory::write::create_use_case_repository(self.transaction)?
359 .remove_multi(event_buffer, &use_cases_ids)?;
360 let affected_owner_ids: Vec<EntityId> = {
362 let owner_repo =
363 repository_factory::write::create_workspace_repository(self.transaction)?;
364 owner_repo
365 .get_relationships_from_right_ids(&WorkspaceRelationshipField::Features, ids)?
366 .into_iter()
367 .map(|(owner_id, _)| owner_id)
368 .collect()
369 };
370 let mut owner_rel_before: std::collections::HashMap<EntityId, Vec<EntityId>> =
372 std::collections::HashMap::new();
373 for owner_id in &affected_owner_ids {
374 owner_rel_before.insert(*owner_id, self.get_relationships_from_owner(owner_id)?);
375 }
376
377 self.table.remove_multi(ids)?;
378 event_buffer.push(Event {
379 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Removed)),
380 ids: ids.into(),
381 data: None,
382 });
383 {
385 let removed_set: std::collections::HashSet<EntityId> = ids.iter().copied().collect();
386 for owner_id in &affected_owner_ids {
387 if let Some(rel_ids) = owner_rel_before.get(owner_id) {
388 let updated: Vec<EntityId> = rel_ids
389 .iter()
390 .copied()
391 .filter(|rid| !removed_set.contains(rid))
392 .collect();
393 self.set_relationships_in_owner(event_buffer, owner_id, &updated)?;
394 }
395 }
396 }
397
398 Ok(())
399 }
400 pub fn get_relationship(
401 &self,
402 id: &EntityId,
403 field: &FeatureRelationshipField,
404 ) -> Result<Vec<EntityId>, RepositoryError> {
405 self.table.get_relationship(id, field)
406 }
407 pub fn get_relationship_many(
408 &self,
409 ids: &[EntityId],
410 field: &FeatureRelationshipField,
411 ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError> {
412 self.table.get_relationship_many(ids, field)
413 }
414 pub fn get_relationship_count(
415 &self,
416 id: &EntityId,
417 field: &FeatureRelationshipField,
418 ) -> Result<usize, RepositoryError> {
419 self.table.get_relationship_count(id, field)
420 }
421 pub fn get_relationship_in_range(
422 &self,
423 id: &EntityId,
424 field: &FeatureRelationshipField,
425 offset: usize,
426 limit: usize,
427 ) -> Result<Vec<EntityId>, RepositoryError> {
428 self.table
429 .get_relationship_in_range(id, field, offset, limit)
430 }
431 pub fn get_relationships_from_right_ids(
432 &self,
433 field: &FeatureRelationshipField,
434 right_ids: &[EntityId],
435 ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
436 self.table
437 .get_relationships_from_right_ids(field, right_ids)
438 }
439
440 pub fn set_relationship_multi(
441 &mut self,
442 event_buffer: &mut EventBuffer,
443 field: &FeatureRelationshipField,
444 relationships: Vec<(EntityId, Vec<EntityId>)>,
445 ) -> Result<(), RepositoryError> {
446 let all_right_ids: Vec<EntityId> = relationships
448 .iter()
449 .flat_map(|(_, ids)| ids.iter().copied())
450 .collect();
451 if !all_right_ids.is_empty() {
452 match field {
453 FeatureRelationshipField::UseCases => {
454 let child_repo =
455 repository_factory::write::create_use_case_repository(self.transaction)?;
456 let found = child_repo.get_multi(&all_right_ids)?;
457 let missing: Vec<_> = all_right_ids
458 .iter()
459 .zip(found.iter())
460 .filter(|(_, entity)| entity.is_none())
461 .map(|(id, _)| *id)
462 .collect();
463 if !missing.is_empty() {
464 return Err(RepositoryError::MissingRelationshipTarget {
465 operation: "set_relationship_multi",
466 ids: missing,
467 });
468 }
469 }
470 }
471 }
472 self.table
473 .set_relationship_multi(field, relationships.clone())?;
474 for (left_id, right_ids) in relationships {
475 event_buffer.push(Event {
476 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
477 ids: vec![left_id],
478 data: Some(format!(
479 "{}:{}",
480 field,
481 right_ids
482 .iter()
483 .map(|id| id.to_string())
484 .collect::<Vec<_>>()
485 .join(",")
486 )),
487 });
488 }
489 Ok(())
490 }
491
492 pub fn set_relationship(
493 &mut self,
494 event_buffer: &mut EventBuffer,
495 id: &EntityId,
496 field: &FeatureRelationshipField,
497 right_ids: &[EntityId],
498 ) -> Result<(), RepositoryError> {
499 if !right_ids.is_empty() {
501 match field {
502 FeatureRelationshipField::UseCases => {
503 let child_repo =
504 repository_factory::write::create_use_case_repository(self.transaction)?;
505 let found = child_repo.get_multi(right_ids)?;
506 let missing: Vec<_> = right_ids
507 .iter()
508 .zip(found.iter())
509 .filter(|(_, entity)| entity.is_none())
510 .map(|(id, _)| *id)
511 .collect();
512 if !missing.is_empty() {
513 return Err(RepositoryError::MissingRelationshipTarget {
514 operation: "set_relationship",
515 ids: missing,
516 });
517 }
518 }
519 }
520 }
521 self.table.set_relationship(id, field, right_ids)?;
522 event_buffer.push(Event {
523 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
524 ids: vec![*id],
525 data: Some(format!(
526 "{}:{}",
527 field,
528 right_ids
529 .iter()
530 .map(|id| id.to_string())
531 .collect::<Vec<_>>()
532 .join(",")
533 )),
534 });
535 Ok(())
536 }
537
538 pub fn move_relationship_ids(
539 &mut self,
540 event_buffer: &mut EventBuffer,
541 id: &EntityId,
542 field: &FeatureRelationshipField,
543 ids_to_move: &[EntityId],
544 new_index: i32,
545 ) -> Result<Vec<EntityId>, RepositoryError> {
546 let reordered = self
547 .table
548 .move_relationship_ids(id, field, ids_to_move, new_index)?;
549 event_buffer.push(Event {
550 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
551 ids: vec![*id],
552 data: Some(format!(
553 "{}:{}",
554 field,
555 reordered
556 .iter()
557 .map(|id| id.to_string())
558 .collect::<Vec<_>>()
559 .join(",")
560 )),
561 });
562 Ok(reordered)
563 }
564 pub fn get_relationships_from_owner(
565 &self,
566 owner_id: &EntityId,
567 ) -> Result<Vec<EntityId>, RepositoryError> {
568 let repo = repository_factory::write::create_workspace_repository(self.transaction)?;
569 repo.get_relationship(owner_id, &WorkspaceRelationshipField::Features)
570 }
571
572 pub fn set_relationships_in_owner(
573 &mut self,
574 event_buffer: &mut EventBuffer,
575 owner_id: &EntityId,
576 ids: &[EntityId],
577 ) -> Result<(), RepositoryError> {
578 let mut repo = repository_factory::write::create_workspace_repository(self.transaction)?;
579 repo.set_relationship(
580 event_buffer,
581 owner_id,
582 &WorkspaceRelationshipField::Features,
583 ids,
584 )
585 }
586
587 pub fn snapshot(&self, _ids: &[EntityId]) -> Result<EntityTreeSnapshot, RepositoryError> {
588 let store_snap = self.transaction.snapshot_store();
589 Ok(EntityTreeSnapshot {
590 store_snapshot: Some(store_snap),
591 })
592 }
593
594 pub fn restore(
595 &mut self,
596 event_buffer: &mut EventBuffer,
597 snap: &EntityTreeSnapshot,
598 ) -> Result<(), RepositoryError> {
599 let store_snap = snap
600 .store_snapshot
601 .as_ref()
602 .ok_or_else(|| RepositoryError::Serialization("missing store snapshot".into()))?;
603 self.transaction.restore_store(store_snap);
604
605 let store = self.transaction.get_store();
606
607 let mut emit = |entity: DirectAccessEntity, ids: Vec<EntityId>| {
608 if !ids.is_empty() {
609 event_buffer.push(Event {
610 origin: Origin::DirectAccess(entity),
611 ids,
612 data: None,
613 });
614 }
615 };
616
617 let feature_ids: Vec<_> = store.features.read().unwrap().keys().copied().collect();
619 emit(
620 DirectAccessEntity::Feature(EntityEvent::Created),
621 feature_ids.clone(),
622 );
623 emit(
624 DirectAccessEntity::Feature(EntityEvent::Updated),
625 feature_ids,
626 );
627
628 {
631 let child_ids: Vec<_> = store.use_cases.read().unwrap().keys().copied().collect();
632 emit(
633 DirectAccessEntity::UseCase(EntityEvent::Created),
634 child_ids.clone(),
635 );
636 emit(DirectAccessEntity::UseCase(EntityEvent::Updated), child_ids);
637 }
638
639 Ok(())
640 }
641}
642
643pub struct FeatureRepositoryRO<'a> {
644 table: Box<dyn FeatureTableRO + 'a>,
645}
646impl<'a> FeatureRepositoryRO<'a> {
647 pub fn new(table: Box<dyn FeatureTableRO + 'a>) -> Self {
648 FeatureRepositoryRO { table }
649 }
650 pub fn get(&self, id: &EntityId) -> Result<Option<Feature>, RepositoryError> {
651 self.table.get(id)
652 }
653 pub fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Feature>>, RepositoryError> {
654 self.table.get_multi(ids)
655 }
656 pub fn get_all(&self) -> Result<Vec<Feature>, RepositoryError> {
657 self.table.get_all()
658 }
659 pub fn get_relationship(
660 &self,
661 id: &EntityId,
662 field: &FeatureRelationshipField,
663 ) -> Result<Vec<EntityId>, RepositoryError> {
664 self.table.get_relationship(id, field)
665 }
666 pub fn get_relationship_many(
667 &self,
668 ids: &[EntityId],
669 field: &FeatureRelationshipField,
670 ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError> {
671 self.table.get_relationship_many(ids, field)
672 }
673 pub fn get_relationship_count(
674 &self,
675 id: &EntityId,
676 field: &FeatureRelationshipField,
677 ) -> Result<usize, RepositoryError> {
678 self.table.get_relationship_count(id, field)
679 }
680 pub fn get_relationship_in_range(
681 &self,
682 id: &EntityId,
683 field: &FeatureRelationshipField,
684 offset: usize,
685 limit: usize,
686 ) -> Result<Vec<EntityId>, RepositoryError> {
687 self.table
688 .get_relationship_in_range(id, field, offset, limit)
689 }
690 pub fn get_relationships_from_right_ids(
691 &self,
692 field: &FeatureRelationshipField,
693 right_ids: &[EntityId],
694 ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
695 self.table
696 .get_relationships_from_right_ids(field, right_ids)
697 }
698}