use crate::dictionary::{Dictionary, Term};
use crate::error::{Result, TdbError};
use crate::index::{Triple, TripleScan};
use crate::store::store_impl::TdbStore;
pub(crate) fn decode_triple_terms(
dictionary: &Dictionary,
triple: Triple,
) -> Result<(Term, Term, Term)> {
let subject = dictionary
.decode(triple.subject)?
.ok_or_else(|| TdbError::Other("Subject id not found in dictionary".to_string()))?;
let predicate = dictionary
.decode(triple.predicate)?
.ok_or_else(|| TdbError::Other("Predicate id not found in dictionary".to_string()))?;
let object = dictionary
.decode(triple.object)?
.ok_or_else(|| TdbError::Other("Object id not found in dictionary".to_string()))?;
Ok((subject, predicate, object))
}
pub struct TripleTermIter<'a> {
scan: Option<TripleScan>,
dictionary: &'a Dictionary,
}
impl<'a> TripleTermIter<'a> {
pub(crate) fn new(scan: TripleScan, dictionary: &'a Dictionary) -> Self {
Self {
scan: Some(scan),
dictionary,
}
}
pub(crate) fn empty(dictionary: &'a Dictionary) -> Self {
Self {
scan: None,
dictionary,
}
}
}
impl Iterator for TripleTermIter<'_> {
type Item = Result<(Term, Term, Term)>;
fn next(&mut self) -> Option<Self::Item> {
let scan = self.scan.as_mut()?;
match scan.next()? {
Ok(triple) => Some(decode_triple_terms(self.dictionary, triple)),
Err(e) => Some(Err(e)),
}
}
}
impl TdbStore {
pub fn stream_triples(
&self,
subject: Option<&Term>,
predicate: Option<&Term>,
object: Option<&Term>,
) -> Result<TripleTermIter<'_>> {
let s_id = match subject {
None => None,
Some(term) => match self.dictionary.lookup(term)? {
Some(id) => Some(id),
None => return Ok(TripleTermIter::empty(&self.dictionary)),
},
};
let p_id = match predicate {
None => None,
Some(term) => match self.dictionary.lookup(term)? {
Some(id) => Some(id),
None => return Ok(TripleTermIter::empty(&self.dictionary)),
},
};
let o_id = match object {
None => None,
Some(term) => match self.dictionary.lookup(term)? {
Some(id) => Some(id),
None => return Ok(TripleTermIter::empty(&self.dictionary)),
},
};
let scan = self.indexes.scan(s_id, p_id, o_id)?;
Ok(TripleTermIter::new(scan, &self.dictionary))
}
pub fn for_each_triple<F>(
&self,
subject: Option<&Term>,
predicate: Option<&Term>,
object: Option<&Term>,
mut f: F,
) -> Result<()>
where
F: FnMut((Term, Term, Term)) -> Result<()>,
{
for item in self.stream_triples(subject, predicate, object)? {
f(item?)?;
}
Ok(())
}
}