parent
cdafcfc2cc
commit
7ed4252ad8
@ -1,3 +1,3 @@ |
|||||||
pub mod algebra; |
pub mod algebra; |
||||||
pub mod model; |
|
||||||
pub mod parser; |
pub mod parser; |
||||||
|
pub mod xml_results; |
||||||
|
@ -1,64 +0,0 @@ |
|||||||
use model::*; |
|
||||||
use sparql::algebra::TermOrVariable; |
|
||||||
use sparql::algebra::Variable; |
|
||||||
use std::collections::BTreeMap; |
|
||||||
use std::fmt; |
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] |
|
||||||
pub struct Binding(BTreeMap<Variable, Term>); |
|
||||||
|
|
||||||
impl Binding { |
|
||||||
pub fn insert(&mut self, var: Variable, value: Term) { |
|
||||||
self.0.insert(var, value); |
|
||||||
} |
|
||||||
|
|
||||||
pub fn get<'a>(&'a self, key: &'a Variable) -> Option<&'a Term> { |
|
||||||
self.0.get(key) |
|
||||||
} |
|
||||||
|
|
||||||
pub fn get_or_constant<'a>(&'a self, key: &'a TermOrVariable) -> Option<Term> { |
|
||||||
match key { |
|
||||||
TermOrVariable::NamedNode(node) => Some(node.clone().into()), |
|
||||||
TermOrVariable::Literal(literal) => Some(literal.clone().into()), |
|
||||||
TermOrVariable::Variable(v) => self.get(v).cloned(), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
pub fn iter(&self) -> <&BTreeMap<Variable, Term> as IntoIterator>::IntoIter { |
|
||||||
self.0.iter() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl Default for Binding { |
|
||||||
fn default() -> Self { |
|
||||||
Binding(BTreeMap::default()) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl IntoIterator for Binding { |
|
||||||
type Item = (Variable, Term); |
|
||||||
type IntoIter = <BTreeMap<Variable, Term> as IntoIterator>::IntoIter; |
|
||||||
|
|
||||||
fn into_iter(self) -> <BTreeMap<Variable, Term> as IntoIterator>::IntoIter { |
|
||||||
self.0.into_iter() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a Binding { |
|
||||||
type Item = (&'a Variable, &'a Term); |
|
||||||
type IntoIter = <&'a BTreeMap<Variable, Term> as IntoIterator>::IntoIter; |
|
||||||
|
|
||||||
fn into_iter(self) -> <&'a BTreeMap<Variable, Term> as IntoIterator>::IntoIter { |
|
||||||
self.0.iter() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl fmt::Display for Binding { |
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
||||||
write!(f, "{{")?; |
|
||||||
for (var, val) in self { |
|
||||||
write!(f, " {} → {} ", var, val)?; |
|
||||||
} |
|
||||||
write!(f, "}}") |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,333 @@ |
|||||||
|
use errors::*; |
||||||
|
use model::*; |
||||||
|
use quick_xml::events::Event; |
||||||
|
use quick_xml::Reader; |
||||||
|
use sparql::algebra::BindingsIterator; |
||||||
|
use sparql::algebra::QueryResult; |
||||||
|
use sparql::algebra::Variable; |
||||||
|
use std::collections::BTreeMap; |
||||||
|
use std::io::BufRead; |
||||||
|
use std::iter::empty; |
||||||
|
use std::str::FromStr; |
||||||
|
|
||||||
|
pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResult> { |
||||||
|
enum State { |
||||||
|
Start, |
||||||
|
Sparql, |
||||||
|
Head, |
||||||
|
AfterHead, |
||||||
|
Boolean, |
||||||
|
} |
||||||
|
|
||||||
|
let mut reader = Reader::from_reader(source); |
||||||
|
reader.trim_text(true); |
||||||
|
|
||||||
|
let mut buffer = Vec::default(); |
||||||
|
let mut namespace_buffer = Vec::default(); |
||||||
|
let mut variables: Vec<String> = Vec::default(); |
||||||
|
let mut state = State::Start; |
||||||
|
|
||||||
|
//Read header
|
||||||
|
loop { |
||||||
|
let event = { |
||||||
|
let (ns, event) = reader.read_namespaced_event(&mut buffer, &mut namespace_buffer)?; |
||||||
|
if let Some(ns) = ns { |
||||||
|
if ns != b"http://www.w3.org/2005/sparql-results#".as_ref() { |
||||||
|
return Err(format!( |
||||||
|
"Unexpected namespace found in RDF/XML query result: {}", |
||||||
|
reader.decode(ns) |
||||||
|
).into()); |
||||||
|
} |
||||||
|
} |
||||||
|
event |
||||||
|
}; |
||||||
|
match event { |
||||||
|
Event::Start(event) => match state { |
||||||
|
State::Start => { |
||||||
|
if event.name() == b"sparql" { |
||||||
|
state = State::Sparql; |
||||||
|
} else { |
||||||
|
return Err(format!("Expecting <sparql> tag, found {}", reader.decode(event.name())).into()); |
||||||
|
} |
||||||
|
} |
||||||
|
State::Sparql => { |
||||||
|
if event.name() == b"head" { |
||||||
|
state = State::Head; |
||||||
|
} else { |
||||||
|
return Err(format!("Expecting <head> tag, found {}", reader.decode(event.name())).into()); |
||||||
|
} |
||||||
|
} |
||||||
|
State::Head => if event.name() == b"variable" || event.name() == b"link" { |
||||||
|
return Err("<variable> and <link> tag should be autoclosing".into()); |
||||||
|
} else { |
||||||
|
return Err(format!("Expecting <variable> or <link> tag, found {}", reader.decode(event.name())).into()); |
||||||
|
}, |
||||||
|
State::AfterHead => { |
||||||
|
if event.name() == b"boolean" { |
||||||
|
state = State::Boolean |
||||||
|
} else if event.name() == b"results" { |
||||||
|
let mut mapping = BTreeMap::default(); |
||||||
|
for (i,var) in variables.iter().enumerate() { |
||||||
|
mapping.insert(var.as_bytes().to_vec(), i); |
||||||
|
} |
||||||
|
return Ok(QueryResult::Bindings(BindingsIterator::new( |
||||||
|
variables.into_iter().map(Variable::new).collect(), |
||||||
|
Box::new(ResultsIterator { |
||||||
|
reader, |
||||||
|
buffer: Vec::default(), |
||||||
|
namespace_buffer, |
||||||
|
mapping, |
||||||
|
bnodes_map: BTreeMap::default(), |
||||||
|
}), |
||||||
|
))); |
||||||
|
} else if event.name() != b"link" && event.name() != b"results" && event.name() != b"boolean" { |
||||||
|
return Err(format!("Expecting sparql tag, found {}", reader.decode(event.name())).into()); |
||||||
|
} |
||||||
|
} |
||||||
|
State::Boolean => return Err(format!("Unexpected tag inside of <boolean> tag: {}", reader.decode(event.name())).into()) |
||||||
|
}, |
||||||
|
Event::Empty(event) => match state { |
||||||
|
State::Head => { |
||||||
|
if event.name() == b"variable" { |
||||||
|
let name = event.attributes() |
||||||
|
.filter(|attr| attr.is_ok()) |
||||||
|
.map(|attr| attr.unwrap()) |
||||||
|
.find(|attr| attr.key == b"name") |
||||||
|
.ok_or("No name attribute found for the <variable> tag"); |
||||||
|
variables.push(name?.unescape_and_decode_value(&reader)?); |
||||||
|
} else if event.name() == b"link" { |
||||||
|
// no op
|
||||||
|
} else { |
||||||
|
return Err(format!("Expecting <variable> or <link> tag, found {}", reader.decode(event.name())).into()); |
||||||
|
} |
||||||
|
}, |
||||||
|
State::AfterHead => { |
||||||
|
if event.name() == b"results" { |
||||||
|
return Ok(QueryResult::Bindings(BindingsIterator::new( |
||||||
|
variables.into_iter().map(Variable::new).collect(), |
||||||
|
Box::new(empty()), |
||||||
|
))) |
||||||
|
} else { |
||||||
|
return Err(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name())).into()) |
||||||
|
} |
||||||
|
} |
||||||
|
_ => return Err(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name())).into()) |
||||||
|
}, |
||||||
|
Event::Text(event) => { |
||||||
|
let value = event.unescaped()?; |
||||||
|
return match state { |
||||||
|
State::Boolean => { |
||||||
|
return if value.as_ref() == b"true" { |
||||||
|
Ok(QueryResult::Boolean(true)) |
||||||
|
} else if value.as_ref() == b"false" { |
||||||
|
Ok(QueryResult::Boolean(false)) |
||||||
|
} else { |
||||||
|
Err(format!("Unexpected boolean value. Found {}", reader.decode(&value)).into()) |
||||||
|
}; |
||||||
|
} |
||||||
|
_ => Err(format!("Unexpected textual value found: {}", reader.decode(&value)).into()) |
||||||
|
}; |
||||||
|
}, |
||||||
|
Event::End(_) => match state { |
||||||
|
State::Head => state = State::AfterHead, |
||||||
|
_ => { |
||||||
|
return Err("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag".into()); |
||||||
|
} |
||||||
|
}, |
||||||
|
Event::Eof => return Err("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag".into()), |
||||||
|
_ => (), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
struct ResultsIterator<R: BufRead> { |
||||||
|
reader: Reader<R>, |
||||||
|
buffer: Vec<u8>, |
||||||
|
namespace_buffer: Vec<u8>, |
||||||
|
mapping: BTreeMap<Vec<u8>, usize>, |
||||||
|
bnodes_map: BTreeMap<Vec<u8>, BlankNode>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<R: BufRead> Iterator for ResultsIterator<R> { |
||||||
|
type Item = Result<Vec<Option<Term>>>; |
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Result<Vec<Option<Term>>>> { |
||||||
|
enum State { |
||||||
|
Start, |
||||||
|
Result, |
||||||
|
Binding, |
||||||
|
Uri, |
||||||
|
BNode, |
||||||
|
Literal, |
||||||
|
End, |
||||||
|
} |
||||||
|
let mut state = State::Start; |
||||||
|
|
||||||
|
let mut new_bindings = Vec::default(); |
||||||
|
new_bindings.resize(self.mapping.len(), None); |
||||||
|
|
||||||
|
let mut current_var = None; |
||||||
|
let mut term: Option<Term> = None; |
||||||
|
let mut lang = None; |
||||||
|
let mut datatype = None; |
||||||
|
loop { |
||||||
|
let (ns, event) = match self |
||||||
|
.reader |
||||||
|
.read_namespaced_event(&mut self.buffer, &mut self.namespace_buffer) |
||||||
|
{ |
||||||
|
Ok(v) => v, |
||||||
|
Err(error) => return Some(Err(error.into())), |
||||||
|
}; |
||||||
|
if let Some(ns) = ns { |
||||||
|
if ns != b"http://www.w3.org/2005/sparql-results#".as_ref() { |
||||||
|
return Some(Err(format!( |
||||||
|
"Unexpected namespace found in RDF/XML query result: {}", |
||||||
|
self.reader.decode(ns) |
||||||
|
).into())); |
||||||
|
} |
||||||
|
} |
||||||
|
match event { |
||||||
|
Event::Start(event) => match state { |
||||||
|
State::Start => if event.name() == b"result" { |
||||||
|
state = State::Result; |
||||||
|
} else { |
||||||
|
return Some(Err(format!( |
||||||
|
"Expecting <result>, found {}", |
||||||
|
self.reader.decode(event.name()) |
||||||
|
).into())); |
||||||
|
}, |
||||||
|
State::Result => if event.name() == b"binding" { |
||||||
|
match event |
||||||
|
.attributes() |
||||||
|
.filter(|attr| attr.is_ok()) |
||||||
|
.map(|attr| attr.unwrap()) |
||||||
|
.find(|attr| attr.key == b"name") |
||||||
|
{ |
||||||
|
Some(attr) => match attr.unescaped_value() { |
||||||
|
Ok(var) => current_var = Some(var.to_vec()), |
||||||
|
Err(error) => return Some(Err(error.into())), |
||||||
|
}, |
||||||
|
None => { |
||||||
|
return Some(Err( |
||||||
|
"No name attribute found for the <binding> tag".into() |
||||||
|
)) |
||||||
|
} |
||||||
|
} |
||||||
|
state = State::Binding; |
||||||
|
} else { |
||||||
|
return Some(Err(format!( |
||||||
|
"Expecting <binding>, found {}", |
||||||
|
self.reader.decode(event.name()) |
||||||
|
).into())); |
||||||
|
}, |
||||||
|
State::Binding => { |
||||||
|
if term.is_some() { |
||||||
|
return Some(Err( |
||||||
|
"There is already a value for the current binding".into() |
||||||
|
)); |
||||||
|
} |
||||||
|
if event.name() == b"uri" { |
||||||
|
state = State::Uri; |
||||||
|
} else if event.name() == b"bnode" { |
||||||
|
state = State::BNode; |
||||||
|
} else if event.name() == b"literal" { |
||||||
|
for attr in event.attributes() { |
||||||
|
if let Ok(attr) = attr { |
||||||
|
if attr.key == b"xml:lang" { |
||||||
|
match attr.unescape_and_decode_value(&self.reader) { |
||||||
|
Ok(val) => lang = Some(val), |
||||||
|
Err(error) => return Some(Err(error.into())), |
||||||
|
} |
||||||
|
} else if attr.key == b"datatype" { |
||||||
|
match attr.unescaped_value() { |
||||||
|
Ok(val) => { |
||||||
|
match NamedNode::from_str(&self.reader.decode(&val)) |
||||||
|
{ |
||||||
|
Ok(dt) => datatype = Some(dt), |
||||||
|
Err(error) => return Some(Err(error)), |
||||||
|
} |
||||||
|
} |
||||||
|
Err(error) => return Some(Err(error.into())), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
state = State::Literal; |
||||||
|
} else { |
||||||
|
return Some(Err(format!( |
||||||
|
"Expecting <uri>, <bnode> or <literal> found {}", |
||||||
|
self.reader.decode(event.name()) |
||||||
|
).into())); |
||||||
|
} |
||||||
|
} |
||||||
|
_ => (), |
||||||
|
}, |
||||||
|
Event::Text(event) => match event.unescaped() { |
||||||
|
Ok(data) => match state { |
||||||
|
State::Uri => match NamedNode::from_str(&self.reader.decode(&data)) { |
||||||
|
Ok(named_node) => term = Some(named_node.into()), |
||||||
|
Err(error) => return Some(Err(error)), |
||||||
|
}, |
||||||
|
State::BNode => { |
||||||
|
term = Some( |
||||||
|
self.bnodes_map |
||||||
|
.entry(data.to_vec()) |
||||||
|
.or_insert_with(BlankNode::default) |
||||||
|
.clone() |
||||||
|
.into(), |
||||||
|
) |
||||||
|
} |
||||||
|
State::Literal => { |
||||||
|
let value = self.reader.decode(&data).to_string(); |
||||||
|
term = Some( |
||||||
|
match datatype { |
||||||
|
Some(ref datatype) => { |
||||||
|
Literal::new_typed_literal(value, datatype.clone()) |
||||||
|
} |
||||||
|
None => match lang { |
||||||
|
Some(ref lang) => Literal::new_language_tagged_literal( |
||||||
|
value, |
||||||
|
lang.clone(), |
||||||
|
), |
||||||
|
None => Literal::new_simple_literal(value), |
||||||
|
}, |
||||||
|
}.into(), |
||||||
|
) |
||||||
|
} |
||||||
|
_ => { |
||||||
|
return Some(Err(format!( |
||||||
|
"Unexpected textual value found: {}", |
||||||
|
self.reader.decode(&data) |
||||||
|
).into())) |
||||||
|
} |
||||||
|
}, |
||||||
|
Err(error) => return Some(Err(error.into())), |
||||||
|
}, |
||||||
|
Event::End(_) => match state { |
||||||
|
State::Start => state = State::End, |
||||||
|
State::Result => return Some(Ok(new_bindings)), |
||||||
|
State::Binding => { |
||||||
|
match (¤t_var, &term) { |
||||||
|
(Some(var), Some(term)) => { |
||||||
|
new_bindings[self.mapping[var]] = Some(term.clone()) |
||||||
|
} |
||||||
|
(Some(var), None) => { |
||||||
|
return Some(Err(format!( |
||||||
|
"No variable found for variable {}", |
||||||
|
self.reader.decode(&var) |
||||||
|
).into())) |
||||||
|
} |
||||||
|
_ => return Some(Err("No name found for <binding> tag".into())), |
||||||
|
} |
||||||
|
term = None; |
||||||
|
state = State::Result; |
||||||
|
} |
||||||
|
State::Uri | State::BNode | State::Literal => state = State::Binding, |
||||||
|
_ => (), |
||||||
|
}, |
||||||
|
Event::Eof => return None, |
||||||
|
_ => (), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,315 @@ |
|||||||
|
use errors::*; |
||||||
|
use sparql::algebra::*; |
||||||
|
use std::iter::once; |
||||||
|
use std::iter::Iterator; |
||||||
|
use std::sync::Arc; |
||||||
|
use store::numeric_encoder::EncodedTerm; |
||||||
|
use store::store::EncodedQuadsStore; |
||||||
|
|
||||||
|
type EncodedBinding = Vec<Option<EncodedTerm>>; |
||||||
|
|
||||||
|
struct EncodedBindingsIterator { |
||||||
|
variables: Vec<Variable>, |
||||||
|
iter: Box<dyn Iterator<Item = Result<EncodedBinding>>>, |
||||||
|
} |
||||||
|
|
||||||
|
impl EncodedBindingsIterator { |
||||||
|
fn take(self, n: usize) -> Self { |
||||||
|
EncodedBindingsIterator { |
||||||
|
variables: self.variables, |
||||||
|
iter: Box::new(self.iter.take(n)), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn skip(self, n: usize) -> Self { |
||||||
|
EncodedBindingsIterator { |
||||||
|
variables: self.variables, |
||||||
|
iter: Box::new(self.iter.skip(n)), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn project(self, on_variables: Vec<Variable>) -> Self { |
||||||
|
let EncodedBindingsIterator { variables, iter } = self; |
||||||
|
let projection: Vec<(usize, usize)> = on_variables |
||||||
|
.iter() |
||||||
|
.enumerate() |
||||||
|
.flat_map(|(new_pos, v)| slice_key(&variables, v).map(|old_pos| (old_pos, new_pos))) |
||||||
|
.collect(); |
||||||
|
let new_len = on_variables.len(); |
||||||
|
EncodedBindingsIterator { |
||||||
|
variables: on_variables, |
||||||
|
iter: Box::new(iter.map(move |binding| { |
||||||
|
let binding = binding?; |
||||||
|
let mut new_binding = Vec::with_capacity(new_len); |
||||||
|
new_binding.resize(new_len, None); |
||||||
|
for (old_pos, new_pos) in &projection { |
||||||
|
new_binding[*new_pos] = binding[*old_pos]; |
||||||
|
} |
||||||
|
Ok(new_binding) |
||||||
|
})), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Default for EncodedBindingsIterator { |
||||||
|
fn default() -> Self { |
||||||
|
EncodedBindingsIterator { |
||||||
|
variables: Vec::default(), |
||||||
|
iter: Box::new(once(Ok(Vec::default()))), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn slice_key<T: Eq>(slice: &[T], element: &T) -> Option<usize> { |
||||||
|
for (i, item) in slice.iter().enumerate() { |
||||||
|
if item == element { |
||||||
|
return Some(i); |
||||||
|
} |
||||||
|
} |
||||||
|
None |
||||||
|
} |
||||||
|
|
||||||
|
pub struct SparqlEvaluator<S: EncodedQuadsStore> { |
||||||
|
store: Arc<S>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<S: EncodedQuadsStore> SparqlEvaluator<S> { |
||||||
|
pub fn new(store: Arc<S>) -> Self { |
||||||
|
Self { store } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn evaluate(&self, query: &Query) -> Result<QueryResult> { |
||||||
|
match query { |
||||||
|
Query::SelectQuery { algebra, dataset } => { |
||||||
|
Ok(QueryResult::Bindings(self.decode_bindings( |
||||||
|
self.eval_list_pattern(algebra, EncodedBindingsIterator::default())?, |
||||||
|
))) |
||||||
|
} |
||||||
|
_ => unimplemented!(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn eval_list_pattern( |
||||||
|
&self, |
||||||
|
pattern: &ListPattern, |
||||||
|
from: EncodedBindingsIterator, |
||||||
|
) -> Result<EncodedBindingsIterator> { |
||||||
|
match pattern { |
||||||
|
ListPattern::Data(bs) => Ok(self.encode_bindings(bs)), |
||||||
|
ListPattern::ToList(l) => self.eval_multi_set_pattern(l, from), |
||||||
|
ListPattern::OrderBy(l, o) => self.eval_list_pattern(l, from), //TODO
|
||||||
|
ListPattern::Project(l, new_variables) => Ok(self |
||||||
|
.eval_list_pattern(l, from)? |
||||||
|
.project(new_variables.to_vec())), |
||||||
|
ListPattern::Distinct(l) => self.eval_list_pattern(l, from), //TODO
|
||||||
|
ListPattern::Reduced(l) => self.eval_list_pattern(l, from), |
||||||
|
ListPattern::Slice(l, start, length) => { |
||||||
|
let mut iter = self.eval_list_pattern(l, from)?; |
||||||
|
if *start > 0 { |
||||||
|
iter = iter.skip(*start); |
||||||
|
} |
||||||
|
if let Some(length) = length { |
||||||
|
iter = iter.take(*length); |
||||||
|
} |
||||||
|
Ok(iter) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn eval_multi_set_pattern( |
||||||
|
&self, |
||||||
|
pattern: &MultiSetPattern, |
||||||
|
from: EncodedBindingsIterator, |
||||||
|
) -> Result<EncodedBindingsIterator> { |
||||||
|
match pattern { |
||||||
|
MultiSetPattern::BGP(p) => { |
||||||
|
let mut iter = from; |
||||||
|
for pattern in p { |
||||||
|
iter = match pattern { |
||||||
|
TripleOrPathPattern::Triple(pattern) => { |
||||||
|
self.eval_triple_pattern(pattern, iter) |
||||||
|
} |
||||||
|
TripleOrPathPattern::Path(pattern) => self.eval_path_pattern(pattern, iter), |
||||||
|
}?; |
||||||
|
} |
||||||
|
Ok(iter) |
||||||
|
} |
||||||
|
MultiSetPattern::Join(a, b) => { |
||||||
|
self.eval_multi_set_pattern(b, self.eval_multi_set_pattern(a, from)?) |
||||||
|
} |
||||||
|
MultiSetPattern::LeftJoin(a, b, e) => unimplemented!(), |
||||||
|
MultiSetPattern::Filter(e, p) => unimplemented!(), |
||||||
|
MultiSetPattern::Union(a, b) => unimplemented!(), |
||||||
|
MultiSetPattern::Graph(g, p) => unimplemented!(), |
||||||
|
MultiSetPattern::Extend(p, v, e) => unimplemented!(), |
||||||
|
MultiSetPattern::Minus(a, b) => unimplemented!(), |
||||||
|
MultiSetPattern::ToMultiSet(l) => self.eval_list_pattern(l, from), |
||||||
|
MultiSetPattern::Service(n, p, s) => unimplemented!(), |
||||||
|
MultiSetPattern::AggregateJoin(g, a) => unimplemented!(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn eval_triple_pattern( |
||||||
|
&self, |
||||||
|
pattern: &TriplePattern, |
||||||
|
from: EncodedBindingsIterator, |
||||||
|
) -> Result<EncodedBindingsIterator> { |
||||||
|
let EncodedBindingsIterator { |
||||||
|
mut variables, |
||||||
|
iter: from_iter, |
||||||
|
} = from; |
||||||
|
let subject = |
||||||
|
self.binding_value_lookup_from_term_or_variable(&pattern.subject, &mut variables)?; |
||||||
|
let predicate = self |
||||||
|
.binding_value_lookup_from_named_node_or_variable(&pattern.predicate, &mut variables)?; |
||||||
|
let object = |
||||||
|
self.binding_value_lookup_from_term_or_variable(&pattern.object, &mut variables)?; |
||||||
|
|
||||||
|
let store = self.store.clone(); |
||||||
|
let variables_len = variables.len(); |
||||||
|
Ok(EncodedBindingsIterator { |
||||||
|
variables, |
||||||
|
iter: Box::new(from_iter.flat_map(move |binding| { |
||||||
|
let result: Box<dyn Iterator<Item = Result<EncodedBinding>>> = match binding { |
||||||
|
Ok(mut binding) => { |
||||||
|
match store.quads_for_pattern( |
||||||
|
subject.get(&binding), |
||||||
|
predicate.get(&binding), |
||||||
|
object.get(&binding), |
||||||
|
None, //TODO
|
||||||
|
) { |
||||||
|
Ok(iter) => Box::new(iter.map(move |quad| { |
||||||
|
let quad = quad?; |
||||||
|
let mut binding = binding.clone(); |
||||||
|
binding.resize(variables_len, None); |
||||||
|
subject.put(quad.subject, &mut binding); |
||||||
|
predicate.put(quad.predicate, &mut binding); |
||||||
|
object.put(quad.object, &mut binding); |
||||||
|
Ok(binding) |
||||||
|
})), |
||||||
|
Err(error) => Box::new(once(Err(error))), |
||||||
|
} |
||||||
|
} |
||||||
|
Err(error) => Box::new(once(Err(error))), |
||||||
|
}; |
||||||
|
result |
||||||
|
})), |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn eval_path_pattern( |
||||||
|
&self, |
||||||
|
pattern: &PathPattern, |
||||||
|
from: EncodedBindingsIterator, |
||||||
|
) -> Result<EncodedBindingsIterator> { |
||||||
|
unimplemented!() |
||||||
|
} |
||||||
|
|
||||||
|
fn binding_value_lookup_from_term_or_variable( |
||||||
|
&self, |
||||||
|
term_or_variable: &TermOrVariable, |
||||||
|
variables: &mut Vec<Variable>, |
||||||
|
) -> Result<BindingValueLookup> { |
||||||
|
Ok(match term_or_variable { |
||||||
|
TermOrVariable::Term(term) => { |
||||||
|
BindingValueLookup::Constant(self.store.encoder().encode_term(term)?) |
||||||
|
} |
||||||
|
TermOrVariable::Variable(variable) => { |
||||||
|
BindingValueLookup::Variable(match slice_key(variables, variable) { |
||||||
|
Some(key) => key, |
||||||
|
None => { |
||||||
|
variables.push(variable.clone()); |
||||||
|
variables.len() - 1 |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn binding_value_lookup_from_named_node_or_variable( |
||||||
|
&self, |
||||||
|
named_node_or_variable: &NamedNodeOrVariable, |
||||||
|
variables: &mut Vec<Variable>, |
||||||
|
) -> Result<BindingValueLookup> { |
||||||
|
Ok(match named_node_or_variable { |
||||||
|
NamedNodeOrVariable::NamedNode(named_node) => { |
||||||
|
BindingValueLookup::Constant(self.store.encoder().encode_named_node(named_node)?) |
||||||
|
} |
||||||
|
NamedNodeOrVariable::Variable(variable) => { |
||||||
|
BindingValueLookup::Variable(match slice_key(variables, variable) { |
||||||
|
Some(key) => key, |
||||||
|
None => { |
||||||
|
variables.push(variable.clone()); |
||||||
|
variables.len() - 1 |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn encode_bindings(&self, bindings: &StaticBindings) -> EncodedBindingsIterator { |
||||||
|
let encoder = self.store.encoder(); |
||||||
|
let encoded_values: Vec<Result<EncodedBinding>> = bindings |
||||||
|
.values_iter() |
||||||
|
.map(move |values| { |
||||||
|
let mut result = Vec::with_capacity(values.len()); |
||||||
|
for value in values { |
||||||
|
result.push(match value { |
||||||
|
Some(term) => Some(encoder.encode_term(term)?), |
||||||
|
None => None, |
||||||
|
}); |
||||||
|
} |
||||||
|
Ok(result) |
||||||
|
}).collect(); |
||||||
|
EncodedBindingsIterator { |
||||||
|
variables: bindings.variables().to_vec(), |
||||||
|
iter: Box::new(encoded_values.into_iter()), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn decode_bindings(&self, iter: EncodedBindingsIterator) -> BindingsIterator { |
||||||
|
let store = self.store.clone(); |
||||||
|
let EncodedBindingsIterator { variables, iter } = iter; |
||||||
|
BindingsIterator::new( |
||||||
|
variables, |
||||||
|
Box::new(iter.map(move |values| { |
||||||
|
let values = values?; |
||||||
|
let encoder = store.encoder(); |
||||||
|
let mut result = Vec::with_capacity(values.len()); |
||||||
|
for value in values { |
||||||
|
result.push(match value { |
||||||
|
Some(term) => Some(encoder.decode_term(term)?), |
||||||
|
None => None, |
||||||
|
}); |
||||||
|
} |
||||||
|
Ok(result) |
||||||
|
})), |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, Copy)] |
||||||
|
enum BindingValueLookup { |
||||||
|
Constant(EncodedTerm), |
||||||
|
Variable(usize), |
||||||
|
} |
||||||
|
|
||||||
|
impl BindingValueLookup { |
||||||
|
fn get(&self, binding: &[Option<EncodedTerm>]) -> Option<EncodedTerm> { |
||||||
|
match self { |
||||||
|
BindingValueLookup::Constant(term) => Some(*term), |
||||||
|
BindingValueLookup::Variable(v) => if *v < binding.len() { |
||||||
|
binding[*v] |
||||||
|
} else { |
||||||
|
None |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn put(&self, value: EncodedTerm, binding: &mut EncodedBinding) { |
||||||
|
match self { |
||||||
|
BindingValueLookup::Constant(_) => (), |
||||||
|
BindingValueLookup::Variable(v) => binding[*v] = Some(value), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue