1use crate::entities::*;
11use crate::snapshot::{StoreSnapshot, StoreSnapshotTrait};
12use crate::types::EntityId;
13use im::HashMap;
14use std::sync::RwLock;
15
16#[derive(Debug, Default)]
21pub struct HashMapStore {
22 pub roots: RwLock<HashMap<EntityId, Root>>,
24 pub documents: RwLock<HashMap<EntityId, Document>>,
25 pub frames: RwLock<HashMap<EntityId, Frame>>,
26 pub blocks: RwLock<HashMap<EntityId, Block>>,
27 pub inline_elements: RwLock<HashMap<EntityId, InlineElement>>,
28 pub lists: RwLock<HashMap<EntityId, List>>,
29 pub resources: RwLock<HashMap<EntityId, Resource>>,
30 pub tables: RwLock<HashMap<EntityId, Table>>,
31 pub table_cells: RwLock<HashMap<EntityId, TableCell>>,
32
33 pub jn_document_from_root_document: RwLock<HashMap<EntityId, Vec<EntityId>>>,
35 pub jn_frame_from_document_frames: RwLock<HashMap<EntityId, Vec<EntityId>>>,
36 pub jn_list_from_document_lists: RwLock<HashMap<EntityId, Vec<EntityId>>>,
37 pub jn_resource_from_document_resources: RwLock<HashMap<EntityId, Vec<EntityId>>>,
38 pub jn_table_from_document_tables: RwLock<HashMap<EntityId, Vec<EntityId>>>,
39 pub jn_block_from_frame_blocks: RwLock<HashMap<EntityId, Vec<EntityId>>>,
40 pub jn_frame_from_frame_parent_frame: RwLock<HashMap<EntityId, Vec<EntityId>>>,
41 pub jn_table_from_frame_table: RwLock<HashMap<EntityId, Vec<EntityId>>>,
42 pub jn_inline_element_from_block_elements: RwLock<HashMap<EntityId, Vec<EntityId>>>,
43 pub jn_list_from_block_list: RwLock<HashMap<EntityId, Vec<EntityId>>>,
44 pub jn_table_cell_from_table_cells: RwLock<HashMap<EntityId, Vec<EntityId>>>,
45 pub jn_frame_from_table_cell_cell_frame: RwLock<HashMap<EntityId, Vec<EntityId>>>,
46
47 pub counters: RwLock<std::collections::HashMap<String, EntityId>>,
49
50 savepoints: RwLock<std::collections::HashMap<u64, HashMapStoreSnapshot>>,
52 next_savepoint_id: RwLock<u64>,
53}
54
55impl HashMapStore {
56 pub fn new() -> Self {
57 Self::default()
58 }
59
60 pub fn snapshot(&self) -> HashMapStoreSnapshot {
62 HashMapStoreSnapshot {
63 roots: self.roots.read().unwrap().clone(),
64 documents: self.documents.read().unwrap().clone(),
65 frames: self.frames.read().unwrap().clone(),
66 blocks: self.blocks.read().unwrap().clone(),
67 inline_elements: self.inline_elements.read().unwrap().clone(),
68 lists: self.lists.read().unwrap().clone(),
69 resources: self.resources.read().unwrap().clone(),
70 tables: self.tables.read().unwrap().clone(),
71 table_cells: self.table_cells.read().unwrap().clone(),
72 jn_document_from_root_document: self
73 .jn_document_from_root_document
74 .read()
75 .unwrap()
76 .clone(),
77 jn_frame_from_document_frames: self
78 .jn_frame_from_document_frames
79 .read()
80 .unwrap()
81 .clone(),
82 jn_list_from_document_lists: self.jn_list_from_document_lists.read().unwrap().clone(),
83 jn_resource_from_document_resources: self
84 .jn_resource_from_document_resources
85 .read()
86 .unwrap()
87 .clone(),
88 jn_table_from_document_tables: self
89 .jn_table_from_document_tables
90 .read()
91 .unwrap()
92 .clone(),
93 jn_block_from_frame_blocks: self.jn_block_from_frame_blocks.read().unwrap().clone(),
94 jn_frame_from_frame_parent_frame: self
95 .jn_frame_from_frame_parent_frame
96 .read()
97 .unwrap()
98 .clone(),
99 jn_table_from_frame_table: self.jn_table_from_frame_table.read().unwrap().clone(),
100 jn_inline_element_from_block_elements: self
101 .jn_inline_element_from_block_elements
102 .read()
103 .unwrap()
104 .clone(),
105 jn_list_from_block_list: self.jn_list_from_block_list.read().unwrap().clone(),
106 jn_table_cell_from_table_cells: self
107 .jn_table_cell_from_table_cells
108 .read()
109 .unwrap()
110 .clone(),
111 jn_frame_from_table_cell_cell_frame: self
112 .jn_frame_from_table_cell_cell_frame
113 .read()
114 .unwrap()
115 .clone(),
116 counters: self.counters.read().unwrap().clone(),
117 }
118 }
119
120 pub fn restore(&self, snap: &HashMapStoreSnapshot) {
122 *self.roots.write().unwrap() = snap.roots.clone();
123 *self.documents.write().unwrap() = snap.documents.clone();
124 *self.frames.write().unwrap() = snap.frames.clone();
125 *self.blocks.write().unwrap() = snap.blocks.clone();
126 *self.inline_elements.write().unwrap() = snap.inline_elements.clone();
127 *self.lists.write().unwrap() = snap.lists.clone();
128 *self.resources.write().unwrap() = snap.resources.clone();
129 *self.tables.write().unwrap() = snap.tables.clone();
130 *self.table_cells.write().unwrap() = snap.table_cells.clone();
131 *self.jn_document_from_root_document.write().unwrap() =
132 snap.jn_document_from_root_document.clone();
133 *self.jn_frame_from_document_frames.write().unwrap() =
134 snap.jn_frame_from_document_frames.clone();
135 *self.jn_list_from_document_lists.write().unwrap() =
136 snap.jn_list_from_document_lists.clone();
137 *self.jn_resource_from_document_resources.write().unwrap() =
138 snap.jn_resource_from_document_resources.clone();
139 *self.jn_table_from_document_tables.write().unwrap() =
140 snap.jn_table_from_document_tables.clone();
141 *self.jn_block_from_frame_blocks.write().unwrap() = snap.jn_block_from_frame_blocks.clone();
142 *self.jn_frame_from_frame_parent_frame.write().unwrap() =
143 snap.jn_frame_from_frame_parent_frame.clone();
144 *self.jn_table_from_frame_table.write().unwrap() = snap.jn_table_from_frame_table.clone();
145 *self.jn_inline_element_from_block_elements.write().unwrap() =
146 snap.jn_inline_element_from_block_elements.clone();
147 *self.jn_list_from_block_list.write().unwrap() = snap.jn_list_from_block_list.clone();
148 *self.jn_table_cell_from_table_cells.write().unwrap() =
149 snap.jn_table_cell_from_table_cells.clone();
150 *self.jn_frame_from_table_cell_cell_frame.write().unwrap() =
151 snap.jn_frame_from_table_cell_cell_frame.clone();
152 *self.counters.write().unwrap() = snap.counters.clone();
153 }
154
155 pub fn create_savepoint(&self) -> u64 {
158 let snap = self.snapshot();
159 let mut id_counter = self.next_savepoint_id.write().unwrap();
160 let id = *id_counter;
161 *id_counter += 1;
162 self.savepoints.write().unwrap().insert(id, snap);
163 id
164 }
165
166 pub fn restore_savepoint(&self, savepoint_id: u64) {
168 let snap = self
169 .savepoints
170 .read()
171 .unwrap()
172 .get(&savepoint_id)
173 .expect("savepoint not found")
174 .clone();
175 self.restore(&snap);
176 }
177
178 pub fn discard_savepoint(&self, savepoint_id: u64) {
180 self.savepoints.write().unwrap().remove(&savepoint_id);
181 }
182
183 pub(crate) fn next_id(&self, entity_name: &str) -> EntityId {
185 let mut counters = self.counters.write().unwrap();
186 let counter = counters.entry(entity_name.to_string()).or_insert(1);
187 let id = *counter;
188 *counter += 1;
189 id
190 }
191
192 pub fn restore_without_counters(&self, snap: &HashMapStoreSnapshot) {
195 *self.roots.write().unwrap() = snap.roots.clone();
196 *self.documents.write().unwrap() = snap.documents.clone();
197 *self.frames.write().unwrap() = snap.frames.clone();
198 *self.blocks.write().unwrap() = snap.blocks.clone();
199 *self.inline_elements.write().unwrap() = snap.inline_elements.clone();
200 *self.lists.write().unwrap() = snap.lists.clone();
201 *self.resources.write().unwrap() = snap.resources.clone();
202 *self.tables.write().unwrap() = snap.tables.clone();
203 *self.table_cells.write().unwrap() = snap.table_cells.clone();
204 *self.jn_document_from_root_document.write().unwrap() =
205 snap.jn_document_from_root_document.clone();
206 *self.jn_frame_from_document_frames.write().unwrap() =
207 snap.jn_frame_from_document_frames.clone();
208 *self.jn_list_from_document_lists.write().unwrap() =
209 snap.jn_list_from_document_lists.clone();
210 *self.jn_resource_from_document_resources.write().unwrap() =
211 snap.jn_resource_from_document_resources.clone();
212 *self.jn_table_from_document_tables.write().unwrap() =
213 snap.jn_table_from_document_tables.clone();
214 *self.jn_block_from_frame_blocks.write().unwrap() = snap.jn_block_from_frame_blocks.clone();
215 *self.jn_frame_from_frame_parent_frame.write().unwrap() =
216 snap.jn_frame_from_frame_parent_frame.clone();
217 *self.jn_table_from_frame_table.write().unwrap() = snap.jn_table_from_frame_table.clone();
218 *self.jn_inline_element_from_block_elements.write().unwrap() =
219 snap.jn_inline_element_from_block_elements.clone();
220 *self.jn_list_from_block_list.write().unwrap() = snap.jn_list_from_block_list.clone();
221 *self.jn_table_cell_from_table_cells.write().unwrap() =
222 snap.jn_table_cell_from_table_cells.clone();
223 *self.jn_frame_from_table_cell_cell_frame.write().unwrap() =
224 snap.jn_frame_from_table_cell_cell_frame.clone();
225 }
227
228 pub fn store_snapshot(&self) -> StoreSnapshot {
230 StoreSnapshot::new(self.snapshot())
231 }
232
233 pub fn restore_store_snapshot(&self, snap: &StoreSnapshot) {
235 let s = snap
236 .downcast_ref::<HashMapStoreSnapshot>()
237 .expect("StoreSnapshot must contain HashMapStoreSnapshot");
238 self.restore_without_counters(s);
239 }
240}
241
242#[derive(Debug, Clone)]
244pub struct HashMapStoreSnapshot {
245 roots: HashMap<EntityId, Root>,
246 documents: HashMap<EntityId, Document>,
247 frames: HashMap<EntityId, Frame>,
248 blocks: HashMap<EntityId, Block>,
249 inline_elements: HashMap<EntityId, InlineElement>,
250 lists: HashMap<EntityId, List>,
251 resources: HashMap<EntityId, Resource>,
252 tables: HashMap<EntityId, Table>,
253 table_cells: HashMap<EntityId, TableCell>,
254 jn_document_from_root_document: HashMap<EntityId, Vec<EntityId>>,
255 jn_frame_from_document_frames: HashMap<EntityId, Vec<EntityId>>,
256 jn_list_from_document_lists: HashMap<EntityId, Vec<EntityId>>,
257 jn_resource_from_document_resources: HashMap<EntityId, Vec<EntityId>>,
258 jn_table_from_document_tables: HashMap<EntityId, Vec<EntityId>>,
259 jn_block_from_frame_blocks: HashMap<EntityId, Vec<EntityId>>,
260 jn_frame_from_frame_parent_frame: HashMap<EntityId, Vec<EntityId>>,
261 jn_table_from_frame_table: HashMap<EntityId, Vec<EntityId>>,
262 jn_inline_element_from_block_elements: HashMap<EntityId, Vec<EntityId>>,
263 jn_list_from_block_list: HashMap<EntityId, Vec<EntityId>>,
264 jn_table_cell_from_table_cells: HashMap<EntityId, Vec<EntityId>>,
265 jn_frame_from_table_cell_cell_frame: HashMap<EntityId, Vec<EntityId>>,
266 counters: std::collections::HashMap<String, EntityId>,
267}
268
269impl StoreSnapshotTrait for HashMapStoreSnapshot {
270 fn clone_box(&self) -> Box<dyn StoreSnapshotTrait> {
271 Box::new(self.clone())
272 }
273
274 fn as_any(&self) -> &dyn std::any::Any {
275 self
276 }
277}
278
279pub(crate) fn delete_from_backward_junction(
284 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
285 id: &EntityId,
286) {
287 let mut jn = junction.write().unwrap();
288 let keys: Vec<EntityId> = jn.keys().copied().collect();
289 for k in keys {
290 if let Some(right_ids) = jn.get(&k)
291 && right_ids.contains(id)
292 {
293 let filtered: Vec<EntityId> =
294 right_ids.iter().copied().filter(|eid| eid != id).collect();
295 jn.insert(k, filtered);
296 }
297 }
298}
299
300pub(crate) fn junction_get(
301 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
302 id: &EntityId,
303) -> Vec<EntityId> {
304 junction
305 .read()
306 .unwrap()
307 .get(id)
308 .cloned()
309 .unwrap_or_default()
310}
311
312pub(crate) fn junction_set(
313 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
314 id: EntityId,
315 ids: Vec<EntityId>,
316) {
317 junction.write().unwrap().insert(id, ids);
318}
319
320pub(crate) fn junction_remove(junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>, id: &EntityId) {
321 junction.write().unwrap().remove(id);
322}
323
324pub(crate) fn junction_get_relationships_from_right_ids(
325 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
326 right_ids: &[EntityId],
327) -> Vec<(EntityId, Vec<EntityId>)> {
328 let jn = junction.read().unwrap();
329 jn.iter()
330 .filter(|(_, rids)| right_ids.iter().any(|eid| rids.contains(eid)))
331 .map(|(left_id, rids)| (*left_id, rids.clone()))
332 .collect()
333}
334
335pub(crate) fn junction_move_ids(
336 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
337 id: &EntityId,
338 ids_to_move: &[EntityId],
339 new_index: i32,
340) -> Vec<EntityId> {
341 let current = junction_get(junction, id);
342 if ids_to_move.is_empty() {
343 return current;
344 }
345 let move_set: std::collections::HashSet<EntityId> = ids_to_move.iter().copied().collect();
346 let mut remaining: Vec<EntityId> = current
347 .into_iter()
348 .filter(|eid| !move_set.contains(eid))
349 .collect();
350 let insert_pos = if new_index < 0 || (new_index as usize) > remaining.len() {
351 remaining.len()
352 } else {
353 new_index as usize
354 };
355 for (i, &eid) in ids_to_move.iter().enumerate() {
356 remaining.insert(insert_pos + i, eid);
357 }
358 junction_set(junction, *id, remaining.clone());
359 remaining
360}
361
362#[macro_export]
368macro_rules! impl_relationship_methods {
369 ($table_type:ty, $field_enum:ty) => {
370 fn get_relationship(
371 &self,
372 id: &$crate::types::EntityId,
373 field: &$field_enum,
374 ) -> Result<Vec<$crate::types::EntityId>, $crate::error::RepositoryError> {
375 Ok($crate::database::hashmap_store::junction_get(
376 self.resolve_junction(field),
377 id,
378 ))
379 }
380
381 fn get_relationship_many(
382 &self,
383 ids: &[$crate::types::EntityId],
384 field: &$field_enum,
385 ) -> Result<
386 std::collections::HashMap<$crate::types::EntityId, Vec<$crate::types::EntityId>>,
387 $crate::error::RepositoryError,
388 > {
389 let jn = self.resolve_junction(field);
390 let mut map = std::collections::HashMap::new();
391 for id in ids {
392 map.insert(*id, $crate::database::hashmap_store::junction_get(jn, id));
393 }
394 Ok(map)
395 }
396
397 fn get_relationship_count(
398 &self,
399 id: &$crate::types::EntityId,
400 field: &$field_enum,
401 ) -> Result<usize, $crate::error::RepositoryError> {
402 Ok(
403 $crate::database::hashmap_store::junction_get(self.resolve_junction(field), id)
404 .len(),
405 )
406 }
407
408 fn get_relationship_in_range(
409 &self,
410 id: &$crate::types::EntityId,
411 field: &$field_enum,
412 offset: usize,
413 limit: usize,
414 ) -> Result<Vec<$crate::types::EntityId>, $crate::error::RepositoryError> {
415 let all =
416 $crate::database::hashmap_store::junction_get(self.resolve_junction(field), id);
417 Ok(all.into_iter().skip(offset).take(limit).collect())
418 }
419
420 fn get_relationships_from_right_ids(
421 &self,
422 field: &$field_enum,
423 right_ids: &[$crate::types::EntityId],
424 ) -> Result<
425 Vec<($crate::types::EntityId, Vec<$crate::types::EntityId>)>,
426 $crate::error::RepositoryError,
427 > {
428 Ok(
429 $crate::database::hashmap_store::junction_get_relationships_from_right_ids(
430 self.resolve_junction(field),
431 right_ids,
432 ),
433 )
434 }
435 };
436}
437
438#[macro_export]
439macro_rules! impl_write_relationship_methods {
440 ($table_type:ty, $field_enum:ty) => {
441 $crate::impl_relationship_methods!($table_type, $field_enum);
442
443 fn set_relationship_multi(
444 &mut self,
445 field: &$field_enum,
446 relationships: Vec<($crate::types::EntityId, Vec<$crate::types::EntityId>)>,
447 ) -> Result<(), $crate::error::RepositoryError> {
448 let jn = self.resolve_junction(field);
449 for (left_id, entities) in relationships {
450 $crate::database::hashmap_store::junction_set(jn, left_id, entities);
451 }
452 Ok(())
453 }
454
455 fn set_relationship(
456 &mut self,
457 id: &$crate::types::EntityId,
458 field: &$field_enum,
459 right_ids: &[$crate::types::EntityId],
460 ) -> Result<(), $crate::error::RepositoryError> {
461 $crate::database::hashmap_store::junction_set(
462 self.resolve_junction(field),
463 *id,
464 right_ids.to_vec(),
465 );
466 Ok(())
467 }
468
469 fn move_relationship_ids(
470 &mut self,
471 id: &$crate::types::EntityId,
472 field: &$field_enum,
473 ids_to_move: &[$crate::types::EntityId],
474 new_index: i32,
475 ) -> Result<Vec<$crate::types::EntityId>, $crate::error::RepositoryError> {
476 Ok($crate::database::hashmap_store::junction_move_ids(
477 self.resolve_junction(field),
478 id,
479 ids_to_move,
480 new_index,
481 ))
482 }
483 };
484}
485
486#[macro_export]
491macro_rules! impl_leaf_entity_table {
492 (
493 entity: $Entity:ident,
494 entity_name: $entity_name:expr,
495 store_field: $store_field:ident,
496 table_trait: $TableTrait:ident,
497 table_ro_trait: $TableROTrait:ident,
498 table_struct: $TableStruct:ident,
499 table_ro_struct: $TableROStruct:ident,
500 backward_junctions: [ $( ($bj_field:ident) ),* $(,)? ],
501 ) => {
502 pub struct $TableStruct<'a> {
503 store: &'a $crate::database::hashmap_store::HashMapStore,
504 }
505
506 impl<'a> $TableStruct<'a> {
507 pub fn new(store: &'a $crate::database::hashmap_store::HashMapStore) -> Self {
508 Self { store }
509 }
510 }
511
512 impl<'a> $TableTrait for $TableStruct<'a> {
513 fn create(&mut self, entity: &$Entity) -> Result<$Entity, $crate::error::RepositoryError> {
514 self.create_multi(std::slice::from_ref(entity))
515 .map(|v| v.into_iter().next().unwrap())
516 }
517
518 fn create_multi(&mut self, entities: &[$Entity]) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
519 let mut created = Vec::with_capacity(entities.len());
520 let mut map = self.store.$store_field.write().unwrap();
521
522 for entity in entities {
523 let new_entity = if entity.id == $crate::types::EntityId::default() {
524 let id = self.store.next_id($entity_name);
525 $Entity {
526 id,
527 ..entity.clone()
528 }
529 } else {
530 if map.contains_key(&entity.id) {
531 return Err($crate::error::RepositoryError::DuplicateId {
532 entity: stringify!($Entity),
533 id: entity.id,
534 });
535 }
536 entity.clone()
537 };
538
539 map.insert(new_entity.id, new_entity.clone());
540 created.push(new_entity);
541 }
542 Ok(created)
543 }
544
545 fn get(&self, id: &$crate::types::EntityId) -> Result<Option<$Entity>, $crate::error::RepositoryError> {
546 Ok(self.store.$store_field.read().unwrap().get(id).cloned())
547 }
548
549 fn get_multi(&self, ids: &[$crate::types::EntityId]) -> Result<Vec<Option<$Entity>>, $crate::error::RepositoryError> {
550 let map = self.store.$store_field.read().unwrap();
551 Ok(ids.iter().map(|id| map.get(id).cloned()).collect())
552 }
553
554 fn get_all(&self) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
555 Ok(self.store.$store_field.read().unwrap().values().cloned().collect())
556 }
557
558 fn update(&mut self, entity: &$Entity) -> Result<$Entity, $crate::error::RepositoryError> {
559 self.update_multi(std::slice::from_ref(entity))
560 .map(|v| v.into_iter().next().unwrap())
561 }
562
563 fn update_multi(&mut self, entities: &[$Entity]) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
564 let mut map = self.store.$store_field.write().unwrap();
565 let mut result = Vec::with_capacity(entities.len());
566 for entity in entities {
567 map.insert(entity.id, entity.clone());
568 result.push(entity.clone());
569 }
570 Ok(result)
571 }
572
573 fn update_with_relationships(&mut self, entity: &$Entity) -> Result<$Entity, $crate::error::RepositoryError> {
574 self.update(entity)
575 }
576
577 fn update_with_relationships_multi(&mut self, entities: &[$Entity]) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
578 self.update_multi(entities)
579 }
580
581 fn remove(&mut self, id: &$crate::types::EntityId) -> Result<(), $crate::error::RepositoryError> {
582 self.remove_multi(std::slice::from_ref(id))
583 }
584
585 fn remove_multi(&mut self, ids: &[$crate::types::EntityId]) -> Result<(), $crate::error::RepositoryError> {
586 let mut map = self.store.$store_field.write().unwrap();
587 for id in ids {
588 map.remove(id);
589 $(
590 $crate::database::hashmap_store::delete_from_backward_junction(&self.store.$bj_field, id);
591 )*
592 }
593 Ok(())
594 }
595 }
596
597 pub struct $TableROStruct<'a> {
598 store: &'a $crate::database::hashmap_store::HashMapStore,
599 }
600
601 impl<'a> $TableROStruct<'a> {
602 pub fn new(store: &'a $crate::database::hashmap_store::HashMapStore) -> Self {
603 Self { store }
604 }
605 }
606
607 impl<'a> $TableROTrait for $TableROStruct<'a> {
608 fn get(&self, id: &$crate::types::EntityId) -> Result<Option<$Entity>, $crate::error::RepositoryError> {
609 Ok(self.store.$store_field.read().unwrap().get(id).cloned())
610 }
611
612 fn get_multi(&self, ids: &[$crate::types::EntityId]) -> Result<Vec<Option<$Entity>>, $crate::error::RepositoryError> {
613 let map = self.store.$store_field.read().unwrap();
614 Ok(ids.iter().map(|id| map.get(id).cloned()).collect())
615 }
616
617 fn get_all(&self) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
618 Ok(self.store.$store_field.read().unwrap().values().cloned().collect())
619 }
620 }
621 };
622}