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 workspaces: RwLock<HashMap<EntityId, Workspace>>,
25 pub systems: RwLock<HashMap<EntityId, System>>,
26 pub entities: RwLock<HashMap<EntityId, Entity>>,
27 pub fields: RwLock<HashMap<EntityId, Field>>,
28 pub features: RwLock<HashMap<EntityId, Feature>>,
29 pub files: RwLock<HashMap<EntityId, File>>,
30 pub use_cases: RwLock<HashMap<EntityId, UseCase>>,
31 pub dtos: RwLock<HashMap<EntityId, Dto>>,
32 pub dto_fields: RwLock<HashMap<EntityId, DtoField>>,
33 pub globals: RwLock<HashMap<EntityId, Global>>,
34 pub relationships: RwLock<HashMap<EntityId, Relationship>>,
35 pub user_interfaces: RwLock<HashMap<EntityId, UserInterface>>,
36
37 pub jn_system_from_root_system: RwLock<HashMap<EntityId, Vec<EntityId>>>,
39 pub jn_workspace_from_root_workspace: RwLock<HashMap<EntityId, Vec<EntityId>>>,
40 pub jn_entity_from_workspace_entities: RwLock<HashMap<EntityId, Vec<EntityId>>>,
41 pub jn_feature_from_workspace_features: RwLock<HashMap<EntityId, Vec<EntityId>>>,
42 pub jn_global_from_workspace_global: RwLock<HashMap<EntityId, Vec<EntityId>>>,
43 pub jn_user_interface_from_workspace_user_interface: RwLock<HashMap<EntityId, Vec<EntityId>>>,
44 pub jn_file_from_system_files: RwLock<HashMap<EntityId, Vec<EntityId>>>,
45 pub jn_field_from_entity_fields: RwLock<HashMap<EntityId, Vec<EntityId>>>,
46 pub jn_entity_from_entity_inherits_from: RwLock<HashMap<EntityId, Vec<EntityId>>>,
47 pub jn_relationship_from_entity_relationships: RwLock<HashMap<EntityId, Vec<EntityId>>>,
48 pub jn_entity_from_field_entity: RwLock<HashMap<EntityId, Vec<EntityId>>>,
49 pub jn_use_case_from_feature_use_cases: RwLock<HashMap<EntityId, Vec<EntityId>>>,
50 pub jn_entity_from_file_entity: RwLock<HashMap<EntityId, Vec<EntityId>>>,
51 pub jn_feature_from_file_feature: RwLock<HashMap<EntityId, Vec<EntityId>>>,
52 pub jn_field_from_file_field: RwLock<HashMap<EntityId, Vec<EntityId>>>,
53 pub jn_use_case_from_file_use_case: RwLock<HashMap<EntityId, Vec<EntityId>>>,
54 pub jn_dto_from_use_case_dto_in: RwLock<HashMap<EntityId, Vec<EntityId>>>,
55 pub jn_dto_from_use_case_dto_out: RwLock<HashMap<EntityId, Vec<EntityId>>>,
56 pub jn_entity_from_use_case_entities: RwLock<HashMap<EntityId, Vec<EntityId>>>,
57 pub jn_dto_field_from_dto_fields: RwLock<HashMap<EntityId, Vec<EntityId>>>,
58 pub jn_entity_from_relationship_left_entity: RwLock<HashMap<EntityId, Vec<EntityId>>>,
59 pub jn_entity_from_relationship_right_entity: RwLock<HashMap<EntityId, Vec<EntityId>>>,
60
61 pub counters: RwLock<std::collections::HashMap<String, EntityId>>,
63
64 savepoints: RwLock<std::collections::HashMap<u64, HashMapStoreSnapshot>>,
66 next_savepoint_id: RwLock<u64>,
67}
68
69impl HashMapStore {
70 pub fn new() -> Self {
71 Self::default()
72 }
73
74 pub fn snapshot(&self) -> HashMapStoreSnapshot {
79 HashMapStoreSnapshot {
80 roots: read_or_recover(&self.roots).clone(),
81 workspaces: read_or_recover(&self.workspaces).clone(),
82 systems: read_or_recover(&self.systems).clone(),
83 entities: read_or_recover(&self.entities).clone(),
84 fields: read_or_recover(&self.fields).clone(),
85 features: read_or_recover(&self.features).clone(),
86 files: read_or_recover(&self.files).clone(),
87 use_cases: read_or_recover(&self.use_cases).clone(),
88 dtos: read_or_recover(&self.dtos).clone(),
89 dto_fields: read_or_recover(&self.dto_fields).clone(),
90 globals: read_or_recover(&self.globals).clone(),
91 relationships: read_or_recover(&self.relationships).clone(),
92 user_interfaces: read_or_recover(&self.user_interfaces).clone(),
93 jn_system_from_root_system: read_or_recover(&self.jn_system_from_root_system).clone(),
94 jn_workspace_from_root_workspace: read_or_recover(
95 &self.jn_workspace_from_root_workspace,
96 )
97 .clone(),
98 jn_entity_from_workspace_entities: read_or_recover(
99 &self.jn_entity_from_workspace_entities,
100 )
101 .clone(),
102 jn_feature_from_workspace_features: read_or_recover(
103 &self.jn_feature_from_workspace_features,
104 )
105 .clone(),
106 jn_global_from_workspace_global: read_or_recover(&self.jn_global_from_workspace_global)
107 .clone(),
108 jn_user_interface_from_workspace_user_interface: read_or_recover(
109 &self.jn_user_interface_from_workspace_user_interface,
110 )
111 .clone(),
112 jn_file_from_system_files: read_or_recover(&self.jn_file_from_system_files).clone(),
113 jn_field_from_entity_fields: read_or_recover(&self.jn_field_from_entity_fields).clone(),
114 jn_entity_from_entity_inherits_from: read_or_recover(
115 &self.jn_entity_from_entity_inherits_from,
116 )
117 .clone(),
118 jn_relationship_from_entity_relationships: read_or_recover(
119 &self.jn_relationship_from_entity_relationships,
120 )
121 .clone(),
122 jn_entity_from_field_entity: read_or_recover(&self.jn_entity_from_field_entity).clone(),
123 jn_use_case_from_feature_use_cases: read_or_recover(
124 &self.jn_use_case_from_feature_use_cases,
125 )
126 .clone(),
127 jn_entity_from_file_entity: read_or_recover(&self.jn_entity_from_file_entity).clone(),
128 jn_feature_from_file_feature: read_or_recover(&self.jn_feature_from_file_feature)
129 .clone(),
130 jn_field_from_file_field: read_or_recover(&self.jn_field_from_file_field).clone(),
131 jn_use_case_from_file_use_case: read_or_recover(&self.jn_use_case_from_file_use_case)
132 .clone(),
133 jn_dto_from_use_case_dto_in: read_or_recover(&self.jn_dto_from_use_case_dto_in).clone(),
134 jn_dto_from_use_case_dto_out: read_or_recover(&self.jn_dto_from_use_case_dto_out)
135 .clone(),
136 jn_entity_from_use_case_entities: read_or_recover(
137 &self.jn_entity_from_use_case_entities,
138 )
139 .clone(),
140 jn_dto_field_from_dto_fields: read_or_recover(&self.jn_dto_field_from_dto_fields)
141 .clone(),
142 jn_entity_from_relationship_left_entity: read_or_recover(
143 &self.jn_entity_from_relationship_left_entity,
144 )
145 .clone(),
146 jn_entity_from_relationship_right_entity: read_or_recover(
147 &self.jn_entity_from_relationship_right_entity,
148 )
149 .clone(),
150 counters: read_or_recover(&self.counters).clone(),
151 }
152 }
153
154 pub fn freeze(&self) -> HashMapStore {
181 let g_roots = read_or_recover(&self.roots);
184 let g_workspaces = read_or_recover(&self.workspaces);
185 let g_systems = read_or_recover(&self.systems);
186 let g_entities = read_or_recover(&self.entities);
187 let g_fields = read_or_recover(&self.fields);
188 let g_features = read_or_recover(&self.features);
189 let g_files = read_or_recover(&self.files);
190 let g_use_cases = read_or_recover(&self.use_cases);
191 let g_dtos = read_or_recover(&self.dtos);
192 let g_dto_fields = read_or_recover(&self.dto_fields);
193 let g_globals = read_or_recover(&self.globals);
194 let g_relationships = read_or_recover(&self.relationships);
195 let g_user_interfaces = read_or_recover(&self.user_interfaces);
196 let g_jn_system_from_root_system = read_or_recover(&self.jn_system_from_root_system);
197 let g_jn_workspace_from_root_workspace =
198 read_or_recover(&self.jn_workspace_from_root_workspace);
199 let g_jn_entity_from_workspace_entities =
200 read_or_recover(&self.jn_entity_from_workspace_entities);
201 let g_jn_feature_from_workspace_features =
202 read_or_recover(&self.jn_feature_from_workspace_features);
203 let g_jn_global_from_workspace_global =
204 read_or_recover(&self.jn_global_from_workspace_global);
205 let g_jn_user_interface_from_workspace_user_interface =
206 read_or_recover(&self.jn_user_interface_from_workspace_user_interface);
207 let g_jn_file_from_system_files = read_or_recover(&self.jn_file_from_system_files);
208 let g_jn_field_from_entity_fields = read_or_recover(&self.jn_field_from_entity_fields);
209 let g_jn_entity_from_entity_inherits_from =
210 read_or_recover(&self.jn_entity_from_entity_inherits_from);
211 let g_jn_relationship_from_entity_relationships =
212 read_or_recover(&self.jn_relationship_from_entity_relationships);
213 let g_jn_entity_from_field_entity = read_or_recover(&self.jn_entity_from_field_entity);
214 let g_jn_use_case_from_feature_use_cases =
215 read_or_recover(&self.jn_use_case_from_feature_use_cases);
216 let g_jn_entity_from_file_entity = read_or_recover(&self.jn_entity_from_file_entity);
217 let g_jn_feature_from_file_feature = read_or_recover(&self.jn_feature_from_file_feature);
218 let g_jn_field_from_file_field = read_or_recover(&self.jn_field_from_file_field);
219 let g_jn_use_case_from_file_use_case =
220 read_or_recover(&self.jn_use_case_from_file_use_case);
221 let g_jn_dto_from_use_case_dto_in = read_or_recover(&self.jn_dto_from_use_case_dto_in);
222 let g_jn_dto_from_use_case_dto_out = read_or_recover(&self.jn_dto_from_use_case_dto_out);
223 let g_jn_entity_from_use_case_entities =
224 read_or_recover(&self.jn_entity_from_use_case_entities);
225 let g_jn_dto_field_from_dto_fields = read_or_recover(&self.jn_dto_field_from_dto_fields);
226 let g_jn_entity_from_relationship_left_entity =
227 read_or_recover(&self.jn_entity_from_relationship_left_entity);
228 let g_jn_entity_from_relationship_right_entity =
229 read_or_recover(&self.jn_entity_from_relationship_right_entity);
230 let g_counters = read_or_recover(&self.counters);
231
232 HashMapStore {
233 roots: RwLock::new(g_roots.clone()),
234 workspaces: RwLock::new(g_workspaces.clone()),
235 systems: RwLock::new(g_systems.clone()),
236 entities: RwLock::new(g_entities.clone()),
237 fields: RwLock::new(g_fields.clone()),
238 features: RwLock::new(g_features.clone()),
239 files: RwLock::new(g_files.clone()),
240 use_cases: RwLock::new(g_use_cases.clone()),
241 dtos: RwLock::new(g_dtos.clone()),
242 dto_fields: RwLock::new(g_dto_fields.clone()),
243 globals: RwLock::new(g_globals.clone()),
244 relationships: RwLock::new(g_relationships.clone()),
245 user_interfaces: RwLock::new(g_user_interfaces.clone()),
246 jn_system_from_root_system: RwLock::new(g_jn_system_from_root_system.clone()),
247 jn_workspace_from_root_workspace: RwLock::new(
248 g_jn_workspace_from_root_workspace.clone(),
249 ),
250 jn_entity_from_workspace_entities: RwLock::new(
251 g_jn_entity_from_workspace_entities.clone(),
252 ),
253 jn_feature_from_workspace_features: RwLock::new(
254 g_jn_feature_from_workspace_features.clone(),
255 ),
256 jn_global_from_workspace_global: RwLock::new(g_jn_global_from_workspace_global.clone()),
257 jn_user_interface_from_workspace_user_interface: RwLock::new(
258 g_jn_user_interface_from_workspace_user_interface.clone(),
259 ),
260 jn_file_from_system_files: RwLock::new(g_jn_file_from_system_files.clone()),
261 jn_field_from_entity_fields: RwLock::new(g_jn_field_from_entity_fields.clone()),
262 jn_entity_from_entity_inherits_from: RwLock::new(
263 g_jn_entity_from_entity_inherits_from.clone(),
264 ),
265 jn_relationship_from_entity_relationships: RwLock::new(
266 g_jn_relationship_from_entity_relationships.clone(),
267 ),
268 jn_entity_from_field_entity: RwLock::new(g_jn_entity_from_field_entity.clone()),
269 jn_use_case_from_feature_use_cases: RwLock::new(
270 g_jn_use_case_from_feature_use_cases.clone(),
271 ),
272 jn_entity_from_file_entity: RwLock::new(g_jn_entity_from_file_entity.clone()),
273 jn_feature_from_file_feature: RwLock::new(g_jn_feature_from_file_feature.clone()),
274 jn_field_from_file_field: RwLock::new(g_jn_field_from_file_field.clone()),
275 jn_use_case_from_file_use_case: RwLock::new(g_jn_use_case_from_file_use_case.clone()),
276 jn_dto_from_use_case_dto_in: RwLock::new(g_jn_dto_from_use_case_dto_in.clone()),
277 jn_dto_from_use_case_dto_out: RwLock::new(g_jn_dto_from_use_case_dto_out.clone()),
278 jn_entity_from_use_case_entities: RwLock::new(
279 g_jn_entity_from_use_case_entities.clone(),
280 ),
281 jn_dto_field_from_dto_fields: RwLock::new(g_jn_dto_field_from_dto_fields.clone()),
282 jn_entity_from_relationship_left_entity: RwLock::new(
283 g_jn_entity_from_relationship_left_entity.clone(),
284 ),
285 jn_entity_from_relationship_right_entity: RwLock::new(
286 g_jn_entity_from_relationship_right_entity.clone(),
287 ),
288 counters: RwLock::new(g_counters.clone()),
289 savepoints: RwLock::new(std::collections::HashMap::new()),
290 next_savepoint_id: RwLock::new(0),
291 }
292 }
293
294 pub fn restore(&self, snap: &HashMapStoreSnapshot) {
296 *write_or_recover(&self.roots) = snap.roots.clone();
297 *write_or_recover(&self.workspaces) = snap.workspaces.clone();
298 *write_or_recover(&self.systems) = snap.systems.clone();
299 *write_or_recover(&self.entities) = snap.entities.clone();
300 *write_or_recover(&self.fields) = snap.fields.clone();
301 *write_or_recover(&self.features) = snap.features.clone();
302 *write_or_recover(&self.files) = snap.files.clone();
303 *write_or_recover(&self.use_cases) = snap.use_cases.clone();
304 *write_or_recover(&self.dtos) = snap.dtos.clone();
305 *write_or_recover(&self.dto_fields) = snap.dto_fields.clone();
306 *write_or_recover(&self.globals) = snap.globals.clone();
307 *write_or_recover(&self.relationships) = snap.relationships.clone();
308 *write_or_recover(&self.user_interfaces) = snap.user_interfaces.clone();
309 *write_or_recover(&self.jn_system_from_root_system) =
310 snap.jn_system_from_root_system.clone();
311 *write_or_recover(&self.jn_workspace_from_root_workspace) =
312 snap.jn_workspace_from_root_workspace.clone();
313 *write_or_recover(&self.jn_entity_from_workspace_entities) =
314 snap.jn_entity_from_workspace_entities.clone();
315 *write_or_recover(&self.jn_feature_from_workspace_features) =
316 snap.jn_feature_from_workspace_features.clone();
317 *write_or_recover(&self.jn_global_from_workspace_global) =
318 snap.jn_global_from_workspace_global.clone();
319 *write_or_recover(&self.jn_user_interface_from_workspace_user_interface) =
320 snap.jn_user_interface_from_workspace_user_interface.clone();
321 *write_or_recover(&self.jn_file_from_system_files) = snap.jn_file_from_system_files.clone();
322 *write_or_recover(&self.jn_field_from_entity_fields) =
323 snap.jn_field_from_entity_fields.clone();
324 *write_or_recover(&self.jn_entity_from_entity_inherits_from) =
325 snap.jn_entity_from_entity_inherits_from.clone();
326 *write_or_recover(&self.jn_relationship_from_entity_relationships) =
327 snap.jn_relationship_from_entity_relationships.clone();
328 *write_or_recover(&self.jn_entity_from_field_entity) =
329 snap.jn_entity_from_field_entity.clone();
330 *write_or_recover(&self.jn_use_case_from_feature_use_cases) =
331 snap.jn_use_case_from_feature_use_cases.clone();
332 *write_or_recover(&self.jn_entity_from_file_entity) =
333 snap.jn_entity_from_file_entity.clone();
334 *write_or_recover(&self.jn_feature_from_file_feature) =
335 snap.jn_feature_from_file_feature.clone();
336 *write_or_recover(&self.jn_field_from_file_field) = snap.jn_field_from_file_field.clone();
337 *write_or_recover(&self.jn_use_case_from_file_use_case) =
338 snap.jn_use_case_from_file_use_case.clone();
339 *write_or_recover(&self.jn_dto_from_use_case_dto_in) =
340 snap.jn_dto_from_use_case_dto_in.clone();
341 *write_or_recover(&self.jn_dto_from_use_case_dto_out) =
342 snap.jn_dto_from_use_case_dto_out.clone();
343 *write_or_recover(&self.jn_entity_from_use_case_entities) =
344 snap.jn_entity_from_use_case_entities.clone();
345 *write_or_recover(&self.jn_dto_field_from_dto_fields) =
346 snap.jn_dto_field_from_dto_fields.clone();
347 *write_or_recover(&self.jn_entity_from_relationship_left_entity) =
348 snap.jn_entity_from_relationship_left_entity.clone();
349 *write_or_recover(&self.jn_entity_from_relationship_right_entity) =
350 snap.jn_entity_from_relationship_right_entity.clone();
351 *write_or_recover(&self.counters) = snap.counters.clone();
352 }
353
354 pub fn create_savepoint(&self) -> u64 {
357 let snap = self.snapshot();
358 let mut id_counter = write_or_recover(&self.next_savepoint_id);
359 let id = *id_counter;
360 *id_counter += 1;
361 write_or_recover(&self.savepoints).insert(id, snap);
362 id
363 }
364
365 pub fn restore_savepoint(&self, savepoint_id: u64) {
367 let Some(snap) = read_or_recover(&self.savepoints)
377 .get(&savepoint_id)
378 .cloned()
379 else {
380 debug_assert!(
381 false,
382 "restore_savepoint: savepoint {savepoint_id} does not exist — it was already \
383 restored, discarded, or never created"
384 );
385 return;
386 };
387 self.restore(&snap);
388 }
389
390 pub fn discard_savepoint(&self, savepoint_id: u64) {
393 write_or_recover(&self.savepoints).remove(&savepoint_id);
394 }
395
396 pub(crate) fn next_id(&self, entity_name: &str) -> EntityId {
398 let mut counters = write_or_recover(&self.counters);
399 let counter = counters.entry(entity_name.to_string()).or_insert(1);
400 let id = *counter;
401 *counter += 1;
402 id
403 }
404
405 pub fn restore_without_counters(&self, snap: &HashMapStoreSnapshot) {
408 *write_or_recover(&self.roots) = snap.roots.clone();
409 *write_or_recover(&self.workspaces) = snap.workspaces.clone();
410 *write_or_recover(&self.systems) = snap.systems.clone();
411 *write_or_recover(&self.entities) = snap.entities.clone();
412 *write_or_recover(&self.fields) = snap.fields.clone();
413 *write_or_recover(&self.features) = snap.features.clone();
414 *write_or_recover(&self.files) = snap.files.clone();
415 *write_or_recover(&self.use_cases) = snap.use_cases.clone();
416 *write_or_recover(&self.dtos) = snap.dtos.clone();
417 *write_or_recover(&self.dto_fields) = snap.dto_fields.clone();
418 *write_or_recover(&self.globals) = snap.globals.clone();
419 *write_or_recover(&self.relationships) = snap.relationships.clone();
420 *write_or_recover(&self.user_interfaces) = snap.user_interfaces.clone();
421 *write_or_recover(&self.jn_system_from_root_system) =
422 snap.jn_system_from_root_system.clone();
423 *write_or_recover(&self.jn_workspace_from_root_workspace) =
424 snap.jn_workspace_from_root_workspace.clone();
425 *write_or_recover(&self.jn_entity_from_workspace_entities) =
426 snap.jn_entity_from_workspace_entities.clone();
427 *write_or_recover(&self.jn_feature_from_workspace_features) =
428 snap.jn_feature_from_workspace_features.clone();
429 *write_or_recover(&self.jn_global_from_workspace_global) =
430 snap.jn_global_from_workspace_global.clone();
431 *write_or_recover(&self.jn_user_interface_from_workspace_user_interface) =
432 snap.jn_user_interface_from_workspace_user_interface.clone();
433 *write_or_recover(&self.jn_file_from_system_files) = snap.jn_file_from_system_files.clone();
434 *write_or_recover(&self.jn_field_from_entity_fields) =
435 snap.jn_field_from_entity_fields.clone();
436 *write_or_recover(&self.jn_entity_from_entity_inherits_from) =
437 snap.jn_entity_from_entity_inherits_from.clone();
438 *write_or_recover(&self.jn_relationship_from_entity_relationships) =
439 snap.jn_relationship_from_entity_relationships.clone();
440 *write_or_recover(&self.jn_entity_from_field_entity) =
441 snap.jn_entity_from_field_entity.clone();
442 *write_or_recover(&self.jn_use_case_from_feature_use_cases) =
443 snap.jn_use_case_from_feature_use_cases.clone();
444 *write_or_recover(&self.jn_entity_from_file_entity) =
445 snap.jn_entity_from_file_entity.clone();
446 *write_or_recover(&self.jn_feature_from_file_feature) =
447 snap.jn_feature_from_file_feature.clone();
448 *write_or_recover(&self.jn_field_from_file_field) = snap.jn_field_from_file_field.clone();
449 *write_or_recover(&self.jn_use_case_from_file_use_case) =
450 snap.jn_use_case_from_file_use_case.clone();
451 *write_or_recover(&self.jn_dto_from_use_case_dto_in) =
452 snap.jn_dto_from_use_case_dto_in.clone();
453 *write_or_recover(&self.jn_dto_from_use_case_dto_out) =
454 snap.jn_dto_from_use_case_dto_out.clone();
455 *write_or_recover(&self.jn_entity_from_use_case_entities) =
456 snap.jn_entity_from_use_case_entities.clone();
457 *write_or_recover(&self.jn_dto_field_from_dto_fields) =
458 snap.jn_dto_field_from_dto_fields.clone();
459 *write_or_recover(&self.jn_entity_from_relationship_left_entity) =
460 snap.jn_entity_from_relationship_left_entity.clone();
461 *write_or_recover(&self.jn_entity_from_relationship_right_entity) =
462 snap.jn_entity_from_relationship_right_entity.clone();
463 }
465
466 pub fn store_snapshot(&self) -> StoreSnapshot {
468 StoreSnapshot::new(self.snapshot())
469 }
470
471 pub fn restore_store_snapshot(&self, snap: &StoreSnapshot) {
473 let s = snap
474 .downcast_ref::<HashMapStoreSnapshot>()
475 .expect("StoreSnapshot must contain HashMapStoreSnapshot");
476 self.restore_without_counters(s);
477 }
478}
479
480#[derive(Debug, Clone)]
486pub struct HashMapStoreSnapshot {
487 pub(crate) roots: HashMap<EntityId, Root>,
488 pub(crate) workspaces: HashMap<EntityId, Workspace>,
489 pub(crate) systems: HashMap<EntityId, System>,
490 pub(crate) entities: HashMap<EntityId, Entity>,
491 pub(crate) fields: HashMap<EntityId, Field>,
492 pub(crate) features: HashMap<EntityId, Feature>,
493 pub(crate) files: HashMap<EntityId, File>,
494 pub(crate) use_cases: HashMap<EntityId, UseCase>,
495 pub(crate) dtos: HashMap<EntityId, Dto>,
496 pub(crate) dto_fields: HashMap<EntityId, DtoField>,
497 pub(crate) globals: HashMap<EntityId, Global>,
498 pub(crate) relationships: HashMap<EntityId, Relationship>,
499 pub(crate) user_interfaces: HashMap<EntityId, UserInterface>,
500 pub(crate) jn_system_from_root_system: HashMap<EntityId, Vec<EntityId>>,
501 pub(crate) jn_workspace_from_root_workspace: HashMap<EntityId, Vec<EntityId>>,
502 pub(crate) jn_entity_from_workspace_entities: HashMap<EntityId, Vec<EntityId>>,
503 pub(crate) jn_feature_from_workspace_features: HashMap<EntityId, Vec<EntityId>>,
504 pub(crate) jn_global_from_workspace_global: HashMap<EntityId, Vec<EntityId>>,
505 pub(crate) jn_user_interface_from_workspace_user_interface: HashMap<EntityId, Vec<EntityId>>,
506 pub(crate) jn_file_from_system_files: HashMap<EntityId, Vec<EntityId>>,
507 pub(crate) jn_field_from_entity_fields: HashMap<EntityId, Vec<EntityId>>,
508 pub(crate) jn_entity_from_entity_inherits_from: HashMap<EntityId, Vec<EntityId>>,
509 pub(crate) jn_relationship_from_entity_relationships: HashMap<EntityId, Vec<EntityId>>,
510 pub(crate) jn_entity_from_field_entity: HashMap<EntityId, Vec<EntityId>>,
511 pub(crate) jn_use_case_from_feature_use_cases: HashMap<EntityId, Vec<EntityId>>,
512 pub(crate) jn_entity_from_file_entity: HashMap<EntityId, Vec<EntityId>>,
513 pub(crate) jn_feature_from_file_feature: HashMap<EntityId, Vec<EntityId>>,
514 pub(crate) jn_field_from_file_field: HashMap<EntityId, Vec<EntityId>>,
515 pub(crate) jn_use_case_from_file_use_case: HashMap<EntityId, Vec<EntityId>>,
516 pub(crate) jn_dto_from_use_case_dto_in: HashMap<EntityId, Vec<EntityId>>,
517 pub(crate) jn_dto_from_use_case_dto_out: HashMap<EntityId, Vec<EntityId>>,
518 pub(crate) jn_entity_from_use_case_entities: HashMap<EntityId, Vec<EntityId>>,
519 pub(crate) jn_dto_field_from_dto_fields: HashMap<EntityId, Vec<EntityId>>,
520 pub(crate) jn_entity_from_relationship_left_entity: HashMap<EntityId, Vec<EntityId>>,
521 pub(crate) jn_entity_from_relationship_right_entity: HashMap<EntityId, Vec<EntityId>>,
522 counters: std::collections::HashMap<String, EntityId>,
523}
524
525impl StoreSnapshotTrait for HashMapStoreSnapshot {
526 fn clone_box(&self) -> Box<dyn StoreSnapshotTrait> {
527 Box::new(self.clone())
528 }
529
530 fn as_any(&self) -> &dyn std::any::Any {
531 self
532 }
533}
534
535pub(crate) fn read_or_recover<T>(lock: &RwLock<T>) -> std::sync::RwLockReadGuard<'_, T> {
547 match lock.read() {
548 Ok(guard) => guard,
549 Err(poisoned) => {
550 let guard = poisoned.into_inner();
551 lock.clear_poison();
552 guard
553 }
554 }
555}
556
557pub(crate) fn write_or_recover<T>(lock: &RwLock<T>) -> std::sync::RwLockWriteGuard<'_, T> {
559 match lock.write() {
560 Ok(guard) => guard,
561 Err(poisoned) => {
562 let guard = poisoned.into_inner();
563 lock.clear_poison();
564 guard
565 }
566 }
567}
568
569pub(crate) fn delete_from_backward_junction(
570 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
571 id: &EntityId,
572) {
573 let mut jn = write_or_recover(junction);
574 let keys: Vec<EntityId> = jn.keys().copied().collect();
575 for k in keys {
576 if let Some(right_ids) = jn.get(&k)
580 && right_ids.contains(id)
581 {
582 let filtered: Vec<EntityId> =
583 right_ids.iter().copied().filter(|eid| eid != id).collect();
584 jn.insert(k, filtered);
585 }
586 }
587}
588
589pub(crate) fn junction_get(
590 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
591 id: &EntityId,
592) -> Vec<EntityId> {
593 read_or_recover(junction)
594 .get(id)
595 .cloned()
596 .unwrap_or_default()
597}
598
599pub(crate) fn junction_set(
600 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
601 id: EntityId,
602 ids: Vec<EntityId>,
603) {
604 write_or_recover(junction).insert(id, ids);
605}
606
607pub(crate) fn junction_remove(junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>, id: &EntityId) {
608 write_or_recover(junction).remove(id);
609}
610
611pub(crate) fn junction_get_relationships_from_right_ids(
612 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
613 right_ids: &[EntityId],
614) -> Vec<(EntityId, Vec<EntityId>)> {
615 let jn = read_or_recover(junction);
616 jn.iter()
617 .filter(|(_, rids)| right_ids.iter().any(|eid| rids.contains(eid)))
618 .map(|(left_id, rids)| (*left_id, rids.clone()))
619 .collect()
620}
621
622pub(crate) fn junction_move_ids(
623 junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
624 id: &EntityId,
625 ids_to_move: &[EntityId],
626 new_index: i32,
627) -> Vec<EntityId> {
628 let current = junction_get(junction, id);
629 if ids_to_move.is_empty() {
630 return current;
631 }
632 let move_set: std::collections::HashSet<EntityId> = ids_to_move.iter().copied().collect();
633 let mut remaining: Vec<EntityId> = current
634 .into_iter()
635 .filter(|eid| !move_set.contains(eid))
636 .collect();
637 let insert_pos = if new_index < 0 || (new_index as usize) > remaining.len() {
638 remaining.len()
639 } else {
640 new_index as usize
641 };
642 for (i, &eid) in ids_to_move.iter().enumerate() {
643 remaining.insert(insert_pos + i, eid);
644 }
645 junction_set(junction, *id, remaining.clone());
646 remaining
647}
648
649pub(crate) fn reconcile_backref_list(
658 live_list: &[EntityId],
659 snap_list: &[EntityId],
660 scope: &std::collections::HashSet<EntityId>,
661) -> Vec<EntityId> {
662 let snap_members: Vec<EntityId> = snap_list
664 .iter()
665 .copied()
666 .filter(|x| scope.contains(x))
667 .collect();
668 let snap_member_set: std::collections::HashSet<EntityId> =
669 snap_members.iter().copied().collect();
670
671 let mut work: Vec<EntityId> = live_list
673 .iter()
674 .copied()
675 .filter(|x| !scope.contains(x) || snap_member_set.contains(x))
679 .collect();
680
681 for id in &snap_members {
684 if work.contains(id) {
685 continue;
686 }
687 let snap_idx = snap_list.iter().position(|x| x == id).unwrap_or(0);
688 let pos = snap_list[..snap_idx]
689 .iter()
690 .filter(|x| work.contains(x))
691 .count()
692 .min(work.len());
693 work.insert(pos, *id);
694 }
695 work
696}
697
698#[macro_export]
704macro_rules! impl_relationship_methods {
705 ($table_type:ty, $field_enum:ty) => {
706 fn get_relationship(
707 &self,
708 id: &$crate::types::EntityId,
709 field: &$field_enum,
710 ) -> Result<Vec<$crate::types::EntityId>, $crate::error::RepositoryError> {
711 Ok($crate::database::hashmap_store::junction_get(
712 self.resolve_junction(field),
713 id,
714 ))
715 }
716
717 fn get_relationship_many(
718 &self,
719 ids: &[$crate::types::EntityId],
720 field: &$field_enum,
721 ) -> Result<
722 std::collections::HashMap<$crate::types::EntityId, Vec<$crate::types::EntityId>>,
723 $crate::error::RepositoryError,
724 > {
725 let jn = self.resolve_junction(field);
726 let mut map = std::collections::HashMap::new();
727 for id in ids {
728 map.insert(*id, $crate::database::hashmap_store::junction_get(jn, id));
729 }
730 Ok(map)
731 }
732
733 fn get_relationship_count(
734 &self,
735 id: &$crate::types::EntityId,
736 field: &$field_enum,
737 ) -> Result<usize, $crate::error::RepositoryError> {
738 Ok(
739 $crate::database::hashmap_store::junction_get(self.resolve_junction(field), id)
740 .len(),
741 )
742 }
743
744 fn get_relationship_in_range(
745 &self,
746 id: &$crate::types::EntityId,
747 field: &$field_enum,
748 offset: usize,
749 limit: usize,
750 ) -> Result<Vec<$crate::types::EntityId>, $crate::error::RepositoryError> {
751 let all =
752 $crate::database::hashmap_store::junction_get(self.resolve_junction(field), id);
753 Ok(all.into_iter().skip(offset).take(limit).collect())
754 }
755
756 fn get_relationships_from_right_ids(
757 &self,
758 field: &$field_enum,
759 right_ids: &[$crate::types::EntityId],
760 ) -> Result<
761 Vec<($crate::types::EntityId, Vec<$crate::types::EntityId>)>,
762 $crate::error::RepositoryError,
763 > {
764 Ok(
765 $crate::database::hashmap_store::junction_get_relationships_from_right_ids(
766 self.resolve_junction(field),
767 right_ids,
768 ),
769 )
770 }
771 };
772}
773
774#[macro_export]
775macro_rules! impl_write_relationship_methods {
776 ($table_type:ty, $field_enum:ty) => {
777 $crate::impl_relationship_methods!($table_type, $field_enum);
778
779 fn set_relationship_multi(
780 &mut self,
781 field: &$field_enum,
782 relationships: Vec<($crate::types::EntityId, Vec<$crate::types::EntityId>)>,
783 ) -> Result<(), $crate::error::RepositoryError> {
784 let jn = self.resolve_junction(field);
785 for (left_id, entities) in relationships {
786 $crate::database::hashmap_store::junction_set(jn, left_id, entities);
787 }
788 Ok(())
789 }
790
791 fn set_relationship(
792 &mut self,
793 id: &$crate::types::EntityId,
794 field: &$field_enum,
795 right_ids: &[$crate::types::EntityId],
796 ) -> Result<(), $crate::error::RepositoryError> {
797 $crate::database::hashmap_store::junction_set(
798 self.resolve_junction(field),
799 *id,
800 right_ids.to_vec(),
801 );
802 Ok(())
803 }
804
805 fn move_relationship_ids(
806 &mut self,
807 id: &$crate::types::EntityId,
808 field: &$field_enum,
809 ids_to_move: &[$crate::types::EntityId],
810 new_index: i32,
811 ) -> Result<Vec<$crate::types::EntityId>, $crate::error::RepositoryError> {
812 Ok($crate::database::hashmap_store::junction_move_ids(
813 self.resolve_junction(field),
814 id,
815 ids_to_move,
816 new_index,
817 ))
818 }
819 };
820}
821
822#[macro_export]
827macro_rules! impl_leaf_entity_table {
828 (
829 entity: $Entity:ident,
830 entity_name: $entity_name:expr,
831 store_field: $store_field:ident,
832 table_trait: $TableTrait:ident,
833 table_ro_trait: $TableROTrait:ident,
834 table_struct: $TableStruct:ident,
835 table_ro_struct: $TableROStruct:ident,
836 backward_junctions: [ $( ($bj_field:ident) ),* $(,)? ],
837 ) => {
838 pub struct $TableStruct<'a> {
839 store: &'a $crate::database::hashmap_store::HashMapStore,
840 }
841
842 impl<'a> $TableStruct<'a> {
843 pub fn new(store: &'a $crate::database::hashmap_store::HashMapStore) -> Self {
844 Self { store }
845 }
846 }
847
848 impl<'a> $TableTrait for $TableStruct<'a> {
849 fn create(&mut self, entity: &$Entity) -> Result<$Entity, $crate::error::RepositoryError> {
850 self.create_multi(std::slice::from_ref(entity))
851 .and_then(|v| {
852 v.into_iter().next().ok_or_else(|| {
853 $crate::error::RepositoryError::Other(::anyhow::anyhow!(
854 "create: the store returned no row for the entity it was given"
855 ))
856 })
857 })
858 }
859
860 fn create_multi(&mut self, entities: &[$Entity]) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
861 let mut created = Vec::with_capacity(entities.len());
862 let mut map = $crate::database::hashmap_store::write_or_recover(&self.store.$store_field);
863
864 for entity in entities {
865 let new_entity = if entity.id == $crate::types::EntityId::default() {
866 let id = self.store.next_id($entity_name);
867 $Entity {
868 id,
869 ..entity.clone()
870 }
871 } else {
872 if map.contains_key(&entity.id) {
873 return Err($crate::error::RepositoryError::DuplicateId {
874 entity: stringify!($Entity),
875 id: entity.id,
876 });
877 }
878 entity.clone()
879 };
880
881 map.insert(new_entity.id, new_entity.clone());
882 created.push(new_entity);
883 }
884 Ok(created)
885 }
886
887 fn get(&self, id: &$crate::types::EntityId) -> Result<Option<$Entity>, $crate::error::RepositoryError> {
888 Ok($crate::database::hashmap_store::read_or_recover(&self.store.$store_field).get(id).cloned())
889 }
890
891 fn get_multi(&self, ids: &[$crate::types::EntityId]) -> Result<Vec<Option<$Entity>>, $crate::error::RepositoryError> {
892 let map = $crate::database::hashmap_store::read_or_recover(&self.store.$store_field);
893 Ok(ids.iter().map(|id| map.get(id).cloned()).collect())
894 }
895
896 fn get_all(&self) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
897 Ok($crate::database::hashmap_store::read_or_recover(&self.store.$store_field).values().cloned().collect())
898 }
899
900 fn update(&mut self, entity: &$Entity) -> Result<$Entity, $crate::error::RepositoryError> {
901 self.update_multi(std::slice::from_ref(entity))
902 .and_then(|v| {
903 v.into_iter().next().ok_or_else(|| {
904 $crate::error::RepositoryError::Other(::anyhow::anyhow!(
905 "update: the store returned no row for the entity it was given"
906 ))
907 })
908 })
909 }
910
911 fn update_multi(&mut self, entities: &[$Entity]) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
912 let mut map = $crate::database::hashmap_store::write_or_recover(&self.store.$store_field);
913 let mut result = Vec::with_capacity(entities.len());
914 for entity in entities {
915 map.insert(entity.id, entity.clone());
916 result.push(entity.clone());
917 }
918 Ok(result)
919 }
920
921 fn update_with_relationships(&mut self, entity: &$Entity) -> Result<$Entity, $crate::error::RepositoryError> {
922 self.update(entity)
923 }
924
925 fn update_with_relationships_multi(&mut self, entities: &[$Entity]) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
926 self.update_multi(entities)
927 }
928
929 fn remove(&mut self, id: &$crate::types::EntityId) -> Result<(), $crate::error::RepositoryError> {
930 self.remove_multi(std::slice::from_ref(id))
931 }
932
933 fn remove_multi(&mut self, ids: &[$crate::types::EntityId]) -> Result<(), $crate::error::RepositoryError> {
934 let mut map = $crate::database::hashmap_store::write_or_recover(&self.store.$store_field);
935 for id in ids {
936 map.remove(id);
937 $(
938 $crate::database::hashmap_store::delete_from_backward_junction(&self.store.$bj_field, id);
939 )*
940 }
941 Ok(())
942 }
943 }
944
945 pub struct $TableROStruct<'a> {
946 store: &'a $crate::database::hashmap_store::HashMapStore,
947 }
948
949 impl<'a> $TableROStruct<'a> {
950 pub fn new(store: &'a $crate::database::hashmap_store::HashMapStore) -> Self {
951 Self { store }
952 }
953 }
954
955 impl<'a> $TableROTrait for $TableROStruct<'a> {
956 fn get(&self, id: &$crate::types::EntityId) -> Result<Option<$Entity>, $crate::error::RepositoryError> {
957 Ok($crate::database::hashmap_store::read_or_recover(&self.store.$store_field).get(id).cloned())
958 }
959
960 fn get_multi(&self, ids: &[$crate::types::EntityId]) -> Result<Vec<Option<$Entity>>, $crate::error::RepositoryError> {
961 let map = $crate::database::hashmap_store::read_or_recover(&self.store.$store_field);
962 Ok(ids.iter().map(|id| map.get(id).cloned()).collect())
963 }
964
965 fn get_all(&self) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
966 Ok($crate::database::hashmap_store::read_or_recover(&self.store.$store_field).values().cloned().collect())
967 }
968 }
969 };
970}