use std::collections::HashMap;
use std::hash::Hash;
use tdb_succinct::{TdbDataType, TypedDictEntry};
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: &TypedDictEntry) -> 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 id_object_node(&self, id: u64) -> Option<String> {
self.id_object(id).map(|o| {
o.node()
.expect("Expected ObjectType to be node but got a value")
})
}
fn id_object_value(&self, id: u64) -> Option<TypedDictEntry> {
self.id_object(id).map(|o| {
o.value()
.expect("Expected ObjectType to be value but got a node")
})
}
fn id_object_is_node(&self, id: u64) -> Option<bool>;
fn id_object_is_value(&self, id: u64) -> Option<bool> {
self.id_object_is_node(id).map(|v| !v)
}
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 value_triple_exists(&self, triple: &ValueTriple) -> bool {
self.value_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 value_triple_to_id(&self, triple: &ValueTriple) -> 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 value_triple_to_partially_resolved(&self, triple: ValueTriple) -> 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<ValueTriple> {
self.id_subject(triple.subject).and_then(|subject| {
self.id_predicate(triple.predicate).and_then(|predicate| {
self.id_object(triple.object).map(|object| ValueTriple {
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()
}
fn single_triple_sp(&self, subject: u64, predicate: u64) -> Option<IdTriple>;
}
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 ValueTriple {
pub subject: String,
pub predicate: String,
pub object: ObjectType,
}
impl ValueTriple {
pub fn new_node(subject: &str, predicate: &str, object: &str) -> ValueTriple {
ValueTriple {
subject: subject.to_owned(),
predicate: predicate.to_owned(),
object: ObjectType::Node(object.to_owned()),
}
}
pub fn new_value(subject: &str, predicate: &str, object: TypedDictEntry) -> ValueTriple {
ValueTriple {
subject: subject.to_owned(),
predicate: predicate.to_owned(),
object: ObjectType::Value(object),
}
}
pub fn new_string_value(subject: &str, predicate: &str, object: &str) -> ValueTriple {
ValueTriple {
subject: subject.to_owned(),
predicate: predicate.to_owned(),
object: ObjectType::Value(String::make_entry(&object)),
}
}
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<TypedDictEntry, 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(TypedDictEntry),
}
impl ObjectType {
pub fn node(self) -> Option<String> {
match self {
ObjectType::Node(s) => Some(s),
ObjectType::Value(_) => None,
}
}
pub fn node_ref(&self) -> Option<&str> {
match self {
ObjectType::Node(s) => Some(s),
ObjectType::Value(_) => None,
}
}
pub fn value(self) -> Option<TypedDictEntry> {
match self {
ObjectType::Node(_) => None,
ObjectType::Value(v) => Some(v),
}
}
pub fn value_ref(&self) -> Option<&TypedDictEntry> {
match self {
ObjectType::Node(_) => None,
ObjectType::Value(v) => Some(v),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::layer::internal::base::base_tests::base_layer_files;
use crate::layer::internal::base::BaseLayer;
use crate::layer::internal::child::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_value_triple(ValueTriple::new_string_value("cow", "says", "moo"));
builder.add_value_triple(ValueTriple::new_string_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_value_triple(ValueTriple::new_string_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![ValueTriple::new_string_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_value_triple(ValueTriple::new_string_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_value_triple(ValueTriple::new_string_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_value_triple(ValueTriple::new_string_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![ValueTriple::new_string_value("cow", "says", "moo")],
triples
);
}
#[tokio::test]
async fn find_single_triple_sp() {
let files = base_layer_files();
let mut builder = SimpleLayerBuilder::new([1, 2, 3, 4, 5], files.clone());
builder.add_value_triple(ValueTriple::new_string_value("duck", "says", "quack"));
builder.add_value_triple(ValueTriple::new_string_value("duck", "says", "neigh"));
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_value_triple(ValueTriple::new_string_value("duck", "says", "neigh"));
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_value_triple(ValueTriple::new_string_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 id_triple_1 = child
.single_triple_sp(
child.subject_id("cow").unwrap(),
child.predicate_id("says").unwrap(),
)
.unwrap();
let triple_1 = child.id_triple_to_string(&id_triple_1).unwrap();
let id_triple_2 = child
.single_triple_sp(
child.subject_id("duck").unwrap(),
child.predicate_id("says").unwrap(),
)
.unwrap();
let triple_2 = child.id_triple_to_string(&id_triple_2).unwrap();
assert_eq!(
ValueTriple::new_string_value("cow", "says", "moo"),
triple_1
);
assert_eq!(
ValueTriple::new_string_value("duck", "says", "quack"),
triple_2
);
}
#[tokio::test]
async fn find_nonstring_triples() {
let files = base_layer_files();
let mut builder = SimpleLayerBuilder::new([1, 2, 3, 4, 5], files.clone());
builder.add_value_triple(ValueTriple::new_value(
"duck",
"num_feet",
u32::make_entry(&2),
));
builder.add_value_triple(ValueTriple::new_value(
"cow",
"num_feet",
u32::make_entry(&4),
));
builder.add_value_triple(ValueTriple::new_value(
"disabled_cow",
"num_feet",
u32::make_entry(&3),
));
builder.add_value_triple(ValueTriple::new_value(
"duck",
"swims",
String::make_entry(&"true"),
));
builder.add_value_triple(ValueTriple::new_value(
"cow",
"swims",
String::make_entry(&"false"),
));
builder.add_value_triple(ValueTriple::new_value(
"disabled_cow",
"swims",
String::make_entry(&"false"),
));
builder.commit().await.unwrap();
let base: Arc<InternalLayer> = Arc::new(
BaseLayer::load_from_files([1, 2, 3, 4, 5], &files)
.await
.unwrap()
.into(),
);
let mut results: Vec<_> = base
.triples_p(base.predicate_id("num_feet").unwrap())
.map(|t| {
(
base.id_subject(t.subject).unwrap(),
base.id_object_value(t.object).unwrap().as_val::<u32, u32>(),
)
})
.collect();
results.sort();
let expected = vec![
("cow".to_owned(), 4),
("disabled_cow".to_owned(), 3),
("duck".to_owned(), 2),
];
assert_eq!(expected, results);
}
}