use crate::database::hashmap_store::{
HashMapJunction, HashMapStore, delete_from_backward_junction, junction_get, junction_remove,
junction_set, read_or_recover, write_or_recover,
};
use crate::entities::Entity;
use crate::error::RepositoryError;
use crate::types::EntityId;
use crate::{impl_relationship_methods, impl_write_relationship_methods};
use std::sync::RwLock;
use super::entity_repository::EntityRelationshipField;
use super::entity_repository::EntityTable;
use super::entity_repository::EntityTableRO;
pub struct EntityHashMapTable<'a> {
store: &'a HashMapStore,
}
impl<'a> EntityHashMapTable<'a> {
pub fn new(store: &'a HashMapStore) -> Self {
Self { store }
}
fn resolve_junction(&self, field: &EntityRelationshipField) -> &RwLock<HashMapJunction> {
match field {
EntityRelationshipField::Fields => &self.store.jn_field_from_entity_fields,
EntityRelationshipField::InheritsFrom => {
&self.store.jn_entity_from_entity_inherits_from
}
EntityRelationshipField::Relationships => {
&self.store.jn_relationship_from_entity_relationships
}
}
}
fn relationship_source_exists(&self, id: &EntityId) -> bool {
read_or_recover(&self.store.entities).contains_key(id)
}
fn relationship_is_ordered(&self, field: &EntityRelationshipField) -> bool {
match field {
EntityRelationshipField::Fields => true,
EntityRelationshipField::InheritsFrom => false,
EntityRelationshipField::Relationships => false,
}
}
fn validate_relationship_updates(
&self,
field: &EntityRelationshipField,
rows: &[(EntityId, Vec<EntityId>)],
_creating_ids: &[EntityId],
) -> Result<(), RepositoryError> {
let scalar = match field {
EntityRelationshipField::Fields => {
let targets = read_or_recover(&self.store.fields);
let missing: Vec<_> = rows
.iter()
.flat_map(|(_, ids)| ids)
.copied()
.filter(|id| !targets.contains_key(id))
.collect();
if !missing.is_empty() {
return Err(RepositoryError::MissingRelationshipTarget {
operation: "relationship update",
ids: missing,
});
}
false
}
EntityRelationshipField::InheritsFrom => {
let targets = read_or_recover(&self.store.entities);
let mut missing: Vec<_> = rows
.iter()
.flat_map(|(_, ids)| ids)
.copied()
.filter(|id| !targets.contains_key(id))
.collect();
if !missing.is_empty() {
let creating: std::collections::HashSet<EntityId> =
_creating_ids.iter().copied().collect();
missing.retain(|id| !creating.contains(id));
}
if !missing.is_empty() {
return Err(RepositoryError::MissingRelationshipTarget {
operation: "relationship update",
ids: missing,
});
}
true
}
EntityRelationshipField::Relationships => {
let targets = read_or_recover(&self.store.relationships);
let missing: Vec<_> = rows
.iter()
.flat_map(|(_, ids)| ids)
.copied()
.filter(|id| !targets.contains_key(id))
.collect();
if !missing.is_empty() {
return Err(RepositoryError::MissingRelationshipTarget {
operation: "relationship update",
ids: missing,
});
}
false
}
};
crate::database::hashmap_store::validate_junction_updates(
self.resolve_junction(field),
rows,
scalar,
)
}
fn hydrate(&self, entity: &mut Entity) {
entity.inherits_from =
junction_get(&self.store.jn_entity_from_entity_inherits_from, &entity.id)
.into_iter()
.next();
entity.fields = junction_get(&self.store.jn_field_from_entity_fields, &entity.id);
entity.relationships = junction_get(
&self.store.jn_relationship_from_entity_relationships,
&entity.id,
);
}
}
impl<'a> EntityTable for EntityHashMapTable<'a> {
fn create(&mut self, entity: &Entity) -> Result<Entity, RepositoryError> {
self.create_multi(std::slice::from_ref(entity))
.and_then(|v| {
v.into_iter().next().ok_or_else(|| {
RepositoryError::Other(anyhow::anyhow!(
"create: the store returned no row for the entity it was given"
))
})
})
}
fn create_multi(&mut self, entities: &[Entity]) -> Result<Vec<Entity>, RepositoryError> {
let entities: Vec<_> = entities
.iter()
.map(|entity| {
let mut entity = entity.clone();
if entity.id == EntityId::default() {
entity.id = self.store.next_id("entity");
}
entity
})
.collect();
self.validate_relationship_updates(
&EntityRelationshipField::Fields,
&entities
.iter()
.map(|e| (e.id, e.fields.clone()))
.collect::<Vec<_>>(),
&entities.iter().map(|e| e.id).collect::<Vec<_>>(),
)?;
self.validate_relationship_updates(
&EntityRelationshipField::Relationships,
&entities
.iter()
.map(|e| (e.id, e.relationships.clone()))
.collect::<Vec<_>>(),
&entities.iter().map(|e| e.id).collect::<Vec<_>>(),
)?;
let mut created = Vec::with_capacity(entities.len());
let mut entity_map = write_or_recover(&self.store.entities);
for entity in &entities {
let new_entity = if entity.id == EntityId::default() {
let id = self.store.next_id("entity");
Entity {
id,
..entity.clone()
}
} else {
if entity_map.contains_key(&entity.id) {
return Err(RepositoryError::DuplicateId {
entity: "Entity",
id: entity.id,
});
}
entity.clone()
};
entity_map.insert(new_entity.id, new_entity.clone());
junction_set(
&self.store.jn_field_from_entity_fields,
new_entity.id,
new_entity.fields.clone(),
);
junction_set(
&self.store.jn_entity_from_entity_inherits_from,
new_entity.id,
new_entity
.inherits_from
.into_iter()
.collect::<Vec<EntityId>>(),
);
junction_set(
&self.store.jn_relationship_from_entity_relationships,
new_entity.id,
new_entity.relationships.clone(),
);
created.push(new_entity);
}
Ok(created)
}
fn get(&self, id: &EntityId) -> Result<Option<Entity>, RepositoryError> {
let entity_map = read_or_recover(&self.store.entities);
match entity_map.get(id) {
Some(entity) => {
let mut e = entity.clone();
drop(entity_map);
self.hydrate(&mut e);
Ok(Some(e))
}
None => Ok(None),
}
}
fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Entity>>, RepositoryError> {
let mut result = Vec::with_capacity(ids.len());
for id in ids {
result.push(self.get(id)?);
}
Ok(result)
}
fn get_all(&self) -> Result<Vec<Entity>, RepositoryError> {
let entity_map = read_or_recover(&self.store.entities);
let entries: Vec<Entity> = entity_map.values().cloned().collect();
drop(entity_map);
let mut result = Vec::with_capacity(entries.len());
for mut entity in entries {
self.hydrate(&mut entity);
result.push(entity);
}
Ok(result)
}
fn update(&mut self, entity: &Entity) -> Result<Entity, RepositoryError> {
self.update_multi(std::slice::from_ref(entity))
.and_then(|v| {
v.into_iter().next().ok_or_else(|| {
RepositoryError::Other(anyhow::anyhow!(
"update: the store returned no row for the entity it was given"
))
})
})
}
fn update_multi(&mut self, entities: &[Entity]) -> Result<Vec<Entity>, RepositoryError> {
let mut entity_map = write_or_recover(&self.store.entities);
for entity in entities {
entity_map.insert(entity.id, entity.clone());
}
drop(entity_map);
let ids: Vec<EntityId> = entities.iter().map(|e| e.id).collect();
let result = self.get_multi(&ids)?;
Ok(result.into_iter().flatten().collect())
}
fn update_with_relationships(&mut self, entity: &Entity) -> Result<Entity, RepositoryError> {
self.update_with_relationships_multi(std::slice::from_ref(entity))
.and_then(|v| {
v.into_iter().next().ok_or_else(|| {
RepositoryError::Other(anyhow::anyhow!(
"update_with_relationships: the store returned no row for the entity it was given"
))
})
})
}
fn update_with_relationships_multi(
&mut self,
entities: &[Entity],
) -> Result<Vec<Entity>, RepositoryError> {
self.validate_relationship_updates(
&EntityRelationshipField::Fields,
&entities
.iter()
.map(|e| (e.id, e.fields.clone()))
.collect::<Vec<_>>(),
&[],
)?;
self.validate_relationship_updates(
&EntityRelationshipField::Relationships,
&entities
.iter()
.map(|e| (e.id, e.relationships.clone()))
.collect::<Vec<_>>(),
&[],
)?;
let mut entity_map = write_or_recover(&self.store.entities);
for entity in entities {
entity_map.insert(entity.id, entity.clone());
junction_set(
&self.store.jn_entity_from_entity_inherits_from,
entity.id,
entity.inherits_from.into_iter().collect::<Vec<EntityId>>(),
);
junction_set(
&self.store.jn_field_from_entity_fields,
entity.id,
entity.fields.clone(),
);
junction_set(
&self.store.jn_relationship_from_entity_relationships,
entity.id,
entity.relationships.clone(),
);
}
drop(entity_map);
let ids: Vec<EntityId> = entities.iter().map(|e| e.id).collect();
let result = self.get_multi(&ids)?;
Ok(result.into_iter().flatten().collect())
}
fn remove(&mut self, id: &EntityId) -> Result<(), RepositoryError> {
self.remove_multi(std::slice::from_ref(id))
}
fn remove_multi(&mut self, ids: &[EntityId]) -> Result<(), RepositoryError> {
let mut entity_map = write_or_recover(&self.store.entities);
for id in ids {
entity_map.remove(id);
junction_remove(&self.store.jn_entity_from_entity_inherits_from, id);
junction_remove(&self.store.jn_field_from_entity_fields, id);
junction_remove(&self.store.jn_relationship_from_entity_relationships, id);
delete_from_backward_junction(&self.store.jn_entity_from_use_case_entities, id);
delete_from_backward_junction(&self.store.jn_entity_from_workspace_entities, id);
delete_from_backward_junction(&self.store.jn_entity_from_field_entity, id);
delete_from_backward_junction(&self.store.jn_entity_from_file_entity, id);
delete_from_backward_junction(&self.store.jn_entity_from_entity_inherits_from, id);
delete_from_backward_junction(&self.store.jn_entity_from_relationship_left_entity, id);
delete_from_backward_junction(&self.store.jn_entity_from_relationship_right_entity, id);
}
Ok(())
}
impl_write_relationship_methods!(EntityHashMapTable<'a>, EntityRelationshipField);
}
pub struct EntityHashMapTableRO<'a> {
store: &'a HashMapStore,
}
impl<'a> EntityHashMapTableRO<'a> {
pub fn new(store: &'a HashMapStore) -> Self {
Self { store }
}
fn resolve_junction(&self, field: &EntityRelationshipField) -> &RwLock<HashMapJunction> {
match field {
EntityRelationshipField::Fields => &self.store.jn_field_from_entity_fields,
EntityRelationshipField::InheritsFrom => {
&self.store.jn_entity_from_entity_inherits_from
}
EntityRelationshipField::Relationships => {
&self.store.jn_relationship_from_entity_relationships
}
}
}
fn hydrate(&self, entity: &mut Entity) {
entity.inherits_from =
junction_get(&self.store.jn_entity_from_entity_inherits_from, &entity.id)
.into_iter()
.next();
entity.fields = junction_get(&self.store.jn_field_from_entity_fields, &entity.id);
entity.relationships = junction_get(
&self.store.jn_relationship_from_entity_relationships,
&entity.id,
);
}
}
impl<'a> EntityTableRO for EntityHashMapTableRO<'a> {
fn get(&self, id: &EntityId) -> Result<Option<Entity>, RepositoryError> {
let entity_map = read_or_recover(&self.store.entities);
match entity_map.get(id) {
Some(entity) => {
let mut e = entity.clone();
drop(entity_map);
self.hydrate(&mut e);
Ok(Some(e))
}
None => Ok(None),
}
}
fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Entity>>, RepositoryError> {
let mut result = Vec::with_capacity(ids.len());
for id in ids {
result.push(self.get(id)?);
}
Ok(result)
}
fn get_all(&self) -> Result<Vec<Entity>, RepositoryError> {
let entity_map = read_or_recover(&self.store.entities);
let entries: Vec<Entity> = entity_map.values().cloned().collect();
drop(entity_map);
let mut result = Vec::with_capacity(entries.len());
for mut entity in entries {
self.hydrate(&mut entity);
result.push(entity);
}
Ok(result)
}
impl_relationship_methods!(EntityHashMapTableRO<'a>, EntityRelationshipField);
}