Skip to main content

common/direct_access/root/
root_repository.rs

1// Generated by Qleany v1.11.0 from common_entity_repository.tera
2
3use std::fmt::Display;
4
5use crate::{
6    database::hashmap_store::HashMapStoreSnapshot,
7    // `*_or_recover` rather than a plain `.read()/.write().unwrap()`: a panic
8    // anywhere under a table's guard poisons that lock for the rest of the
9    // process, and the release profile unwinds, so the poison is reachable in a
10    // shipped build. Recovering (and clearing) it keeps one unrelated failure
11    // from escalating into a second panic on every later access to the store.
12    database::hashmap_store::{read_or_recover, write_or_recover},
13    database::transactions::Transaction,
14    direct_access::repository_factory,
15    entities::Root,
16    event::{DirectAccessEntity, EntityEvent, Event, EventBuffer, Origin},
17    snapshot::EntityTreeSnapshot,
18    types::EntityId,
19};
20
21use crate::error::RepositoryError;
22use serde::{Deserialize, Serialize};
23
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub enum RootRelationshipField {
26    System,
27    Workspace,
28}
29
30impl Display for RootRelationshipField {
31    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
32        write!(f, "{:?}", self)
33    }
34}
35
36pub trait RootTable {
37    fn create(&mut self, entity: &Root) -> Result<Root, RepositoryError>;
38    fn create_multi(&mut self, entities: &[Root]) -> Result<Vec<Root>, RepositoryError>;
39    fn get(&self, id: &EntityId) -> Result<Option<Root>, RepositoryError>;
40    fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Root>>, RepositoryError>;
41    fn get_all(&self) -> Result<Vec<Root>, RepositoryError>;
42    fn update(&mut self, entity: &Root) -> Result<Root, RepositoryError>;
43    fn update_multi(&mut self, entities: &[Root]) -> Result<Vec<Root>, RepositoryError>;
44    fn update_with_relationships(&mut self, entity: &Root) -> Result<Root, RepositoryError>;
45    fn update_with_relationships_multi(
46        &mut self,
47        entities: &[Root],
48    ) -> Result<Vec<Root>, 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: &RootRelationshipField,
55    ) -> Result<Vec<EntityId>, RepositoryError>;
56    fn get_relationship_many(
57        &self,
58        ids: &[EntityId],
59        field: &RootRelationshipField,
60    ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError>;
61    fn get_relationship_count(
62        &self,
63        id: &EntityId,
64        field: &RootRelationshipField,
65    ) -> Result<usize, RepositoryError>;
66    fn get_relationship_in_range(
67        &self,
68        id: &EntityId,
69        field: &RootRelationshipField,
70        offset: usize,
71        limit: usize,
72    ) -> Result<Vec<EntityId>, RepositoryError>;
73    fn get_relationships_from_right_ids(
74        &self,
75        field: &RootRelationshipField,
76        right_ids: &[EntityId],
77    ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError>;
78    fn set_relationship_multi(
79        &mut self,
80        field: &RootRelationshipField,
81        relationships: Vec<(EntityId, Vec<EntityId>)>,
82    ) -> Result<(), RepositoryError>;
83    fn set_relationship(
84        &mut self,
85        id: &EntityId,
86        field: &RootRelationshipField,
87        right_ids: &[EntityId],
88    ) -> Result<(), RepositoryError>;
89    fn move_relationship_ids(
90        &mut self,
91        id: &EntityId,
92        field: &RootRelationshipField,
93        ids_to_move: &[EntityId],
94        new_index: i32,
95    ) -> Result<Vec<EntityId>, RepositoryError>;
96}
97
98pub trait RootTableRO {
99    fn get(&self, id: &EntityId) -> Result<Option<Root>, RepositoryError>;
100    fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Root>>, RepositoryError>;
101    fn get_all(&self) -> Result<Vec<Root>, RepositoryError>;
102    fn get_relationship(
103        &self,
104        id: &EntityId,
105        field: &RootRelationshipField,
106    ) -> Result<Vec<EntityId>, RepositoryError>;
107    fn get_relationship_many(
108        &self,
109        ids: &[EntityId],
110        field: &RootRelationshipField,
111    ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError>;
112    fn get_relationship_count(
113        &self,
114        id: &EntityId,
115        field: &RootRelationshipField,
116    ) -> Result<usize, RepositoryError>;
117    fn get_relationship_in_range(
118        &self,
119        id: &EntityId,
120        field: &RootRelationshipField,
121        offset: usize,
122        limit: usize,
123    ) -> Result<Vec<EntityId>, RepositoryError>;
124    fn get_relationships_from_right_ids(
125        &self,
126        field: &RootRelationshipField,
127        right_ids: &[EntityId],
128    ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError>;
129}
130
131pub struct RootRepository<'a> {
132    table: Box<dyn RootTable + 'a>,
133    transaction: &'a Transaction,
134}
135
136impl<'a> RootRepository<'a> {
137    pub fn new(table: Box<dyn RootTable + 'a>, transaction: &'a Transaction) -> Self {
138        RootRepository { table, transaction }
139    }
140
141    pub fn create_orphan(
142        &mut self,
143        event_buffer: &mut EventBuffer,
144        entity: &Root,
145    ) -> Result<Root, RepositoryError> {
146        let new = self.table.create(entity)?;
147        event_buffer.push(Event {
148            origin: Origin::DirectAccess(DirectAccessEntity::Root(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: &[Root],
159    ) -> Result<Vec<Root>, RepositoryError> {
160        let new_entities = self.table.create_multi(entities)?;
161        event_buffer.push(Event {
162            origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Created)),
163            ids: new_entities.iter().map(|e| e.id).collect(),
164            data: None,
165        });
166        Ok(new_entities)
167    }
168
169    pub fn get(&self, id: &EntityId) -> Result<Option<Root>, RepositoryError> {
170        self.table.get(id)
171    }
172    pub fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Root>>, RepositoryError> {
173        self.table.get_multi(ids)
174    }
175    pub fn get_all(&self) -> Result<Vec<Root>, RepositoryError> {
176        self.table.get_all()
177    }
178
179    pub fn update(
180        &mut self,
181        event_buffer: &mut EventBuffer,
182        entity: &Root,
183    ) -> Result<Root, RepositoryError> {
184        let updated = self.table.update(entity)?;
185        event_buffer.push(Event {
186            origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Updated)),
187            ids: vec![updated.id],
188            data: None,
189        });
190        Ok(updated)
191    }
192
193    pub fn update_multi(
194        &mut self,
195        event_buffer: &mut EventBuffer,
196        entities: &[Root],
197    ) -> Result<Vec<Root>, RepositoryError> {
198        let updated = self.table.update_multi(entities)?;
199        event_buffer.push(Event {
200            origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Updated)),
201            ids: updated.iter().map(|e| e.id).collect(),
202            data: None,
203        });
204        Ok(updated)
205    }
206
207    pub fn update_with_relationships(
208        &mut self,
209        event_buffer: &mut EventBuffer,
210        entity: &Root,
211    ) -> Result<Root, RepositoryError> {
212        let updated = self.table.update_with_relationships(entity)?;
213        event_buffer.push(Event {
214            origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Updated)),
215            ids: vec![updated.id],
216            data: None,
217        });
218        Ok(updated)
219    }
220
221    pub fn update_with_relationships_multi(
222        &mut self,
223        event_buffer: &mut EventBuffer,
224        entities: &[Root],
225    ) -> Result<Vec<Root>, RepositoryError> {
226        let updated = self.table.update_with_relationships_multi(entities)?;
227        event_buffer.push(Event {
228            origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Updated)),
229            ids: updated.iter().map(|e| e.id).collect(),
230            data: None,
231        });
232        Ok(updated)
233    }
234
235    pub fn remove(
236        &mut self,
237        event_buffer: &mut EventBuffer,
238        id: &EntityId,
239    ) -> Result<(), RepositoryError> {
240        let entity = match self.table.get(id)? {
241            Some(e) => e,
242            None => return Ok(()),
243        };
244        // get all strong forward relationship fields
245
246        let workspace = entity.workspace;
247        let system = entity.system;
248
249        // remove all strong relationships, initiating a cascade remove
250
251        if let Some(workspace_id) = workspace {
252            repository_factory::write::create_workspace_repository(self.transaction)?
253                .remove(event_buffer, &workspace_id)?;
254        }
255        if let Some(system_id) = system {
256            repository_factory::write::create_system_repository(self.transaction)?
257                .remove(event_buffer, &system_id)?;
258        }
259
260        // remove entity
261        self.table.remove(id)?;
262        event_buffer.push(Event {
263            origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Removed)),
264            ids: vec![*id],
265            data: None,
266        });
267
268        Ok(())
269    }
270
271    pub fn remove_multi(
272        &mut self,
273        event_buffer: &mut EventBuffer,
274        ids: &[EntityId],
275    ) -> Result<(), RepositoryError> {
276        let entities = self.table.get_multi(ids)?;
277        if entities.is_empty() || entities.iter().all(|e| e.is_none()) {
278            return Ok(());
279        }
280
281        // get all strong forward relationship fields
282
283        let workspace_ids: Vec<EntityId> = entities
284            .iter()
285            .filter_map(|entity| entity.as_ref().and_then(|entity| entity.workspace))
286            .collect();
287        let system_ids: Vec<EntityId> = entities
288            .iter()
289            .filter_map(|entity| entity.as_ref().and_then(|entity| entity.system))
290            .collect();
291
292        // remove all strong relationships, initiating a cascade remove
293
294        repository_factory::write::create_workspace_repository(self.transaction)?
295            .remove_multi(event_buffer, &workspace_ids)?;
296        repository_factory::write::create_system_repository(self.transaction)?
297            .remove_multi(event_buffer, &system_ids)?;
298
299        self.table.remove_multi(ids)?;
300        event_buffer.push(Event {
301            origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Removed)),
302            ids: ids.into(),
303            data: None,
304        });
305
306        Ok(())
307    }
308    pub fn get_relationship(
309        &self,
310        id: &EntityId,
311        field: &RootRelationshipField,
312    ) -> Result<Vec<EntityId>, RepositoryError> {
313        self.table.get_relationship(id, field)
314    }
315    pub fn get_relationship_many(
316        &self,
317        ids: &[EntityId],
318        field: &RootRelationshipField,
319    ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError> {
320        self.table.get_relationship_many(ids, field)
321    }
322    pub fn get_relationship_count(
323        &self,
324        id: &EntityId,
325        field: &RootRelationshipField,
326    ) -> Result<usize, RepositoryError> {
327        self.table.get_relationship_count(id, field)
328    }
329    pub fn get_relationship_in_range(
330        &self,
331        id: &EntityId,
332        field: &RootRelationshipField,
333        offset: usize,
334        limit: usize,
335    ) -> Result<Vec<EntityId>, RepositoryError> {
336        self.table
337            .get_relationship_in_range(id, field, offset, limit)
338    }
339    pub fn get_relationships_from_right_ids(
340        &self,
341        field: &RootRelationshipField,
342        right_ids: &[EntityId],
343    ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
344        self.table
345            .get_relationships_from_right_ids(field, right_ids)
346    }
347
348    pub fn set_relationship_multi(
349        &mut self,
350        event_buffer: &mut EventBuffer,
351        field: &RootRelationshipField,
352        relationships: Vec<(EntityId, Vec<EntityId>)>,
353    ) -> Result<(), RepositoryError> {
354        // Validate that all right_ids exist
355        let all_right_ids: Vec<EntityId> = relationships
356            .iter()
357            .flat_map(|(_, ids)| ids.iter().copied())
358            .collect();
359        if !all_right_ids.is_empty() {
360            match field {
361                RootRelationshipField::System => {
362                    let child_repo =
363                        repository_factory::write::create_system_repository(self.transaction)?;
364                    let found = child_repo.get_multi(&all_right_ids)?;
365                    let missing: Vec<_> = all_right_ids
366                        .iter()
367                        .zip(found.iter())
368                        .filter(|(_, entity)| entity.is_none())
369                        .map(|(id, _)| *id)
370                        .collect();
371                    if !missing.is_empty() {
372                        return Err(RepositoryError::MissingRelationshipTarget {
373                            operation: "set_relationship_multi",
374                            ids: missing,
375                        });
376                    }
377                }
378                RootRelationshipField::Workspace => {
379                    let child_repo =
380                        repository_factory::write::create_workspace_repository(self.transaction)?;
381                    let found = child_repo.get_multi(&all_right_ids)?;
382                    let missing: Vec<_> = all_right_ids
383                        .iter()
384                        .zip(found.iter())
385                        .filter(|(_, entity)| entity.is_none())
386                        .map(|(id, _)| *id)
387                        .collect();
388                    if !missing.is_empty() {
389                        return Err(RepositoryError::MissingRelationshipTarget {
390                            operation: "set_relationship_multi",
391                            ids: missing,
392                        });
393                    }
394                }
395            }
396        }
397        self.table
398            .set_relationship_multi(field, relationships.clone())?;
399        for (left_id, right_ids) in relationships {
400            event_buffer.push(Event {
401                origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Updated)),
402                ids: vec![left_id],
403                data: Some(format!(
404                    "{}:{}",
405                    field,
406                    right_ids
407                        .iter()
408                        .map(|id| id.to_string())
409                        .collect::<Vec<_>>()
410                        .join(",")
411                )),
412            });
413        }
414        Ok(())
415    }
416
417    pub fn set_relationship(
418        &mut self,
419        event_buffer: &mut EventBuffer,
420        id: &EntityId,
421        field: &RootRelationshipField,
422        right_ids: &[EntityId],
423    ) -> Result<(), RepositoryError> {
424        // Validate that all right_ids exist
425        if !right_ids.is_empty() {
426            match field {
427                RootRelationshipField::System => {
428                    let child_repo =
429                        repository_factory::write::create_system_repository(self.transaction)?;
430                    let found = child_repo.get_multi(right_ids)?;
431                    let missing: Vec<_> = right_ids
432                        .iter()
433                        .zip(found.iter())
434                        .filter(|(_, entity)| entity.is_none())
435                        .map(|(id, _)| *id)
436                        .collect();
437                    if !missing.is_empty() {
438                        return Err(RepositoryError::MissingRelationshipTarget {
439                            operation: "set_relationship",
440                            ids: missing,
441                        });
442                    }
443                }
444                RootRelationshipField::Workspace => {
445                    let child_repo =
446                        repository_factory::write::create_workspace_repository(self.transaction)?;
447                    let found = child_repo.get_multi(right_ids)?;
448                    let missing: Vec<_> = right_ids
449                        .iter()
450                        .zip(found.iter())
451                        .filter(|(_, entity)| entity.is_none())
452                        .map(|(id, _)| *id)
453                        .collect();
454                    if !missing.is_empty() {
455                        return Err(RepositoryError::MissingRelationshipTarget {
456                            operation: "set_relationship",
457                            ids: missing,
458                        });
459                    }
460                }
461            }
462        }
463        self.table.set_relationship(id, field, right_ids)?;
464        event_buffer.push(Event {
465            origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Updated)),
466            ids: vec![*id],
467            data: Some(format!(
468                "{}:{}",
469                field,
470                right_ids
471                    .iter()
472                    .map(|id| id.to_string())
473                    .collect::<Vec<_>>()
474                    .join(",")
475            )),
476        });
477        Ok(())
478    }
479
480    pub fn move_relationship_ids(
481        &mut self,
482        event_buffer: &mut EventBuffer,
483        id: &EntityId,
484        field: &RootRelationshipField,
485        ids_to_move: &[EntityId],
486        new_index: i32,
487    ) -> Result<Vec<EntityId>, RepositoryError> {
488        let reordered = self
489            .table
490            .move_relationship_ids(id, field, ids_to_move, new_index)?;
491        event_buffer.push(Event {
492            origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Updated)),
493            ids: vec![*id],
494            data: Some(format!(
495                "{}:{}",
496                field,
497                reordered
498                    .iter()
499                    .map(|id| id.to_string())
500                    .collect::<Vec<_>>()
501                    .join(",")
502            )),
503        });
504        Ok(reordered)
505    }
506
507    pub fn snapshot(&self, ids: &[EntityId]) -> Result<EntityTreeSnapshot, RepositoryError> {
508        // O(1) whole-store capture (im::HashMap structural sharing). Restore is scoped to `ids`.
509        let store_snap = self.transaction.snapshot_store();
510        Ok(EntityTreeSnapshot {
511            store_snapshot: Some(store_snap),
512            root_ids: ids.to_vec(),
513        })
514    }
515
516    pub fn restore(
517        &mut self,
518        event_buffer: &mut EventBuffer,
519        snap: &EntityTreeSnapshot,
520    ) -> Result<(), RepositoryError> {
521        let store_snap = snap
522            .store_snapshot
523            .as_ref()
524            .ok_or_else(|| RepositoryError::Serialization("missing store snapshot".into()))?;
525        let snap_store = store_snap
526            .downcast_ref::<HashMapStoreSnapshot>()
527            .ok_or_else(|| RepositoryError::Serialization("snapshot type mismatch".into()))?;
528
529        // Scoped restore: walk the subtree rooted at the captured ids (strong relationships only),
530        // in both the snapshot and the live store, and reconcile only it.
531        let mut visited = std::collections::HashSet::new();
532        self.restore_subtree(event_buffer, snap_store, &snap.root_ids, &mut visited)?;
533
534        Ok(())
535    }
536
537    /// Restore the subtree rooted at `ids` (of this entity type) to the snapshot state, recursing
538    /// into strong children. Touches only the subtree: in-scope rows and the forward junctions they
539    /// own are restored wholesale; external referrers are reconciled surgically; everything else
540    /// (other trunks, non-undoable data) is left untouched. `visited` guards against cycles.
541    pub(crate) fn restore_subtree(
542        &self,
543        event_buffer: &mut EventBuffer,
544        snap: &HashMapStoreSnapshot,
545        ids: &[EntityId],
546        // Keyed by (entity type, id): EntityIds are per-type, not globally unique, so a bare
547        // id set would let one entity type's id falsely mask another's.
548        visited: &mut std::collections::HashSet<(&'static str, EntityId)>,
549    ) -> Result<(), RepositoryError> {
550        let ids: Vec<EntityId> = ids
551            .iter()
552            .copied()
553            .filter(|id| visited.insert(("root", *id)))
554            .collect();
555        if ids.is_empty() {
556            return Ok(());
557        }
558
559        let store = self.transaction.get_store();
560
561        // Three-way partition by presence in snapshot vs live store (read before mutating).
562        let mut to_create: Vec<EntityId> = Vec::new(); // in snapshot, gone from live -> re-add
563        let mut to_update: Vec<EntityId> = Vec::new(); // in both                    -> revert
564        let mut to_delete: Vec<EntityId> = Vec::new(); // live only (created after)  -> delete
565        {
566            let live = read_or_recover(&store.roots);
567            for id in &ids {
568                match (snap.roots.contains_key(id), live.contains_key(id)) {
569                    (true, false) => to_create.push(*id),
570                    (true, true) => to_update.push(*id),
571                    (false, true) => to_delete.push(*id),
572                    (false, false) => {}
573                }
574            }
575        }
576
577        // 1. Recurse into strong children first (collect child ids from snapshot + live, then drop
578        //    all locks before recursing so self-referential ownership cannot deadlock).
579        {
580            let mut child_ids: Vec<EntityId> = Vec::new();
581            for id in to_create.iter().chain(to_update.iter()) {
582                if let Some(list) = snap.jn_workspace_from_root_workspace.get(id) {
583                    child_ids.extend(list.iter().copied());
584                }
585            }
586            {
587                let live_jn = read_or_recover(&store.jn_workspace_from_root_workspace);
588                for id in &ids {
589                    if let Some(list) = live_jn.get(id) {
590                        child_ids.extend(list.iter().copied());
591                    }
592                }
593            }
594            child_ids.sort();
595            child_ids.dedup();
596            if !child_ids.is_empty() {
597                repository_factory::write::create_workspace_repository(self.transaction)?
598                    .restore_subtree(event_buffer, snap, &child_ids, visited)?;
599            }
600        }
601        {
602            let mut child_ids: Vec<EntityId> = Vec::new();
603            for id in to_create.iter().chain(to_update.iter()) {
604                if let Some(list) = snap.jn_system_from_root_system.get(id) {
605                    child_ids.extend(list.iter().copied());
606                }
607            }
608            {
609                let live_jn = read_or_recover(&store.jn_system_from_root_system);
610                for id in &ids {
611                    if let Some(list) = live_jn.get(id) {
612                        child_ids.extend(list.iter().copied());
613                    }
614                }
615            }
616            child_ids.sort();
617            child_ids.dedup();
618            if !child_ids.is_empty() {
619                repository_factory::write::create_system_repository(self.transaction)?
620                    .restore_subtree(event_buffer, snap, &child_ids, visited)?;
621            }
622        }
623
624        // 2. Entity rows: revert/re-add from snapshot, delete the ones created after it.
625        {
626            let mut live = write_or_recover(&store.roots);
627            for id in to_create.iter().chain(to_update.iter()) {
628                if let Some(row) = snap.roots.get(id) {
629                    live.insert(*id, row.clone());
630                }
631            }
632            for id in &to_delete {
633                live.remove(id);
634            }
635        }
636
637        // 3. This entity's own forward junctions (strong + weak): restored wholesale because the
638        //    junction key is in-scope (owned exclusively by this trunk).
639        {
640            let mut live_jn = write_or_recover(&store.jn_system_from_root_system);
641            for id in to_create.iter().chain(to_update.iter()) {
642                match snap.jn_system_from_root_system.get(id) {
643                    Some(v) => {
644                        live_jn.insert(*id, v.clone());
645                    }
646                    None => {
647                        live_jn.remove(id);
648                    }
649                }
650            }
651            for id in &to_delete {
652                live_jn.remove(id);
653            }
654        }
655        {
656            let mut live_jn = write_or_recover(&store.jn_workspace_from_root_workspace);
657            for id in to_create.iter().chain(to_update.iter()) {
658                match snap.jn_workspace_from_root_workspace.get(id) {
659                    Some(v) => {
660                        live_jn.insert(*id, v.clone());
661                    }
662                    None => {
663                        live_jn.remove(id);
664                    }
665                }
666            }
667            for id in &to_delete {
668                live_jn.remove(id);
669            }
670        }
671
672        // 4. External weak referrers of these ids: reconcile surgically (membership only).
673
674        // 5. Events: precise per-id (Created/Updated/Removed), not a whole-store storm.
675        if !to_create.is_empty() {
676            event_buffer.push(Event {
677                origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Created)),
678                ids: to_create.clone(),
679                data: None,
680            });
681            event_buffer.push(Event {
682                origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Updated)),
683                ids: to_create.clone(),
684                data: None,
685            });
686        }
687        if !to_update.is_empty() {
688            event_buffer.push(Event {
689                origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Updated)),
690                ids: to_update.clone(),
691                data: None,
692            });
693        }
694        if !to_delete.is_empty() {
695            event_buffer.push(Event {
696                origin: Origin::DirectAccess(DirectAccessEntity::Root(EntityEvent::Removed)),
697                ids: to_delete.clone(),
698                data: None,
699            });
700        }
701
702        Ok(())
703    }
704}
705
706pub struct RootRepositoryRO<'a> {
707    table: Box<dyn RootTableRO + 'a>,
708}
709impl<'a> RootRepositoryRO<'a> {
710    pub fn new(table: Box<dyn RootTableRO + 'a>) -> Self {
711        RootRepositoryRO { table }
712    }
713    pub fn get(&self, id: &EntityId) -> Result<Option<Root>, RepositoryError> {
714        self.table.get(id)
715    }
716    pub fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Root>>, RepositoryError> {
717        self.table.get_multi(ids)
718    }
719    pub fn get_all(&self) -> Result<Vec<Root>, RepositoryError> {
720        self.table.get_all()
721    }
722    pub fn get_relationship(
723        &self,
724        id: &EntityId,
725        field: &RootRelationshipField,
726    ) -> Result<Vec<EntityId>, RepositoryError> {
727        self.table.get_relationship(id, field)
728    }
729    pub fn get_relationship_many(
730        &self,
731        ids: &[EntityId],
732        field: &RootRelationshipField,
733    ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError> {
734        self.table.get_relationship_many(ids, field)
735    }
736    pub fn get_relationship_count(
737        &self,
738        id: &EntityId,
739        field: &RootRelationshipField,
740    ) -> Result<usize, RepositoryError> {
741        self.table.get_relationship_count(id, field)
742    }
743    pub fn get_relationship_in_range(
744        &self,
745        id: &EntityId,
746        field: &RootRelationshipField,
747        offset: usize,
748        limit: usize,
749    ) -> Result<Vec<EntityId>, RepositoryError> {
750        self.table
751            .get_relationship_in_range(id, field, offset, limit)
752    }
753    pub fn get_relationships_from_right_ids(
754        &self,
755        field: &RootRelationshipField,
756        right_ids: &[EntityId],
757    ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
758        self.table
759            .get_relationships_from_right_ids(field, right_ids)
760    }
761}