diff --git a/lib/src/lib.rs b/lib/src/lib.rs index a5e53098..69dba29e 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -27,9 +27,8 @@ //! assert_eq!(vec![quad], results.unwrap()); //! //! // SPARQL query -//! let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", None).unwrap(); -//! let options = QueryOptions::default(); -//! let results = prepared_query.exec(&options).unwrap(); +//! let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default()).unwrap(); +//! let results = prepared_query.exec().unwrap(); //! if let QueryResult::Bindings(results) = results { //! assert_eq!(results.into_values_iter().next().unwrap().unwrap()[0], Some(ex.into())); //! } diff --git a/lib/src/repository.rs b/lib/src/repository.rs index 097c90cd..637da767 100644 --- a/lib/src/repository.rs +++ b/lib/src/repository.rs @@ -1,5 +1,5 @@ use crate::model::*; -use crate::sparql::{GraphPattern, PreparedQuery}; +use crate::sparql::{GraphPattern, PreparedQuery, QueryOptions}; use crate::{DatasetSyntax, GraphSyntax, Result}; use std::io::BufRead; @@ -30,9 +30,8 @@ use std::io::BufRead; /// assert_eq!(vec![quad], results.unwrap()); /// /// // SPARQL query -/// let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", None).unwrap(); -/// let options = QueryOptions::default(); -/// let results = prepared_query.exec(&options).unwrap(); +/// let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default()).unwrap(); +/// let results = prepared_query.exec().unwrap(); /// if let QueryResult::Bindings(results) = results { /// assert_eq!(results.into_values_iter().next().unwrap().unwrap()[0], Some(ex.into())); /// } @@ -76,24 +75,19 @@ pub trait RepositoryConnection: Clone { /// connection.insert(&Quad::new(ex.clone(), ex.clone(), ex.clone(), None)); /// /// // SPARQL query - /// let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", None).unwrap(); - /// let options = QueryOptions::default(); - /// let results = prepared_query.exec(&options).unwrap(); + /// let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default()).unwrap(); + /// let results = prepared_query.exec().unwrap(); /// if let QueryResult::Bindings(results) = results { /// 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; + fn prepare_query(&self, query: &str, options: QueryOptions) -> Result; /// 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>( - &'a self, - graph_pattern: &'a GraphPattern, - base_iri: Option<&str>, + fn prepare_query_from_pattern( + &self, + graph_pattern: &GraphPattern, + options: QueryOptions, ) -> Result; /// Retrieves quads with a filter on each quad component diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index 1a15002f..f436d1c4 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -1,8 +1,9 @@ use crate::model::BlankNode; use crate::model::Triple; +use crate::sparql::algebra::GraphPattern; use crate::sparql::model::*; use crate::sparql::plan::*; -use crate::sparql::QueryOptions; +use crate::sparql::ServiceHandler; use crate::store::numeric_encoder::*; use crate::store::StoreConnection; use crate::Result; @@ -43,15 +44,21 @@ pub struct SimpleEvaluator { base_iri: Option>, bnodes_map: Mutex>, now: DateTime, + service_handler: Box, } impl<'a, S: StoreConnection + 'a> SimpleEvaluator { - pub fn new(dataset: DatasetView, base_iri: Option>) -> Self { + pub fn new( + dataset: DatasetView, + base_iri: Option>, + service_handler: Box, + ) -> Self { Self { dataset, bnodes_map: Mutex::new(BTreeMap::default()), base_iri, now: Utc::now().with_timezone(&FixedOffset::east(0)), + service_handler, } } @@ -59,26 +66,21 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { &'b self, plan: &'b PlanNode, variables: &[Variable], - options: &'b QueryOptions<'b>, ) -> Result> where 'a: 'b, { - let iter = self.eval_plan(plan, vec![None; variables.len()], &options); + let iter = self.eval_plan(plan, vec![None; variables.len()]); Ok(QueryResult::Bindings( self.decode_bindings(iter, variables.to_vec()), )) } - pub fn evaluate_ask_plan<'b>( - &'b self, - plan: &'b PlanNode, - options: &'b QueryOptions<'b>, - ) -> Result> + pub fn evaluate_ask_plan<'b>(&'b self, plan: &'b PlanNode) -> Result> where 'a: 'b, { - match self.eval_plan(plan, vec![], &options).next() { + match self.eval_plan(plan, vec![]).next() { Some(Ok(_)) => Ok(QueryResult::Boolean(true)), Some(Err(error)) => Err(error), None => Ok(QueryResult::Boolean(false)), @@ -89,42 +91,31 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { &'b self, plan: &'b PlanNode, construct: &'b [TripleTemplate], - options: &'b QueryOptions<'b>, ) -> Result> where 'a: 'b, { Ok(QueryResult::Graph(Box::new(ConstructIterator { eval: self, - iter: self.eval_plan(plan, vec![], options), + iter: self.eval_plan(plan, vec![]), template: construct, buffered_results: Vec::default(), bnodes: Vec::default(), }))) } - pub fn evaluate_describe_plan<'b>( - &'b self, - plan: &'b PlanNode, - options: &'b QueryOptions<'b>, - ) -> Result> + pub fn evaluate_describe_plan<'b>(&'b self, plan: &'b PlanNode) -> Result> where 'a: 'b, { Ok(QueryResult::Graph(Box::new(DescribeIterator { eval: self, - options, - iter: self.eval_plan(plan, vec![], options), + iter: self.eval_plan(plan, vec![]), quads: Box::new(empty()), }))) } - fn eval_plan<'b>( - &'b self, - node: &'b PlanNode, - from: EncodedTuple, - options: &'b QueryOptions<'b>, - ) -> EncodedTuplesIterator<'b> + fn eval_plan<'b>(&'b self, node: &'b PlanNode, from: EncodedTuple) -> EncodedTuplesIterator<'b> where 'a: 'b, { @@ -137,70 +128,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { service_name, graph_pattern, .. - } => match &options.service_handler { - None => { + } => match self.evaluate_service(service_name, graph_pattern, variables, from) { + Ok(result) => result, + Err(e) => { if *silent { - return Box::new(empty()); + Box::new(empty()) } else { - return Box::new(once(Err(format_err!( - "No handler was supplied to resolve the given service" - )))) as EncodedTuplesIterator<'_>; - } - } - Some(handler) => { - let pattern_option = match get_pattern_value(service_name, &[]) { - None => { - if *silent { - return Box::new(empty()); - } else { - return Box::new(once(Err(format_err!( - "The handler supplied was unable to evaluate the given service" - )))) - as EncodedTuplesIterator<'_>; - } - } - Some(term) => match self.dataset.decode_named_node(term) { - Err(err) => { - if *silent { - return Box::new(empty()); - } else { - return Box::new(once(Err(err))) as EncodedTuplesIterator<'_>; - } - } - Ok(named_node) => { - println!("named_node: {:?}", named_node); - handler.handle(named_node) - } - }, - }; - 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" - )))) as EncodedTuplesIterator<'_>; - } - } - Some(pattern_fn) => match pattern_fn(graph_pattern.clone()) { - Ok(bindings) => { - let encoded = self.encode_bindings(variables, bindings); - let collected = encoded.collect::>(); - 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<'_>; - } - } - }, + Box::new(once(Err(e))) } } }, @@ -210,140 +144,127 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { predicate, object, graph_name, - } => Box::new( - self.eval_plan(&*child, from, options) - .flat_map_ok(move |tuple| { - let mut iter = self.dataset.quads_for_pattern( - get_pattern_value(&subject, &tuple), - get_pattern_value(&predicate, &tuple), - get_pattern_value(&object, &tuple), - get_pattern_value(&graph_name, &tuple), - options.default_graph_as_union, - ); - if subject.is_var() && subject == 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, - Ok(quad) => quad.subject == quad.object, - })) - } - if predicate.is_var() && predicate == 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, - Ok(quad) => quad.graph_name != ENCODED_DEFAULT_GRAPH, - })); - if graph_name == 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, - Ok(quad) => quad.graph_name == quad.predicate, - })) - } - if graph_name == 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(); - put_pattern_value(&subject, quad.subject, &mut new_tuple); - put_pattern_value(&predicate, quad.predicate, &mut new_tuple); - put_pattern_value(&object, quad.object, &mut new_tuple); - put_pattern_value(&graph_name, quad.graph_name, &mut new_tuple); - Ok(new_tuple) - })); - iter - }), - ), + } => Box::new(self.eval_plan(&*child, from).flat_map_ok(move |tuple| { + let mut iter = self.dataset.quads_for_pattern( + get_pattern_value(&subject, &tuple), + get_pattern_value(&predicate, &tuple), + get_pattern_value(&object, &tuple), + get_pattern_value(&graph_name, &tuple), + ); + if subject.is_var() && subject == 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, + Ok(quad) => quad.subject == quad.object, + })) + } + if predicate.is_var() && predicate == object { + iter = Box::new(iter.filter(|quad| match quad { + Err(_) => true, + Ok(quad) => quad.predicate == quad.object, + })) + } + if graph_name.is_var() { + if graph_name == 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, + Ok(quad) => quad.graph_name == quad.predicate, + })) + } + if graph_name == 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(); + put_pattern_value(&subject, quad.subject, &mut new_tuple); + put_pattern_value(&predicate, quad.predicate, &mut new_tuple); + put_pattern_value(&object, quad.object, &mut new_tuple); + put_pattern_value(&graph_name, quad.graph_name, &mut new_tuple); + Ok(new_tuple) + })); + iter + })), PlanNode::PathPatternJoin { child, subject, path, object, graph_name, - } => Box::new( - self.eval_plan(&*child, from, options) - .flat_map_ok(move |tuple| { - let input_subject = get_pattern_value(&subject, &tuple); - let input_object = get_pattern_value(&object, &tuple); - let input_graph_name = - if let Some(graph_name) = get_pattern_value(&graph_name, &tuple) { - graph_name - } else { - return Box::new(once(Err(format_err!( + } => Box::new(self.eval_plan(&*child, from).flat_map_ok(move |tuple| { + let input_subject = get_pattern_value(&subject, &tuple); + let input_object = get_pattern_value(&object, &tuple); + let input_graph_name = + if let Some(graph_name) = get_pattern_value(&graph_name, &tuple) { + graph_name + } else { + return Box::new(once(Err(format_err!( "Unknown graph name is not allowed when evaluating property path" )))) as EncodedTuplesIterator<'_>; - }; - match (input_subject, input_object) { - (Some(input_subject), Some(input_object)) => Box::new( - self.eval_path_from(path, input_subject, input_graph_name, options) - .filter_map(move |o| match o { - Ok(o) => { - if o == input_object { - Some(Ok(tuple.clone())) - } else { - None - } - } - Err(error) => Some(Err(error)), - }), - ) - as EncodedTuplesIterator<'_>, - (Some(input_subject), None) => Box::new( - self.eval_path_from(path, input_subject, input_graph_name, options) - .map(move |o| { - let mut new_tuple = tuple.clone(); - put_pattern_value(&object, o?, &mut new_tuple); - Ok(new_tuple) - }), - ), - (None, Some(input_object)) => Box::new( - self.eval_path_to(path, input_object, input_graph_name, options) - .map(move |s| { - let mut new_tuple = tuple.clone(); - put_pattern_value(&subject, s?, &mut new_tuple); - Ok(new_tuple) - }), - ), - (None, None) => { - Box::new(self.eval_open_path(path, input_graph_name, options).map( - move |so| { - let mut new_tuple = tuple.clone(); - so.map(move |(s, o)| { - put_pattern_value(&subject, s, &mut new_tuple); - put_pattern_value(&object, o, &mut new_tuple); - new_tuple - }) - }, - )) - } - } - }), - ), + }; + match (input_subject, input_object) { + (Some(input_subject), Some(input_object)) => Box::new( + self.eval_path_from(path, input_subject, input_graph_name) + .filter_map(move |o| match o { + Ok(o) => { + if o == input_object { + Some(Ok(tuple.clone())) + } else { + None + } + } + Err(error) => Some(Err(error)), + }), + ) + as EncodedTuplesIterator<'_>, + (Some(input_subject), None) => Box::new( + self.eval_path_from(path, input_subject, input_graph_name) + .map(move |o| { + let mut new_tuple = tuple.clone(); + put_pattern_value(&object, o?, &mut new_tuple); + Ok(new_tuple) + }), + ), + (None, Some(input_object)) => Box::new( + self.eval_path_to(path, input_object, input_graph_name) + .map(move |s| { + let mut new_tuple = tuple.clone(); + put_pattern_value(&subject, s?, &mut new_tuple); + Ok(new_tuple) + }), + ), + (None, None) => { + Box::new(self.eval_open_path(path, input_graph_name).map(move |so| { + let mut new_tuple = tuple.clone(); + so.map(move |(s, o)| { + put_pattern_value(&subject, s, &mut new_tuple); + put_pattern_value(&object, o, &mut new_tuple); + new_tuple + }) + })) + } + } + })), PlanNode::Join { left, right } => { //TODO: very dumb implementation let mut errors = Vec::default(); let left_values = self - .eval_plan(&*left, from.clone(), options) + .eval_plan(&*left, from.clone()) .filter_map(|result| match result { Ok(result) => Some(result), Err(error) => { @@ -354,18 +275,18 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .collect::>(); Box::new(JoinIterator { left: left_values, - right_iter: self.eval_plan(&*right, from, options), + right_iter: self.eval_plan(&*right, from), buffered_results: errors, }) } PlanNode::AntiJoin { left, right } => { //TODO: dumb implementation let right: Vec<_> = self - .eval_plan(&*right, from.clone(), options) + .eval_plan(&*right, from.clone()) .filter_map(|result| result.ok()) .collect(); Box::new(AntiJoinIterator { - left_iter: self.eval_plan(&*left, from, options), + left_iter: self.eval_plan(&*left, from), right, }) } @@ -380,9 +301,8 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { let iter = LeftJoinIterator { eval: self, right_plan: &*right, - left_iter: self.eval_plan(&*left, filtered_from, options), + left_iter: self.eval_plan(&*left, filtered_from), current_right: Box::new(empty()), - options, }; if problem_vars.is_empty() { Box::new(iter) @@ -396,10 +316,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanNode::Filter { child, expression } => { let eval = self; - Box::new(self.eval_plan(&*child, from, options).filter(move |tuple| { + Box::new(self.eval_plan(&*child, from).filter(move |tuple| { match tuple { Ok(tuple) => eval - .eval_expression(&expression, tuple, options) + .eval_expression(&expression, tuple) .and_then(|term| eval.to_bool(term)) .unwrap_or(false), Err(_) => true, @@ -412,7 +332,6 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { input: from, current_iterator: Box::new(empty()), current_plan: 0, - options, }), PlanNode::Extend { child, @@ -420,9 +339,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { expression, } => { let eval = self; - Box::new(self.eval_plan(&*child, from, options).map(move |tuple| { + Box::new(self.eval_plan(&*child, from).map(move |tuple| { let mut tuple = tuple?; - if let Some(value) = eval.eval_expression(&expression, &tuple, options) { + if let Some(value) = eval.eval_expression(&expression, &tuple) { put_value(*position, value, &mut tuple) } Ok(tuple) @@ -431,7 +350,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { PlanNode::Sort { child, by } => { let mut errors = Vec::default(); let mut values = self - .eval_plan(&*child, from, options) + .eval_plan(&*child, from) .filter_map(|result| match result { Ok(result) => Some(result), Err(error) => { @@ -444,14 +363,14 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { for comp in by { match comp { Comparator::Asc(expression) => { - match self.cmp_according_to_expression(a, b, &expression, options) { + match self.cmp_according_to_expression(a, b, &expression) { Ordering::Greater => return Ordering::Greater, Ordering::Less => return Ordering::Less, Ordering::Equal => (), } } Comparator::Desc(expression) => { - match self.cmp_according_to_expression(a, b, &expression, options) { + match self.cmp_according_to_expression(a, b, &expression) { Ordering::Greater => return Ordering::Less, Ordering::Less => return Ordering::Greater, Ordering::Equal => (), @@ -464,18 +383,16 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { Box::new(errors.into_iter().chain(values.into_iter().map(Ok))) } PlanNode::HashDeduplicate { child } => { - Box::new(hash_deduplicate(self.eval_plan(&*child, from, options))) - } - PlanNode::Skip { child, count } => { - Box::new(self.eval_plan(&*child, from, options).skip(*count)) + Box::new(hash_deduplicate(self.eval_plan(&*child, from))) } + PlanNode::Skip { child, count } => Box::new(self.eval_plan(&*child, from).skip(*count)), PlanNode::Limit { child, count } => { - Box::new(self.eval_plan(&*child, from, options).take(*count)) + Box::new(self.eval_plan(&*child, from).take(*count)) } PlanNode::Project { child, mapping } => { //TODO: use from somewhere? Box::new( - self.eval_plan(&*child, vec![None; mapping.len()], options) + self.eval_plan(&*child, vec![None; mapping.len()]) .map(move |tuple| { let tuple = tuple?; let mut output_tuple = vec![None; from.len()]; @@ -497,7 +414,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { let mut errors = Vec::default(); let mut accumulators_for_group = HashMap::>, Vec>>::default(); - self.eval_plan(child, from, options) + self.eval_plan(child, from) .filter_map(|result| match result { Ok(result) => Some(result), Err(error) => { @@ -525,9 +442,12 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { }); for (i, accumulator) in key_accumulators.iter_mut().enumerate() { let (aggregate, _) = &aggregates[i]; - accumulator.add(aggregate.parameter.as_ref().and_then(|parameter| { - self.eval_expression(¶meter, &tuple, options) - })); + accumulator.add( + aggregate + .parameter + .as_ref() + .and_then(|parameter| self.eval_expression(¶meter, &tuple)), + ); } }); if accumulators_for_group.is_empty() { @@ -559,6 +479,34 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } } + fn evaluate_service<'b>( + &'b self, + service_name: &PatternValue, + graph_pattern: &GraphPattern, + variables: &'b [Variable], + from: EncodedTuple, + ) -> Result> { + let service_name = + self.dataset + .decode_named_node(get_pattern_value(service_name, &[]).ok_or_else(|| { + format_err!("The SERVICE handler name variable is not bound") + })?)?; + let service = self.service_handler.handle(&service_name).ok_or_else(|| { + format_err!( + "The handler supplied was unable to produce any result set for service {}", + service_name + ) + })?; + Ok(Box::new( + self.encode_bindings(variables, service(graph_pattern.clone())?) + .flat_map(move |binding| { + binding + .map(|binding| combine_tuples(&binding, &from)) + .transpose() + }), + )) + } + fn accumulator_for_aggregate<'b>( &'b self, function: &'b PlanAggregationFunction, @@ -606,7 +554,6 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { path: &'b PlanPropertyPath, start: EncodedTerm, graph_name: EncodedTerm, - options: &'b QueryOptions<'b>, ) -> Box> + 'b> where 'a: 'b, @@ -614,47 +561,33 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { match path { PlanPropertyPath::PredicatePath(p) => Box::new( 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)) .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), PlanPropertyPath::SequencePath(a, b) => Box::new( - self.eval_path_from(&a, start, graph_name, options) - .flat_map_ok(move |middle| { - self.eval_path_from(&b, middle, graph_name, options) - }), + self.eval_path_from(&a, start, graph_name) + .flat_map_ok(move |middle| self.eval_path_from(&b, middle, graph_name)), ), PlanPropertyPath::AlternativePath(a, b) => Box::new( - self.eval_path_from(&a, start, graph_name, options) - .chain(self.eval_path_from(&b, start, graph_name, options)), + self.eval_path_from(&a, start, graph_name) + .chain(self.eval_path_from(&b, start, graph_name)), ), PlanPropertyPath::ZeroOrMorePath(p) => { Box::new(transitive_closure(Some(Ok(start)), move |e| { - self.eval_path_from(p, e, graph_name, options) + self.eval_path_from(p, e, graph_name) })) } PlanPropertyPath::OneOrMorePath(p) => Box::new(transitive_closure( - self.eval_path_from(p, start, graph_name, options), - move |e| self.eval_path_from(p, e, graph_name, options), + self.eval_path_from(p, start, graph_name), + move |e| self.eval_path_from(p, e, graph_name), )), PlanPropertyPath::ZeroOrOnePath(p) => Box::new(hash_deduplicate( - once(Ok(start)).chain(self.eval_path_from(&p, start, graph_name, options)), + once(Ok(start)).chain(self.eval_path_from(&p, start, graph_name)), )), PlanPropertyPath::NegatedPropertySet(ps) => Box::new( 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)) .filter(move |t| match t { Ok(t) => !ps.contains(&t.predicate), Err(_) => true, @@ -669,7 +602,6 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { path: &'b PlanPropertyPath, end: EncodedTerm, graph_name: EncodedTerm, - options: &'a QueryOptions<'b>, ) -> Box> + 'b> where 'a: 'b, @@ -677,45 +609,33 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { match path { PlanPropertyPath::PredicatePath(p) => Box::new( 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)) .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), PlanPropertyPath::SequencePath(a, b) => Box::new( - self.eval_path_to(&b, end, graph_name, options) - .flat_map_ok(move |middle| self.eval_path_to(&a, middle, graph_name, options)), + self.eval_path_to(&b, end, graph_name) + .flat_map_ok(move |middle| self.eval_path_to(&a, middle, graph_name)), ), PlanPropertyPath::AlternativePath(a, b) => Box::new( - self.eval_path_to(&a, end, graph_name, options) - .chain(self.eval_path_to(&b, end, graph_name, options)), + self.eval_path_to(&a, end, graph_name) + .chain(self.eval_path_to(&b, end, graph_name)), ), PlanPropertyPath::ZeroOrMorePath(p) => { Box::new(transitive_closure(Some(Ok(end)), move |e| { - self.eval_path_to(p, e, graph_name, options) + self.eval_path_to(p, e, graph_name) })) } PlanPropertyPath::OneOrMorePath(p) => Box::new(transitive_closure( - self.eval_path_to(p, end, graph_name, options), - move |e| self.eval_path_to(p, e, graph_name, options), + self.eval_path_to(p, end, graph_name), + move |e| self.eval_path_to(p, e, graph_name), )), PlanPropertyPath::ZeroOrOnePath(p) => Box::new(hash_deduplicate( - once(Ok(end)).chain(self.eval_path_to(&p, end, graph_name, options)), + once(Ok(end)).chain(self.eval_path_to(&p, end, graph_name)), )), PlanPropertyPath::NegatedPropertySet(ps) => Box::new( 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)) .filter(move |t| match t { Ok(t) => !ps.contains(&t.predicate), Err(_) => true, @@ -729,7 +649,6 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { &'b self, path: &'b PlanPropertyPath, graph_name: EncodedTerm, - options: &'b QueryOptions<'b>, ) -> Box> + 'b> where 'a: 'b, @@ -737,57 +656,45 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { match path { PlanPropertyPath::PredicatePath(p) => Box::new( 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)) .map(|t| t.map(|t| (t.subject, t.object))), ), PlanPropertyPath::InversePath(p) => Box::new( - self.eval_open_path(&p, graph_name, options) + self.eval_open_path(&p, graph_name) .map(|t| t.map(|(s, o)| (o, s))), ), PlanPropertyPath::SequencePath(a, b) => Box::new( - self.eval_open_path(&a, graph_name, options) + self.eval_open_path(&a, graph_name) .flat_map_ok(move |(start, middle)| { - self.eval_path_from(&b, middle, graph_name, options) + self.eval_path_from(&b, middle, graph_name) .map(move |end| Ok((start, end?))) }), ), PlanPropertyPath::AlternativePath(a, b) => Box::new( - self.eval_open_path(&a, graph_name, options) - .chain(self.eval_open_path(&b, graph_name, options)), + self.eval_open_path(&a, graph_name) + .chain(self.eval_open_path(&b, graph_name)), ), PlanPropertyPath::ZeroOrMorePath(p) => Box::new(transitive_closure( - self.get_subject_or_object_identity_pairs(graph_name, options), //TODO: avoid to inject everything + self.get_subject_or_object_identity_pairs(graph_name), //TODO: avoid to inject everything move |(start, middle)| { - self.eval_path_from(p, middle, graph_name, options) + self.eval_path_from(p, middle, graph_name) .map(move |end| Ok((start, end?))) }, )), PlanPropertyPath::OneOrMorePath(p) => Box::new(transitive_closure( - self.eval_open_path(p, graph_name, options), + self.eval_open_path(p, graph_name), move |(start, middle)| { - self.eval_path_from(p, middle, graph_name, options) + self.eval_path_from(p, middle, graph_name) .map(move |end| Ok((start, end?))) }, )), PlanPropertyPath::ZeroOrOnePath(p) => Box::new(hash_deduplicate( - self.get_subject_or_object_identity_pairs(graph_name, options) - .chain(self.eval_open_path(&p, graph_name, options)), + self.get_subject_or_object_identity_pairs(graph_name) + .chain(self.eval_open_path(&p, graph_name)), )), PlanPropertyPath::NegatedPropertySet(ps) => Box::new( 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)) .filter(move |t| match t { Ok(t) => !ps.contains(&t.predicate), Err(_) => true, @@ -800,16 +707,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { fn get_subject_or_object_identity_pairs<'b>( &'b self, graph_name: EncodedTerm, - options: &'b QueryOptions<'b>, ) -> impl Iterator> + 'b { 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)) .flat_map_ok(|t| once(Ok(t.subject)).chain(once(Ok(t.object)))) .map(|e| e.map(|e| (e, e))) } @@ -818,29 +718,20 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { &'b self, expression: &PlanExpression, tuple: &[Option], - options: &QueryOptions<'b>, ) -> Option { match expression { PlanExpression::Constant(t) => Some(*t), PlanExpression::Variable(v) => get_tuple_value(*v, tuple), - PlanExpression::Exists(node) => Some( - self.eval_plan(node, tuple.to_vec(), options) - .next() - .is_some() - .into(), - ), + PlanExpression::Exists(node) => { + Some(self.eval_plan(node, tuple.to_vec()).next().is_some().into()) + } PlanExpression::Or(a, b) => { - match self - .eval_expression(a, tuple, options) - .and_then(|v| self.to_bool(v)) - { + match self.eval_expression(a, tuple).and_then(|v| self.to_bool(v)) { Some(true) => Some(true.into()), - Some(false) => self.eval_expression(b, tuple, options), + Some(false) => self.eval_expression(b, tuple), None => { if Some(true) - == self - .eval_expression(b, tuple, options) - .and_then(|v| self.to_bool(v)) + == self.eval_expression(b, tuple).and_then(|v| self.to_bool(v)) { Some(true.into()) } else { @@ -850,17 +741,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } } PlanExpression::And(a, b) => match self - .eval_expression(a, tuple, options) + .eval_expression(a, tuple) .and_then(|v| self.to_bool(v)) { - Some(true) => self.eval_expression(b, tuple, options), + Some(true) => self.eval_expression(b, tuple), Some(false) => Some(false.into()), 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).and_then(|v| self.to_bool(v)) { Some(false.into()) } else { None @@ -868,26 +755,26 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } }, PlanExpression::Equal(a, b) => { - let a = self.eval_expression(a, tuple, options)?; - let b = self.eval_expression(b, tuple, options)?; + let a = self.eval_expression(a, tuple)?; + let b = self.eval_expression(b, tuple)?; self.equals(a, b).map(|v| v.into()) } PlanExpression::NotEqual(a, b) => { - let a = self.eval_expression(a, tuple, options)?; - let b = self.eval_expression(b, tuple, options)?; + let a = self.eval_expression(a, tuple)?; + let b = self.eval_expression(b, tuple)?; self.equals(a, b).map(|v| (!v).into()) } PlanExpression::Greater(a, b) => Some( (self.partial_cmp_literals( - self.eval_expression(a, tuple, options)?, - self.eval_expression(b, tuple, options)?, + self.eval_expression(a, tuple)?, + self.eval_expression(b, tuple)?, )? == Ordering::Greater) .into(), ), PlanExpression::GreaterOrEq(a, b) => Some( match self.partial_cmp_literals( - self.eval_expression(a, tuple, options)?, - self.eval_expression(b, tuple, options)?, + self.eval_expression(a, tuple)?, + self.eval_expression(b, tuple)?, )? { Ordering::Greater | Ordering::Equal => true, Ordering::Less => false, @@ -896,15 +783,15 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { ), PlanExpression::Lower(a, b) => Some( (self.partial_cmp_literals( - self.eval_expression(a, tuple, options)?, - self.eval_expression(b, tuple, options)?, + self.eval_expression(a, tuple)?, + self.eval_expression(b, tuple)?, )? == Ordering::Less) .into(), ), PlanExpression::LowerOrEq(a, b) => Some( match self.partial_cmp_literals( - self.eval_expression(a, tuple, options)?, - self.eval_expression(b, tuple, options)?, + self.eval_expression(a, tuple)?, + self.eval_expression(b, tuple)?, )? { Ordering::Less | Ordering::Equal => true, Ordering::Greater => false, @@ -912,10 +799,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .into(), ), PlanExpression::In(e, l) => { - let needed = self.eval_expression(e, tuple, options)?; + let needed = self.eval_expression(e, tuple)?; let mut error = false; for possible in l { - if let Some(possible) = self.eval_expression(possible, tuple, options) { + if let Some(possible) = self.eval_expression(possible, tuple) { if Some(true) == self.equals(needed, possible) { return Some(true.into()); } @@ -929,48 +816,40 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { Some(false.into()) } } - PlanExpression::Add(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) => 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(), - NumericBinaryOperands::Integer(v1, v2) => v1.checked_sub(v2)?.into(), - NumericBinaryOperands::Decimal(v1, v2) => v1.checked_sub(v2)?.into(), - }) - } - PlanExpression::Mul(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) => v1.checked_mul(v2)?.into(), - NumericBinaryOperands::Decimal(v1, v2) => v1.checked_mul(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::Add(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? { + NumericBinaryOperands::Float(v1, v2) => (v1 + v2).into(), + NumericBinaryOperands::Double(v1, v2) => (v1 + 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)? { + NumericBinaryOperands::Float(v1, v2) => (v1 - v2).into(), + NumericBinaryOperands::Double(v1, v2) => (v1 - v2).into(), + NumericBinaryOperands::Integer(v1, v2) => v1.checked_sub(v2)?.into(), + NumericBinaryOperands::Decimal(v1, v2) => v1.checked_sub(v2)?.into(), + }), + PlanExpression::Mul(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? { + NumericBinaryOperands::Float(v1, v2) => (v1 * 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::Div(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? { + 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)? { EncodedTerm::FloatLiteral(value) => Some((*value).into()), EncodedTerm::DoubleLiteral(value) => Some((*value).into()), EncodedTerm::IntegerLiteral(value) => Some((value).into()), EncodedTerm::DecimalLiteral(value) => Some((value).into()), _ => None, }, - PlanExpression::UnaryMinus(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::UnaryMinus(e) => match self.eval_expression(e, tuple)? { EncodedTerm::FloatLiteral(value) => Some((-*value).into()), EncodedTerm::DoubleLiteral(value) => Some((-*value).into()), EncodedTerm::IntegerLiteral(value) => Some((-value).into()), @@ -978,12 +857,12 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { _ => None, }, PlanExpression::UnaryNot(e) => self - .to_bool(self.eval_expression(e, tuple, options)?) + .to_bool(self.eval_expression(e, tuple)?) .map(|v| (!v).into()), PlanExpression::Str(e) => Some(EncodedTerm::StringLiteral { - value_id: self.to_string_id(self.eval_expression(e, tuple, options)?)?, + value_id: self.to_string_id(self.eval_expression(e, tuple)?)?, }), - PlanExpression::Lang(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Lang(e) => match self.eval_expression(e, tuple)? { EncodedTerm::LangStringLiteral { language_id, .. } => { Some(EncodedTerm::StringLiteral { value_id: language_id, @@ -994,9 +873,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { }, PlanExpression::LangMatches(language_tag, language_range) => { let language_tag = - self.to_simple_string(self.eval_expression(language_tag, tuple, options)?)?; + self.to_simple_string(self.eval_expression(language_tag, tuple)?)?; let language_range = - self.to_simple_string(self.eval_expression(language_range, tuple, options)?)?; + self.to_simple_string(self.eval_expression(language_range, tuple)?)?; Some( if &*language_range == "*" { !language_tag.is_empty() @@ -1014,20 +893,16 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .into(), ) } - PlanExpression::Datatype(e) => self.eval_expression(e, tuple, options)?.datatype(), + PlanExpression::Datatype(e) => self.eval_expression(e, tuple)?.datatype(), PlanExpression::Bound(v) => Some(has_tuple_value(*v, tuple).into()), PlanExpression::IRI(e) => { - let iri_id = match self.eval_expression(e, tuple, options)? { + let iri_id = match self.eval_expression(e, tuple)? { EncodedTerm::NamedNode { iri_id } => Some(iri_id), EncodedTerm::StringLiteral { value_id } => Some(value_id), _ => None, }?; let iri = self.dataset.get_str(iri_id).ok()??; - let base_iri = options - .base_iri - .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(base_iri) = &self.base_iri { self.build_named_node(&base_iri.resolve(&iri).ok()?.into_inner()) } else { Iri::parse(iri).ok()?; @@ -1037,7 +912,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { PlanExpression::BNode(id) => match id { Some(id) => { if let EncodedTerm::StringLiteral { value_id } = - self.eval_expression(id, tuple, options)? + self.eval_expression(id, tuple)? { Some(EncodedTerm::BlankNode { id: *self @@ -1056,28 +931,28 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { }), }, PlanExpression::Rand => Some(random::().into()), - PlanExpression::Abs(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Abs(e) => match self.eval_expression(e, tuple)? { EncodedTerm::IntegerLiteral(value) => Some(value.checked_abs()?.into()), EncodedTerm::DecimalLiteral(value) => Some(value.abs().into()), EncodedTerm::FloatLiteral(value) => Some(value.abs().into()), EncodedTerm::DoubleLiteral(value) => Some(value.abs().into()), _ => None, }, - PlanExpression::Ceil(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Ceil(e) => match self.eval_expression(e, tuple)? { EncodedTerm::IntegerLiteral(value) => Some(value.into()), EncodedTerm::DecimalLiteral(value) => Some(value.ceil().into()), EncodedTerm::FloatLiteral(value) => Some(value.ceil().into()), EncodedTerm::DoubleLiteral(value) => Some(value.ceil().into()), _ => None, }, - PlanExpression::Floor(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Floor(e) => match self.eval_expression(e, tuple)? { EncodedTerm::IntegerLiteral(value) => Some(value.into()), EncodedTerm::DecimalLiteral(value) => Some(value.floor().into()), EncodedTerm::FloatLiteral(value) => Some(value.floor().into()), EncodedTerm::DoubleLiteral(value) => Some(value.floor().into()), _ => None, }, - PlanExpression::Round(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Round(e) => match self.eval_expression(e, tuple)? { EncodedTerm::IntegerLiteral(value) => Some(value.into()), EncodedTerm::DecimalLiteral(value) => Some( value @@ -1093,7 +968,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { let mut language = None; for e in l { let (value, e_language) = - self.to_string_and_language(self.eval_expression(e, tuple, options)?)?; + self.to_string_and_language(self.eval_expression(e, tuple)?)?; if let Some(lang) = language { if lang != e_language { language = Some(None) @@ -1107,19 +982,17 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanExpression::SubStr(source, starting_loc, length) => { let (source, language) = - self.to_string_and_language(self.eval_expression(source, tuple, options)?)?; + self.to_string_and_language(self.eval_expression(source, tuple)?)?; let starting_location: usize = if let EncodedTerm::IntegerLiteral(v) = - self.eval_expression(starting_loc, tuple, options)? + self.eval_expression(starting_loc, tuple)? { v.try_into().ok()? } else { return None; }; let length: Option = 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)? { Some(v.try_into().ok()?) } else { return None; @@ -1151,45 +1024,45 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanExpression::StrLen(arg) => Some( (self - .to_string(self.eval_expression(arg, tuple, options)?)? + .to_string(self.eval_expression(arg, tuple)?)? .chars() .count() as i128) .into(), ), PlanExpression::Replace(arg, pattern, replacement, flags) => { let regex = self.compile_pattern( - self.eval_expression(pattern, tuple, options)?, + self.eval_expression(pattern, tuple)?, if let Some(flags) = flags { - Some(self.eval_expression(flags, tuple, options)?) + Some(self.eval_expression(flags, tuple)?) } else { None }, )?; let (text, language) = - self.to_string_and_language(self.eval_expression(arg, tuple, options)?)?; + self.to_string_and_language(self.eval_expression(arg, tuple)?)?; let replacement = - self.to_simple_string(self.eval_expression(replacement, tuple, options)?)?; + self.to_simple_string(self.eval_expression(replacement, tuple)?)?; self.build_plain_literal(®ex.replace_all(&text, &replacement as &str), language) } PlanExpression::UCase(e) => { let (value, language) = - self.to_string_and_language(self.eval_expression(e, tuple, options)?)?; + self.to_string_and_language(self.eval_expression(e, tuple)?)?; self.build_plain_literal(&value.to_uppercase(), language) } PlanExpression::LCase(e) => { let (value, language) = - self.to_string_and_language(self.eval_expression(e, tuple, options)?)?; + self.to_string_and_language(self.eval_expression(e, tuple)?)?; self.build_plain_literal(&value.to_lowercase(), language) } PlanExpression::StrStarts(arg1, arg2) => { let (arg1, arg2, _) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple, options)?, - self.eval_expression(arg2, tuple, options)?, + self.eval_expression(arg1, tuple)?, + self.eval_expression(arg2, tuple)?, )?; Some((&arg1).starts_with(&arg2 as &str).into()) } PlanExpression::EncodeForURI(ltrl) => { - let ltlr = self.to_string(self.eval_expression(ltrl, tuple, options)?)?; + let ltlr = self.to_string(self.eval_expression(ltrl, tuple)?)?; let mut result = Vec::with_capacity(ltlr.len()); for c in ltlr.bytes() { match c { @@ -1217,22 +1090,22 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanExpression::StrEnds(arg1, arg2) => { let (arg1, arg2, _) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple, options)?, - self.eval_expression(arg2, tuple, options)?, + self.eval_expression(arg1, tuple)?, + self.eval_expression(arg2, tuple)?, )?; Some((&arg1).ends_with(&arg2 as &str).into()) } PlanExpression::Contains(arg1, arg2) => { let (arg1, arg2, _) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple, options)?, - self.eval_expression(arg2, tuple, options)?, + self.eval_expression(arg1, tuple)?, + self.eval_expression(arg2, tuple)?, )?; Some((&arg1).contains(&arg2 as &str).into()) } PlanExpression::StrBefore(arg1, arg2) => { let (arg1, arg2, language) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple, options)?, - self.eval_expression(arg2, tuple, options)?, + self.eval_expression(arg1, tuple)?, + self.eval_expression(arg2, tuple)?, )?; if let Some(position) = (&arg1).find(&arg2 as &str) { self.build_plain_literal(&arg1[..position], language) @@ -1242,8 +1115,8 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } PlanExpression::StrAfter(arg1, arg2) => { let (arg1, arg2, language) = self.to_argument_compatible_strings( - self.eval_expression(arg1, tuple, options)?, - self.eval_expression(arg2, tuple, options)?, + self.eval_expression(arg1, tuple)?, + self.eval_expression(arg2, tuple)?, )?; if let Some(position) = (&arg1).find(&arg2 as &str) { self.build_plain_literal(&arg1[position + arg2.len()..], language) @@ -1251,40 +1124,40 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { Some(ENCODED_EMPTY_STRING_LITERAL) } } - PlanExpression::Year(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Year(e) => match self.eval_expression(e, tuple)? { EncodedTerm::DateLiteral(date) => Some(date.year().into()), EncodedTerm::NaiveDateLiteral(date) => Some(date.year().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.year().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.year().into()), _ => None, }, - PlanExpression::Month(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Month(e) => match self.eval_expression(e, tuple)? { EncodedTerm::DateLiteral(date) => Some(date.year().into()), EncodedTerm::NaiveDateLiteral(date) => Some(date.month().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.month().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.month().into()), _ => None, }, - PlanExpression::Day(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Day(e) => match self.eval_expression(e, tuple)? { EncodedTerm::DateLiteral(date) => Some(date.year().into()), EncodedTerm::NaiveDateLiteral(date) => Some(date.day().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.day().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.day().into()), _ => None, }, - PlanExpression::Hours(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Hours(e) => match self.eval_expression(e, tuple)? { EncodedTerm::NaiveTimeLiteral(time) => Some(time.hour().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.hour().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.hour().into()), _ => None, }, - PlanExpression::Minutes(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Minutes(e) => match self.eval_expression(e, tuple)? { EncodedTerm::NaiveTimeLiteral(time) => Some(time.minute().into()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.minute().into()), EncodedTerm::NaiveDateTimeLiteral(date_time) => Some(date_time.minute().into()), _ => None, }, - PlanExpression::Seconds(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::Seconds(e) => match self.eval_expression(e, tuple)? { EncodedTerm::NaiveTimeLiteral(time) => Some( (Decimal::new(time.nanosecond().into(), 9) + Decimal::from(time.second())) .into(), @@ -1302,7 +1175,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { _ => None, }, PlanExpression::Timezone(e) => { - let timezone = match self.eval_expression(e, tuple, options)? { + let timezone = match self.eval_expression(e, tuple)? { EncodedTerm::DateLiteral(date) => date.timezone(), EncodedTerm::DateTimeLiteral(date_time) => date_time.timezone(), _ => return None, @@ -1336,7 +1209,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { }) } PlanExpression::Tz(e) => { - let timezone = match self.eval_expression(e, tuple, options)? { + let timezone = match self.eval_expression(e, tuple)? { EncodedTerm::DateLiteral(date) => Some(date.timezone()), EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.timezone()), EncodedTerm::NaiveDateLiteral(_) @@ -1367,42 +1240,38 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { .to_hyphenated() .encode_lower(&mut Uuid::encode_buffer()), ), - PlanExpression::MD5(arg) => self.hash::(arg, tuple, options), - PlanExpression::SHA1(arg) => self.hash::(arg, tuple, options), - PlanExpression::SHA256(arg) => self.hash::(arg, tuple, options), - PlanExpression::SHA384(arg) => self.hash::(arg, tuple, options), - PlanExpression::SHA512(arg) => self.hash::(arg, tuple, options), + PlanExpression::MD5(arg) => self.hash::(arg, tuple), + PlanExpression::SHA1(arg) => self.hash::(arg, tuple), + PlanExpression::SHA256(arg) => self.hash::(arg, tuple), + PlanExpression::SHA384(arg) => self.hash::(arg, tuple), + PlanExpression::SHA512(arg) => self.hash::(arg, tuple), PlanExpression::Coalesce(l) => { for e in l { - if let Some(result) = self.eval_expression(e, tuple, options) { + if let Some(result) = self.eval_expression(e, tuple) { return Some(result); } } None } PlanExpression::If(a, b, c) => { - if self.to_bool(self.eval_expression(a, tuple, options)?)? { - self.eval_expression(b, tuple, options) + if self.to_bool(self.eval_expression(a, tuple)?)? { + self.eval_expression(b, tuple) } else { - self.eval_expression(c, tuple, options) + self.eval_expression(c, tuple) } } PlanExpression::StrLang(lexical_form, lang_tag) => { Some(EncodedTerm::LangStringLiteral { - value_id: self.to_simple_string_id(self.eval_expression( - lexical_form, - tuple, - options, - )?)?, + value_id: self + .to_simple_string_id(self.eval_expression(lexical_form, tuple)?)?, language_id: self - .to_simple_string_id(self.eval_expression(lang_tag, tuple, options)?)?, + .to_simple_string_id(self.eval_expression(lang_tag, tuple)?)?, }) } 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)?)?; let datatype = if let EncodedTerm::NamedNode { iri_id } = - self.eval_expression(datatype, tuple, options)? + self.eval_expression(datatype, tuple)? { self.dataset.get_str(iri_id).ok()? } else { @@ -1416,26 +1285,20 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { }) .ok() } - PlanExpression::SameTerm(a, b) => Some( - (self.eval_expression(a, tuple, options)? - == self.eval_expression(b, tuple, options)?) - .into(), - ), - PlanExpression::IsIRI(e) => Some( - self.eval_expression(e, tuple, options)? - .is_named_node() - .into(), - ), - PlanExpression::IsBlank(e) => Some( - self.eval_expression(e, tuple, options)? - .is_blank_node() - .into(), - ), + PlanExpression::SameTerm(a, b) => { + Some((self.eval_expression(a, tuple)? == self.eval_expression(b, tuple)?).into()) + } + PlanExpression::IsIRI(e) => { + Some(self.eval_expression(e, tuple)?.is_named_node().into()) + } + PlanExpression::IsBlank(e) => { + Some(self.eval_expression(e, tuple)?.is_blank_node().into()) + } PlanExpression::IsLiteral(e) => { - Some(self.eval_expression(e, tuple, options)?.is_literal().into()) + Some(self.eval_expression(e, tuple)?.is_literal().into()) } PlanExpression::IsNumeric(e) => Some( - match self.eval_expression(e, tuple, options)? { + match self.eval_expression(e, tuple)? { EncodedTerm::FloatLiteral(_) | EncodedTerm::DoubleLiteral(_) | EncodedTerm::IntegerLiteral(_) @@ -1446,24 +1309,24 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { ), PlanExpression::Regex(text, pattern, flags) => { let regex = self.compile_pattern( - self.eval_expression(pattern, tuple, options)?, + self.eval_expression(pattern, tuple)?, if let Some(flags) = flags { - Some(self.eval_expression(flags, tuple, options)?) + Some(self.eval_expression(flags, tuple)?) } else { None }, )?; - let text = self.to_string(self.eval_expression(text, tuple, options)?)?; + let text = self.to_string(self.eval_expression(text, tuple)?)?; Some(regex.is_match(&text).into()) } - PlanExpression::BooleanCast(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::BooleanCast(e) => match self.eval_expression(e, tuple)? { EncodedTerm::BooleanLiteral(value) => Some(value.into()), EncodedTerm::StringLiteral { value_id } => { parse_boolean_str(&*self.dataset.get_str(value_id).ok()??) } _ => None, }, - PlanExpression::DoubleCast(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::DoubleCast(e) => match self.eval_expression(e, tuple)? { EncodedTerm::FloatLiteral(value) => Some(value.to_f64()?.into()), EncodedTerm::DoubleLiteral(value) => Some(value.to_f64()?.into()), EncodedTerm::IntegerLiteral(value) => Some(value.to_f64()?.into()), @@ -1476,7 +1339,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::FloatCast(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::FloatCast(e) => match self.eval_expression(e, tuple)? { EncodedTerm::FloatLiteral(value) => Some(value.to_f32()?.into()), EncodedTerm::DoubleLiteral(value) => Some(value.to_f32()?.into()), EncodedTerm::IntegerLiteral(value) => Some(value.to_f32()?.into()), @@ -1489,7 +1352,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::IntegerCast(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::IntegerCast(e) => match self.eval_expression(e, tuple)? { EncodedTerm::FloatLiteral(value) => Some(value.to_i128()?.into()), EncodedTerm::DoubleLiteral(value) => Some(value.to_i128()?.into()), EncodedTerm::IntegerLiteral(value) => Some(value.to_i128()?.into()), @@ -1500,7 +1363,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::DecimalCast(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::DecimalCast(e) => match self.eval_expression(e, tuple)? { EncodedTerm::FloatLiteral(value) => Some(Decimal::from_f32(*value)?.into()), EncodedTerm::DoubleLiteral(value) => Some(Decimal::from_f64(*value)?.into()), EncodedTerm::IntegerLiteral(value) => Some(Decimal::from_i128(value)?.into()), @@ -1518,7 +1381,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::DateCast(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::DateCast(e) => match self.eval_expression(e, tuple)? { EncodedTerm::DateLiteral(value) => Some(value.into()), EncodedTerm::NaiveDateLiteral(value) => Some(value.into()), EncodedTerm::DateTimeLiteral(value) => Some(value.date().into()), @@ -1528,7 +1391,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::TimeCast(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::TimeCast(e) => match self.eval_expression(e, tuple)? { EncodedTerm::NaiveTimeLiteral(value) => Some(value.into()), EncodedTerm::DateTimeLiteral(value) => Some(value.time().into()), EncodedTerm::NaiveDateTimeLiteral(value) => Some(value.time().into()), @@ -1537,7 +1400,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } _ => None, }, - PlanExpression::DateTimeCast(e) => match self.eval_expression(e, tuple, options)? { + PlanExpression::DateTimeCast(e) => match self.eval_expression(e, tuple)? { EncodedTerm::DateTimeLiteral(value) => Some(value.into()), EncodedTerm::NaiveDateTimeLiteral(value) => Some(value.into()), EncodedTerm::StringLiteral { value_id } => { @@ -1546,7 +1409,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { _ => None, }, PlanExpression::StringCast(e) => Some(EncodedTerm::StringLiteral { - value_id: self.to_string_id(self.eval_expression(e, tuple, options)?)?, + value_id: self.to_string_id(self.eval_expression(e, tuple)?)?, }), } } @@ -1716,11 +1579,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { e1: &PlanExpression, e2: &PlanExpression, tuple: &[Option], - options: &QueryOptions<'b>, ) -> Option { NumericBinaryOperands::new( - self.eval_expression(&e1, tuple, options)?, - self.eval_expression(&e2, tuple, options)?, + self.eval_expression(&e1, tuple)?, + self.eval_expression(&e2, tuple)?, ) } @@ -1757,7 +1619,6 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { where 'a: 'b, { - let mut encoder = self.dataset.encoder(); let (binding_variables, iter) = BindingsIterator::destruct(iter); let mut combined_variables = variables.to_vec(); for v in binding_variables.clone() { @@ -1766,6 +1627,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { } } Box::new(iter.map(move |terms| { + let mut encoder = self.dataset.encoder(); let mut encoded_terms = vec![None; combined_variables.len()]; for (i, term_option) in terms?.into_iter().enumerate() { match term_option { @@ -1904,11 +1766,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { tuple_a: &[Option], tuple_b: &[Option], expression: &PlanExpression, - options: &QueryOptions<'b>, ) -> Ordering { self.cmp_terms( - self.eval_expression(expression, tuple_a, options), - self.eval_expression(expression, tuple_b, options), + self.eval_expression(expression, tuple_a), + self.eval_expression(expression, tuple_b), ) } @@ -2023,9 +1884,8 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { &'b self, arg: &PlanExpression, tuple: &[Option], - options: &QueryOptions<'b>, ) -> Option { - let input = self.to_simple_string(self.eval_expression(arg, tuple, options)?)?; + let input = self.to_simple_string(self.eval_expression(arg, tuple)?)?; let hash = hex::encode(H::new().chain(&input as &str).result()); self.build_string_literal(&hash) } @@ -2308,7 +2168,6 @@ struct LeftJoinIterator<'a, S: StoreConnection + 'a> { right_plan: &'a PlanNode, left_iter: EncodedTuplesIterator<'a>, current_right: EncodedTuplesIterator<'a>, - options: &'a QueryOptions<'a>, } impl<'a, S: StoreConnection> Iterator for LeftJoinIterator<'a, S> { @@ -2320,9 +2179,7 @@ impl<'a, S: StoreConnection> Iterator for LeftJoinIterator<'a, S> { } match self.left_iter.next()? { 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()); if let Some(right_tuple) = self.current_right.next() { Some(right_tuple) } else { @@ -2376,7 +2233,6 @@ struct UnionIterator<'a, S: StoreConnection + 'a> { input: EncodedTuple, current_iterator: EncodedTuplesIterator<'a>, current_plan: usize, - options: &'a QueryOptions<'a>, } impl<'a, S: StoreConnection> Iterator for UnionIterator<'a, S> { @@ -2390,11 +2246,9 @@ impl<'a, S: StoreConnection> Iterator for UnionIterator<'a, S> { if self.current_plan >= self.plans.len() { return None; } - self.current_iterator = self.eval.eval_plan( - &self.plans[self.current_plan], - self.input.clone(), - self.options, - ); + self.current_iterator = self + .eval + .eval_plan(&self.plans[self.current_plan], self.input.clone()); self.current_plan += 1; } } @@ -2473,7 +2327,6 @@ fn decode_triple( struct DescribeIterator<'a, S: StoreConnection + 'a> { eval: &'a SimpleEvaluator, - options: &'a QueryOptions<'a>, iter: EncodedTuplesIterator<'a>, quads: Box> + 'a>, } @@ -2499,13 +2352,10 @@ impl<'a, S: StoreConnection + 'a> Iterator for DescribeIterator<'a, S> { }; for subject in tuple { if let Some(subject) = subject { - self.quads = self.eval.dataset.quads_for_pattern( - Some(subject), - None, - None, - None, - self.options.default_graph_as_union, - ); + self.quads = + self.eval + .dataset + .quads_for_pattern(Some(subject), None, None, None); } } } diff --git a/lib/src/sparql/mod.rs b/lib/src/sparql/mod.rs index 6b93c208..f0c62666 100644 --- a/lib/src/sparql/mod.rs +++ b/lib/src/sparql/mod.rs @@ -18,7 +18,6 @@ use crate::sparql::plan::{DatasetView, PlanNode}; use crate::sparql::plan_builder::PlanBuilder; use crate::store::StoreConnection; use crate::Result; -use failure::format_err; use rio_api::iri::Iri; use std::fmt; @@ -31,7 +30,7 @@ pub use crate::sparql::model::Variable; /// A prepared [SPARQL query](https://www.w3.org/TR/sparql11-query/) pub trait PreparedQuery { /// Evaluates the query and returns its results - fn exec<'a>(&'a self, options: &'a QueryOptions<'a>) -> Result>; + fn exec(&self) -> Result; } /// An implementation of `PreparedQuery` for internal use @@ -59,10 +58,9 @@ enum SimplePreparedQueryAction { } impl<'a, S: StoreConnection + 'a> SimplePreparedQuery { - pub(crate) fn new(connection: S, query: &str, base_iri: Option<&'a str>) -> Result { - let dataset = DatasetView::new(connection); - //TODO avoid inserting terms in the Repository StringStore - Ok(Self(match read_sparql_query(query, base_iri)? { + pub(crate) fn new(connection: S, query: &str, options: QueryOptions) -> Result { + let dataset = DatasetView::new(connection, options.default_graph_as_union); + Ok(Self(match read_sparql_query(query, options.base_iri)? { QueryVariants::Select { algebra, dataset: _, @@ -72,7 +70,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery { SimplePreparedQueryAction::Select { plan, variables, - evaluator: SimpleEvaluator::new(dataset, base_iri), + evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), } } QueryVariants::Ask { @@ -83,7 +81,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery { let (plan, _) = PlanBuilder::build(dataset.encoder(), &algebra)?; SimplePreparedQueryAction::Ask { plan, - evaluator: SimpleEvaluator::new(dataset, base_iri), + evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), } } QueryVariants::Construct { @@ -100,7 +98,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery { &construct, variables, )?, - evaluator: SimpleEvaluator::new(dataset, base_iri), + evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), } } QueryVariants::Describe { @@ -111,7 +109,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery { let (plan, _) = PlanBuilder::build(dataset.encoder(), &algebra)?; SimplePreparedQueryAction::Describe { plan, - evaluator: SimpleEvaluator::new(dataset, base_iri), + evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), } } })) @@ -121,62 +119,77 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery { pub(crate) fn new_from_pattern( connection: S, pattern: &GraphPattern, - base_iri: Option<&'a str>, + options: QueryOptions, ) -> Result { - let dataset = DatasetView::new(connection); + let dataset = DatasetView::new(connection, options.default_graph_as_union); let (plan, variables) = PlanBuilder::build(dataset.encoder(), pattern)?; - let base_iri = base_iri.map(|str_iri| Iri::parse(str_iri.to_string())); - match base_iri { - Some(Err(_)) => Err(format_err!("Failed to parse base_iri")), - Some(Ok(base_iri)) => Ok(Self(SimplePreparedQueryAction::Select { - plan, - variables, - evaluator: SimpleEvaluator::new(dataset, Some(base_iri)), - })), - None => Ok(Self(SimplePreparedQueryAction::Select { - plan, - variables, - evaluator: SimpleEvaluator::new(dataset, None), - })), - } + let base_iri = if let Some(base_iri) = options.base_iri { + Some(Iri::parse(base_iri.to_string())?) + } else { + None + }; + Ok(Self(SimplePreparedQueryAction::Select { + plan, + variables, + evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), + })) } } impl PreparedQuery for SimplePreparedQuery { - fn exec<'a>(&'a self, options: &'a QueryOptions<'a>) -> Result> { + fn exec(&self) -> Result { match &self.0 { SimplePreparedQueryAction::Select { plan, variables, evaluator, - } => evaluator.evaluate_select_plan(&plan, &variables, options), + } => evaluator.evaluate_select_plan(&plan, &variables), SimplePreparedQueryAction::Ask { plan, evaluator } => { - evaluator.evaluate_ask_plan(&plan, options) + evaluator.evaluate_ask_plan(&plan) } SimplePreparedQueryAction::Construct { plan, construct, evaluator, - } => evaluator.evaluate_construct_plan(&plan, &construct, &options), + } => evaluator.evaluate_construct_plan(&plan, &construct), SimplePreparedQueryAction::Describe { plan, evaluator } => { - evaluator.evaluate_describe_plan(&plan, &options) + evaluator.evaluate_describe_plan(&plan) } } } } +/// Handler for SPARQL SERVICEs. +/// +/// Might be used to implement [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) pub trait ServiceHandler { + /// Get the handler for a given service identified by a RDF IRI. + /// + /// A service is a function that returns an iterator of bindings from a `GraphPattern`. + /// Returns `None` if there is no handler for the service. fn handle<'a>( &'a self, - node: NamedNode, + node: &NamedNode, ) -> Option<(fn(GraphPattern) -> Result>)>; } +#[derive(Default)] +struct EmptyServiceHandler {} + +impl ServiceHandler for EmptyServiceHandler { + fn handle( + &self, + _node: &NamedNode, + ) -> Option<(fn(GraphPattern) -> Result>)> { + None + } +} + /// Options for SPARQL query parsing and evaluation like the query base IRI pub struct QueryOptions<'a> { pub(crate) base_iri: Option<&'a str>, pub(crate) default_graph_as_union: bool, - pub(crate) service_handler: Option>, + pub(crate) service_handler: Box, } impl<'a> Default for QueryOptions<'a> { @@ -184,7 +197,7 @@ impl<'a> Default for QueryOptions<'a> { Self { base_iri: None, default_graph_as_union: false, - service_handler: None as Option>, + service_handler: Box::new(EmptyServiceHandler::default()), } } } @@ -204,7 +217,7 @@ impl<'a> QueryOptions<'a> { /// Consider the union of all graphs in the repository as the default graph pub fn with_service_handler(mut self, service_handler: Box) -> Self { - self.service_handler = Some(service_handler); + self.service_handler = service_handler; self } } diff --git a/lib/src/sparql/plan.rs b/lib/src/sparql/plan.rs index 970f4b58..83050629 100644 --- a/lib/src/sparql/plan.rs +++ b/lib/src/sparql/plan.rs @@ -22,7 +22,7 @@ pub enum PlanNode { service_name: PatternValue, variables: Vec, child: Box, - graph_pattern: GraphPattern, + graph_pattern: Box, silent: bool, }, QuadPatternJoin { @@ -175,7 +175,7 @@ impl PlanNode { PlanNode::HashDeduplicate { child } => child.add_variables(set), PlanNode::Skip { child, .. } => child.add_variables(set), PlanNode::Limit { child, .. } => child.add_variables(set), - PlanNode::Project { child: _, mapping } => { + PlanNode::Project { mapping, .. } => { for i in 0..mapping.len() { set.insert(i); } @@ -473,13 +473,15 @@ pub enum TripleTemplateValue { pub struct DatasetView { store: S, extra: RefCell, + default_graph_as_union: bool, } impl DatasetView { - pub fn new(store: S) -> Self { + pub fn new(store: S, default_graph_as_union: bool) -> Self { Self { store, extra: RefCell::new(MemoryStrStore::default()), + default_graph_as_union, } } @@ -489,7 +491,6 @@ impl DatasetView { predicate: Option, object: Option, graph_name: Option, - default_graph_as_union: bool, ) -> Box> + 'a> { if graph_name == None { Box::new( @@ -500,7 +501,7 @@ impl DatasetView { Ok(quad) => quad.graph_name != ENCODED_DEFAULT_GRAPH, }), ) - } else if graph_name == Some(ENCODED_DEFAULT_GRAPH) && default_graph_as_union { + } else if graph_name == Some(ENCODED_DEFAULT_GRAPH) && self.default_graph_as_union { Box::new( self.store .quads_for_pattern(subject, predicate, object, None) diff --git a/lib/src/sparql/plan_builder.rs b/lib/src/sparql/plan_builder.rs index a32da1a0..041e8ecc 100644 --- a/lib/src/sparql/plan_builder.rs +++ b/lib/src/sparql/plan_builder.rs @@ -104,13 +104,14 @@ impl PlanBuilder { right: Box::new(self.build_for_graph_pattern(b, variables, graph_name)?), }, GraphPattern::Service(n, p, s) => { + // Child building should be at the begging in order for `variables` to be filled + let child = self.build_for_graph_pattern(p, variables, graph_name)?; let service_name = self.pattern_value_from_named_node_or_variable(n, variables)?; - let graph_pattern = *p.clone(); PlanNode::Service { service_name, variables: variables.clone(), - child: Box::new(self.build_for_graph_pattern(p, variables, service_name)?), - graph_pattern, + child: Box::new(child), + graph_pattern: Box::new(*p.clone()), silent: *s, } } diff --git a/lib/src/store/memory.rs b/lib/src/store/memory.rs index 55ffac64..d9cbe5cd 100644 --- a/lib/src/store/memory.rs +++ b/lib/src/store/memory.rs @@ -29,9 +29,8 @@ use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}; /// assert_eq!(vec![quad], results.unwrap()); /// /// // SPARQL query -/// let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", None).unwrap(); -/// let options = QueryOptions::default(); -/// let results = prepared_query.exec(&options).unwrap(); +/// let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default()).unwrap(); +/// let results = prepared_query.exec().unwrap(); /// if let QueryResult::Bindings(results) = results { /// assert_eq!(results.into_values_iter().next().unwrap().unwrap()[0], Some(ex.into())); /// } diff --git a/lib/src/store/mod.rs b/lib/src/store/mod.rs index fd421570..f1314a0e 100644 --- a/lib/src/store/mod.rs +++ b/lib/src/store/mod.rs @@ -11,7 +11,7 @@ pub use crate::store::memory::MemoryRepository; pub use crate::store::rocksdb::RocksDbRepository; use crate::model::*; -use crate::sparql::SimplePreparedQuery; +use crate::sparql::{QueryOptions, SimplePreparedQuery}; use crate::store::numeric_encoder::*; use crate::{DatasetSyntax, GraphSyntax, RepositoryConnection, Result}; use rio_api::parser::{QuadsParser, TriplesParser}; @@ -72,12 +72,8 @@ impl From for StoreRepositoryConnection { impl RepositoryConnection for StoreRepositoryConnection { type PreparedQuery = SimplePreparedQuery; - fn prepare_query<'a>( - &self, - query: &str, - base_iri: Option<&'a str>, - ) -> Result> { - SimplePreparedQuery::new(self.inner.clone(), query, base_iri) //TODO: avoid clone + fn prepare_query(&self, query: &str, options: QueryOptions) -> Result> { + SimplePreparedQuery::new(self.inner.clone(), query, options) //TODO: avoid clone } fn quads_for_pattern<'a>( @@ -101,12 +97,12 @@ impl RepositoryConnection for StoreRepositoryConnection { ) } - fn prepare_query_from_pattern<'a>( - &'a self, + fn prepare_query_from_pattern( + &self, pattern: &GraphPattern, - base_iri: Option<&'a str>, + options: QueryOptions, ) -> Result { - SimplePreparedQuery::new_from_pattern(self.inner.clone(), pattern, base_iri) + SimplePreparedQuery::new_from_pattern(self.inner.clone(), pattern, options) //TODO: avoid clone } diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index 6e5eff52..416855bf 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -40,9 +40,8 @@ use std::str; /// assert_eq!(vec![quad], results.unwrap()); /// /// // SPARQL query -/// let options = QueryOptions::default(); -/// let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", None).unwrap(); -/// let results = prepared_query.exec(&options).unwrap(); +/// let prepared_query = connection.prepare_query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default()).unwrap(); +/// let results = prepared_query.exec().unwrap(); /// if let QueryResult::Bindings(results) = results { /// assert_eq!(results.into_values_iter().next().unwrap().unwrap()[0], Some(ex.into())); /// } diff --git a/lib/tests/service_test_cases.rs b/lib/tests/service_test_cases.rs index d1a173db..1e4a76a5 100644 --- a/lib/tests/service_test_cases.rs +++ b/lib/tests/service_test_cases.rs @@ -12,7 +12,7 @@ fn simple_service_test() { impl ServiceHandler for TestServiceHandler { fn handle<'a>( &'a self, - _named_node: NamedNode, + _named_node: &NamedNode, ) -> Option<(fn(GraphPattern) -> Result>)> { fn pattern_handler<'a>(graph_pattern: GraphPattern) -> Result> { let triples = @@ -56,13 +56,13 @@ fn two_service_test() { impl ServiceHandler for TwoServiceTest { fn handle<'a>( &'a self, - named_node: NamedNode, + named_node: &NamedNode, ) -> Option<(fn(GraphPattern) -> Result>)> { let service1 = NamedNode::parse("http://service1.org").unwrap(); let service2 = NamedNode::parse("http://service2.org").unwrap(); - if named_node == service1 { + if named_node == &service1 { Some(TwoServiceTest::handle_service1) - } else if named_node == service2 { + } else if named_node == &service2 { Some(TwoServiceTest::handle_service2) } else { None @@ -133,7 +133,7 @@ fn silent_service_empty_set_test() { impl ServiceHandler for ServiceTest { fn handle<'a>( &'a self, - _named_node: NamedNode, + _named_node: &NamedNode, ) -> Option<(fn(GraphPattern) -> Result>)> { Some(ServiceTest::handle_service) } @@ -177,7 +177,7 @@ fn non_silent_service_test() { impl ServiceHandler for ServiceTest { fn handle<'a>( &'a self, - _named_node: NamedNode, + _named_node: &NamedNode, ) -> Option<(fn(GraphPattern) -> Result>)> { Some(ServiceTest::handle_service) } @@ -242,10 +242,11 @@ fn query_repository<'a>( query: String, options: QueryOptions<'a>, ) -> Result> { - let connection = repository.connection()?; - let prepared_query = connection.prepare_query(&query, None)?; - let result = prepared_query.exec(&options)?; - match result { + match repository + .connection()? + .prepare_query(&query, options)? + .exec()? + { QueryResult::Bindings(iterator) => { let (varaibles, iter) = iterator.destruct(); let collected = iter.collect::>(); @@ -265,10 +266,11 @@ fn pattern_repository<'a>( pattern: GraphPattern, options: QueryOptions<'a>, ) -> Result> { - let connection = repository.connection()?; - let prepared_query = connection.prepare_query_from_pattern(&pattern, None)?; - let result = prepared_query.exec(&options)?; - match result { + match repository + .connection()? + .prepare_query_from_pattern(&pattern, options)? + .exec()? + { QueryResult::Bindings(iterator) => { let (varaibles, iter) = iterator.destruct(); let collected = iter.collect::>(); @@ -277,9 +279,7 @@ fn pattern_repository<'a>( Box::new(collected.into_iter()), )) } - _ => Err(format_err!( - "Excpected bindings but got another QueryResult" - )), + _ => Err(format_err!("Expected bindings but got another QueryResult")), } } diff --git a/lib/tests/sparql_test_cases.rs b/lib/tests/sparql_test_cases.rs index d4d0601f..fcef66c3 100644 --- a/lib/tests/sparql_test_cases.rs +++ b/lib/tests/sparql_test_cases.rs @@ -158,13 +158,13 @@ fn sparql_w3c_query_evaluation_testsuite() -> Result<()> { } match repository .connection()? - .prepare_query(&read_file_to_string(&test.query)?, Some(&test.query)) + .prepare_query(&read_file_to_string(&test.query)?, QueryOptions::default().with_base_iri(&test.query)) { Err(error) => Err(format_err!( "Failure to parse query of {} with error: {}", test, error )), - Ok(query) => match query.exec(&QueryOptions::default()) { + Ok(query) => match query.exec() { Err(error) => Err(format_err!( "Failure to execute query of {} with error: {}", test, error diff --git a/server/src/main.rs b/server/src/main.rs index 5918593a..3c2cd587 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -148,10 +148,9 @@ fn evaluate_sparql_query( request: &Request, ) -> Response { //TODO: stream - let options = QueryOptions::default(); - match connection.prepare_query(query, None) { + match connection.prepare_query(query, QueryOptions::default()) { Ok(query) => { - let results = query.exec(&options).unwrap(); + let results = query.exec().unwrap(); if let QueryResult::Graph(_) = results { let supported_formats = [ GraphSyntax::NTriples.media_type(),