use crate::{
prelude::*,
traits::{IdType, Property},
IdGenerator,
};
use std::{
collections::{BTreeMap, HashMap, HashSet},
hash::{Hash, Hasher},
};
mod extend;
mod insert;
mod iter;
mod merge;
mod query;
mod remove;
mod set;
pub struct MemTripleStore<Id: IdType, NodeProps: Property, EdgeProps: Property> {
node_props: BTreeMap<Id, NodeProps>,
edge_props: BTreeMap<Id, EdgeProps>,
spo_data: BTreeMap<Id::TripleByteArrayType, Id>,
pos_data: BTreeMap<Id::TripleByteArrayType, Id>,
osp_data: BTreeMap<Id::TripleByteArrayType, Id>,
id_generator: Box<dyn IdGenerator<Id>>,
}
impl<Id: IdType, NodeProps: Property, EdgeProps: Property> std::fmt::Debug
for MemTripleStore<Id, NodeProps, EdgeProps>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("MemTripleStore:\n")?;
f.write_str(" Node Properties:\n")?;
for (id, node_props) in self.node_props.iter() {
f.write_fmt(format_args!(" {} -> {:?}\n", id, node_props))?;
}
f.write_str(" Edge Properties:\n")?;
let ulid_to_spo_edge_hash = self
.spo_data
.iter()
.map(|(k, v)| {
let hash;
{
let mut hash_builder = std::hash::DefaultHasher::new();
k.hash(&mut hash_builder);
hash = hash_builder.finish();
}
(v.clone(), hash)
})
.collect::<HashMap<_, _>>();
let hash_to_edge_data = self
.edge_props
.iter()
.map(|(ulid, edge_data)| match ulid_to_spo_edge_hash.get(ulid) {
Some(hash) => (Some(hash), edge_data),
None => (None, edge_data),
})
.collect::<BTreeMap<_, _>>();
for (hash, node_props) in hash_to_edge_data {
match hash {
None => {
f.write_fmt(format_args!(" _ -> {:?}\n", node_props))?;
}
Some(hash) => {
f.write_fmt(format_args!(" {:#016x} -> {:?}\n", hash, node_props))?;
}
}
}
f.write_str(" Edges (SPO):\n")?;
for (triple, ulid) in self.spo_data.iter() {
let triple = Id::decode_spo_triple(&triple);
f.write_fmt(format_args!(
" ({}, {}, {}) -> ",
triple.sub, triple.pred, triple.obj
))?;
match ulid_to_spo_edge_hash.get(ulid) {
Some(hash) => {
f.write_fmt(format_args!("{:#016x}\n", hash))?;
}
None => {
f.write_str("_\n")?;
}
}
}
f.write_str(" Edges (POS):\n")?;
for (triple, ulid) in self.pos_data.iter() {
let triple = Id::decode_pos_triple(&triple);
f.write_fmt(format_args!(
" ({}, {}, {}) -> ",
triple.sub, triple.pred, triple.obj
))?;
match ulid_to_spo_edge_hash.get(ulid) {
Some(hash) => {
f.write_fmt(format_args!("{:#016x}\n", hash))?;
}
None => {
f.write_str("_\n")?;
}
}
}
f.write_str(" Edges (OSP):\n")?;
for (triple, ulid) in self.osp_data.iter() {
let triple = Id::decode_osp_triple(&triple);
f.write_fmt(format_args!(
" ({}, {}, {}) -> ",
triple.sub, triple.pred, triple.obj
))?;
match ulid_to_spo_edge_hash.get(ulid) {
Some(hash) => {
f.write_fmt(format_args!("{:#016x}\n", hash))?;
}
None => {
f.write_str("_\n")?;
}
}
}
Ok(())
}
}
impl<Id: IdType, NodeProps: Property, EdgeProps: Property> PartialEq
for MemTripleStore<Id, NodeProps, EdgeProps>
{
fn eq(&self, other: &Self) -> bool {
if !self.node_props.eq(&other.node_props) {
return false;
}
let mut cached_comparisons: HashSet<(Id, Id)> = HashSet::new();
let mut eq_edge_prop_by_id = |self_edge_prop_id, other_edge_prop_id| {
let self_edge_props = self.edge_props.get(&self_edge_prop_id);
let other_edge_props = other.edge_props.get(&other_edge_prop_id);
if self_edge_props.is_none() || other_edge_props.is_none() {
return false;
}
if cached_comparisons.contains(&(self_edge_prop_id, other_edge_prop_id)) {
return true;
}
if self_edge_props == other_edge_props {
cached_comparisons.insert((self_edge_prop_id, other_edge_prop_id));
true
} else {
false
}
};
let mut check_edge =
move |((self_edge, self_edge_prop_id), (other_edge, other_edge_prop_id)): (
(&Id::TripleByteArrayType, &Id),
(&Id::TripleByteArrayType, &Id),
)| {
if self_edge.ne(other_edge) {
return false;
}
eq_edge_prop_by_id(self_edge_prop_id.clone(), other_edge_prop_id.clone())
};
for edge_pair in self.spo_data.iter().zip(other.spo_data.iter()) {
if !check_edge(edge_pair) {
return false;
}
}
true
}
}
impl<Id: IdType, NodeProps: Property, EdgeProps: Property>
MemTripleStore<Id, NodeProps, EdgeProps>
{
pub fn new(id_generator: impl IdGenerator<Id> + 'static) -> Self {
Self::new_from_boxed_id_generator(Box::new(id_generator))
}
pub(crate) fn new_from_boxed_id_generator(
id_generator: Box<dyn IdGenerator<Id> + 'static>,
) -> Self {
Self {
node_props: BTreeMap::new(),
edge_props: BTreeMap::new(),
spo_data: BTreeMap::new(),
pos_data: BTreeMap::new(),
osp_data: BTreeMap::new(),
id_generator: id_generator,
}
}
}
impl<Id: IdType, NodeProps: Property, EdgeProps: Property> TripleStore<Id, NodeProps, EdgeProps>
for MemTripleStore<Id, NodeProps, EdgeProps>
{
}
impl<Id: IdType, NodeProps: Property, EdgeProps: Property> TripleStoreError
for MemTripleStore<Id, NodeProps, EdgeProps>
{
type Error = ();
}