1use std::fmt::Display;
4
5use crate::{
6 database::hashmap_store::HashMapStoreSnapshot,
7 database::hashmap_store::{read_or_recover, write_or_recover},
13 database::transactions::Transaction,
14 direct_access::repository_factory,
15 entities::Feature,
16 event::{DirectAccessEntity, EntityEvent, Event, EventBuffer, Origin},
17 snapshot::EntityTreeSnapshot,
18 types::EntityId,
19};
20
21use crate::direct_access::workspace::WorkspaceRelationshipField;
22use crate::error::RepositoryError;
23use serde::{Deserialize, Serialize};
24
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub enum FeatureRelationshipField {
27 UseCases,
28}
29
30impl Display for FeatureRelationshipField {
31 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
32 write!(f, "{:?}", self)
33 }
34}
35
36pub trait FeatureTable {
37 fn create(&mut self, entity: &Feature) -> Result<Feature, RepositoryError>;
38 fn create_multi(&mut self, entities: &[Feature]) -> Result<Vec<Feature>, RepositoryError>;
39 fn get(&self, id: &EntityId) -> Result<Option<Feature>, RepositoryError>;
40 fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Feature>>, RepositoryError>;
41 fn get_all(&self) -> Result<Vec<Feature>, RepositoryError>;
42 fn update(&mut self, entity: &Feature) -> Result<Feature, RepositoryError>;
43 fn update_multi(&mut self, entities: &[Feature]) -> Result<Vec<Feature>, RepositoryError>;
44 fn update_with_relationships(&mut self, entity: &Feature) -> Result<Feature, RepositoryError>;
45 fn update_with_relationships_multi(
46 &mut self,
47 entities: &[Feature],
48 ) -> Result<Vec<Feature>, RepositoryError>;
49 fn remove(&mut self, id: &EntityId) -> Result<(), RepositoryError>;
50 fn remove_multi(&mut self, ids: &[EntityId]) -> Result<(), RepositoryError>;
51 fn get_relationship(
52 &self,
53 id: &EntityId,
54 field: &FeatureRelationshipField,
55 ) -> Result<Vec<EntityId>, RepositoryError>;
56 fn get_relationship_many(
57 &self,
58 ids: &[EntityId],
59 field: &FeatureRelationshipField,
60 ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError>;
61 fn get_relationship_count(
62 &self,
63 id: &EntityId,
64 field: &FeatureRelationshipField,
65 ) -> Result<usize, RepositoryError>;
66 fn get_relationship_in_range(
67 &self,
68 id: &EntityId,
69 field: &FeatureRelationshipField,
70 offset: usize,
71 limit: usize,
72 ) -> Result<Vec<EntityId>, RepositoryError>;
73 fn get_relationships_from_right_ids(
74 &self,
75 field: &FeatureRelationshipField,
76 right_ids: &[EntityId],
77 ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError>;
78 fn set_relationship_multi(
79 &mut self,
80 field: &FeatureRelationshipField,
81 relationships: Vec<(EntityId, Vec<EntityId>)>,
82 ) -> Result<(), RepositoryError>;
83 fn set_relationship(
84 &mut self,
85 id: &EntityId,
86 field: &FeatureRelationshipField,
87 right_ids: &[EntityId],
88 ) -> Result<(), RepositoryError>;
89 fn move_relationship_ids(
90 &mut self,
91 id: &EntityId,
92 field: &FeatureRelationshipField,
93 ids_to_move: &[EntityId],
94 new_index: i32,
95 ) -> Result<Vec<EntityId>, RepositoryError>;
96}
97
98pub trait FeatureTableRO {
99 fn get(&self, id: &EntityId) -> Result<Option<Feature>, RepositoryError>;
100 fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Feature>>, RepositoryError>;
101 fn get_all(&self) -> Result<Vec<Feature>, RepositoryError>;
102 fn get_relationship(
103 &self,
104 id: &EntityId,
105 field: &FeatureRelationshipField,
106 ) -> Result<Vec<EntityId>, RepositoryError>;
107 fn get_relationship_many(
108 &self,
109 ids: &[EntityId],
110 field: &FeatureRelationshipField,
111 ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError>;
112 fn get_relationship_count(
113 &self,
114 id: &EntityId,
115 field: &FeatureRelationshipField,
116 ) -> Result<usize, RepositoryError>;
117 fn get_relationship_in_range(
118 &self,
119 id: &EntityId,
120 field: &FeatureRelationshipField,
121 offset: usize,
122 limit: usize,
123 ) -> Result<Vec<EntityId>, RepositoryError>;
124 fn get_relationships_from_right_ids(
125 &self,
126 field: &FeatureRelationshipField,
127 right_ids: &[EntityId],
128 ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError>;
129}
130
131pub struct FeatureRepository<'a> {
132 table: Box<dyn FeatureTable + 'a>,
133 transaction: &'a Transaction,
134}
135
136impl<'a> FeatureRepository<'a> {
137 pub fn new(table: Box<dyn FeatureTable + 'a>, transaction: &'a Transaction) -> Self {
138 FeatureRepository { table, transaction }
139 }
140
141 pub fn create_orphan(
142 &mut self,
143 event_buffer: &mut EventBuffer,
144 entity: &Feature,
145 ) -> Result<Feature, RepositoryError> {
146 let new = self.table.create(entity)?;
147 event_buffer.push(Event {
148 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Created)),
149 ids: vec![new.id],
150 data: None,
151 });
152 Ok(new)
153 }
154
155 pub fn create_orphan_multi(
156 &mut self,
157 event_buffer: &mut EventBuffer,
158 entities: &[Feature],
159 ) -> Result<Vec<Feature>, RepositoryError> {
160 let new_entities = self.table.create_multi(entities)?;
161 event_buffer.push(Event {
162 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Created)),
163 ids: new_entities.iter().map(|e| e.id).collect(),
164 data: None,
165 });
166 Ok(new_entities)
167 }
168 pub fn create(
169 &mut self,
170 event_buffer: &mut EventBuffer,
171 entity: &Feature,
172 owner_id: EntityId,
173 index: i32,
174 ) -> Result<Feature, RepositoryError> {
175 let new = self.table.create(entity)?;
176 let created_id = new.id;
177
178 let mut relationship_ids = self.get_relationships_from_owner(&owner_id)?;
179 if index >= 0 && (index as usize) < relationship_ids.len() {
181 relationship_ids.insert(index as usize, created_id);
182 } else {
183 relationship_ids.push(created_id);
184 }
185
186 self.set_relationships_in_owner(event_buffer, &owner_id, &relationship_ids)?;
187 event_buffer.push(Event {
188 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Created)),
189 ids: vec![created_id],
190 data: None,
191 });
192 Ok(new)
193 }
194
195 pub fn create_multi(
196 &mut self,
197 event_buffer: &mut EventBuffer,
198 entities: &[Feature],
199 owner_id: EntityId,
200 index: i32,
201 ) -> Result<Vec<Feature>, RepositoryError> {
202 let new_entities = self.table.create_multi(entities)?;
203 let created_ids: Vec<EntityId> = new_entities.iter().map(|e| e.id).collect();
204
205 let mut relationship_ids = self.get_relationships_from_owner(&owner_id)?;
206 if index >= 0 && (index as usize) < relationship_ids.len() {
207 for (i, id) in created_ids.iter().enumerate() {
208 relationship_ids.insert(index as usize + i, *id);
209 }
210 } else {
211 relationship_ids.extend(created_ids.iter());
212 }
213
214 self.set_relationships_in_owner(event_buffer, &owner_id, &relationship_ids)?;
215 event_buffer.push(Event {
216 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Created)),
217 ids: created_ids,
218 data: None,
219 });
220 Ok(new_entities)
221 }
222
223 pub fn get(&self, id: &EntityId) -> Result<Option<Feature>, RepositoryError> {
224 self.table.get(id)
225 }
226 pub fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Feature>>, RepositoryError> {
227 self.table.get_multi(ids)
228 }
229 pub fn get_all(&self) -> Result<Vec<Feature>, RepositoryError> {
230 self.table.get_all()
231 }
232
233 pub fn update(
234 &mut self,
235 event_buffer: &mut EventBuffer,
236 entity: &Feature,
237 ) -> Result<Feature, RepositoryError> {
238 let updated = self.table.update(entity)?;
239 event_buffer.push(Event {
240 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
241 ids: vec![updated.id],
242 data: None,
243 });
244 Ok(updated)
245 }
246
247 pub fn update_multi(
248 &mut self,
249 event_buffer: &mut EventBuffer,
250 entities: &[Feature],
251 ) -> Result<Vec<Feature>, RepositoryError> {
252 let updated = self.table.update_multi(entities)?;
253 event_buffer.push(Event {
254 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
255 ids: updated.iter().map(|e| e.id).collect(),
256 data: None,
257 });
258 Ok(updated)
259 }
260
261 pub fn update_with_relationships(
262 &mut self,
263 event_buffer: &mut EventBuffer,
264 entity: &Feature,
265 ) -> Result<Feature, RepositoryError> {
266 let updated = self.table.update_with_relationships(entity)?;
267 event_buffer.push(Event {
268 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
269 ids: vec![updated.id],
270 data: None,
271 });
272 Ok(updated)
273 }
274
275 pub fn update_with_relationships_multi(
276 &mut self,
277 event_buffer: &mut EventBuffer,
278 entities: &[Feature],
279 ) -> Result<Vec<Feature>, RepositoryError> {
280 let updated = self.table.update_with_relationships_multi(entities)?;
281 event_buffer.push(Event {
282 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
283 ids: updated.iter().map(|e| e.id).collect(),
284 data: None,
285 });
286 Ok(updated)
287 }
288
289 pub fn remove(
290 &mut self,
291 event_buffer: &mut EventBuffer,
292 id: &EntityId,
293 ) -> Result<(), RepositoryError> {
294 let entity = match self.table.get(id)? {
295 Some(e) => e,
296 None => return Ok(()),
297 };
298 let use_cases = entity.use_cases.clone();
301
302 repository_factory::write::create_use_case_repository(self.transaction)?
305 .remove_multi(event_buffer, &use_cases)?;
306 let affected_owner_ids: Vec<EntityId> = {
308 let owner_repo =
309 repository_factory::write::create_workspace_repository(self.transaction)?;
310 owner_repo
311 .get_relationships_from_right_ids(&WorkspaceRelationshipField::Features, &[*id])?
312 .into_iter()
313 .map(|(owner_id, _)| owner_id)
314 .collect()
315 };
316 let mut owner_rel_before: std::collections::HashMap<EntityId, Vec<EntityId>> =
318 std::collections::HashMap::new();
319 for owner_id in &affected_owner_ids {
320 owner_rel_before.insert(*owner_id, self.get_relationships_from_owner(owner_id)?);
321 }
322
323 self.table.remove(id)?;
325 event_buffer.push(Event {
326 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Removed)),
327 ids: vec![*id],
328 data: None,
329 });
330 for owner_id in &affected_owner_ids {
332 if let Some(rel_ids) = owner_rel_before.get(owner_id) {
333 let updated: Vec<EntityId> =
334 rel_ids.iter().copied().filter(|rid| *rid != *id).collect();
335 self.set_relationships_in_owner(event_buffer, owner_id, &updated)?;
336 }
337 }
338
339 Ok(())
340 }
341
342 pub fn remove_multi(
343 &mut self,
344 event_buffer: &mut EventBuffer,
345 ids: &[EntityId],
346 ) -> Result<(), RepositoryError> {
347 let entities = self.table.get_multi(ids)?;
348 if entities.is_empty() || entities.iter().all(|e| e.is_none()) {
349 return Ok(());
350 }
351
352 let mut use_cases_ids: Vec<EntityId> = entities
355 .iter()
356 .flat_map(|entity| entity.as_ref().map(|entity| entity.use_cases.clone()))
357 .flatten()
358 .collect();
359 use_cases_ids.sort();
361 use_cases_ids.dedup();
362
363 repository_factory::write::create_use_case_repository(self.transaction)?
366 .remove_multi(event_buffer, &use_cases_ids)?;
367 let affected_owner_ids: Vec<EntityId> = {
369 let owner_repo =
370 repository_factory::write::create_workspace_repository(self.transaction)?;
371 owner_repo
372 .get_relationships_from_right_ids(&WorkspaceRelationshipField::Features, ids)?
373 .into_iter()
374 .map(|(owner_id, _)| owner_id)
375 .collect()
376 };
377 let mut owner_rel_before: std::collections::HashMap<EntityId, Vec<EntityId>> =
379 std::collections::HashMap::new();
380 for owner_id in &affected_owner_ids {
381 owner_rel_before.insert(*owner_id, self.get_relationships_from_owner(owner_id)?);
382 }
383
384 self.table.remove_multi(ids)?;
385 event_buffer.push(Event {
386 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Removed)),
387 ids: ids.into(),
388 data: None,
389 });
390 {
392 let removed_set: std::collections::HashSet<EntityId> = ids.iter().copied().collect();
393 for owner_id in &affected_owner_ids {
394 if let Some(rel_ids) = owner_rel_before.get(owner_id) {
395 let updated: Vec<EntityId> = rel_ids
396 .iter()
397 .copied()
398 .filter(|rid| !removed_set.contains(rid))
399 .collect();
400 self.set_relationships_in_owner(event_buffer, owner_id, &updated)?;
401 }
402 }
403 }
404
405 Ok(())
406 }
407 pub fn get_relationship(
408 &self,
409 id: &EntityId,
410 field: &FeatureRelationshipField,
411 ) -> Result<Vec<EntityId>, RepositoryError> {
412 self.table.get_relationship(id, field)
413 }
414 pub fn get_relationship_many(
415 &self,
416 ids: &[EntityId],
417 field: &FeatureRelationshipField,
418 ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError> {
419 self.table.get_relationship_many(ids, field)
420 }
421 pub fn get_relationship_count(
422 &self,
423 id: &EntityId,
424 field: &FeatureRelationshipField,
425 ) -> Result<usize, RepositoryError> {
426 self.table.get_relationship_count(id, field)
427 }
428 pub fn get_relationship_in_range(
429 &self,
430 id: &EntityId,
431 field: &FeatureRelationshipField,
432 offset: usize,
433 limit: usize,
434 ) -> Result<Vec<EntityId>, RepositoryError> {
435 self.table
436 .get_relationship_in_range(id, field, offset, limit)
437 }
438 pub fn get_relationships_from_right_ids(
439 &self,
440 field: &FeatureRelationshipField,
441 right_ids: &[EntityId],
442 ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
443 self.table
444 .get_relationships_from_right_ids(field, right_ids)
445 }
446
447 pub fn set_relationship_multi(
448 &mut self,
449 event_buffer: &mut EventBuffer,
450 field: &FeatureRelationshipField,
451 relationships: Vec<(EntityId, Vec<EntityId>)>,
452 ) -> Result<(), RepositoryError> {
453 let all_right_ids: Vec<EntityId> = relationships
455 .iter()
456 .flat_map(|(_, ids)| ids.iter().copied())
457 .collect();
458 if !all_right_ids.is_empty() {
459 match field {
460 FeatureRelationshipField::UseCases => {
461 let child_repo =
462 repository_factory::write::create_use_case_repository(self.transaction)?;
463 let found = child_repo.get_multi(&all_right_ids)?;
464 let missing: Vec<_> = all_right_ids
465 .iter()
466 .zip(found.iter())
467 .filter(|(_, entity)| entity.is_none())
468 .map(|(id, _)| *id)
469 .collect();
470 if !missing.is_empty() {
471 return Err(RepositoryError::MissingRelationshipTarget {
472 operation: "set_relationship_multi",
473 ids: missing,
474 });
475 }
476 }
477 }
478 }
479 self.table
480 .set_relationship_multi(field, relationships.clone())?;
481 for (left_id, right_ids) in relationships {
482 event_buffer.push(Event {
483 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
484 ids: vec![left_id],
485 data: Some(format!(
486 "{}:{}",
487 field,
488 right_ids
489 .iter()
490 .map(|id| id.to_string())
491 .collect::<Vec<_>>()
492 .join(",")
493 )),
494 });
495 }
496 Ok(())
497 }
498
499 pub fn set_relationship(
500 &mut self,
501 event_buffer: &mut EventBuffer,
502 id: &EntityId,
503 field: &FeatureRelationshipField,
504 right_ids: &[EntityId],
505 ) -> Result<(), RepositoryError> {
506 if !right_ids.is_empty() {
508 match field {
509 FeatureRelationshipField::UseCases => {
510 let child_repo =
511 repository_factory::write::create_use_case_repository(self.transaction)?;
512 let found = child_repo.get_multi(right_ids)?;
513 let missing: Vec<_> = right_ids
514 .iter()
515 .zip(found.iter())
516 .filter(|(_, entity)| entity.is_none())
517 .map(|(id, _)| *id)
518 .collect();
519 if !missing.is_empty() {
520 return Err(RepositoryError::MissingRelationshipTarget {
521 operation: "set_relationship",
522 ids: missing,
523 });
524 }
525 }
526 }
527 }
528 self.table.set_relationship(id, field, right_ids)?;
529 event_buffer.push(Event {
530 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
531 ids: vec![*id],
532 data: Some(format!(
533 "{}:{}",
534 field,
535 right_ids
536 .iter()
537 .map(|id| id.to_string())
538 .collect::<Vec<_>>()
539 .join(",")
540 )),
541 });
542 Ok(())
543 }
544
545 pub fn move_relationship_ids(
546 &mut self,
547 event_buffer: &mut EventBuffer,
548 id: &EntityId,
549 field: &FeatureRelationshipField,
550 ids_to_move: &[EntityId],
551 new_index: i32,
552 ) -> Result<Vec<EntityId>, RepositoryError> {
553 let reordered = self
554 .table
555 .move_relationship_ids(id, field, ids_to_move, new_index)?;
556 event_buffer.push(Event {
557 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
558 ids: vec![*id],
559 data: Some(format!(
560 "{}:{}",
561 field,
562 reordered
563 .iter()
564 .map(|id| id.to_string())
565 .collect::<Vec<_>>()
566 .join(",")
567 )),
568 });
569 Ok(reordered)
570 }
571 pub fn get_relationships_from_owner(
572 &self,
573 owner_id: &EntityId,
574 ) -> Result<Vec<EntityId>, RepositoryError> {
575 let repo = repository_factory::write::create_workspace_repository(self.transaction)?;
576 repo.get_relationship(owner_id, &WorkspaceRelationshipField::Features)
577 }
578
579 pub fn set_relationships_in_owner(
580 &mut self,
581 event_buffer: &mut EventBuffer,
582 owner_id: &EntityId,
583 ids: &[EntityId],
584 ) -> Result<(), RepositoryError> {
585 let mut repo = repository_factory::write::create_workspace_repository(self.transaction)?;
586 repo.set_relationship(
587 event_buffer,
588 owner_id,
589 &WorkspaceRelationshipField::Features,
590 ids,
591 )
592 }
593
594 pub fn snapshot(&self, ids: &[EntityId]) -> Result<EntityTreeSnapshot, RepositoryError> {
595 let store_snap = self.transaction.snapshot_store();
597 Ok(EntityTreeSnapshot {
598 store_snapshot: Some(store_snap),
599 root_ids: ids.to_vec(),
600 })
601 }
602
603 pub fn restore(
604 &mut self,
605 event_buffer: &mut EventBuffer,
606 snap: &EntityTreeSnapshot,
607 ) -> Result<(), RepositoryError> {
608 let store_snap = snap
609 .store_snapshot
610 .as_ref()
611 .ok_or_else(|| RepositoryError::Serialization("missing store snapshot".into()))?;
612 let snap_store = store_snap
613 .downcast_ref::<HashMapStoreSnapshot>()
614 .ok_or_else(|| RepositoryError::Serialization("snapshot type mismatch".into()))?;
615
616 let mut visited = std::collections::HashSet::new();
619 self.restore_subtree(event_buffer, snap_store, &snap.root_ids, &mut visited)?;
620
621 self.reconcile_backref_workspace_features(event_buffer, snap_store, &snap.root_ids)?;
624
625 Ok(())
626 }
627
628 pub(crate) fn restore_subtree(
633 &self,
634 event_buffer: &mut EventBuffer,
635 snap: &HashMapStoreSnapshot,
636 ids: &[EntityId],
637 visited: &mut std::collections::HashSet<(&'static str, EntityId)>,
640 ) -> Result<(), RepositoryError> {
641 let ids: Vec<EntityId> = ids
642 .iter()
643 .copied()
644 .filter(|id| visited.insert(("feature", *id)))
645 .collect();
646 if ids.is_empty() {
647 return Ok(());
648 }
649
650 let store = self.transaction.get_store();
651
652 let mut to_create: Vec<EntityId> = Vec::new(); let mut to_update: Vec<EntityId> = Vec::new(); let mut to_delete: Vec<EntityId> = Vec::new(); {
657 let live = read_or_recover(&store.features);
658 for id in &ids {
659 match (snap.features.contains_key(id), live.contains_key(id)) {
660 (true, false) => to_create.push(*id),
661 (true, true) => to_update.push(*id),
662 (false, true) => to_delete.push(*id),
663 (false, false) => {}
664 }
665 }
666 }
667
668 {
671 let mut child_ids: Vec<EntityId> = Vec::new();
672 for id in to_create.iter().chain(to_update.iter()) {
673 if let Some(list) = snap.jn_use_case_from_feature_use_cases.get(id) {
674 child_ids.extend(list.iter().copied());
675 }
676 }
677 {
678 let live_jn = read_or_recover(&store.jn_use_case_from_feature_use_cases);
679 for id in &ids {
680 if let Some(list) = live_jn.get(id) {
681 child_ids.extend(list.iter().copied());
682 }
683 }
684 }
685 child_ids.sort();
686 child_ids.dedup();
687 if !child_ids.is_empty() {
688 repository_factory::write::create_use_case_repository(self.transaction)?
689 .restore_subtree(event_buffer, snap, &child_ids, visited)?;
690 }
691 }
692
693 {
695 let mut live = write_or_recover(&store.features);
696 for id in to_create.iter().chain(to_update.iter()) {
697 if let Some(row) = snap.features.get(id) {
698 live.insert(*id, row.clone());
699 }
700 }
701 for id in &to_delete {
702 live.remove(id);
703 }
704 }
705
706 {
709 let mut live_jn = write_or_recover(&store.jn_use_case_from_feature_use_cases);
710 for id in to_create.iter().chain(to_update.iter()) {
711 match snap.jn_use_case_from_feature_use_cases.get(id) {
712 Some(v) => {
713 live_jn.insert(*id, v.clone());
714 }
715 None => {
716 live_jn.remove(id);
717 }
718 }
719 }
720 for id in &to_delete {
721 live_jn.remove(id);
722 }
723 }
724
725 self.reconcile_backref_file_feature(event_buffer, snap, &ids)?;
727
728 if !to_create.is_empty() {
730 event_buffer.push(Event {
731 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Created)),
732 ids: to_create.clone(),
733 data: None,
734 });
735 event_buffer.push(Event {
736 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
737 ids: to_create.clone(),
738 data: None,
739 });
740 }
741 if !to_update.is_empty() {
742 event_buffer.push(Event {
743 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Updated)),
744 ids: to_update.clone(),
745 data: None,
746 });
747 }
748 if !to_delete.is_empty() {
749 event_buffer.push(Event {
750 origin: Origin::DirectAccess(DirectAccessEntity::Feature(EntityEvent::Removed)),
751 ids: to_delete.clone(),
752 data: None,
753 });
754 }
755
756 Ok(())
757 }
758
759 fn reconcile_backref_file_feature(
762 &self,
763 event_buffer: &mut EventBuffer,
764 snap: &HashMapStoreSnapshot,
765 scope_ids: &[EntityId],
766 ) -> Result<(), RepositoryError> {
767 let scope: std::collections::HashSet<EntityId> = scope_ids.iter().copied().collect();
768 if scope.is_empty() {
769 return Ok(());
770 }
771 let store = self.transaction.get_store();
772
773 let mut left_keys: std::collections::HashSet<EntityId> = std::collections::HashSet::new();
775 for (left, rights) in snap.jn_feature_from_file_feature.iter() {
776 if rights.iter().any(|rid| scope.contains(rid)) {
777 left_keys.insert(*left);
778 }
779 }
780 {
781 let live_jn = read_or_recover(&store.jn_feature_from_file_feature);
782 for (left, rights) in live_jn.iter() {
783 if rights.iter().any(|rid| scope.contains(rid)) {
784 left_keys.insert(*left);
785 }
786 }
787 }
788
789 for left in left_keys {
790 let snap_list: Vec<EntityId> = snap
791 .jn_feature_from_file_feature
792 .get(&left)
793 .cloned()
794 .unwrap_or_default();
795 let new_list = {
796 let live_jn = read_or_recover(&store.jn_feature_from_file_feature);
797 let live_list: Vec<EntityId> = live_jn.get(&left).cloned().unwrap_or_default();
798 let reconciled = crate::database::hashmap_store::reconcile_backref_list(
799 &live_list, &snap_list, &scope,
800 );
801 if reconciled == live_list {
802 None
803 } else {
804 Some(reconciled)
805 }
806 };
807 if let Some(reconciled) = new_list {
808 write_or_recover(&store.jn_feature_from_file_feature).insert(left, reconciled);
809 event_buffer.push(Event {
810 origin: Origin::DirectAccess(DirectAccessEntity::File(EntityEvent::Updated)),
811 ids: vec![left],
812 data: None,
813 });
814 }
815 }
816 Ok(())
817 }
818
819 fn reconcile_backref_workspace_features(
822 &self,
823 event_buffer: &mut EventBuffer,
824 snap: &HashMapStoreSnapshot,
825 scope_ids: &[EntityId],
826 ) -> Result<(), RepositoryError> {
827 let scope: std::collections::HashSet<EntityId> = scope_ids.iter().copied().collect();
828 if scope.is_empty() {
829 return Ok(());
830 }
831 let store = self.transaction.get_store();
832
833 let mut left_keys: std::collections::HashSet<EntityId> = std::collections::HashSet::new();
835 for (left, rights) in snap.jn_feature_from_workspace_features.iter() {
836 if rights.iter().any(|rid| scope.contains(rid)) {
837 left_keys.insert(*left);
838 }
839 }
840 {
841 let live_jn = read_or_recover(&store.jn_feature_from_workspace_features);
842 for (left, rights) in live_jn.iter() {
843 if rights.iter().any(|rid| scope.contains(rid)) {
844 left_keys.insert(*left);
845 }
846 }
847 }
848
849 for left in left_keys {
850 let snap_list: Vec<EntityId> = snap
851 .jn_feature_from_workspace_features
852 .get(&left)
853 .cloned()
854 .unwrap_or_default();
855 let new_list = {
856 let live_jn = read_or_recover(&store.jn_feature_from_workspace_features);
857 let live_list: Vec<EntityId> = live_jn.get(&left).cloned().unwrap_or_default();
858 let reconciled = crate::database::hashmap_store::reconcile_backref_list(
859 &live_list, &snap_list, &scope,
860 );
861 if reconciled == live_list {
862 None
863 } else {
864 Some(reconciled)
865 }
866 };
867 if let Some(reconciled) = new_list {
868 write_or_recover(&store.jn_feature_from_workspace_features)
869 .insert(left, reconciled);
870 event_buffer.push(Event {
871 origin: Origin::DirectAccess(DirectAccessEntity::Workspace(
872 EntityEvent::Updated,
873 )),
874 ids: vec![left],
875 data: None,
876 });
877 }
878 }
879 Ok(())
880 }
881}
882
883pub struct FeatureRepositoryRO<'a> {
884 table: Box<dyn FeatureTableRO + 'a>,
885}
886impl<'a> FeatureRepositoryRO<'a> {
887 pub fn new(table: Box<dyn FeatureTableRO + 'a>) -> Self {
888 FeatureRepositoryRO { table }
889 }
890 pub fn get(&self, id: &EntityId) -> Result<Option<Feature>, RepositoryError> {
891 self.table.get(id)
892 }
893 pub fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Feature>>, RepositoryError> {
894 self.table.get_multi(ids)
895 }
896 pub fn get_all(&self) -> Result<Vec<Feature>, RepositoryError> {
897 self.table.get_all()
898 }
899 pub fn get_relationship(
900 &self,
901 id: &EntityId,
902 field: &FeatureRelationshipField,
903 ) -> Result<Vec<EntityId>, RepositoryError> {
904 self.table.get_relationship(id, field)
905 }
906 pub fn get_relationship_many(
907 &self,
908 ids: &[EntityId],
909 field: &FeatureRelationshipField,
910 ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError> {
911 self.table.get_relationship_many(ids, field)
912 }
913 pub fn get_relationship_count(
914 &self,
915 id: &EntityId,
916 field: &FeatureRelationshipField,
917 ) -> Result<usize, RepositoryError> {
918 self.table.get_relationship_count(id, field)
919 }
920 pub fn get_relationship_in_range(
921 &self,
922 id: &EntityId,
923 field: &FeatureRelationshipField,
924 offset: usize,
925 limit: usize,
926 ) -> Result<Vec<EntityId>, RepositoryError> {
927 self.table
928 .get_relationship_in_range(id, field, offset, limit)
929 }
930 pub fn get_relationships_from_right_ids(
931 &self,
932 field: &FeatureRelationshipField,
933 right_ids: &[EntityId],
934 ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
935 self.table
936 .get_relationships_from_right_ids(field, right_ids)
937 }
938}