use std::collections::HashMap;
use std::hash::Hash;
pub trait Layer: Send + Sync {
fn name(&self) -> [u32; 5];
fn parent_name(&self) -> Option<[u32; 5]>;
fn node_and_value_count(&self) -> usize;
fn predicate_count(&self) -> usize;
fn subject_id(&self, subject: &str) -> Option<u64>;
fn predicate_id(&self, predicate: &str) -> Option<u64>;
fn object_node_id(&self, object: &str) -> Option<u64>;
fn object_value_id(&self, object: &str) -> Option<u64>;
fn id_subject(&self, id: u64) -> Option<String>;
fn id_predicate(&self, id: u64) -> Option<String>;
fn id_object(&self, id: u64) -> Option<ObjectType>;
fn all_counts(&self) -> LayerCounts;
fn clone_boxed(&self) -> Box<dyn Layer>;
fn triple_exists(&self, subject: u64, predicate: u64, object: u64) -> bool;
fn id_triple_exists(&self, triple: IdTriple) -> bool {
self.triple_exists(triple.subject, triple.predicate, triple.object)
}
fn string_triple_exists(&self, triple: &StringTriple) -> bool {
self.string_triple_to_id(triple)
.map(|t| self.id_triple_exists(t))
.unwrap_or(false)
}
fn triples(&self) -> Box<dyn Iterator<Item = IdTriple> + Send>;
fn triples_s(&self, subject: u64) -> Box<dyn Iterator<Item = IdTriple> + Send>;
fn triples_sp(&self, subject: u64, predicate: u64)
-> Box<dyn Iterator<Item = IdTriple> + Send>;
fn string_triple_to_id(&self, triple: &StringTriple) -> Option<IdTriple> {
self.subject_id(&triple.subject).and_then(|subject| {
self.predicate_id(&triple.predicate).and_then(|predicate| {
match &triple.object {
ObjectType::Node(node) => self.object_node_id(&node),
ObjectType::Value(value) => self.object_value_id(&value),
}
.map(|object| IdTriple {
subject,
predicate,
object,
})
})
})
}
fn triples_p(&self, predicate: u64) -> Box<dyn Iterator<Item = IdTriple> + Send>;
fn triples_o(&self, object: u64) -> Box<dyn Iterator<Item = IdTriple> + Send>;
fn string_triple_to_partially_resolved(&self, triple: StringTriple) -> PartiallyResolvedTriple {
PartiallyResolvedTriple {
subject: self
.subject_id(&triple.subject)
.map(PossiblyResolved::Resolved)
.unwrap_or(PossiblyResolved::Unresolved(triple.subject)),
predicate: self
.predicate_id(&triple.predicate)
.map(PossiblyResolved::Resolved)
.unwrap_or(PossiblyResolved::Unresolved(triple.predicate)),
object: match &triple.object {
ObjectType::Node(node) => self
.object_node_id(&node)
.map(PossiblyResolved::Resolved)
.unwrap_or(PossiblyResolved::Unresolved(triple.object)),
ObjectType::Value(value) => self
.object_value_id(&value)
.map(PossiblyResolved::Resolved)
.unwrap_or(PossiblyResolved::Unresolved(triple.object)),
},
}
}
fn id_triple_to_string(&self, triple: &IdTriple) -> Option<StringTriple> {
self.id_subject(triple.subject).and_then(|subject| {
self.id_predicate(triple.predicate).and_then(|predicate| {
self.id_object(triple.object).map(|object| StringTriple {
subject,
predicate,
object,
})
})
})
}
fn triple_addition_count(&self) -> usize;
fn triple_removal_count(&self) -> usize;
fn triple_count(&self) -> usize {
self.triple_addition_count() - self.triple_removal_count()
}
}
pub struct LayerCounts {
pub node_count: usize,
pub predicate_count: usize,
pub value_count: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct IdTriple {
pub subject: u64,
pub predicate: u64,
pub object: u64,
}
impl IdTriple {
pub fn new(subject: u64, predicate: u64, object: u64) -> Self {
IdTriple {
subject,
predicate,
object,
}
}
pub fn to_resolved(&self) -> PartiallyResolvedTriple {
PartiallyResolvedTriple {
subject: PossiblyResolved::Resolved(self.subject),
predicate: PossiblyResolved::Resolved(self.predicate),
object: PossiblyResolved::Resolved(self.object),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StringTriple {
pub subject: String,
pub predicate: String,
pub object: ObjectType,
}
impl StringTriple {
pub fn new_node(subject: &str, predicate: &str, object: &str) -> StringTriple {
StringTriple {
subject: subject.to_owned(),
predicate: predicate.to_owned(),
object: ObjectType::Node(object.to_owned()),
}
}
pub fn new_value(subject: &str, predicate: &str, object: &str) -> StringTriple {
StringTriple {
subject: subject.to_owned(),
predicate: predicate.to_owned(),
object: ObjectType::Value(object.to_owned()),
}
}
pub fn to_unresolved(self) -> PartiallyResolvedTriple {
PartiallyResolvedTriple {
subject: PossiblyResolved::Unresolved(self.subject),
predicate: PossiblyResolved::Unresolved(self.predicate),
object: PossiblyResolved::Unresolved(self.object),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PossiblyResolved<T: Clone + PartialEq + Eq + PartialOrd + Ord + Hash> {
Unresolved(T),
Resolved(u64),
}
impl<T: Clone + PartialEq + Eq + PartialOrd + Ord + Hash> PossiblyResolved<T> {
pub fn is_resolved(&self) -> bool {
match self {
Self::Unresolved(_) => false,
Self::Resolved(_) => true,
}
}
pub fn as_ref(&self) -> PossiblyResolved<&T> {
match self {
Self::Unresolved(u) => PossiblyResolved::Unresolved(&u),
Self::Resolved(id) => PossiblyResolved::Resolved(*id),
}
}
pub fn unwrap_unresolved(self) -> T {
match self {
Self::Unresolved(u) => u,
Self::Resolved(_) => panic!("tried to unwrap unresolved, but got a resolved"),
}
}
pub fn unwrap_resolved(self) -> u64 {
match self {
Self::Unresolved(_) => panic!("tried to unwrap resolved, but got an unresolved"),
Self::Resolved(id) => id,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PartiallyResolvedTriple {
pub subject: PossiblyResolved<String>,
pub predicate: PossiblyResolved<String>,
pub object: PossiblyResolved<ObjectType>,
}
impl PartiallyResolvedTriple {
pub fn resolve_with(
&self,
node_map: &HashMap<String, u64>,
predicate_map: &HashMap<String, u64>,
value_map: &HashMap<String, u64>,
) -> Option<IdTriple> {
let subject = match self.subject.as_ref() {
PossiblyResolved::Unresolved(s) => *node_map.get(s)?,
PossiblyResolved::Resolved(id) => id,
};
let predicate = match self.predicate.as_ref() {
PossiblyResolved::Unresolved(p) => *predicate_map.get(p)?,
PossiblyResolved::Resolved(id) => id,
};
let object = match self.object.as_ref() {
PossiblyResolved::Unresolved(ObjectType::Node(n)) => *node_map.get(n)?,
PossiblyResolved::Unresolved(ObjectType::Value(v)) => *value_map.get(v)?,
PossiblyResolved::Resolved(id) => id,
};
Some(IdTriple {
subject,
predicate,
object,
})
}
pub fn as_resolved(&self) -> Option<IdTriple> {
if !self.subject.is_resolved()
|| !self.predicate.is_resolved()
|| !self.object.is_resolved()
{
None
} else {
Some(IdTriple::new(
self.subject.as_ref().unwrap_resolved(),
self.predicate.as_ref().unwrap_resolved(),
self.object.as_ref().unwrap_resolved(),
))
}
}
pub fn make_resolved_or_zero(&mut self) {
if !self.subject.is_resolved()
|| !self.predicate.is_resolved()
|| !self.object.is_resolved()
{
self.subject = PossiblyResolved::Resolved(0);
self.predicate = PossiblyResolved::Resolved(0);
self.object = PossiblyResolved::Resolved(0);
}
}
}
#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
pub enum ObjectType {
Node(String),
Value(String),
}
#[cfg(test)]
mod tests {
use super::*;
use crate::layer::internal::base::tests::base_layer_files;
use crate::layer::internal::base::BaseLayer;
use crate::layer::internal::child::tests::child_layer_files;
use crate::layer::internal::child::ChildLayer;
use crate::layer::internal::InternalLayer;
use crate::layer::simple_builder::{LayerBuilder, SimpleLayerBuilder};
use std::sync::Arc;
#[tokio::test]
async fn find_triple_after_adjacent_removal() {
let files = base_layer_files();
let mut builder = SimpleLayerBuilder::new([1, 2, 3, 4, 5], files.clone());
builder.add_string_triple(StringTriple::new_value("cow", "says", "moo"));
builder.add_string_triple(StringTriple::new_value("cow", "says", "sniff"));
builder.commit().await.unwrap();
let base: Arc<InternalLayer> = Arc::new(
BaseLayer::load_from_files([1, 2, 3, 4, 5], &files)
.await
.unwrap()
.into(),
);
let files = child_layer_files();
let mut builder =
SimpleLayerBuilder::from_parent([5, 4, 3, 2, 1], base.clone(), files.clone());
builder.remove_string_triple(StringTriple::new_value("cow", "says", "moo"));
builder.commit().await.unwrap();
let child: Arc<InternalLayer> = Arc::new(
ChildLayer::load_from_files([5, 4, 3, 2, 1], base.clone(), &files)
.await
.unwrap()
.into(),
);
let _base_triples_additions: Vec<_> = base
.internal_triple_additions()
.map(|t| child.id_triple_to_string(&t).unwrap())
.collect();
let _triples_additions: Vec<_> = child
.internal_triple_additions()
.map(|t| child.id_triple_to_string(&t).unwrap())
.collect();
let _triples_removals: Vec<_> = child
.internal_triple_removals()
.map(|t| child.id_triple_to_string(&t).unwrap())
.collect();
let triples: Vec<_> = child
.triples()
.map(|t| child.id_triple_to_string(&t).unwrap())
.collect();
assert_eq!(
vec![StringTriple::new_value("cow", "says", "sniff")],
triples
);
}
#[tokio::test]
async fn find_triple_after_removal_and_readdition() {
let files = base_layer_files();
let mut builder = SimpleLayerBuilder::new([1, 2, 3, 4, 5], files.clone());
builder.add_string_triple(StringTriple::new_value("cow", "says", "moo"));
builder.commit().await.unwrap();
let base: Arc<InternalLayer> = Arc::new(
BaseLayer::load_from_files([1, 2, 3, 4, 5], &files)
.await
.unwrap()
.into(),
);
let files = child_layer_files();
let mut builder =
SimpleLayerBuilder::from_parent([5, 4, 3, 2, 1], base.clone(), files.clone());
builder.remove_string_triple(StringTriple::new_value("cow", "says", "moo"));
builder.commit().await.unwrap();
let child: Arc<InternalLayer> = Arc::new(
ChildLayer::load_from_files([5, 4, 3, 2, 1], base, &files)
.await
.unwrap()
.into(),
);
let files = child_layer_files();
let mut builder =
SimpleLayerBuilder::from_parent([5, 4, 3, 2, 2], child.clone(), files.clone());
builder.add_string_triple(StringTriple::new_value("cow", "says", "moo"));
builder.commit().await.unwrap();
let child: Arc<InternalLayer> = Arc::new(
ChildLayer::load_from_files([5, 4, 3, 2, 2], child, &files)
.await
.unwrap()
.into(),
);
let triples: Vec<_> = child
.triples()
.map(|t| child.id_triple_to_string(&t).unwrap())
.collect();
assert_eq!(vec![StringTriple::new_value("cow", "says", "moo")], triples);
}
}