use crate::entities::*;
use crate::snapshot::{StoreSnapshot, StoreSnapshotTrait};
use crate::types::EntityId;
use im::HashMap;
use std::sync::RwLock;
#[derive(Debug, Default)]
pub struct HashMapStore {
pub roots: RwLock<HashMap<EntityId, Root>>,
pub workspaces: RwLock<HashMap<EntityId, Workspace>>,
pub systems: RwLock<HashMap<EntityId, System>>,
pub entities: RwLock<HashMap<EntityId, Entity>>,
pub fields: RwLock<HashMap<EntityId, Field>>,
pub features: RwLock<HashMap<EntityId, Feature>>,
pub files: RwLock<HashMap<EntityId, File>>,
pub use_cases: RwLock<HashMap<EntityId, UseCase>>,
pub dtos: RwLock<HashMap<EntityId, Dto>>,
pub dto_fields: RwLock<HashMap<EntityId, DtoField>>,
pub globals: RwLock<HashMap<EntityId, Global>>,
pub relationships: RwLock<HashMap<EntityId, Relationship>>,
pub user_interfaces: RwLock<HashMap<EntityId, UserInterface>>,
pub jn_system_from_root_system: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_workspace_from_root_workspace: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_entity_from_workspace_entities: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_feature_from_workspace_features: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_global_from_workspace_global: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_user_interface_from_workspace_user_interface: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_file_from_system_files: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_field_from_entity_fields: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_entity_from_entity_inherits_from: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_relationship_from_entity_relationships: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_entity_from_field_entity: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_use_case_from_feature_use_cases: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_entity_from_file_entity: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_feature_from_file_feature: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_field_from_file_field: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_use_case_from_file_use_case: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_dto_from_use_case_dto_in: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_dto_from_use_case_dto_out: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_entity_from_use_case_entities: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_dto_field_from_dto_fields: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_entity_from_relationship_left_entity: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub jn_entity_from_relationship_right_entity: RwLock<HashMap<EntityId, Vec<EntityId>>>,
pub counters: RwLock<std::collections::HashMap<String, EntityId>>,
savepoints: RwLock<std::collections::HashMap<u64, HashMapStoreSnapshot>>,
next_savepoint_id: RwLock<u64>,
}
impl HashMapStore {
pub fn new() -> Self {
Self::default()
}
pub fn snapshot(&self) -> HashMapStoreSnapshot {
HashMapStoreSnapshot {
roots: self.roots.read().unwrap().clone(),
workspaces: self.workspaces.read().unwrap().clone(),
systems: self.systems.read().unwrap().clone(),
entities: self.entities.read().unwrap().clone(),
fields: self.fields.read().unwrap().clone(),
features: self.features.read().unwrap().clone(),
files: self.files.read().unwrap().clone(),
use_cases: self.use_cases.read().unwrap().clone(),
dtos: self.dtos.read().unwrap().clone(),
dto_fields: self.dto_fields.read().unwrap().clone(),
globals: self.globals.read().unwrap().clone(),
relationships: self.relationships.read().unwrap().clone(),
user_interfaces: self.user_interfaces.read().unwrap().clone(),
jn_system_from_root_system: self.jn_system_from_root_system.read().unwrap().clone(),
jn_workspace_from_root_workspace: self
.jn_workspace_from_root_workspace
.read()
.unwrap()
.clone(),
jn_entity_from_workspace_entities: self
.jn_entity_from_workspace_entities
.read()
.unwrap()
.clone(),
jn_feature_from_workspace_features: self
.jn_feature_from_workspace_features
.read()
.unwrap()
.clone(),
jn_global_from_workspace_global: self
.jn_global_from_workspace_global
.read()
.unwrap()
.clone(),
jn_user_interface_from_workspace_user_interface: self
.jn_user_interface_from_workspace_user_interface
.read()
.unwrap()
.clone(),
jn_file_from_system_files: self.jn_file_from_system_files.read().unwrap().clone(),
jn_field_from_entity_fields: self.jn_field_from_entity_fields.read().unwrap().clone(),
jn_entity_from_entity_inherits_from: self
.jn_entity_from_entity_inherits_from
.read()
.unwrap()
.clone(),
jn_relationship_from_entity_relationships: self
.jn_relationship_from_entity_relationships
.read()
.unwrap()
.clone(),
jn_entity_from_field_entity: self.jn_entity_from_field_entity.read().unwrap().clone(),
jn_use_case_from_feature_use_cases: self
.jn_use_case_from_feature_use_cases
.read()
.unwrap()
.clone(),
jn_entity_from_file_entity: self.jn_entity_from_file_entity.read().unwrap().clone(),
jn_feature_from_file_feature: self.jn_feature_from_file_feature.read().unwrap().clone(),
jn_field_from_file_field: self.jn_field_from_file_field.read().unwrap().clone(),
jn_use_case_from_file_use_case: self
.jn_use_case_from_file_use_case
.read()
.unwrap()
.clone(),
jn_dto_from_use_case_dto_in: self.jn_dto_from_use_case_dto_in.read().unwrap().clone(),
jn_dto_from_use_case_dto_out: self.jn_dto_from_use_case_dto_out.read().unwrap().clone(),
jn_entity_from_use_case_entities: self
.jn_entity_from_use_case_entities
.read()
.unwrap()
.clone(),
jn_dto_field_from_dto_fields: self.jn_dto_field_from_dto_fields.read().unwrap().clone(),
jn_entity_from_relationship_left_entity: self
.jn_entity_from_relationship_left_entity
.read()
.unwrap()
.clone(),
jn_entity_from_relationship_right_entity: self
.jn_entity_from_relationship_right_entity
.read()
.unwrap()
.clone(),
counters: self.counters.read().unwrap().clone(),
}
}
pub fn restore(&self, snap: &HashMapStoreSnapshot) {
*self.roots.write().unwrap() = snap.roots.clone();
*self.workspaces.write().unwrap() = snap.workspaces.clone();
*self.systems.write().unwrap() = snap.systems.clone();
*self.entities.write().unwrap() = snap.entities.clone();
*self.fields.write().unwrap() = snap.fields.clone();
*self.features.write().unwrap() = snap.features.clone();
*self.files.write().unwrap() = snap.files.clone();
*self.use_cases.write().unwrap() = snap.use_cases.clone();
*self.dtos.write().unwrap() = snap.dtos.clone();
*self.dto_fields.write().unwrap() = snap.dto_fields.clone();
*self.globals.write().unwrap() = snap.globals.clone();
*self.relationships.write().unwrap() = snap.relationships.clone();
*self.user_interfaces.write().unwrap() = snap.user_interfaces.clone();
*self.jn_system_from_root_system.write().unwrap() = snap.jn_system_from_root_system.clone();
*self.jn_workspace_from_root_workspace.write().unwrap() =
snap.jn_workspace_from_root_workspace.clone();
*self.jn_entity_from_workspace_entities.write().unwrap() =
snap.jn_entity_from_workspace_entities.clone();
*self.jn_feature_from_workspace_features.write().unwrap() =
snap.jn_feature_from_workspace_features.clone();
*self.jn_global_from_workspace_global.write().unwrap() =
snap.jn_global_from_workspace_global.clone();
*self
.jn_user_interface_from_workspace_user_interface
.write()
.unwrap() = snap.jn_user_interface_from_workspace_user_interface.clone();
*self.jn_file_from_system_files.write().unwrap() = snap.jn_file_from_system_files.clone();
*self.jn_field_from_entity_fields.write().unwrap() =
snap.jn_field_from_entity_fields.clone();
*self.jn_entity_from_entity_inherits_from.write().unwrap() =
snap.jn_entity_from_entity_inherits_from.clone();
*self
.jn_relationship_from_entity_relationships
.write()
.unwrap() = snap.jn_relationship_from_entity_relationships.clone();
*self.jn_entity_from_field_entity.write().unwrap() =
snap.jn_entity_from_field_entity.clone();
*self.jn_use_case_from_feature_use_cases.write().unwrap() =
snap.jn_use_case_from_feature_use_cases.clone();
*self.jn_entity_from_file_entity.write().unwrap() = snap.jn_entity_from_file_entity.clone();
*self.jn_feature_from_file_feature.write().unwrap() =
snap.jn_feature_from_file_feature.clone();
*self.jn_field_from_file_field.write().unwrap() = snap.jn_field_from_file_field.clone();
*self.jn_use_case_from_file_use_case.write().unwrap() =
snap.jn_use_case_from_file_use_case.clone();
*self.jn_dto_from_use_case_dto_in.write().unwrap() =
snap.jn_dto_from_use_case_dto_in.clone();
*self.jn_dto_from_use_case_dto_out.write().unwrap() =
snap.jn_dto_from_use_case_dto_out.clone();
*self.jn_entity_from_use_case_entities.write().unwrap() =
snap.jn_entity_from_use_case_entities.clone();
*self.jn_dto_field_from_dto_fields.write().unwrap() =
snap.jn_dto_field_from_dto_fields.clone();
*self
.jn_entity_from_relationship_left_entity
.write()
.unwrap() = snap.jn_entity_from_relationship_left_entity.clone();
*self
.jn_entity_from_relationship_right_entity
.write()
.unwrap() = snap.jn_entity_from_relationship_right_entity.clone();
*self.counters.write().unwrap() = snap.counters.clone();
}
pub fn create_savepoint(&self) -> u64 {
let snap = self.snapshot();
let mut id_counter = self.next_savepoint_id.write().unwrap();
let id = *id_counter;
*id_counter += 1;
self.savepoints.write().unwrap().insert(id, snap);
id
}
pub fn restore_savepoint(&self, savepoint_id: u64) {
let snap = self
.savepoints
.read()
.unwrap()
.get(&savepoint_id)
.expect("savepoint not found")
.clone();
self.restore(&snap);
}
pub fn discard_savepoint(&self, savepoint_id: u64) {
self.savepoints.write().unwrap().remove(&savepoint_id);
}
pub(crate) fn next_id(&self, entity_name: &str) -> EntityId {
let mut counters = self.counters.write().unwrap();
let counter = counters.entry(entity_name.to_string()).or_insert(1);
let id = *counter;
*counter += 1;
id
}
pub fn restore_without_counters(&self, snap: &HashMapStoreSnapshot) {
*self.roots.write().unwrap() = snap.roots.clone();
*self.workspaces.write().unwrap() = snap.workspaces.clone();
*self.systems.write().unwrap() = snap.systems.clone();
*self.entities.write().unwrap() = snap.entities.clone();
*self.fields.write().unwrap() = snap.fields.clone();
*self.features.write().unwrap() = snap.features.clone();
*self.files.write().unwrap() = snap.files.clone();
*self.use_cases.write().unwrap() = snap.use_cases.clone();
*self.dtos.write().unwrap() = snap.dtos.clone();
*self.dto_fields.write().unwrap() = snap.dto_fields.clone();
*self.globals.write().unwrap() = snap.globals.clone();
*self.relationships.write().unwrap() = snap.relationships.clone();
*self.user_interfaces.write().unwrap() = snap.user_interfaces.clone();
*self.jn_system_from_root_system.write().unwrap() = snap.jn_system_from_root_system.clone();
*self.jn_workspace_from_root_workspace.write().unwrap() =
snap.jn_workspace_from_root_workspace.clone();
*self.jn_entity_from_workspace_entities.write().unwrap() =
snap.jn_entity_from_workspace_entities.clone();
*self.jn_feature_from_workspace_features.write().unwrap() =
snap.jn_feature_from_workspace_features.clone();
*self.jn_global_from_workspace_global.write().unwrap() =
snap.jn_global_from_workspace_global.clone();
*self
.jn_user_interface_from_workspace_user_interface
.write()
.unwrap() = snap.jn_user_interface_from_workspace_user_interface.clone();
*self.jn_file_from_system_files.write().unwrap() = snap.jn_file_from_system_files.clone();
*self.jn_field_from_entity_fields.write().unwrap() =
snap.jn_field_from_entity_fields.clone();
*self.jn_entity_from_entity_inherits_from.write().unwrap() =
snap.jn_entity_from_entity_inherits_from.clone();
*self
.jn_relationship_from_entity_relationships
.write()
.unwrap() = snap.jn_relationship_from_entity_relationships.clone();
*self.jn_entity_from_field_entity.write().unwrap() =
snap.jn_entity_from_field_entity.clone();
*self.jn_use_case_from_feature_use_cases.write().unwrap() =
snap.jn_use_case_from_feature_use_cases.clone();
*self.jn_entity_from_file_entity.write().unwrap() = snap.jn_entity_from_file_entity.clone();
*self.jn_feature_from_file_feature.write().unwrap() =
snap.jn_feature_from_file_feature.clone();
*self.jn_field_from_file_field.write().unwrap() = snap.jn_field_from_file_field.clone();
*self.jn_use_case_from_file_use_case.write().unwrap() =
snap.jn_use_case_from_file_use_case.clone();
*self.jn_dto_from_use_case_dto_in.write().unwrap() =
snap.jn_dto_from_use_case_dto_in.clone();
*self.jn_dto_from_use_case_dto_out.write().unwrap() =
snap.jn_dto_from_use_case_dto_out.clone();
*self.jn_entity_from_use_case_entities.write().unwrap() =
snap.jn_entity_from_use_case_entities.clone();
*self.jn_dto_field_from_dto_fields.write().unwrap() =
snap.jn_dto_field_from_dto_fields.clone();
*self
.jn_entity_from_relationship_left_entity
.write()
.unwrap() = snap.jn_entity_from_relationship_left_entity.clone();
*self
.jn_entity_from_relationship_right_entity
.write()
.unwrap() = snap.jn_entity_from_relationship_right_entity.clone();
}
pub fn store_snapshot(&self) -> StoreSnapshot {
StoreSnapshot::new(self.snapshot())
}
pub fn restore_store_snapshot(&self, snap: &StoreSnapshot) {
let s = snap
.downcast_ref::<HashMapStoreSnapshot>()
.expect("StoreSnapshot must contain HashMapStoreSnapshot");
self.restore_without_counters(s);
}
}
#[derive(Debug, Clone)]
pub struct HashMapStoreSnapshot {
roots: HashMap<EntityId, Root>,
workspaces: HashMap<EntityId, Workspace>,
systems: HashMap<EntityId, System>,
entities: HashMap<EntityId, Entity>,
fields: HashMap<EntityId, Field>,
features: HashMap<EntityId, Feature>,
files: HashMap<EntityId, File>,
use_cases: HashMap<EntityId, UseCase>,
dtos: HashMap<EntityId, Dto>,
dto_fields: HashMap<EntityId, DtoField>,
globals: HashMap<EntityId, Global>,
relationships: HashMap<EntityId, Relationship>,
user_interfaces: HashMap<EntityId, UserInterface>,
jn_system_from_root_system: HashMap<EntityId, Vec<EntityId>>,
jn_workspace_from_root_workspace: HashMap<EntityId, Vec<EntityId>>,
jn_entity_from_workspace_entities: HashMap<EntityId, Vec<EntityId>>,
jn_feature_from_workspace_features: HashMap<EntityId, Vec<EntityId>>,
jn_global_from_workspace_global: HashMap<EntityId, Vec<EntityId>>,
jn_user_interface_from_workspace_user_interface: HashMap<EntityId, Vec<EntityId>>,
jn_file_from_system_files: HashMap<EntityId, Vec<EntityId>>,
jn_field_from_entity_fields: HashMap<EntityId, Vec<EntityId>>,
jn_entity_from_entity_inherits_from: HashMap<EntityId, Vec<EntityId>>,
jn_relationship_from_entity_relationships: HashMap<EntityId, Vec<EntityId>>,
jn_entity_from_field_entity: HashMap<EntityId, Vec<EntityId>>,
jn_use_case_from_feature_use_cases: HashMap<EntityId, Vec<EntityId>>,
jn_entity_from_file_entity: HashMap<EntityId, Vec<EntityId>>,
jn_feature_from_file_feature: HashMap<EntityId, Vec<EntityId>>,
jn_field_from_file_field: HashMap<EntityId, Vec<EntityId>>,
jn_use_case_from_file_use_case: HashMap<EntityId, Vec<EntityId>>,
jn_dto_from_use_case_dto_in: HashMap<EntityId, Vec<EntityId>>,
jn_dto_from_use_case_dto_out: HashMap<EntityId, Vec<EntityId>>,
jn_entity_from_use_case_entities: HashMap<EntityId, Vec<EntityId>>,
jn_dto_field_from_dto_fields: HashMap<EntityId, Vec<EntityId>>,
jn_entity_from_relationship_left_entity: HashMap<EntityId, Vec<EntityId>>,
jn_entity_from_relationship_right_entity: HashMap<EntityId, Vec<EntityId>>,
counters: std::collections::HashMap<String, EntityId>,
}
impl StoreSnapshotTrait for HashMapStoreSnapshot {
fn clone_box(&self) -> Box<dyn StoreSnapshotTrait> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
pub(crate) fn delete_from_backward_junction(
junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
id: &EntityId,
) {
let mut jn = junction.write().unwrap();
let keys: Vec<EntityId> = jn.keys().copied().collect();
for k in keys {
if let Some(right_ids) = jn.get(&k)
&& right_ids.contains(id)
{
let filtered: Vec<EntityId> =
right_ids.iter().copied().filter(|eid| eid != id).collect();
jn.insert(k, filtered);
}
}
}
pub(crate) fn junction_get(
junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
id: &EntityId,
) -> Vec<EntityId> {
junction
.read()
.unwrap()
.get(id)
.cloned()
.unwrap_or_default()
}
pub(crate) fn junction_set(
junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
id: EntityId,
ids: Vec<EntityId>,
) {
junction.write().unwrap().insert(id, ids);
}
pub(crate) fn junction_remove(junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>, id: &EntityId) {
junction.write().unwrap().remove(id);
}
pub(crate) fn junction_get_relationships_from_right_ids(
junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
right_ids: &[EntityId],
) -> Vec<(EntityId, Vec<EntityId>)> {
let jn = junction.read().unwrap();
jn.iter()
.filter(|(_, rids)| right_ids.iter().any(|eid| rids.contains(eid)))
.map(|(left_id, rids)| (*left_id, rids.clone()))
.collect()
}
pub(crate) fn junction_move_ids(
junction: &RwLock<HashMap<EntityId, Vec<EntityId>>>,
id: &EntityId,
ids_to_move: &[EntityId],
new_index: i32,
) -> Vec<EntityId> {
let current = junction_get(junction, id);
if ids_to_move.is_empty() {
return current;
}
let move_set: std::collections::HashSet<EntityId> = ids_to_move.iter().copied().collect();
let mut remaining: Vec<EntityId> = current
.into_iter()
.filter(|eid| !move_set.contains(eid))
.collect();
let insert_pos = if new_index < 0 || (new_index as usize) > remaining.len() {
remaining.len()
} else {
new_index as usize
};
for (i, &eid) in ids_to_move.iter().enumerate() {
remaining.insert(insert_pos + i, eid);
}
junction_set(junction, *id, remaining.clone());
remaining
}
#[macro_export]
macro_rules! impl_relationship_methods {
($table_type:ty, $field_enum:ty) => {
fn get_relationship(
&self,
id: &$crate::types::EntityId,
field: &$field_enum,
) -> Result<Vec<$crate::types::EntityId>, $crate::error::RepositoryError> {
Ok($crate::database::hashmap_store::junction_get(
self.resolve_junction(field),
id,
))
}
fn get_relationship_many(
&self,
ids: &[$crate::types::EntityId],
field: &$field_enum,
) -> Result<
std::collections::HashMap<$crate::types::EntityId, Vec<$crate::types::EntityId>>,
$crate::error::RepositoryError,
> {
let jn = self.resolve_junction(field);
let mut map = std::collections::HashMap::new();
for id in ids {
map.insert(*id, $crate::database::hashmap_store::junction_get(jn, id));
}
Ok(map)
}
fn get_relationship_count(
&self,
id: &$crate::types::EntityId,
field: &$field_enum,
) -> Result<usize, $crate::error::RepositoryError> {
Ok(
$crate::database::hashmap_store::junction_get(self.resolve_junction(field), id)
.len(),
)
}
fn get_relationship_in_range(
&self,
id: &$crate::types::EntityId,
field: &$field_enum,
offset: usize,
limit: usize,
) -> Result<Vec<$crate::types::EntityId>, $crate::error::RepositoryError> {
let all =
$crate::database::hashmap_store::junction_get(self.resolve_junction(field), id);
Ok(all.into_iter().skip(offset).take(limit).collect())
}
fn get_relationships_from_right_ids(
&self,
field: &$field_enum,
right_ids: &[$crate::types::EntityId],
) -> Result<
Vec<($crate::types::EntityId, Vec<$crate::types::EntityId>)>,
$crate::error::RepositoryError,
> {
Ok(
$crate::database::hashmap_store::junction_get_relationships_from_right_ids(
self.resolve_junction(field),
right_ids,
),
)
}
};
}
#[macro_export]
macro_rules! impl_write_relationship_methods {
($table_type:ty, $field_enum:ty) => {
$crate::impl_relationship_methods!($table_type, $field_enum);
fn set_relationship_multi(
&mut self,
field: &$field_enum,
relationships: Vec<($crate::types::EntityId, Vec<$crate::types::EntityId>)>,
) -> Result<(), $crate::error::RepositoryError> {
let jn = self.resolve_junction(field);
for (left_id, entities) in relationships {
$crate::database::hashmap_store::junction_set(jn, left_id, entities);
}
Ok(())
}
fn set_relationship(
&mut self,
id: &$crate::types::EntityId,
field: &$field_enum,
right_ids: &[$crate::types::EntityId],
) -> Result<(), $crate::error::RepositoryError> {
$crate::database::hashmap_store::junction_set(
self.resolve_junction(field),
*id,
right_ids.to_vec(),
);
Ok(())
}
fn move_relationship_ids(
&mut self,
id: &$crate::types::EntityId,
field: &$field_enum,
ids_to_move: &[$crate::types::EntityId],
new_index: i32,
) -> Result<Vec<$crate::types::EntityId>, $crate::error::RepositoryError> {
Ok($crate::database::hashmap_store::junction_move_ids(
self.resolve_junction(field),
id,
ids_to_move,
new_index,
))
}
};
}
#[macro_export]
macro_rules! impl_leaf_entity_table {
(
entity: $Entity:ident,
entity_name: $entity_name:expr,
store_field: $store_field:ident,
table_trait: $TableTrait:ident,
table_ro_trait: $TableROTrait:ident,
table_struct: $TableStruct:ident,
table_ro_struct: $TableROStruct:ident,
backward_junctions: [ $( ($bj_field:ident) ),* $(,)? ],
) => {
pub struct $TableStruct<'a> {
store: &'a $crate::database::hashmap_store::HashMapStore,
}
impl<'a> $TableStruct<'a> {
pub fn new(store: &'a $crate::database::hashmap_store::HashMapStore) -> Self {
Self { store }
}
}
impl<'a> $TableTrait for $TableStruct<'a> {
fn create(&mut self, entity: &$Entity) -> Result<$Entity, $crate::error::RepositoryError> {
self.create_multi(std::slice::from_ref(entity))
.map(|v| v.into_iter().next().unwrap())
}
fn create_multi(&mut self, entities: &[$Entity]) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
let mut created = Vec::with_capacity(entities.len());
let mut map = self.store.$store_field.write().unwrap();
for entity in entities {
let new_entity = if entity.id == $crate::types::EntityId::default() {
let id = self.store.next_id($entity_name);
$Entity {
id,
..entity.clone()
}
} else {
if map.contains_key(&entity.id) {
return Err($crate::error::RepositoryError::DuplicateId {
entity: stringify!($Entity),
id: entity.id,
});
}
entity.clone()
};
map.insert(new_entity.id, new_entity.clone());
created.push(new_entity);
}
Ok(created)
}
fn get(&self, id: &$crate::types::EntityId) -> Result<Option<$Entity>, $crate::error::RepositoryError> {
Ok(self.store.$store_field.read().unwrap().get(id).cloned())
}
fn get_multi(&self, ids: &[$crate::types::EntityId]) -> Result<Vec<Option<$Entity>>, $crate::error::RepositoryError> {
let map = self.store.$store_field.read().unwrap();
Ok(ids.iter().map(|id| map.get(id).cloned()).collect())
}
fn get_all(&self) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
Ok(self.store.$store_field.read().unwrap().values().cloned().collect())
}
fn update(&mut self, entity: &$Entity) -> Result<$Entity, $crate::error::RepositoryError> {
self.update_multi(std::slice::from_ref(entity))
.map(|v| v.into_iter().next().unwrap())
}
fn update_multi(&mut self, entities: &[$Entity]) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
let mut map = self.store.$store_field.write().unwrap();
let mut result = Vec::with_capacity(entities.len());
for entity in entities {
map.insert(entity.id, entity.clone());
result.push(entity.clone());
}
Ok(result)
}
fn update_with_relationships(&mut self, entity: &$Entity) -> Result<$Entity, $crate::error::RepositoryError> {
self.update(entity)
}
fn update_with_relationships_multi(&mut self, entities: &[$Entity]) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
self.update_multi(entities)
}
fn remove(&mut self, id: &$crate::types::EntityId) -> Result<(), $crate::error::RepositoryError> {
self.remove_multi(std::slice::from_ref(id))
}
fn remove_multi(&mut self, ids: &[$crate::types::EntityId]) -> Result<(), $crate::error::RepositoryError> {
let mut map = self.store.$store_field.write().unwrap();
for id in ids {
map.remove(id);
$(
$crate::database::hashmap_store::delete_from_backward_junction(&self.store.$bj_field, id);
)*
}
Ok(())
}
}
pub struct $TableROStruct<'a> {
store: &'a $crate::database::hashmap_store::HashMapStore,
}
impl<'a> $TableROStruct<'a> {
pub fn new(store: &'a $crate::database::hashmap_store::HashMapStore) -> Self {
Self { store }
}
}
impl<'a> $TableROTrait for $TableROStruct<'a> {
fn get(&self, id: &$crate::types::EntityId) -> Result<Option<$Entity>, $crate::error::RepositoryError> {
Ok(self.store.$store_field.read().unwrap().get(id).cloned())
}
fn get_multi(&self, ids: &[$crate::types::EntityId]) -> Result<Vec<Option<$Entity>>, $crate::error::RepositoryError> {
let map = self.store.$store_field.read().unwrap();
Ok(ids.iter().map(|id| map.get(id).cloned()).collect())
}
fn get_all(&self) -> Result<Vec<$Entity>, $crate::error::RepositoryError> {
Ok(self.store.$store_field.read().unwrap().values().cloned().collect())
}
}
};
}