Runs cargo fmt

pull/14/head
Tpt 5 years ago
parent 033ee373d2
commit b4065e607c
  1. 6
      lib/src/repository.rs
  2. 611
      lib/src/sparql/eval.rs
  3. 30
      lib/src/sparql/mod.rs
  4. 4
      lib/src/sparql/plan.rs
  5. 2
      lib/src/sparql/plan_builder.rs
  6. 14
      lib/src/store/mod.rs
  7. 354
      lib/tests/service_test_cases.rs

@ -83,7 +83,11 @@ pub trait RepositoryConnection: Clone {
/// assert_eq!(results.into_values_iter().next().unwrap().unwrap()[0], Some(ex.into())); /// assert_eq!(results.into_values_iter().next().unwrap().unwrap()[0], Some(ex.into()));
/// } /// }
/// ``` /// ```
fn prepare_query<'a>(&'a self, query: &str, base_iri: Option<&'a str>) -> Result<Self::PreparedQuery>; fn prepare_query<'a>(
&'a self,
query: &str,
base_iri: Option<&'a str>,
) -> Result<Self::PreparedQuery>;
/// This is similar to `prepare_query`, but useful if a SPARQL query has already been parsed, which is the case when building `ServiceHandler`s for federated queries with `SERVICE` clauses. For examples, look in the tests. /// This is similar to `prepare_query`, but useful if a SPARQL query has already been parsed, which is the case when building `ServiceHandler`s for federated queries with `SERVICE` clauses. For examples, look in the tests.
fn prepare_query_from_pattern<'a>( fn prepare_query_from_pattern<'a>(

@ -1,8 +1,8 @@
use crate::model::BlankNode; use crate::model::BlankNode;
use crate::model::Triple; use crate::model::Triple;
use crate::sparql::model::*; use crate::sparql::model::*;
use crate::sparql::QueryOptions;
use crate::sparql::plan::*; use crate::sparql::plan::*;
use crate::sparql::QueryOptions;
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
use crate::store::StoreConnection; use crate::store::StoreConnection;
use crate::Result; use crate::Result;
@ -59,7 +59,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
&'b self, &'b self,
plan: &'b PlanNode, plan: &'b PlanNode,
variables: &[Variable], variables: &[Variable],
options: &'b QueryOptions<'b> options: &'b QueryOptions<'b>,
) -> Result<QueryResult<'b>> ) -> Result<QueryResult<'b>>
where where
'a: 'b, 'a: 'b,
@ -73,7 +73,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
pub fn evaluate_ask_plan<'b>( pub fn evaluate_ask_plan<'b>(
&'b self, &'b self,
plan: &'b PlanNode, plan: &'b PlanNode,
options: &'b QueryOptions<'b> options: &'b QueryOptions<'b>,
) -> Result<QueryResult<'b>> ) -> Result<QueryResult<'b>>
where where
'a: 'b, 'a: 'b,
@ -89,7 +89,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
&'b self, &'b self,
plan: &'b PlanNode, plan: &'b PlanNode,
construct: &'b [TripleTemplate], construct: &'b [TripleTemplate],
options: &'b QueryOptions<'b> options: &'b QueryOptions<'b>,
) -> Result<QueryResult<'b>> ) -> Result<QueryResult<'b>>
where where
'a: 'b, 'a: 'b,
@ -106,7 +106,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
pub fn evaluate_describe_plan<'b>( pub fn evaluate_describe_plan<'b>(
&'b self, &'b self,
plan: &'b PlanNode, plan: &'b PlanNode,
options: &'b QueryOptions<'b> options: &'b QueryOptions<'b>,
) -> Result<QueryResult<'b>> ) -> Result<QueryResult<'b>>
where where
'a: 'b, 'a: 'b,
@ -123,7 +123,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
&'b self, &'b self,
node: &'b PlanNode, node: &'b PlanNode,
from: EncodedTuple, from: EncodedTuple,
options: &'b QueryOptions<'b> options: &'b QueryOptions<'b>,
) -> EncodedTuplesIterator<'b> ) -> EncodedTuplesIterator<'b>
where where
'a: 'b, 'a: 'b,
@ -137,68 +137,70 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
service_name, service_name,
graph_pattern, graph_pattern,
.. ..
} => { } => match &options.service_handler {
match &options.service_handler { None => {
None => if *silent { if *silent {
return Box::new(empty()); return Box::new(empty());
} else { } else {
return Box::new(once(Err(format_err!( return Box::new(once(Err(format_err!(
"No handler was supplied to resolve the given service" "No handler was supplied to resolve the given service"
)))) as EncodedTuplesIterator<'_>; )))) as EncodedTuplesIterator<'_>;
}, }
Some(handler) => { }
let pattern_option = match get_pattern_value(service_name, &[]) { Some(handler) => {
None => if *silent { let pattern_option = match get_pattern_value(service_name, &[]) {
return Box::new(empty()); None => {
} else { if *silent {
return Box::new(once(Err(format_err!( return Box::new(empty());
"The handler supplied was unable to evaluate the given service" } else {
)))) as EncodedTuplesIterator<'_>; return Box::new(once(Err(format_err!(
}, "The handler supplied was unable to evaluate the given service"
Some(term) => { ))))
match self.dataset.decode_named_node(term) { as EncodedTuplesIterator<'_>;
Err(err) => if *silent { }
return Box::new(empty()); }
} else { Some(term) => match self.dataset.decode_named_node(term) {
return Box::new(once(Err(err))) as EncodedTuplesIterator<'_>; Err(err) => {
}, if *silent {
Ok(named_node) => { return Box::new(empty());
println!("named_node: {:?}", named_node); } else {
handler.handle(named_node) return Box::new(once(Err(err))) as EncodedTuplesIterator<'_>;
}
} }
}, }
}; Ok(named_node) => {
match pattern_option { println!("named_node: {:?}", named_node);
None => if *silent { handler.handle(named_node)
return Box::new(empty()); }
} else { },
return Box::new(once(Err(format_err!( };
match pattern_option {
None => {
if *silent {
return Box::new(empty());
} else {
return Box::new(once(Err(format_err!(
"The handler supplied was unable to produce any result set on the given service" "The handler supplied was unable to produce any result set on the given service"
)))) as EncodedTuplesIterator<'_>; )))) as EncodedTuplesIterator<'_>;
}, }
Some(pattern_fn) => {
match pattern_fn(graph_pattern.clone()) {
Ok(bindings) => {
let encoded = self.encode_bindings(variables, bindings);
let collected = encoded.collect::<Vec<_>>();
Box::new(JoinIterator {
left: vec![from],
right_iter: Box::new(collected.into_iter()),
buffered_results: vec![],
})
},
Err(err) => {
if *silent {
return Box::new(empty());
} else {
return Box::new(once(Err(err))) as EncodedTuplesIterator<'_>
}
}
}
},
} }
Some(pattern_fn) => match pattern_fn(graph_pattern.clone()) {
Ok(bindings) => {
let encoded = self.encode_bindings(variables, bindings);
let collected = encoded.collect::<Vec<_>>();
Box::new(JoinIterator {
left: vec![from],
right_iter: Box::new(collected.into_iter()),
buffered_results: vec![],
})
}
Err(err) => {
if *silent {
return Box::new(empty());
} else {
return Box::new(once(Err(err))) as EncodedTuplesIterator<'_>;
}
}
},
} }
} }
}, },
@ -208,127 +210,135 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
predicate, predicate,
object, object,
graph_name, graph_name,
} => Box::new(self.eval_plan(&*child, from, options).flat_map_ok(move |tuple| { } => Box::new(
let mut iter = self.dataset.quads_for_pattern( self.eval_plan(&*child, from, options)
get_pattern_value(&subject, &tuple), .flat_map_ok(move |tuple| {
get_pattern_value(&predicate, &tuple), let mut iter = self.dataset.quads_for_pattern(
get_pattern_value(&object, &tuple), get_pattern_value(&subject, &tuple),
get_pattern_value(&graph_name, &tuple), get_pattern_value(&predicate, &tuple),
options.default_graph_as_union get_pattern_value(&object, &tuple),
); get_pattern_value(&graph_name, &tuple),
if subject.is_var() && subject == predicate { options.default_graph_as_union,
iter = Box::new(iter.filter(|quad| match quad { );
Err(_) => true, if subject.is_var() && subject == predicate {
Ok(quad) => quad.subject == quad.predicate, iter = Box::new(iter.filter(|quad| match quad {
})) Err(_) => true,
} Ok(quad) => quad.subject == quad.predicate,
if subject.is_var() && subject == object { }))
iter = Box::new(iter.filter(|quad| match quad { }
Err(_) => true, if subject.is_var() && subject == object {
Ok(quad) => quad.subject == quad.object, iter = Box::new(iter.filter(|quad| match quad {
})) Err(_) => true,
} Ok(quad) => quad.subject == quad.object,
if predicate.is_var() && predicate == object { }))
iter = Box::new(iter.filter(|quad| match quad { }
Err(_) => true, if predicate.is_var() && predicate == object {
Ok(quad) => quad.predicate == quad.object, iter = Box::new(iter.filter(|quad| match quad {
})) Err(_) => true,
} Ok(quad) => quad.predicate == quad.object,
if graph_name.is_var() { }))
iter = Box::new(iter.filter(|quad| match quad { }
Err(_) => true, if graph_name.is_var() {
Ok(quad) => quad.graph_name != ENCODED_DEFAULT_GRAPH, iter = Box::new(iter.filter(|quad| match quad {
})); Err(_) => true,
if graph_name == subject { Ok(quad) => quad.graph_name != ENCODED_DEFAULT_GRAPH,
iter = Box::new(iter.filter(|quad| match quad { }));
Err(_) => true, if graph_name == subject {
Ok(quad) => quad.graph_name == quad.subject, iter = Box::new(iter.filter(|quad| match quad {
})) Err(_) => true,
} Ok(quad) => quad.graph_name == quad.subject,
if graph_name == predicate { }))
iter = Box::new(iter.filter(|quad| match quad { }
Err(_) => true, if graph_name == predicate {
Ok(quad) => quad.graph_name == quad.predicate, iter = Box::new(iter.filter(|quad| match quad {
})) Err(_) => true,
} Ok(quad) => quad.graph_name == quad.predicate,
if graph_name == object { }))
iter = Box::new(iter.filter(|quad| match quad { }
Err(_) => true, if graph_name == object {
Ok(quad) => quad.graph_name == quad.object, iter = Box::new(iter.filter(|quad| match quad {
})) Err(_) => true,
} Ok(quad) => quad.graph_name == quad.object,
} }))
let iter: EncodedTuplesIterator<'_> = Box::new(iter.map(move |quad| { }
let quad = quad?; }
let mut new_tuple = tuple.clone(); let iter: EncodedTuplesIterator<'_> = Box::new(iter.map(move |quad| {
put_pattern_value(&subject, quad.subject, &mut new_tuple); let quad = quad?;
put_pattern_value(&predicate, quad.predicate, &mut new_tuple); let mut new_tuple = tuple.clone();
put_pattern_value(&object, quad.object, &mut new_tuple); put_pattern_value(&subject, quad.subject, &mut new_tuple);
put_pattern_value(&graph_name, quad.graph_name, &mut new_tuple); put_pattern_value(&predicate, quad.predicate, &mut new_tuple);
Ok(new_tuple) put_pattern_value(&object, quad.object, &mut new_tuple);
})); put_pattern_value(&graph_name, quad.graph_name, &mut new_tuple);
iter Ok(new_tuple)
})), }));
iter
}),
),
PlanNode::PathPatternJoin { PlanNode::PathPatternJoin {
child, child,
subject, subject,
path, path,
object, object,
graph_name, graph_name,
} => Box::new(self.eval_plan(&*child, from, options).flat_map_ok(move |tuple| { } => Box::new(
let input_subject = get_pattern_value(&subject, &tuple); self.eval_plan(&*child, from, options)
let input_object = get_pattern_value(&object, &tuple); .flat_map_ok(move |tuple| {
let input_graph_name = let input_subject = get_pattern_value(&subject, &tuple);
if let Some(graph_name) = get_pattern_value(&graph_name, &tuple) { let input_object = get_pattern_value(&object, &tuple);
graph_name let input_graph_name =
} else { if let Some(graph_name) = get_pattern_value(&graph_name, &tuple) {
return Box::new(once(Err(format_err!( graph_name
} else {
return Box::new(once(Err(format_err!(
"Unknown graph name is not allowed when evaluating property path" "Unknown graph name is not allowed when evaluating property path"
)))) as EncodedTuplesIterator<'_>; )))) as EncodedTuplesIterator<'_>;
}; };
match (input_subject, input_object) { match (input_subject, input_object) {
(Some(input_subject), Some(input_object)) => Box::new( (Some(input_subject), Some(input_object)) => Box::new(
self.eval_path_from(path, input_subject, input_graph_name, options) self.eval_path_from(path, input_subject, input_graph_name, options)
.filter_map(move |o| match o { .filter_map(move |o| match o {
Ok(o) => { Ok(o) => {
if o == input_object { if o == input_object {
Some(Ok(tuple.clone())) Some(Ok(tuple.clone()))
} else { } else {
None None
} }
} }
Err(error) => Some(Err(error)), Err(error) => Some(Err(error)),
}), }),
) )
as EncodedTuplesIterator<'_>, as EncodedTuplesIterator<'_>,
(Some(input_subject), None) => Box::new( (Some(input_subject), None) => Box::new(
self.eval_path_from(path, input_subject, input_graph_name, options) self.eval_path_from(path, input_subject, input_graph_name, options)
.map(move |o| { .map(move |o| {
let mut new_tuple = tuple.clone(); let mut new_tuple = tuple.clone();
put_pattern_value(&object, o?, &mut new_tuple); put_pattern_value(&object, o?, &mut new_tuple);
Ok(new_tuple) Ok(new_tuple)
}), }),
), ),
(None, Some(input_object)) => Box::new( (None, Some(input_object)) => Box::new(
self.eval_path_to(path, input_object, input_graph_name, options) self.eval_path_to(path, input_object, input_graph_name, options)
.map(move |s| { .map(move |s| {
let mut new_tuple = tuple.clone(); let mut new_tuple = tuple.clone();
put_pattern_value(&subject, s?, &mut new_tuple); put_pattern_value(&subject, s?, &mut new_tuple);
Ok(new_tuple) Ok(new_tuple)
}), }),
), ),
(None, None) => { (None, None) => {
Box::new(self.eval_open_path(path, input_graph_name, options).map(move |so| { Box::new(self.eval_open_path(path, input_graph_name, options).map(
let mut new_tuple = tuple.clone(); move |so| {
so.map(move |(s, o)| { let mut new_tuple = tuple.clone();
put_pattern_value(&subject, s, &mut new_tuple); so.map(move |(s, o)| {
put_pattern_value(&object, o, &mut new_tuple); put_pattern_value(&subject, s, &mut new_tuple);
new_tuple put_pattern_value(&object, o, &mut new_tuple);
}) new_tuple
})) })
} },
} ))
})), }
}
}),
),
PlanNode::Join { left, right } => { PlanNode::Join { left, right } => {
//TODO: very dumb implementation //TODO: very dumb implementation
let mut errors = Vec::default(); let mut errors = Vec::default();
@ -456,7 +466,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
PlanNode::HashDeduplicate { child } => { PlanNode::HashDeduplicate { child } => {
Box::new(hash_deduplicate(self.eval_plan(&*child, from, options))) Box::new(hash_deduplicate(self.eval_plan(&*child, from, options)))
} }
PlanNode::Skip { child, count } => Box::new(self.eval_plan(&*child, from, options).skip(*count)), PlanNode::Skip { child, count } => {
Box::new(self.eval_plan(&*child, from, options).skip(*count))
}
PlanNode::Limit { child, count } => { PlanNode::Limit { child, count } => {
Box::new(self.eval_plan(&*child, from, options).take(*count)) Box::new(self.eval_plan(&*child, from, options).take(*count))
} }
@ -513,12 +525,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}); });
for (i, accumulator) in key_accumulators.iter_mut().enumerate() { for (i, accumulator) in key_accumulators.iter_mut().enumerate() {
let (aggregate, _) = &aggregates[i]; let (aggregate, _) = &aggregates[i];
accumulator.add( accumulator.add(aggregate.parameter.as_ref().and_then(|parameter| {
aggregate self.eval_expression(&parameter, &tuple, options)
.parameter }));
.as_ref()
.and_then(|parameter| self.eval_expression(&parameter, &tuple, options)),
);
} }
}); });
if accumulators_for_group.is_empty() { if accumulators_for_group.is_empty() {
@ -597,7 +606,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
path: &'b PlanPropertyPath, path: &'b PlanPropertyPath,
start: EncodedTerm, start: EncodedTerm,
graph_name: EncodedTerm, graph_name: EncodedTerm,
options: &'b QueryOptions<'b> options: &'b QueryOptions<'b>,
) -> Box<dyn Iterator<Item = Result<EncodedTerm>> + 'b> ) -> Box<dyn Iterator<Item = Result<EncodedTerm>> + 'b>
where where
'a: 'b, 'a: 'b,
@ -605,13 +614,21 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
match path { match path {
PlanPropertyPath::PredicatePath(p) => Box::new( PlanPropertyPath::PredicatePath(p) => Box::new(
self.dataset self.dataset
.quads_for_pattern(Some(start), Some(*p), None, Some(graph_name), options.default_graph_as_union) .quads_for_pattern(
Some(start),
Some(*p),
None,
Some(graph_name),
options.default_graph_as_union,
)
.map(|t| Ok(t?.object)), .map(|t| Ok(t?.object)),
), ),
PlanPropertyPath::InversePath(p) => self.eval_path_to(&p, start, graph_name, options), PlanPropertyPath::InversePath(p) => self.eval_path_to(&p, start, graph_name, options),
PlanPropertyPath::SequencePath(a, b) => Box::new( PlanPropertyPath::SequencePath(a, b) => Box::new(
self.eval_path_from(&a, start, graph_name, options) self.eval_path_from(&a, start, graph_name, options)
.flat_map_ok(move |middle| self.eval_path_from(&b, middle, graph_name, options)), .flat_map_ok(move |middle| {
self.eval_path_from(&b, middle, graph_name, options)
}),
), ),
PlanPropertyPath::AlternativePath(a, b) => Box::new( PlanPropertyPath::AlternativePath(a, b) => Box::new(
self.eval_path_from(&a, start, graph_name, options) self.eval_path_from(&a, start, graph_name, options)
@ -631,7 +648,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
)), )),
PlanPropertyPath::NegatedPropertySet(ps) => Box::new( PlanPropertyPath::NegatedPropertySet(ps) => Box::new(
self.dataset self.dataset
.quads_for_pattern(Some(start), None, None, Some(graph_name), options.default_graph_as_union) .quads_for_pattern(
Some(start),
None,
None,
Some(graph_name),
options.default_graph_as_union,
)
.filter(move |t| match t { .filter(move |t| match t {
Ok(t) => !ps.contains(&t.predicate), Ok(t) => !ps.contains(&t.predicate),
Err(_) => true, Err(_) => true,
@ -646,7 +669,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
path: &'b PlanPropertyPath, path: &'b PlanPropertyPath,
end: EncodedTerm, end: EncodedTerm,
graph_name: EncodedTerm, graph_name: EncodedTerm,
options: &'a QueryOptions<'b> options: &'a QueryOptions<'b>,
) -> Box<dyn Iterator<Item = Result<EncodedTerm>> + 'b> ) -> Box<dyn Iterator<Item = Result<EncodedTerm>> + 'b>
where where
'a: 'b, 'a: 'b,
@ -654,7 +677,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
match path { match path {
PlanPropertyPath::PredicatePath(p) => Box::new( PlanPropertyPath::PredicatePath(p) => Box::new(
self.dataset self.dataset
.quads_for_pattern(None, Some(*p), Some(end), Some(graph_name), options.default_graph_as_union) .quads_for_pattern(
None,
Some(*p),
Some(end),
Some(graph_name),
options.default_graph_as_union,
)
.map(|t| Ok(t?.subject)), .map(|t| Ok(t?.subject)),
), ),
PlanPropertyPath::InversePath(p) => self.eval_path_from(&p, end, graph_name, options), PlanPropertyPath::InversePath(p) => self.eval_path_from(&p, end, graph_name, options),
@ -680,7 +709,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
)), )),
PlanPropertyPath::NegatedPropertySet(ps) => Box::new( PlanPropertyPath::NegatedPropertySet(ps) => Box::new(
self.dataset self.dataset
.quads_for_pattern(None, None, Some(end), Some(graph_name), options.default_graph_as_union) .quads_for_pattern(
None,
None,
Some(end),
Some(graph_name),
options.default_graph_as_union,
)
.filter(move |t| match t { .filter(move |t| match t {
Ok(t) => !ps.contains(&t.predicate), Ok(t) => !ps.contains(&t.predicate),
Err(_) => true, Err(_) => true,
@ -694,7 +729,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
&'b self, &'b self,
path: &'b PlanPropertyPath, path: &'b PlanPropertyPath,
graph_name: EncodedTerm, graph_name: EncodedTerm,
options: &'b QueryOptions<'b> options: &'b QueryOptions<'b>,
) -> Box<dyn Iterator<Item = Result<(EncodedTerm, EncodedTerm)>> + 'b> ) -> Box<dyn Iterator<Item = Result<(EncodedTerm, EncodedTerm)>> + 'b>
where where
'a: 'b, 'a: 'b,
@ -702,7 +737,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
match path { match path {
PlanPropertyPath::PredicatePath(p) => Box::new( PlanPropertyPath::PredicatePath(p) => Box::new(
self.dataset self.dataset
.quads_for_pattern(None, Some(*p), None, Some(graph_name), options.default_graph_as_union) .quads_for_pattern(
None,
Some(*p),
None,
Some(graph_name),
options.default_graph_as_union,
)
.map(|t| t.map(|t| (t.subject, t.object))), .map(|t| t.map(|t| (t.subject, t.object))),
), ),
PlanPropertyPath::InversePath(p) => Box::new( PlanPropertyPath::InversePath(p) => Box::new(
@ -740,7 +781,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
)), )),
PlanPropertyPath::NegatedPropertySet(ps) => Box::new( PlanPropertyPath::NegatedPropertySet(ps) => Box::new(
self.dataset self.dataset
.quads_for_pattern(None, None, None, Some(graph_name), options.default_graph_as_union) .quads_for_pattern(
None,
None,
None,
Some(graph_name),
options.default_graph_as_union,
)
.filter(move |t| match t { .filter(move |t| match t {
Ok(t) => !ps.contains(&t.predicate), Ok(t) => !ps.contains(&t.predicate),
Err(_) => true, Err(_) => true,
@ -753,10 +800,16 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
fn get_subject_or_object_identity_pairs<'b>( fn get_subject_or_object_identity_pairs<'b>(
&'b self, &'b self,
graph_name: EncodedTerm, graph_name: EncodedTerm,
options: &'b QueryOptions<'b> options: &'b QueryOptions<'b>,
) -> impl Iterator<Item = Result<(EncodedTerm, EncodedTerm)>> + 'b { ) -> impl Iterator<Item = Result<(EncodedTerm, EncodedTerm)>> + 'b {
self.dataset self.dataset
.quads_for_pattern(None, None, None, Some(graph_name), options.default_graph_as_union) .quads_for_pattern(
None,
None,
None,
Some(graph_name),
options.default_graph_as_union,
)
.flat_map_ok(|t| once(Ok(t.subject)).chain(once(Ok(t.object)))) .flat_map_ok(|t| once(Ok(t.subject)).chain(once(Ok(t.object))))
.map(|e| e.map(|e| (e, e))) .map(|e| e.map(|e| (e, e)))
} }
@ -765,21 +818,29 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
&'b self, &'b self,
expression: &PlanExpression, expression: &PlanExpression,
tuple: &[Option<EncodedTerm>], tuple: &[Option<EncodedTerm>],
options: &QueryOptions<'b> options: &QueryOptions<'b>,
) -> Option<EncodedTerm> { ) -> Option<EncodedTerm> {
match expression { match expression {
PlanExpression::Constant(t) => Some(*t), PlanExpression::Constant(t) => Some(*t),
PlanExpression::Variable(v) => get_tuple_value(*v, tuple), PlanExpression::Variable(v) => get_tuple_value(*v, tuple),
PlanExpression::Exists(node) => { PlanExpression::Exists(node) => Some(
Some(self.eval_plan(node, tuple.to_vec(), options).next().is_some().into()) self.eval_plan(node, tuple.to_vec(), options)
} .next()
.is_some()
.into(),
),
PlanExpression::Or(a, b) => { PlanExpression::Or(a, b) => {
match self.eval_expression(a, tuple, options).and_then(|v| self.to_bool(v)) { match self
.eval_expression(a, tuple, options)
.and_then(|v| self.to_bool(v))
{
Some(true) => Some(true.into()), Some(true) => Some(true.into()),
Some(false) => self.eval_expression(b, tuple, options), Some(false) => self.eval_expression(b, tuple, options),
None => { None => {
if Some(true) if Some(true)
== self.eval_expression(b, tuple, options).and_then(|v| self.to_bool(v)) == self
.eval_expression(b, tuple, options)
.and_then(|v| self.to_bool(v))
{ {
Some(true.into()) Some(true.into())
} else { } else {
@ -795,7 +856,11 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
Some(true) => self.eval_expression(b, tuple, options), Some(true) => self.eval_expression(b, tuple, options),
Some(false) => Some(false.into()), Some(false) => Some(false.into()),
None => { None => {
if Some(false) == self.eval_expression(b, tuple, options).and_then(|v| self.to_bool(v)) { if Some(false)
== self
.eval_expression(b, tuple, options)
.and_then(|v| self.to_bool(v))
{
Some(false.into()) Some(false.into())
} else { } else {
None None
@ -864,32 +929,40 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
Some(false.into()) Some(false.into())
} }
} }
PlanExpression::Add(a, b) => Some(match self.parse_numeric_operands(a, b, tuple, options)? { PlanExpression::Add(a, b) => {
NumericBinaryOperands::Float(v1, v2) => (v1 + v2).into(), Some(match self.parse_numeric_operands(a, b, tuple, options)? {
NumericBinaryOperands::Double(v1, v2) => (v1 + v2).into(), NumericBinaryOperands::Float(v1, v2) => (v1 + v2).into(),
NumericBinaryOperands::Integer(v1, v2) => v1.checked_add(v2)?.into(), NumericBinaryOperands::Double(v1, v2) => (v1 + v2).into(),
NumericBinaryOperands::Decimal(v1, v2) => v1.checked_add(v2)?.into(), NumericBinaryOperands::Integer(v1, v2) => v1.checked_add(v2)?.into(),
}), NumericBinaryOperands::Decimal(v1, v2) => v1.checked_add(v2)?.into(),
PlanExpression::Sub(a, b) => Some(match self.parse_numeric_operands(a, b, tuple, options)? { })
NumericBinaryOperands::Float(v1, v2) => (v1 - v2).into(), }
NumericBinaryOperands::Double(v1, v2) => (v1 - v2).into(), PlanExpression::Sub(a, b) => {
NumericBinaryOperands::Integer(v1, v2) => v1.checked_sub(v2)?.into(), Some(match self.parse_numeric_operands(a, b, tuple, options)? {
NumericBinaryOperands::Decimal(v1, v2) => v1.checked_sub(v2)?.into(), NumericBinaryOperands::Float(v1, v2) => (v1 - v2).into(),
}), NumericBinaryOperands::Double(v1, v2) => (v1 - v2).into(),
PlanExpression::Mul(a, b) => Some(match self.parse_numeric_operands(a, b, tuple, options)? { NumericBinaryOperands::Integer(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::Float(v1, v2) => (v1 * v2).into(), NumericBinaryOperands::Decimal(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::Double(v1, v2) => (v1 * v2).into(), })
NumericBinaryOperands::Integer(v1, v2) => v1.checked_mul(v2)?.into(), }
NumericBinaryOperands::Decimal(v1, v2) => v1.checked_mul(v2)?.into(), PlanExpression::Mul(a, b) => {
}), Some(match self.parse_numeric_operands(a, b, tuple, options)? {
PlanExpression::Div(a, b) => Some(match self.parse_numeric_operands(a, b, tuple, options)? { NumericBinaryOperands::Float(v1, v2) => (v1 * v2).into(),
NumericBinaryOperands::Float(v1, v2) => (v1 / v2).into(), NumericBinaryOperands::Double(v1, v2) => (v1 * v2).into(),
NumericBinaryOperands::Double(v1, v2) => (v1 / v2).into(), NumericBinaryOperands::Integer(v1, v2) => v1.checked_mul(v2)?.into(),
NumericBinaryOperands::Integer(v1, v2) => Decimal::from_i128(v1)? NumericBinaryOperands::Decimal(v1, v2) => v1.checked_mul(v2)?.into(),
.checked_div(Decimal::from_i128(v2)?)? })
.into(), }
NumericBinaryOperands::Decimal(v1, v2) => v1.checked_div(v2)?.into(), PlanExpression::Div(a, b) => {
}), Some(match self.parse_numeric_operands(a, b, tuple, options)? {
NumericBinaryOperands::Float(v1, v2) => (v1 / v2).into(),
NumericBinaryOperands::Double(v1, v2) => (v1 / v2).into(),
NumericBinaryOperands::Integer(v1, v2) => Decimal::from_i128(v1)?
.checked_div(Decimal::from_i128(v2)?)?
.into(),
NumericBinaryOperands::Decimal(v1, v2) => v1.checked_div(v2)?.into(),
})
}
PlanExpression::UnaryPlus(e) => match self.eval_expression(e, tuple, options)? { PlanExpression::UnaryPlus(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::FloatLiteral(value) => Some((*value).into()), EncodedTerm::FloatLiteral(value) => Some((*value).into()),
EncodedTerm::DoubleLiteral(value) => Some((*value).into()), EncodedTerm::DoubleLiteral(value) => Some((*value).into()),
@ -950,9 +1023,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
_ => None, _ => None,
}?; }?;
let iri = self.dataset.get_str(iri_id).ok()??; let iri = self.dataset.get_str(iri_id).ok()??;
let base_iri = options.base_iri let base_iri = options
.map(|base_iri| Iri::parse(base_iri.to_string())) .base_iri
.or(self.base_iri.as_ref().map(|iri| Ok(iri.clone()))); .map(|base_iri| Iri::parse(base_iri.to_string()))
.or(self.base_iri.as_ref().map(|iri| Ok(iri.clone())));
if let Some(Ok(base_iri)) = base_iri { if let Some(Ok(base_iri)) = base_iri {
self.build_named_node(&base_iri.resolve(&iri).ok()?.into_inner()) self.build_named_node(&base_iri.resolve(&iri).ok()?.into_inner())
} else { } else {
@ -1043,7 +1117,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
return None; return None;
}; };
let length: Option<usize> = if let Some(length) = length { let length: Option<usize> = if let Some(length) = length {
if let EncodedTerm::IntegerLiteral(v) = self.eval_expression(length, tuple, options)? { if let EncodedTerm::IntegerLiteral(v) =
self.eval_expression(length, tuple, options)?
{
Some(v.try_into().ok()?) Some(v.try_into().ok()?)
} else { } else {
return None; return None;
@ -1313,14 +1389,18 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
} }
PlanExpression::StrLang(lexical_form, lang_tag) => { PlanExpression::StrLang(lexical_form, lang_tag) => {
Some(EncodedTerm::LangStringLiteral { Some(EncodedTerm::LangStringLiteral {
value_id: self value_id: self.to_simple_string_id(self.eval_expression(
.to_simple_string_id(self.eval_expression(lexical_form, tuple, options)?)?, lexical_form,
tuple,
options,
)?)?,
language_id: self language_id: self
.to_simple_string_id(self.eval_expression(lang_tag, tuple, options)?)?, .to_simple_string_id(self.eval_expression(lang_tag, tuple, options)?)?,
}) })
} }
PlanExpression::StrDT(lexical_form, datatype) => { PlanExpression::StrDT(lexical_form, datatype) => {
let value = self.to_simple_string(self.eval_expression(lexical_form, tuple, options)?)?; let value =
self.to_simple_string(self.eval_expression(lexical_form, tuple, options)?)?;
let datatype = if let EncodedTerm::NamedNode { iri_id } = let datatype = if let EncodedTerm::NamedNode { iri_id } =
self.eval_expression(datatype, tuple, options)? self.eval_expression(datatype, tuple, options)?
{ {
@ -1336,15 +1416,21 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}) })
.ok() .ok()
} }
PlanExpression::SameTerm(a, b) => { PlanExpression::SameTerm(a, b) => Some(
Some((self.eval_expression(a, tuple, options)? == self.eval_expression(b, tuple, options)?).into()) (self.eval_expression(a, tuple, options)?
} == self.eval_expression(b, tuple, options)?)
PlanExpression::IsIRI(e) => { .into(),
Some(self.eval_expression(e, tuple, options)?.is_named_node().into()) ),
} PlanExpression::IsIRI(e) => Some(
PlanExpression::IsBlank(e) => { self.eval_expression(e, tuple, options)?
Some(self.eval_expression(e, tuple, options)?.is_blank_node().into()) .is_named_node()
} .into(),
),
PlanExpression::IsBlank(e) => Some(
self.eval_expression(e, tuple, options)?
.is_blank_node()
.into(),
),
PlanExpression::IsLiteral(e) => { PlanExpression::IsLiteral(e) => {
Some(self.eval_expression(e, tuple, options)?.is_literal().into()) Some(self.eval_expression(e, tuple, options)?.is_literal().into())
} }
@ -1630,7 +1716,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
e1: &PlanExpression, e1: &PlanExpression,
e2: &PlanExpression, e2: &PlanExpression,
tuple: &[Option<EncodedTerm>], tuple: &[Option<EncodedTerm>],
options: &QueryOptions<'b> options: &QueryOptions<'b>,
) -> Option<NumericBinaryOperands> { ) -> Option<NumericBinaryOperands> {
NumericBinaryOperands::new( NumericBinaryOperands::new(
self.eval_expression(&e1, tuple, options)?, self.eval_expression(&e1, tuple, options)?,
@ -1687,7 +1773,12 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
Some(term) => { Some(term) => {
if let Ok(encoded) = encoder.encode_term(&term) { if let Ok(encoded) = encoder.encode_term(&term) {
let variable = binding_variables[i].clone(); let variable = binding_variables[i].clone();
put_variable_value(&variable, &combined_variables, encoded, &mut encoded_terms) put_variable_value(
&variable,
&combined_variables,
encoded,
&mut encoded_terms,
)
} }
} }
} }
@ -1696,7 +1787,6 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
})) }))
} }
#[allow(clippy::float_cmp)] #[allow(clippy::float_cmp)]
fn equals(&self, a: EncodedTerm, b: EncodedTerm) -> Option<bool> { fn equals(&self, a: EncodedTerm, b: EncodedTerm) -> Option<bool> {
match a { match a {
@ -1814,7 +1904,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
tuple_a: &[Option<EncodedTerm>], tuple_a: &[Option<EncodedTerm>],
tuple_b: &[Option<EncodedTerm>], tuple_b: &[Option<EncodedTerm>],
expression: &PlanExpression, expression: &PlanExpression,
options: &QueryOptions<'b> options: &QueryOptions<'b>,
) -> Ordering { ) -> Ordering {
self.cmp_terms( self.cmp_terms(
self.eval_expression(expression, tuple_a, options), self.eval_expression(expression, tuple_a, options),
@ -1933,7 +2023,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
&'b self, &'b self,
arg: &PlanExpression, arg: &PlanExpression,
tuple: &[Option<EncodedTerm>], tuple: &[Option<EncodedTerm>],
options: &QueryOptions<'b> options: &QueryOptions<'b>,
) -> Option<EncodedTerm> { ) -> Option<EncodedTerm> {
let input = self.to_simple_string(self.eval_expression(arg, tuple, options)?)?; let input = self.to_simple_string(self.eval_expression(arg, tuple, options)?)?;
let hash = hex::encode(H::new().chain(&input as &str).result()); let hash = hex::encode(H::new().chain(&input as &str).result());
@ -2071,7 +2161,12 @@ fn put_pattern_value(selector: &PatternValue, value: EncodedTerm, tuple: &mut En
} }
} }
fn put_variable_value(selector: &Variable, variables: &[Variable], value: EncodedTerm, tuple: &mut EncodedTuple) { fn put_variable_value(
selector: &Variable,
variables: &[Variable],
value: EncodedTerm,
tuple: &mut EncodedTuple,
) {
for (i, v) in variables.iter().enumerate() { for (i, v) in variables.iter().enumerate() {
if selector == v { if selector == v {
put_value(i, value, tuple); put_value(i, value, tuple);
@ -2080,7 +2175,6 @@ fn put_variable_value(selector: &Variable, variables: &[Variable], value: Encode
} }
} }
fn put_value(position: usize, value: EncodedTerm, tuple: &mut EncodedTuple) { fn put_value(position: usize, value: EncodedTerm, tuple: &mut EncodedTuple) {
if position < tuple.len() { if position < tuple.len() {
tuple[position] = Some(value) tuple[position] = Some(value)
@ -2226,7 +2320,9 @@ impl<'a, S: StoreConnection> Iterator for LeftJoinIterator<'a, S> {
} }
match self.left_iter.next()? { match self.left_iter.next()? {
Ok(left_tuple) => { Ok(left_tuple) => {
self.current_right = self.eval.eval_plan(self.right_plan, left_tuple.clone(), self.options); self.current_right =
self.eval
.eval_plan(self.right_plan, left_tuple.clone(), self.options);
if let Some(right_tuple) = self.current_right.next() { if let Some(right_tuple) = self.current_right.next() {
Some(right_tuple) Some(right_tuple)
} else { } else {
@ -2294,9 +2390,11 @@ impl<'a, S: StoreConnection> Iterator for UnionIterator<'a, S> {
if self.current_plan >= self.plans.len() { if self.current_plan >= self.plans.len() {
return None; return None;
} }
self.current_iterator = self self.current_iterator = self.eval.eval_plan(
.eval &self.plans[self.current_plan],
.eval_plan(&self.plans[self.current_plan], self.input.clone(), self.options); self.input.clone(),
self.options,
);
self.current_plan += 1; self.current_plan += 1;
} }
} }
@ -2401,10 +2499,13 @@ impl<'a, S: StoreConnection + 'a> Iterator for DescribeIterator<'a, S> {
}; };
for subject in tuple { for subject in tuple {
if let Some(subject) = subject { if let Some(subject) = subject {
self.quads = self.quads = self.eval.dataset.quads_for_pattern(
self.eval Some(subject),
.dataset None,
.quads_for_pattern(Some(subject), None, None, None, self.options.default_graph_as_union); None,
None,
self.options.default_graph_as_union,
);
} }
} }
} }

@ -121,27 +121,24 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
pub(crate) fn new_from_pattern( pub(crate) fn new_from_pattern(
connection: S, connection: S,
pattern: &GraphPattern, pattern: &GraphPattern,
base_iri: Option<&'a str> base_iri: Option<&'a str>,
) -> Result<Self> { ) -> Result<Self> {
let dataset = DatasetView::new(connection); let dataset = DatasetView::new(connection);
let (plan, variables) = PlanBuilder::build(dataset.encoder(), pattern)?; let (plan, variables) = PlanBuilder::build(dataset.encoder(), pattern)?;
let base_iri = base_iri.map(|str_iri| Iri::parse(str_iri.to_string())); let base_iri = base_iri.map(|str_iri| Iri::parse(str_iri.to_string()));
match base_iri { match base_iri {
Some(Err(_)) => Err(format_err!("Failed to parse base_iri")), Some(Err(_)) => Err(format_err!("Failed to parse base_iri")),
Some(Ok(base_iri)) => Some(Ok(base_iri)) => Ok(Self(SimplePreparedQueryAction::Select {
Ok(Self(SimplePreparedQueryAction::Select { plan,
plan, variables,
variables, evaluator: SimpleEvaluator::new(dataset, Some(base_iri)),
evaluator: SimpleEvaluator::new(dataset, Some(base_iri)), })),
})), None => Ok(Self(SimplePreparedQueryAction::Select {
None => plan,
Ok(Self(SimplePreparedQueryAction::Select { variables,
plan, evaluator: SimpleEvaluator::new(dataset, None),
variables, })),
evaluator: SimpleEvaluator::new(dataset, None),
}))
} }
} }
} }
@ -169,7 +166,10 @@ impl<S: StoreConnection> PreparedQuery for SimplePreparedQuery<S> {
} }
pub trait ServiceHandler { pub trait ServiceHandler {
fn handle<'a>(&'a self, node: NamedNode) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)>; fn handle<'a>(
&'a self,
node: NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)>;
} }
/// Options for SPARQL query parsing and evaluation like the query base IRI /// Options for SPARQL query parsing and evaluation like the query base IRI

@ -1,6 +1,6 @@
use crate::sparql::GraphPattern;
use crate::sparql::model::Variable;
use crate::sparql::eval::StringOrStoreString; use crate::sparql::eval::StringOrStoreString;
use crate::sparql::model::Variable;
use crate::sparql::GraphPattern;
use crate::store::numeric_encoder::{ use crate::store::numeric_encoder::{
EncodedQuad, EncodedTerm, Encoder, MemoryStrStore, StrContainer, StrLookup, EncodedQuad, EncodedTerm, Encoder, MemoryStrStore, StrContainer, StrLookup,
ENCODED_DEFAULT_GRAPH, ENCODED_DEFAULT_GRAPH,

@ -113,7 +113,7 @@ impl<E: Encoder> PlanBuilder<E> {
graph_pattern, graph_pattern,
silent: *s, silent: *s,
} }
}, }
GraphPattern::AggregateJoin(GroupPattern(key, p), aggregates) => { GraphPattern::AggregateJoin(GroupPattern(key, p), aggregates) => {
let mut inner_variables = key.clone(); let mut inner_variables = key.clone();
let inner_graph_name = let inner_graph_name =

@ -11,7 +11,7 @@ pub use crate::store::memory::MemoryRepository;
pub use crate::store::rocksdb::RocksDbRepository; pub use crate::store::rocksdb::RocksDbRepository;
use crate::model::*; use crate::model::*;
use crate::sparql::{SimplePreparedQuery}; use crate::sparql::SimplePreparedQuery;
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
use crate::{DatasetSyntax, GraphSyntax, RepositoryConnection, Result}; use crate::{DatasetSyntax, GraphSyntax, RepositoryConnection, Result};
use rio_api::parser::{QuadsParser, TriplesParser}; use rio_api::parser::{QuadsParser, TriplesParser};
@ -72,7 +72,11 @@ impl<S: StoreConnection> From<S> for StoreRepositoryConnection<S> {
impl<S: StoreConnection> RepositoryConnection for StoreRepositoryConnection<S> { impl<S: StoreConnection> RepositoryConnection for StoreRepositoryConnection<S> {
type PreparedQuery = SimplePreparedQuery<S>; type PreparedQuery = SimplePreparedQuery<S>;
fn prepare_query<'a>(&self, query: &str, base_iri: Option<&'a str>) -> Result<SimplePreparedQuery<S>> { fn prepare_query<'a>(
&self,
query: &str,
base_iri: Option<&'a str>,
) -> Result<SimplePreparedQuery<S>> {
SimplePreparedQuery::new(self.inner.clone(), query, base_iri) //TODO: avoid clone SimplePreparedQuery::new(self.inner.clone(), query, base_iri) //TODO: avoid clone
} }
@ -97,13 +101,13 @@ impl<S: StoreConnection> RepositoryConnection for StoreRepositoryConnection<S> {
) )
} }
fn prepare_query_from_pattern<'a>( fn prepare_query_from_pattern<'a>(
&'a self, &'a self,
pattern: &GraphPattern, pattern: &GraphPattern,
base_iri: Option<&'a str> base_iri: Option<&'a str>,
) -> Result<Self::PreparedQuery> { ) -> Result<Self::PreparedQuery> {
SimplePreparedQuery::new_from_pattern(self.inner.clone(), pattern, base_iri) //TODO: avoid clone SimplePreparedQuery::new_from_pattern(self.inner.clone(), pattern, base_iri)
//TODO: avoid clone
} }
fn load_graph( fn load_graph(

@ -1,26 +1,30 @@
use rudf::model::*;
use rudf::{GraphSyntax, Repository, RepositoryConnection, MemoryRepository, Result};
use rudf::sparql::{BindingsIterator, GraphPattern, PreparedQuery, QueryOptions, QueryResult, ServiceHandler};
use failure::format_err; use failure::format_err;
use rudf::model::*;
use rudf::sparql::{
BindingsIterator, GraphPattern, PreparedQuery, QueryOptions, QueryResult, ServiceHandler,
};
use rudf::{GraphSyntax, MemoryRepository, Repository, RepositoryConnection, Result};
use std::io::BufRead; use std::io::BufRead;
#[test] #[test]
fn simple_service_test() { fn simple_service_test() {
struct TestServiceHandler;
struct TestServiceHandler; impl ServiceHandler for TestServiceHandler {
impl ServiceHandler for TestServiceHandler { fn handle<'a>(
fn handle<'a>(&'a self, _named_node: NamedNode) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> { &'a self,
fn pattern_handler<'a>(graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> { _named_node: NamedNode,
let triples = b"<http://example.com/s> <http://example.com/p> <http://example.com/o> .".as_ref(); ) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> {
do_pattern(triples, graph_pattern, QueryOptions::default()) fn pattern_handler<'a>(graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
}; let triples =
Some(pattern_handler) b"<http://example.com/s> <http://example.com/p> <http://example.com/o> ."
.as_ref();
do_pattern(triples, graph_pattern, QueryOptions::default())
};
Some(pattern_handler)
}
} }
}
let query = r#" let query = r#"
SELECT ?s ?p ?o SELECT ?s ?p ?o
WHERE WHERE
{ {
@ -28,57 +32,65 @@ fn simple_service_test() {
{ ?s ?p ?o { ?s ?p ?o
} }
} }
"#.to_string(); "#
.to_string();
let options = QueryOptions::default().with_service_handler(Box::new(TestServiceHandler)); let options = QueryOptions::default().with_service_handler(Box::new(TestServiceHandler));
let results = do_query(b"".as_ref(), query, options).unwrap(); let results = do_query(b"".as_ref(), query, options).unwrap();
let collected = results.into_values_iter().map(move |b| b.unwrap()).collect::<Vec<_>>(); let collected = results
let solution = vec![ .into_values_iter()
vec![ Some(ex(String::from("s"))), Some(ex(String::from("p"))), Some(ex(String::from("o"))) ], .map(move |b| b.unwrap())
]; .collect::<Vec<_>>();
assert_eq!(collected, solution); let solution = vec![vec![
Some(ex(String::from("s"))),
Some(ex(String::from("p"))),
Some(ex(String::from("o"))),
]];
assert_eq!(collected, solution);
} }
#[test] #[test]
fn two_service_test() { fn two_service_test() {
#[derive(Clone, Copy)]
struct TwoServiceTest;
impl ServiceHandler for TwoServiceTest {
fn handle<'a>(
&'a self,
named_node: NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> {
let service1 = NamedNode::parse("http://service1.org").unwrap();
let service2 = NamedNode::parse("http://service2.org").unwrap();
if named_node == service1 {
Some(TwoServiceTest::handle_service1)
} else if named_node == service2 {
Some(TwoServiceTest::handle_service2)
} else {
None
}
}
}
#[derive(Clone,Copy)] impl TwoServiceTest {
struct TwoServiceTest; fn handle_service1<'a>(graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
impl ServiceHandler for TwoServiceTest { let triples = br#"
fn handle<'a>(&'a self, named_node: NamedNode) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> {
let service1 = NamedNode::parse("http://service1.org").unwrap();
let service2 = NamedNode::parse("http://service2.org").unwrap();
if named_node == service1 { Some(TwoServiceTest::handle_service1) }
else if named_node == service2 { Some(TwoServiceTest::handle_service2) }
else { None }
}
}
impl TwoServiceTest {
fn handle_service1<'a>(graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
let triples = br#"
<http://example.com/bob> <http://xmlns.com/foaf/0.1/name> "Bob" . <http://example.com/bob> <http://xmlns.com/foaf/0.1/name> "Bob" .
<http://example.com/alice> <http://xmlns.com/foaf/0.1/name> "Alice" . <http://example.com/alice> <http://xmlns.com/foaf/0.1/name> "Alice" .
"#.as_ref(); "#
do_pattern(triples, graph_pattern, QueryOptions::default()) .as_ref();
} do_pattern(triples, graph_pattern, QueryOptions::default())
}
fn handle_service2<'a>(graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> { fn handle_service2<'a>(graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
let triples = br#" let triples = br#"
<http://example.com/bob> <http://xmlns.com/foaf/0.1/mbox> <mailto:bob@example.com> . <http://example.com/bob> <http://xmlns.com/foaf/0.1/mbox> <mailto:bob@example.com> .
<http://example.com/alice> <http://xmlns.com/foaf/0.1/mbox> <mailto:alice@example.com> . <http://example.com/alice> <http://xmlns.com/foaf/0.1/mbox> <mailto:alice@example.com> .
"#.as_ref(); "#
do_pattern(triples, graph_pattern, QueryOptions::default()) .as_ref();
do_pattern(triples, graph_pattern, QueryOptions::default())
}
} }
} let query = r#"
let query = r#"
PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name ?mbox SELECT ?name ?mbox
WHERE WHERE
@ -92,36 +104,48 @@ fn two_service_test() {
} }
} }
ORDER BY ?name ORDER BY ?name
"#.to_string(); "#
.to_string();
let options = QueryOptions::default().with_service_handler(Box::new(TwoServiceTest));
let results = do_query(b"".as_ref(), query, options).unwrap(); let options = QueryOptions::default().with_service_handler(Box::new(TwoServiceTest));
let collected = results.into_values_iter().map(move |b| b.unwrap()).collect::<Vec<_>>(); let results = do_query(b"".as_ref(), query, options).unwrap();
let solution = vec![ let collected = results
vec![ Some(literal("Alice".to_string())), Some(mailto("alice@example.com".to_string())) ], .into_values_iter()
vec![ Some(literal("Bob".to_string())), Some(mailto("bob@example.com".to_string())) ], .map(move |b| b.unwrap())
.collect::<Vec<_>>();
let solution = vec![
vec![
Some(literal("Alice".to_string())),
Some(mailto("alice@example.com".to_string())),
],
vec![
Some(literal("Bob".to_string())),
Some(mailto("bob@example.com".to_string())),
],
]; ];
assert_eq!(collected, solution); assert_eq!(collected, solution);
} }
#[test] #[test]
fn silent_service_empty_set_test() { fn silent_service_empty_set_test() {
#[derive(Clone, Copy)]
struct ServiceTest;
impl ServiceHandler for ServiceTest {
fn handle<'a>(
&'a self,
_named_node: NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> {
Some(ServiceTest::handle_service)
}
}
#[derive(Clone,Copy)] impl ServiceTest {
struct ServiceTest; fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
impl ServiceHandler for ServiceTest { Err(format_err!("This is supposed to fail"))
fn handle<'a>(&'a self, _named_node: NamedNode) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> { }
Some(ServiceTest::handle_service)
}
}
impl ServiceTest {
fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
Err(format_err!("This is supposed to fail"))
} }
}
let query = r#" let query = r#"
PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name ?mbox SELECT ?name ?mbox
WHERE WHERE
@ -132,34 +156,40 @@ fn silent_service_empty_set_test() {
} }
ORDER BY ?name ORDER BY ?name
"#.to_string(); "#
.to_string();
let triples = b"".as_ref();
let options = QueryOptions::default().with_service_handler(Box::new(ServiceTest)); let triples = b"".as_ref();
let results = do_query(triples, query, options).unwrap(); let options = QueryOptions::default().with_service_handler(Box::new(ServiceTest));
let collected = results.into_values_iter().map(move |b| b.unwrap()).collect::<Vec<_>>(); let results = do_query(triples, query, options).unwrap();
println!("Collected: {:?}", collected); let collected = results
assert_eq!(collected.len(), 0); .into_values_iter()
.map(move |b| b.unwrap())
.collect::<Vec<_>>();
println!("Collected: {:?}", collected);
assert_eq!(collected.len(), 0);
} }
#[test] #[test]
fn non_silent_service_test() { fn non_silent_service_test() {
#[derive(Clone, Copy)]
struct ServiceTest;
impl ServiceHandler for ServiceTest {
fn handle<'a>(
&'a self,
_named_node: NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> {
Some(ServiceTest::handle_service)
}
}
#[derive(Clone,Copy)] impl ServiceTest {
struct ServiceTest; fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
impl ServiceHandler for ServiceTest { Err(format_err!("This is supposed to fail"))
fn handle<'a>(&'a self, _named_node: NamedNode) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> { }
Some(ServiceTest::handle_service)
}
}
impl ServiceTest {
fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
Err(format_err!("This is supposed to fail"))
} }
}
let query = r#" let query = r#"
PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name SELECT ?name
WHERE WHERE
@ -170,71 +200,103 @@ fn non_silent_service_test() {
} }
ORDER BY ?name ORDER BY ?name
"#.to_string(); "#
.to_string();
let triples = b"".as_ref();
let options = QueryOptions::default().with_service_handler(Box::new(ServiceTest)); let triples = b"".as_ref();
let results = do_query(triples, query, options).unwrap(); let options = QueryOptions::default().with_service_handler(Box::new(ServiceTest));
let result = results.into_values_iter().next(); let results = do_query(triples, query, options).unwrap();
match result { let result = results.into_values_iter().next();
Some(Err(_)) => assert_eq!(true, true), match result {
_ => assert_eq!(true, false, "This should have been an error since the service fails"), Some(Err(_)) => assert_eq!(true, true),
} _ => assert_eq!(
true, false,
"This should have been an error since the service fails"
),
}
} }
fn ex(id: String) -> Term { fn ex(id: String) -> Term {
Term::NamedNode(NamedNode::parse(format!("http://example.com/{}", &id)).unwrap()) Term::NamedNode(NamedNode::parse(format!("http://example.com/{}", &id)).unwrap())
} }
fn mailto(id: String) -> Term { fn mailto(id: String) -> Term {
Term::NamedNode(NamedNode::parse(format!("mailto:{}", &id)).unwrap()) Term::NamedNode(NamedNode::parse(format!("mailto:{}", &id)).unwrap())
} }
fn literal(str: String) -> Term { fn literal(str: String) -> Term {
Term::Literal(Literal::new_simple_literal(str)) Term::Literal(Literal::new_simple_literal(str))
} }
fn make_repository(reader: impl BufRead) -> Result<MemoryRepository> { fn make_repository(reader: impl BufRead) -> Result<MemoryRepository> {
let repository = MemoryRepository::default(); let repository = MemoryRepository::default();
let mut connection = repository.connection()?; let mut connection = repository.connection()?;
connection.load_graph(reader, GraphSyntax::NTriples, None, None).unwrap(); connection
Ok(repository) .load_graph(reader, GraphSyntax::NTriples, None, None)
.unwrap();
Ok(repository)
}
fn query_repository<'a>(
repository: MemoryRepository,
query: String,
options: QueryOptions<'a>,
) -> Result<BindingsIterator<'a>> {
let connection = repository.connection()?;
let prepared_query = connection.prepare_query(&query, None)?;
let result = prepared_query.exec(&options)?;
match result {
QueryResult::Bindings(iterator) => {
let (varaibles, iter) = iterator.destruct();
let collected = iter.collect::<Vec<_>>();
Ok(BindingsIterator::new(
varaibles,
Box::new(collected.into_iter()),
))
}
_ => Err(format_err!(
"Excpected bindings but got another QueryResult"
)),
}
} }
fn query_repository<'a>(repository: MemoryRepository, query: String, options: QueryOptions<'a>) -> Result<BindingsIterator<'a>> { fn pattern_repository<'a>(
let connection = repository.connection()?; repository: MemoryRepository,
let prepared_query = connection.prepare_query(&query, None)?; pattern: GraphPattern,
let result = prepared_query.exec(&options)?; options: QueryOptions<'a>,
match result { ) -> Result<BindingsIterator<'a>> {
QueryResult::Bindings(iterator) => { let connection = repository.connection()?;
let (varaibles, iter) = iterator.destruct(); let prepared_query = connection.prepare_query_from_pattern(&pattern, None)?;
let collected = iter.collect::<Vec<_>>(); let result = prepared_query.exec(&options)?;
Ok(BindingsIterator::new(varaibles, Box::new(collected.into_iter()))) match result {
}, QueryResult::Bindings(iterator) => {
_ => Err(format_err!("Excpected bindings but got another QueryResult")) let (varaibles, iter) = iterator.destruct();
} let collected = iter.collect::<Vec<_>>();
} Ok(BindingsIterator::new(
varaibles,
fn pattern_repository<'a>(repository: MemoryRepository, pattern: GraphPattern, options: QueryOptions<'a>) -> Result<BindingsIterator<'a>> { Box::new(collected.into_iter()),
let connection = repository.connection()?; ))
let prepared_query = connection.prepare_query_from_pattern(&pattern, None)?; }
let result = prepared_query.exec(&options)?; _ => Err(format_err!(
match result { "Excpected bindings but got another QueryResult"
QueryResult::Bindings(iterator) => { )),
let (varaibles, iter) = iterator.destruct();
let collected = iter.collect::<Vec<_>>();
Ok(BindingsIterator::new(varaibles, Box::new(collected.into_iter())))
} }
_ => Err(format_err!("Excpected bindings but got another QueryResult"))
}
} }
fn do_query<'a>(reader: impl BufRead, query: String, options: QueryOptions<'a>) -> Result<BindingsIterator<'a>> { fn do_query<'a>(
let repository = make_repository(reader)?; reader: impl BufRead,
query_repository(repository, query, options) query: String,
options: QueryOptions<'a>,
) -> Result<BindingsIterator<'a>> {
let repository = make_repository(reader)?;
query_repository(repository, query, options)
} }
fn do_pattern<'a>(reader: impl BufRead, pattern: GraphPattern, options: QueryOptions<'a>) -> Result<BindingsIterator<'a>> { fn do_pattern<'a>(
let repository = make_repository(reader)?; reader: impl BufRead,
pattern_repository(repository, pattern, options) pattern: GraphPattern,
options: QueryOptions<'a>,
) -> Result<BindingsIterator<'a>> {
let repository = make_repository(reader)?;
pattern_repository(repository, pattern, options)
} }

Loading…
Cancel
Save