use eav::{eavi::EntityAttributeValueIndex, query::EaviQuery, Attribute};
use error::PersistenceResult;
use objekt;
use reporting::ReportStorage;
use std::{
collections::BTreeSet,
fmt::Debug,
sync::{Arc, RwLock},
};
pub trait EntityAttributeValueStorage<A: Attribute>:
objekt::Clone + Send + Sync + Debug + ReportStorage
{
fn add_eavi(
&mut self,
eav: &EntityAttributeValueIndex<A>,
) -> PersistenceResult<Option<EntityAttributeValueIndex<A>>>;
fn fetch_eavi(
&self,
query: &EaviQuery<A>,
) -> PersistenceResult<BTreeSet<EntityAttributeValueIndex<A>>>;
}
clone_trait_object!(<A:Attribute>EntityAttributeValueStorage<A>);
#[derive(Clone, Debug, Default)]
pub struct ExampleEntityAttributeValueStorage<A: Attribute> {
storage: Arc<RwLock<BTreeSet<EntityAttributeValueIndex<A>>>>,
}
impl<A: Attribute> ExampleEntityAttributeValueStorage<A> {
pub fn new() -> ExampleEntityAttributeValueStorage<A>
where
A: std::default::Default,
{
Default::default()
}
}
impl<A: Attribute> EntityAttributeValueStorage<A> for ExampleEntityAttributeValueStorage<A>
where
A: std::marker::Send + std::marker::Sync,
{
fn add_eavi(
&mut self,
eav: &EntityAttributeValueIndex<A>,
) -> PersistenceResult<Option<EntityAttributeValueIndex<A>>> {
let mut map = self.storage.write()?;
let new_eav = increment_key_till_no_collision(eav.clone(), map.clone())?;
map.insert(new_eav.clone());
Ok(Some(new_eav.clone()))
}
fn fetch_eavi(
&self,
query: &EaviQuery<A>,
) -> PersistenceResult<BTreeSet<EntityAttributeValueIndex<A>>> {
let lock = self.storage.read()?;
let set = (*lock).clone();
let iter = set.iter().cloned();
Ok(query.run(iter))
}
}
impl<A: Attribute> ReportStorage for ExampleEntityAttributeValueStorage<A> {}
impl<A: Attribute> PartialEq for dyn EntityAttributeValueStorage<A> {
fn eq(&self, other: &dyn EntityAttributeValueStorage<A>) -> bool {
let query = EaviQuery::default();
self.fetch_eavi(&query) == other.fetch_eavi(&query)
}
}
pub fn increment_key_till_no_collision<A: Attribute>(
mut eav: EntityAttributeValueIndex<A>,
map: BTreeSet<EntityAttributeValueIndex<A>>,
) -> PersistenceResult<EntityAttributeValueIndex<A>> {
if map.iter().any(|e| e.index() == eav.index()) {
let timestamp = eav.clone().index() + 1;
eav.set_index(timestamp);
increment_key_till_no_collision(eav, map)
} else {
Ok(eav)
}
}