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::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 let workspace = entity.workspace;
247 let system = entity.system;
248
249 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 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 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 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 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 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 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 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 pub(crate) fn restore_subtree(
542 &self,
543 event_buffer: &mut EventBuffer,
544 snap: &HashMapStoreSnapshot,
545 ids: &[EntityId],
546 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 let mut to_create: Vec<EntityId> = Vec::new(); let mut to_update: Vec<EntityId> = Vec::new(); let mut to_delete: Vec<EntityId> = Vec::new(); {
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 {
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 {
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 {
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 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}