Skip to main content

text_document_common/direct_access/frame/
frame_repository.rs

1// Generated by Qleany v1.5.1 from common_entity_repository.tera
2
3use std::fmt::Display;
4
5use crate::{
6    database::transactions::Transaction,
7    direct_access::repository_factory,
8    entities::Frame,
9    event::{DirectAccessEntity, EntityEvent, Event, EventBuffer, Origin},
10    snapshot::{EntityTreeSnapshot, TableLevelSnapshot},
11    types::EntityId,
12};
13
14use crate::direct_access::document::DocumentRelationshipField;
15use crate::error::RepositoryError;
16use serde::{Deserialize, Serialize};
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub enum FrameRelationshipField {
20    Blocks,
21    ParentFrame,
22    Table,
23}
24
25impl Display for FrameRelationshipField {
26    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
27        write!(f, "{:?}", self)
28    }
29}
30
31pub trait FrameTable {
32    fn create(&mut self, entity: &Frame) -> Result<Frame, RepositoryError>;
33    fn create_multi(&mut self, entities: &[Frame]) -> Result<Vec<Frame>, RepositoryError>;
34    fn get(&self, id: &EntityId) -> Result<Option<Frame>, RepositoryError>;
35    fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Frame>>, RepositoryError>;
36    fn get_all(&self) -> Result<Vec<Frame>, RepositoryError>;
37    fn update(&mut self, entity: &Frame) -> Result<Frame, RepositoryError>;
38    fn update_multi(&mut self, entities: &[Frame]) -> Result<Vec<Frame>, RepositoryError>;
39    fn update_with_relationships(&mut self, entity: &Frame) -> Result<Frame, RepositoryError>;
40    fn update_with_relationships_multi(
41        &mut self,
42        entities: &[Frame],
43    ) -> Result<Vec<Frame>, RepositoryError>;
44    fn remove(&mut self, id: &EntityId) -> Result<(), RepositoryError>;
45    fn remove_multi(&mut self, ids: &[EntityId]) -> Result<(), RepositoryError>;
46    fn get_relationship(
47        &self,
48        id: &EntityId,
49        field: &FrameRelationshipField,
50    ) -> Result<Vec<EntityId>, RepositoryError>;
51    fn get_relationship_many(
52        &self,
53        ids: &[EntityId],
54        field: &FrameRelationshipField,
55    ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError>;
56    fn get_relationship_count(
57        &self,
58        id: &EntityId,
59        field: &FrameRelationshipField,
60    ) -> Result<usize, RepositoryError>;
61    fn get_relationship_in_range(
62        &self,
63        id: &EntityId,
64        field: &FrameRelationshipField,
65        offset: usize,
66        limit: usize,
67    ) -> Result<Vec<EntityId>, RepositoryError>;
68    fn get_relationships_from_right_ids(
69        &self,
70        field: &FrameRelationshipField,
71        right_ids: &[EntityId],
72    ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError>;
73    fn set_relationship_multi(
74        &mut self,
75        field: &FrameRelationshipField,
76        relationships: Vec<(EntityId, Vec<EntityId>)>,
77    ) -> Result<(), RepositoryError>;
78    fn set_relationship(
79        &mut self,
80        id: &EntityId,
81        field: &FrameRelationshipField,
82        right_ids: &[EntityId],
83    ) -> Result<(), RepositoryError>;
84    fn move_relationship_ids(
85        &mut self,
86        id: &EntityId,
87        field: &FrameRelationshipField,
88        ids_to_move: &[EntityId],
89        new_index: i32,
90    ) -> Result<Vec<EntityId>, RepositoryError>;
91    fn snapshot_rows(&self, ids: &[EntityId]) -> Result<TableLevelSnapshot, RepositoryError>;
92    fn restore_rows(&mut self, snap: &TableLevelSnapshot) -> Result<(), RepositoryError>;
93}
94
95pub trait FrameTableRO {
96    fn get(&self, id: &EntityId) -> Result<Option<Frame>, RepositoryError>;
97    fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Frame>>, RepositoryError>;
98    fn get_all(&self) -> Result<Vec<Frame>, RepositoryError>;
99    fn get_relationship(
100        &self,
101        id: &EntityId,
102        field: &FrameRelationshipField,
103    ) -> Result<Vec<EntityId>, RepositoryError>;
104    fn get_relationship_many(
105        &self,
106        ids: &[EntityId],
107        field: &FrameRelationshipField,
108    ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError>;
109    fn get_relationship_count(
110        &self,
111        id: &EntityId,
112        field: &FrameRelationshipField,
113    ) -> Result<usize, RepositoryError>;
114    fn get_relationship_in_range(
115        &self,
116        id: &EntityId,
117        field: &FrameRelationshipField,
118        offset: usize,
119        limit: usize,
120    ) -> Result<Vec<EntityId>, RepositoryError>;
121    fn get_relationships_from_right_ids(
122        &self,
123        field: &FrameRelationshipField,
124        right_ids: &[EntityId],
125    ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError>;
126}
127
128pub struct FrameRepository<'a> {
129    redb_table: Box<dyn FrameTable + 'a>,
130    transaction: &'a Transaction,
131}
132
133impl<'a> FrameRepository<'a> {
134    pub fn new(redb_table: Box<dyn FrameTable + 'a>, transaction: &'a Transaction) -> Self {
135        FrameRepository {
136            redb_table,
137            transaction,
138        }
139    }
140
141    pub fn create_orphan(
142        &mut self,
143        event_buffer: &mut EventBuffer,
144        entity: &Frame,
145    ) -> Result<Frame, RepositoryError> {
146        let new = self.redb_table.create(entity)?;
147        event_buffer.push(Event {
148            origin: Origin::DirectAccess(DirectAccessEntity::Frame(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: &[Frame],
159    ) -> Result<Vec<Frame>, RepositoryError> {
160        let new_entities = self.redb_table.create_multi(entities)?;
161        event_buffer.push(Event {
162            origin: Origin::DirectAccess(DirectAccessEntity::Frame(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: &Frame,
172        owner_id: EntityId,
173        index: i32,
174    ) -> Result<Frame, RepositoryError> {
175        let new = self.redb_table.create(entity)?;
176        let created_id = new.id;
177
178        let mut relationship_ids = self.get_relationships_from_owner(&owner_id)?;
179        // Insert at index
180        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::Frame(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: &[Frame],
199        owner_id: EntityId,
200        index: i32,
201    ) -> Result<Vec<Frame>, RepositoryError> {
202        let new_entities = self.redb_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::Frame(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<Frame>, RepositoryError> {
224        self.redb_table.get(id)
225    }
226    pub fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Frame>>, RepositoryError> {
227        self.redb_table.get_multi(ids)
228    }
229    pub fn get_all(&self) -> Result<Vec<Frame>, RepositoryError> {
230        self.redb_table.get_all()
231    }
232
233    pub fn update(
234        &mut self,
235        event_buffer: &mut EventBuffer,
236        entity: &Frame,
237    ) -> Result<Frame, RepositoryError> {
238        let updated = self.redb_table.update(entity)?;
239        event_buffer.push(Event {
240            origin: Origin::DirectAccess(DirectAccessEntity::Frame(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: &[Frame],
251    ) -> Result<Vec<Frame>, RepositoryError> {
252        let updated = self.redb_table.update_multi(entities)?;
253        event_buffer.push(Event {
254            origin: Origin::DirectAccess(DirectAccessEntity::Frame(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: &Frame,
265    ) -> Result<Frame, RepositoryError> {
266        let updated = self.redb_table.update_with_relationships(entity)?;
267        event_buffer.push(Event {
268            origin: Origin::DirectAccess(DirectAccessEntity::Frame(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: &[Frame],
279    ) -> Result<Vec<Frame>, RepositoryError> {
280        let updated = self.redb_table.update_with_relationships_multi(entities)?;
281        event_buffer.push(Event {
282            origin: Origin::DirectAccess(DirectAccessEntity::Frame(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.redb_table.get(id)? {
295            Some(e) => e,
296            None => return Ok(()),
297        };
298        // get all strong forward relationship fields
299
300        let blocks = entity.blocks.clone();
301
302        // remove all strong relationships, initiating a cascade remove
303
304        repository_factory::write::create_block_repository(self.transaction)
305            .remove_multi(event_buffer, &blocks)?;
306        // Before removal, find which owner(s) reference this entity
307        let affected_owner_ids: Vec<EntityId> = {
308            let owner_repo =
309                repository_factory::write::create_document_repository(self.transaction);
310            owner_repo
311                .get_relationships_from_right_ids(&DocumentRelationshipField::Frames, &[*id])?
312                .into_iter()
313                .map(|(owner_id, _)| owner_id)
314                .collect()
315        };
316        // Save each owner's current relationship IDs (properly ordered via get_relationships_from_owner)
317        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        // remove entity
324        self.redb_table.remove(id)?;
325        event_buffer.push(Event {
326            origin: Origin::DirectAccess(DirectAccessEntity::Frame(EntityEvent::Removed)),
327            ids: vec![*id],
328            data: None,
329        });
330        // Update each affected owner's relationship to exclude removed ID (emits Updated event)
331        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.redb_table.get_multi(ids)?;
348        if entities.is_empty() || entities.iter().all(|e| e.is_none()) {
349            return Ok(());
350        }
351
352        // get all strong forward relationship fields
353
354        let mut blocks_ids: Vec<EntityId> = entities
355            .iter()
356            .flat_map(|entity| entity.as_ref().map(|entity| entity.blocks.clone()))
357            .flatten()
358            .collect();
359        // remove duplicates
360        blocks_ids.sort();
361        blocks_ids.dedup();
362
363        // remove all strong relationships, initiating a cascade remove
364
365        repository_factory::write::create_block_repository(self.transaction)
366            .remove_multi(event_buffer, &blocks_ids)?;
367        // Before removal, find which owner(s) reference these entities
368        let affected_owner_ids: Vec<EntityId> = {
369            let owner_repo =
370                repository_factory::write::create_document_repository(self.transaction);
371            owner_repo
372                .get_relationships_from_right_ids(&DocumentRelationshipField::Frames, ids)?
373                .into_iter()
374                .map(|(owner_id, _)| owner_id)
375                .collect()
376        };
377        // Save each owner's current relationship IDs (properly ordered via get_relationships_from_owner)
378        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.redb_table.remove_multi(ids)?;
385        event_buffer.push(Event {
386            origin: Origin::DirectAccess(DirectAccessEntity::Frame(EntityEvent::Removed)),
387            ids: ids.into(),
388            data: None,
389        });
390        // Update each affected owner's relationship to exclude removed IDs (emits Updated event)
391        {
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: &FrameRelationshipField,
411    ) -> Result<Vec<EntityId>, RepositoryError> {
412        self.redb_table.get_relationship(id, field)
413    }
414    pub fn get_relationship_many(
415        &self,
416        ids: &[EntityId],
417        field: &FrameRelationshipField,
418    ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError> {
419        self.redb_table.get_relationship_many(ids, field)
420    }
421    pub fn get_relationship_count(
422        &self,
423        id: &EntityId,
424        field: &FrameRelationshipField,
425    ) -> Result<usize, RepositoryError> {
426        self.redb_table.get_relationship_count(id, field)
427    }
428    pub fn get_relationship_in_range(
429        &self,
430        id: &EntityId,
431        field: &FrameRelationshipField,
432        offset: usize,
433        limit: usize,
434    ) -> Result<Vec<EntityId>, RepositoryError> {
435        self.redb_table
436            .get_relationship_in_range(id, field, offset, limit)
437    }
438    pub fn get_relationships_from_right_ids(
439        &self,
440        field: &FrameRelationshipField,
441        right_ids: &[EntityId],
442    ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
443        self.redb_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: &FrameRelationshipField,
451        relationships: Vec<(EntityId, Vec<EntityId>)>,
452    ) -> Result<(), RepositoryError> {
453        // Validate that all right_ids exist
454        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                FrameRelationshipField::Blocks => {
461                    let child_repo =
462                        repository_factory::write::create_block_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                FrameRelationshipField::ParentFrame => {
478                    let child_repo =
479                        repository_factory::write::create_frame_repository(self.transaction);
480                    let found = child_repo.get_multi(&all_right_ids)?;
481                    let missing: Vec<_> = all_right_ids
482                        .iter()
483                        .zip(found.iter())
484                        .filter(|(_, entity)| entity.is_none())
485                        .map(|(id, _)| *id)
486                        .collect();
487                    if !missing.is_empty() {
488                        return Err(RepositoryError::MissingRelationshipTarget {
489                            operation: "set_relationship_multi",
490                            ids: missing,
491                        });
492                    }
493                }
494                FrameRelationshipField::Table => {
495                    let child_repo =
496                        repository_factory::write::create_table_repository(self.transaction);
497                    let found = child_repo.get_multi(&all_right_ids)?;
498                    let missing: Vec<_> = all_right_ids
499                        .iter()
500                        .zip(found.iter())
501                        .filter(|(_, entity)| entity.is_none())
502                        .map(|(id, _)| *id)
503                        .collect();
504                    if !missing.is_empty() {
505                        return Err(RepositoryError::MissingRelationshipTarget {
506                            operation: "set_relationship_multi",
507                            ids: missing,
508                        });
509                    }
510                }
511            }
512        }
513        self.redb_table
514            .set_relationship_multi(field, relationships.clone())?;
515        for (left_id, right_ids) in relationships {
516            event_buffer.push(Event {
517                origin: Origin::DirectAccess(DirectAccessEntity::Frame(EntityEvent::Updated)),
518                ids: vec![left_id],
519                data: Some(format!(
520                    "{}:{}",
521                    field,
522                    right_ids
523                        .iter()
524                        .map(|id| id.to_string())
525                        .collect::<Vec<_>>()
526                        .join(",")
527                )),
528            });
529        }
530        Ok(())
531    }
532
533    pub fn set_relationship(
534        &mut self,
535        event_buffer: &mut EventBuffer,
536        id: &EntityId,
537        field: &FrameRelationshipField,
538        right_ids: &[EntityId],
539    ) -> Result<(), RepositoryError> {
540        // Validate that all right_ids exist
541        if !right_ids.is_empty() {
542            match field {
543                FrameRelationshipField::Blocks => {
544                    let child_repo =
545                        repository_factory::write::create_block_repository(self.transaction);
546                    let found = child_repo.get_multi(right_ids)?;
547                    let missing: Vec<_> = right_ids
548                        .iter()
549                        .zip(found.iter())
550                        .filter(|(_, entity)| entity.is_none())
551                        .map(|(id, _)| *id)
552                        .collect();
553                    if !missing.is_empty() {
554                        return Err(RepositoryError::MissingRelationshipTarget {
555                            operation: "set_relationship",
556                            ids: missing,
557                        });
558                    }
559                }
560                FrameRelationshipField::ParentFrame => {
561                    let child_repo =
562                        repository_factory::write::create_frame_repository(self.transaction);
563                    let found = child_repo.get_multi(right_ids)?;
564                    let missing: Vec<_> = right_ids
565                        .iter()
566                        .zip(found.iter())
567                        .filter(|(_, entity)| entity.is_none())
568                        .map(|(id, _)| *id)
569                        .collect();
570                    if !missing.is_empty() {
571                        return Err(RepositoryError::MissingRelationshipTarget {
572                            operation: "set_relationship",
573                            ids: missing,
574                        });
575                    }
576                }
577                FrameRelationshipField::Table => {
578                    let child_repo =
579                        repository_factory::write::create_table_repository(self.transaction);
580                    let found = child_repo.get_multi(right_ids)?;
581                    let missing: Vec<_> = right_ids
582                        .iter()
583                        .zip(found.iter())
584                        .filter(|(_, entity)| entity.is_none())
585                        .map(|(id, _)| *id)
586                        .collect();
587                    if !missing.is_empty() {
588                        return Err(RepositoryError::MissingRelationshipTarget {
589                            operation: "set_relationship",
590                            ids: missing,
591                        });
592                    }
593                }
594            }
595        }
596        self.redb_table.set_relationship(id, field, right_ids)?;
597        event_buffer.push(Event {
598            origin: Origin::DirectAccess(DirectAccessEntity::Frame(EntityEvent::Updated)),
599            ids: vec![*id],
600            data: Some(format!(
601                "{}:{}",
602                field,
603                right_ids
604                    .iter()
605                    .map(|id| id.to_string())
606                    .collect::<Vec<_>>()
607                    .join(",")
608            )),
609        });
610        Ok(())
611    }
612
613    pub fn move_relationship_ids(
614        &mut self,
615        event_buffer: &mut EventBuffer,
616        id: &EntityId,
617        field: &FrameRelationshipField,
618        ids_to_move: &[EntityId],
619        new_index: i32,
620    ) -> Result<Vec<EntityId>, RepositoryError> {
621        let reordered = self
622            .redb_table
623            .move_relationship_ids(id, field, ids_to_move, new_index)?;
624        event_buffer.push(Event {
625            origin: Origin::DirectAccess(DirectAccessEntity::Frame(EntityEvent::Updated)),
626            ids: vec![*id],
627            data: Some(format!(
628                "{}:{}",
629                field,
630                reordered
631                    .iter()
632                    .map(|id| id.to_string())
633                    .collect::<Vec<_>>()
634                    .join(",")
635            )),
636        });
637        Ok(reordered)
638    }
639    pub fn get_relationships_from_owner(
640        &self,
641        owner_id: &EntityId,
642    ) -> Result<Vec<EntityId>, RepositoryError> {
643        let repo = repository_factory::write::create_document_repository(self.transaction);
644        repo.get_relationship(owner_id, &DocumentRelationshipField::Frames)
645    }
646
647    pub fn set_relationships_in_owner(
648        &mut self,
649        event_buffer: &mut EventBuffer,
650        owner_id: &EntityId,
651        ids: &[EntityId],
652    ) -> Result<(), RepositoryError> {
653        let mut repo = repository_factory::write::create_document_repository(self.transaction);
654        repo.set_relationship(
655            event_buffer,
656            owner_id,
657            &DocumentRelationshipField::Frames,
658            ids,
659        )
660    }
661
662    pub fn snapshot(&self, ids: &[EntityId]) -> Result<EntityTreeSnapshot, RepositoryError> {
663        let table_data = self.redb_table.snapshot_rows(ids)?;
664
665        // Recursively snapshot strong children
666        #[allow(unused_mut)]
667        let mut children = Vec::new();
668
669        {
670            // Extract child IDs from the forward junction snapshot for blocks
671            let junction_name = "block_from_frame_blocks_junction";
672            let child_ids: Vec<EntityId> = table_data
673                .forward_junctions
674                .iter()
675                .filter(|j| j.table_name == junction_name)
676                .flat_map(|j| {
677                    j.entries
678                        .iter()
679                        .flat_map(|(_, right_ids)| right_ids.iter().copied())
680                })
681                .collect();
682            if !child_ids.is_empty() {
683                let child_repo =
684                    repository_factory::write::create_block_repository(self.transaction);
685                children.push(child_repo.snapshot(&child_ids)?);
686            }
687        }
688
689        Ok(EntityTreeSnapshot {
690            table_data,
691            children,
692        })
693    }
694
695    pub fn restore(
696        &mut self,
697        event_buffer: &mut EventBuffer,
698        snap: &EntityTreeSnapshot,
699    ) -> Result<(), RepositoryError> {
700        // Restore children first (bottom-up)
701
702        for child_snap in &snap.children {
703            if child_snap.table_data.entity_rows.table_name == "block" {
704                repository_factory::write::create_block_repository(self.transaction)
705                    .restore(event_buffer, child_snap)?;
706            }
707        }
708
709        // Restore this entity's rows
710        self.redb_table.restore_rows(&snap.table_data)?;
711
712        // Emit Created events for restored entity IDs
713        let restored_ids: Vec<EntityId> = snap
714            .table_data
715            .entity_rows
716            .rows
717            .iter()
718            .map(|(id, _)| *id)
719            .collect();
720        if !restored_ids.is_empty() {
721            event_buffer.push(Event {
722                origin: Origin::DirectAccess(DirectAccessEntity::Frame(EntityEvent::Created)),
723                ids: restored_ids.clone(),
724                data: None,
725            });
726        }
727        // Emit Updated events for restored relationships
728        if !restored_ids.is_empty() {
729            event_buffer.push(Event {
730                origin: Origin::DirectAccess(DirectAccessEntity::Frame(EntityEvent::Updated)),
731                ids: restored_ids,
732                data: None,
733            });
734        }
735        Ok(())
736    }
737}
738
739pub struct FrameRepositoryRO<'a> {
740    redb_table: Box<dyn FrameTableRO + 'a>,
741}
742impl<'a> FrameRepositoryRO<'a> {
743    pub fn new(redb_table: Box<dyn FrameTableRO + 'a>) -> Self {
744        FrameRepositoryRO { redb_table }
745    }
746    pub fn get(&self, id: &EntityId) -> Result<Option<Frame>, RepositoryError> {
747        self.redb_table.get(id)
748    }
749    pub fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Frame>>, RepositoryError> {
750        self.redb_table.get_multi(ids)
751    }
752    pub fn get_all(&self) -> Result<Vec<Frame>, RepositoryError> {
753        self.redb_table.get_all()
754    }
755    pub fn get_relationship(
756        &self,
757        id: &EntityId,
758        field: &FrameRelationshipField,
759    ) -> Result<Vec<EntityId>, RepositoryError> {
760        self.redb_table.get_relationship(id, field)
761    }
762    pub fn get_relationship_many(
763        &self,
764        ids: &[EntityId],
765        field: &FrameRelationshipField,
766    ) -> Result<std::collections::HashMap<EntityId, Vec<EntityId>>, RepositoryError> {
767        self.redb_table.get_relationship_many(ids, field)
768    }
769    pub fn get_relationship_count(
770        &self,
771        id: &EntityId,
772        field: &FrameRelationshipField,
773    ) -> Result<usize, RepositoryError> {
774        self.redb_table.get_relationship_count(id, field)
775    }
776    pub fn get_relationship_in_range(
777        &self,
778        id: &EntityId,
779        field: &FrameRelationshipField,
780        offset: usize,
781        limit: usize,
782    ) -> Result<Vec<EntityId>, RepositoryError> {
783        self.redb_table
784            .get_relationship_in_range(id, field, offset, limit)
785    }
786    pub fn get_relationships_from_right_ids(
787        &self,
788        field: &FrameRelationshipField,
789        right_ids: &[EntityId],
790    ) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
791        self.redb_table
792            .get_relationships_from_right_ids(field, right_ids)
793    }
794}