setup ServiceHandler

pull/11/head
Dustin Whitney 5 years ago
parent e3fe4c5dc6
commit 40680956ba
  1. 312
      lib/src/sparql/eval.rs
  2. 20
      lib/src/sparql/mod.rs

@ -1,6 +1,7 @@
use crate::model::BlankNode;
use crate::model::Triple;
use crate::sparql::model::*;
use crate::sparql::QueryOptions;
use crate::sparql::plan::*;
use crate::store::numeric_encoder::*;
use crate::store::StoreConnection;
@ -58,21 +59,26 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
&'b self,
plan: &'b PlanNode,
variables: &[Variable],
options: &'b QueryOptions<'b>
) -> Result<QueryResult<'b>>
where
'a: 'b,
{
let iter = self.eval_plan(plan, vec![None; variables.len()]);
let iter = self.eval_plan(plan, vec![None; variables.len()], &options);
Ok(QueryResult::Bindings(
self.decode_bindings(iter, variables.to_vec()),
))
}
pub fn evaluate_ask_plan<'b>(&'b self, plan: &'b PlanNode) -> Result<QueryResult<'b>>
pub fn evaluate_ask_plan<'b>(
&'b self,
plan: &'b PlanNode,
options: &'b QueryOptions<'b>
) -> Result<QueryResult<'b>>
where
'a: 'b,
{
match self.eval_plan(plan, vec![]).next() {
match self.eval_plan(plan, vec![], &options).next() {
Some(Ok(_)) => Ok(QueryResult::Boolean(true)),
Some(Err(error)) => Err(error),
None => Ok(QueryResult::Boolean(false)),
@ -83,31 +89,41 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
&'b self,
plan: &'b PlanNode,
construct: &'b [TripleTemplate],
options: &'b QueryOptions<'b>
) -> Result<QueryResult<'b>>
where
'a: 'b,
{
Ok(QueryResult::Graph(Box::new(ConstructIterator {
eval: self,
iter: self.eval_plan(plan, vec![]),
iter: self.eval_plan(plan, vec![], options),
template: construct,
buffered_results: Vec::default(),
bnodes: Vec::default(),
})))
}
pub fn evaluate_describe_plan<'b>(&'b self, plan: &'b PlanNode) -> Result<QueryResult<'b>>
pub fn evaluate_describe_plan<'b>(
&'b self,
plan: &'b PlanNode,
options: &'b QueryOptions<'b>
) -> Result<QueryResult<'b>>
where
'a: 'b,
{
Ok(QueryResult::Graph(Box::new(DescribeIterator {
eval: self,
iter: self.eval_plan(plan, vec![]),
iter: self.eval_plan(plan, vec![], options),
quads: Box::new(empty()),
})))
}
fn eval_plan<'b>(&'b self, node: &'b PlanNode, from: EncodedTuple) -> EncodedTuplesIterator<'b>
fn eval_plan<'b>(
&'b self,
node: &'b PlanNode,
from: EncodedTuple,
options: &'b QueryOptions<'b>
) -> EncodedTuplesIterator<'b>
where
'a: 'b,
{
@ -120,7 +136,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
predicate,
object,
graph_name,
} => Box::new(self.eval_plan(&*child, from).flat_map_ok(move |tuple| {
} => 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),
@ -186,7 +202,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
path,
object,
graph_name,
} => Box::new(self.eval_plan(&*child, from).flat_map_ok(move |tuple| {
} => 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 =
@ -244,7 +260,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
//TODO: very dumb implementation
let mut errors = Vec::default();
let left_values = self
.eval_plan(&*left, from.clone())
.eval_plan(&*left, from.clone(), options)
.filter_map(|result| match result {
Ok(result) => Some(result),
Err(error) => {
@ -255,18 +271,18 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
.collect::<Vec<_>>();
Box::new(JoinIterator {
left: left_values,
right_iter: self.eval_plan(&*right, from),
right_iter: self.eval_plan(&*right, from, options),
buffered_results: errors,
})
}
PlanNode::AntiJoin { left, right } => {
//TODO: dumb implementation
let right: Vec<_> = self
.eval_plan(&*right, from.clone())
.eval_plan(&*right, from.clone(), options)
.filter_map(|result| result.ok())
.collect();
Box::new(AntiJoinIterator {
left_iter: self.eval_plan(&*left, from),
left_iter: self.eval_plan(&*left, from, options),
right,
})
}
@ -281,8 +297,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
let iter = LeftJoinIterator {
eval: self,
right_plan: &*right,
left_iter: self.eval_plan(&*left, filtered_from),
left_iter: self.eval_plan(&*left, filtered_from, options),
current_right: Box::new(empty()),
options,
};
if problem_vars.is_empty() {
Box::new(iter)
@ -296,10 +313,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
PlanNode::Filter { child, expression } => {
let eval = self;
Box::new(self.eval_plan(&*child, from).filter(move |tuple| {
Box::new(self.eval_plan(&*child, from, options).filter(move |tuple| {
match tuple {
Ok(tuple) => eval
.eval_expression(&expression, tuple)
.eval_expression(&expression, tuple, options)
.and_then(|term| eval.to_bool(term))
.unwrap_or(false),
Err(_) => true,
@ -312,6 +329,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
input: from,
current_iterator: Box::new(empty()),
current_plan: 0,
options,
}),
PlanNode::Extend {
child,
@ -319,9 +337,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
expression,
} => {
let eval = self;
Box::new(self.eval_plan(&*child, from).map(move |tuple| {
Box::new(self.eval_plan(&*child, from, options).map(move |tuple| {
let mut tuple = tuple?;
if let Some(value) = eval.eval_expression(&expression, &tuple) {
if let Some(value) = eval.eval_expression(&expression, &tuple, options) {
put_value(*position, value, &mut tuple)
}
Ok(tuple)
@ -330,7 +348,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
PlanNode::Sort { child, by } => {
let mut errors = Vec::default();
let mut values = self
.eval_plan(&*child, from)
.eval_plan(&*child, from, options)
.filter_map(|result| match result {
Ok(result) => Some(result),
Err(error) => {
@ -343,14 +361,14 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
for comp in by {
match comp {
Comparator::Asc(expression) => {
match self.cmp_according_to_expression(a, b, &expression) {
match self.cmp_according_to_expression(a, b, &expression, options) {
Ordering::Greater => return Ordering::Greater,
Ordering::Less => return Ordering::Less,
Ordering::Equal => (),
}
}
Comparator::Desc(expression) => {
match self.cmp_according_to_expression(a, b, &expression) {
match self.cmp_according_to_expression(a, b, &expression, options) {
Ordering::Greater => return Ordering::Less,
Ordering::Less => return Ordering::Greater,
Ordering::Equal => (),
@ -363,16 +381,16 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
Box::new(errors.into_iter().chain(values.into_iter().map(Ok)))
}
PlanNode::HashDeduplicate { child } => {
Box::new(hash_deduplicate(self.eval_plan(&*child, from)))
Box::new(hash_deduplicate(self.eval_plan(&*child, from, options)))
}
PlanNode::Skip { child, count } => Box::new(self.eval_plan(&*child, from).skip(*count)),
PlanNode::Skip { child, count } => Box::new(self.eval_plan(&*child, from, options).skip(*count)),
PlanNode::Limit { child, count } => {
Box::new(self.eval_plan(&*child, from).take(*count))
Box::new(self.eval_plan(&*child, from, options).take(*count))
}
PlanNode::Project { child, mapping } => {
//TODO: use from somewhere?
Box::new(
self.eval_plan(&*child, vec![None; mapping.len()])
self.eval_plan(&*child, vec![None; mapping.len()], options)
.map(move |tuple| {
let tuple = tuple?;
let mut output_tuple = vec![None; from.len()];
@ -394,7 +412,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
let mut errors = Vec::default();
let mut accumulators_for_group =
HashMap::<Vec<Option<EncodedTerm>>, Vec<Box<dyn Accumulator>>>::default();
self.eval_plan(child, from)
self.eval_plan(child, from, options)
.filter_map(|result| match result {
Ok(result) => Some(result),
Err(error) => {
@ -426,7 +444,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
aggregate
.parameter
.as_ref()
.and_then(|parameter| self.eval_expression(&parameter, &tuple)),
.and_then(|parameter| self.eval_expression(&parameter, &tuple, options)),
);
}
});
@ -666,24 +684,25 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
.map(|e| e.map(|e| (e, e)))
}
fn eval_expression(
&self,
fn eval_expression<'b>(
&'b self,
expression: &PlanExpression,
tuple: &[Option<EncodedTerm>],
options: &QueryOptions<'b>
) -> Option<EncodedTerm> {
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()).next().is_some().into())
Some(self.eval_plan(node, tuple.to_vec(), options).next().is_some().into())
}
PlanExpression::Or(a, b) => {
match self.eval_expression(a, tuple).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(false) => self.eval_expression(b, tuple),
Some(false) => self.eval_expression(b, tuple, options),
None => {
if Some(true)
== self.eval_expression(b, tuple).and_then(|v| self.to_bool(v))
== self.eval_expression(b, tuple, options).and_then(|v| self.to_bool(v))
{
Some(true.into())
} else {
@ -693,13 +712,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
}
PlanExpression::And(a, b) => match self
.eval_expression(a, tuple)
.eval_expression(a, tuple, options)
.and_then(|v| self.to_bool(v))
{
Some(true) => self.eval_expression(b, tuple),
Some(true) => self.eval_expression(b, tuple, options),
Some(false) => Some(false.into()),
None => {
if Some(false) == self.eval_expression(b, tuple).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())
} else {
None
@ -707,26 +726,26 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
},
PlanExpression::Equal(a, b) => {
let a = self.eval_expression(a, tuple)?;
let b = self.eval_expression(b, tuple)?;
let a = self.eval_expression(a, tuple, options)?;
let b = self.eval_expression(b, tuple, options)?;
self.equals(a, b).map(|v| v.into())
}
PlanExpression::NotEqual(a, b) => {
let a = self.eval_expression(a, tuple)?;
let b = self.eval_expression(b, tuple)?;
let a = self.eval_expression(a, tuple, options)?;
let b = self.eval_expression(b, tuple, options)?;
self.equals(a, b).map(|v| (!v).into())
}
PlanExpression::Greater(a, b) => Some(
(self.partial_cmp_literals(
self.eval_expression(a, tuple)?,
self.eval_expression(b, tuple)?,
self.eval_expression(a, tuple, options)?,
self.eval_expression(b, tuple, options)?,
)? == Ordering::Greater)
.into(),
),
PlanExpression::GreaterOrEq(a, b) => Some(
match self.partial_cmp_literals(
self.eval_expression(a, tuple)?,
self.eval_expression(b, tuple)?,
self.eval_expression(a, tuple, options)?,
self.eval_expression(b, tuple, options)?,
)? {
Ordering::Greater | Ordering::Equal => true,
Ordering::Less => false,
@ -735,15 +754,15 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
),
PlanExpression::Lower(a, b) => Some(
(self.partial_cmp_literals(
self.eval_expression(a, tuple)?,
self.eval_expression(b, tuple)?,
self.eval_expression(a, tuple, options)?,
self.eval_expression(b, tuple, options)?,
)? == Ordering::Less)
.into(),
),
PlanExpression::LowerOrEq(a, b) => Some(
match self.partial_cmp_literals(
self.eval_expression(a, tuple)?,
self.eval_expression(b, tuple)?,
self.eval_expression(a, tuple, options)?,
self.eval_expression(b, tuple, options)?,
)? {
Ordering::Less | Ordering::Equal => true,
Ordering::Greater => false,
@ -751,10 +770,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
.into(),
),
PlanExpression::In(e, l) => {
let needed = self.eval_expression(e, tuple)?;
let needed = self.eval_expression(e, tuple, options)?;
let mut error = false;
for possible in l {
if let Some(possible) = self.eval_expression(possible, tuple) {
if let Some(possible) = self.eval_expression(possible, tuple, options) {
if Some(true) == self.equals(needed, possible) {
return Some(true.into());
}
@ -768,25 +787,25 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
Some(false.into())
}
}
PlanExpression::Add(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? {
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)? {
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)? {
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)? {
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)?
@ -794,14 +813,14 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
.into(),
NumericBinaryOperands::Decimal(v1, v2) => v1.checked_div(v2)?.into(),
}),
PlanExpression::UnaryPlus(e) => match self.eval_expression(e, tuple)? {
PlanExpression::UnaryPlus(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::UnaryMinus(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::FloatLiteral(value) => Some((-*value).into()),
EncodedTerm::DoubleLiteral(value) => Some((-*value).into()),
EncodedTerm::IntegerLiteral(value) => Some((-value).into()),
@ -809,12 +828,12 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
_ => None,
},
PlanExpression::UnaryNot(e) => self
.to_bool(self.eval_expression(e, tuple)?)
.to_bool(self.eval_expression(e, tuple, options)?)
.map(|v| (!v).into()),
PlanExpression::Str(e) => Some(EncodedTerm::StringLiteral {
value_id: self.to_string_id(self.eval_expression(e, tuple)?)?,
value_id: self.to_string_id(self.eval_expression(e, tuple, options)?)?,
}),
PlanExpression::Lang(e) => match self.eval_expression(e, tuple)? {
PlanExpression::Lang(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::LangStringLiteral { language_id, .. } => {
Some(EncodedTerm::StringLiteral {
value_id: language_id,
@ -825,9 +844,9 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
},
PlanExpression::LangMatches(language_tag, language_range) => {
let language_tag =
self.to_simple_string(self.eval_expression(language_tag, tuple)?)?;
self.to_simple_string(self.eval_expression(language_tag, tuple, options)?)?;
let language_range =
self.to_simple_string(self.eval_expression(language_range, tuple)?)?;
self.to_simple_string(self.eval_expression(language_range, tuple, options)?)?;
Some(
if &*language_range == "*" {
!language_tag.is_empty()
@ -845,10 +864,10 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
.into(),
)
}
PlanExpression::Datatype(e) => self.eval_expression(e, tuple)?.datatype(),
PlanExpression::Datatype(e) => self.eval_expression(e, tuple, options)?.datatype(),
PlanExpression::Bound(v) => Some(has_tuple_value(*v, tuple).into()),
PlanExpression::IRI(e) => {
let iri_id = match self.eval_expression(e, tuple)? {
let iri_id = match self.eval_expression(e, tuple, options)? {
EncodedTerm::NamedNode { iri_id } => Some(iri_id),
EncodedTerm::StringLiteral { value_id } => Some(value_id),
_ => None,
@ -864,7 +883,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
PlanExpression::BNode(id) => match id {
Some(id) => {
if let EncodedTerm::StringLiteral { value_id } =
self.eval_expression(id, tuple)?
self.eval_expression(id, tuple, options)?
{
Some(EncodedTerm::BlankNode {
id: *self
@ -883,28 +902,28 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}),
},
PlanExpression::Rand => Some(random::<f64>().into()),
PlanExpression::Abs(e) => match self.eval_expression(e, tuple)? {
PlanExpression::Abs(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::Ceil(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::Floor(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::Round(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::IntegerLiteral(value) => Some(value.into()),
EncodedTerm::DecimalLiteral(value) => Some(
value
@ -920,7 +939,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
let mut language = None;
for e in l {
let (value, e_language) =
self.to_string_and_language(self.eval_expression(e, tuple)?)?;
self.to_string_and_language(self.eval_expression(e, tuple, options)?)?;
if let Some(lang) = language {
if lang != e_language {
language = Some(None)
@ -934,17 +953,17 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
PlanExpression::SubStr(source, starting_loc, length) => {
let (source, language) =
self.to_string_and_language(self.eval_expression(source, tuple)?)?;
self.to_string_and_language(self.eval_expression(source, tuple, options)?)?;
let starting_location: usize = if let EncodedTerm::IntegerLiteral(v) =
self.eval_expression(starting_loc, tuple)?
self.eval_expression(starting_loc, tuple, options)?
{
v.try_into().ok()?
} else {
return None;
};
let length: Option<usize> = if let Some(length) = length {
if let EncodedTerm::IntegerLiteral(v) = self.eval_expression(length, tuple)? {
if let EncodedTerm::IntegerLiteral(v) = self.eval_expression(length, tuple, options)? {
Some(v.try_into().ok()?)
} else {
return None;
@ -976,45 +995,45 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
PlanExpression::StrLen(arg) => Some(
(self
.to_string(self.eval_expression(arg, tuple)?)?
.to_string(self.eval_expression(arg, tuple, options)?)?
.chars()
.count() as i128)
.into(),
),
PlanExpression::Replace(arg, pattern, replacement, flags) => {
let regex = self.compile_pattern(
self.eval_expression(pattern, tuple)?,
self.eval_expression(pattern, tuple, options)?,
if let Some(flags) = flags {
Some(self.eval_expression(flags, tuple)?)
Some(self.eval_expression(flags, tuple, options)?)
} else {
None
},
)?;
let (text, language) =
self.to_string_and_language(self.eval_expression(arg, tuple)?)?;
self.to_string_and_language(self.eval_expression(arg, tuple, options)?)?;
let replacement =
self.to_simple_string(self.eval_expression(replacement, tuple)?)?;
self.to_simple_string(self.eval_expression(replacement, tuple, options)?)?;
self.build_plain_literal(&regex.replace_all(&text, &replacement as &str), language)
}
PlanExpression::UCase(e) => {
let (value, language) =
self.to_string_and_language(self.eval_expression(e, tuple)?)?;
self.to_string_and_language(self.eval_expression(e, tuple, options)?)?;
self.build_plain_literal(&value.to_uppercase(), language)
}
PlanExpression::LCase(e) => {
let (value, language) =
self.to_string_and_language(self.eval_expression(e, tuple)?)?;
self.to_string_and_language(self.eval_expression(e, tuple, options)?)?;
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)?,
self.eval_expression(arg2, tuple)?,
self.eval_expression(arg1, tuple, options)?,
self.eval_expression(arg2, tuple, options)?,
)?;
Some((&arg1).starts_with(&arg2 as &str).into())
}
PlanExpression::EncodeForURI(ltrl) => {
let ltlr = self.to_string(self.eval_expression(ltrl, tuple)?)?;
let ltlr = self.to_string(self.eval_expression(ltrl, tuple, options)?)?;
let mut result = Vec::with_capacity(ltlr.len());
for c in ltlr.bytes() {
match c {
@ -1042,22 +1061,22 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
PlanExpression::StrEnds(arg1, arg2) => {
let (arg1, arg2, _) = self.to_argument_compatible_strings(
self.eval_expression(arg1, tuple)?,
self.eval_expression(arg2, tuple)?,
self.eval_expression(arg1, tuple, options)?,
self.eval_expression(arg2, tuple, options)?,
)?;
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)?,
self.eval_expression(arg2, tuple)?,
self.eval_expression(arg1, tuple, options)?,
self.eval_expression(arg2, tuple, options)?,
)?;
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)?,
self.eval_expression(arg2, tuple)?,
self.eval_expression(arg1, tuple, options)?,
self.eval_expression(arg2, tuple, options)?,
)?;
if let Some(position) = (&arg1).find(&arg2 as &str) {
self.build_plain_literal(&arg1[..position], language)
@ -1067,8 +1086,8 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
PlanExpression::StrAfter(arg1, arg2) => {
let (arg1, arg2, language) = self.to_argument_compatible_strings(
self.eval_expression(arg1, tuple)?,
self.eval_expression(arg2, tuple)?,
self.eval_expression(arg1, tuple, options)?,
self.eval_expression(arg2, tuple, options)?,
)?;
if let Some(position) = (&arg1).find(&arg2 as &str) {
self.build_plain_literal(&arg1[position + arg2.len()..], language)
@ -1076,40 +1095,40 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
Some(ENCODED_EMPTY_STRING_LITERAL)
}
}
PlanExpression::Year(e) => match self.eval_expression(e, tuple)? {
PlanExpression::Year(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::Month(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::Day(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::Hours(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::Minutes(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::Seconds(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::NaiveTimeLiteral(time) => Some(
(Decimal::new(time.nanosecond().into(), 9) + Decimal::from(time.second()))
.into(),
@ -1127,7 +1146,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
_ => None,
},
PlanExpression::Timezone(e) => {
let timezone = match self.eval_expression(e, tuple)? {
let timezone = match self.eval_expression(e, tuple, options)? {
EncodedTerm::DateLiteral(date) => date.timezone(),
EncodedTerm::DateTimeLiteral(date_time) => date_time.timezone(),
_ => return None,
@ -1161,7 +1180,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
})
}
PlanExpression::Tz(e) => {
let timezone = match self.eval_expression(e, tuple)? {
let timezone = match self.eval_expression(e, tuple, options)? {
EncodedTerm::DateLiteral(date) => Some(date.timezone()),
EncodedTerm::DateTimeLiteral(date_time) => Some(date_time.timezone()),
EncodedTerm::NaiveDateLiteral(_)
@ -1192,38 +1211,38 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
.to_hyphenated()
.encode_lower(&mut Uuid::encode_buffer()),
),
PlanExpression::MD5(arg) => self.hash::<Md5>(arg, tuple),
PlanExpression::SHA1(arg) => self.hash::<Sha1>(arg, tuple),
PlanExpression::SHA256(arg) => self.hash::<Sha256>(arg, tuple),
PlanExpression::SHA384(arg) => self.hash::<Sha384>(arg, tuple),
PlanExpression::SHA512(arg) => self.hash::<Sha512>(arg, tuple),
PlanExpression::MD5(arg) => self.hash::<Md5>(arg, tuple, options),
PlanExpression::SHA1(arg) => self.hash::<Sha1>(arg, tuple, options),
PlanExpression::SHA256(arg) => self.hash::<Sha256>(arg, tuple, options),
PlanExpression::SHA384(arg) => self.hash::<Sha384>(arg, tuple, options),
PlanExpression::SHA512(arg) => self.hash::<Sha512>(arg, tuple, options),
PlanExpression::Coalesce(l) => {
for e in l {
if let Some(result) = self.eval_expression(e, tuple) {
if let Some(result) = self.eval_expression(e, tuple, options) {
return Some(result);
}
}
None
}
PlanExpression::If(a, b, c) => {
if self.to_bool(self.eval_expression(a, tuple)?)? {
self.eval_expression(b, tuple)
if self.to_bool(self.eval_expression(a, tuple, options)?)? {
self.eval_expression(b, tuple, options)
} else {
self.eval_expression(c, tuple)
self.eval_expression(c, tuple, options)
}
}
PlanExpression::StrLang(lexical_form, lang_tag) => {
Some(EncodedTerm::LangStringLiteral {
value_id: self
.to_simple_string_id(self.eval_expression(lexical_form, tuple)?)?,
.to_simple_string_id(self.eval_expression(lexical_form, tuple, options)?)?,
language_id: self
.to_simple_string_id(self.eval_expression(lang_tag, tuple)?)?,
.to_simple_string_id(self.eval_expression(lang_tag, tuple, options)?)?,
})
}
PlanExpression::StrDT(lexical_form, datatype) => {
let value = self.to_simple_string(self.eval_expression(lexical_form, tuple)?)?;
let value = self.to_simple_string(self.eval_expression(lexical_form, tuple, options)?)?;
let datatype = if let EncodedTerm::NamedNode { iri_id } =
self.eval_expression(datatype, tuple)?
self.eval_expression(datatype, tuple, options)?
{
self.dataset.get_str(iri_id).ok()?
} else {
@ -1238,19 +1257,19 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
.ok()
}
PlanExpression::SameTerm(a, b) => {
Some((self.eval_expression(a, tuple)? == self.eval_expression(b, tuple)?).into())
Some((self.eval_expression(a, tuple, options)? == self.eval_expression(b, tuple, options)?).into())
}
PlanExpression::IsIRI(e) => {
Some(self.eval_expression(e, tuple)?.is_named_node().into())
Some(self.eval_expression(e, tuple, options)?.is_named_node().into())
}
PlanExpression::IsBlank(e) => {
Some(self.eval_expression(e, tuple)?.is_blank_node().into())
Some(self.eval_expression(e, tuple, options)?.is_blank_node().into())
}
PlanExpression::IsLiteral(e) => {
Some(self.eval_expression(e, tuple)?.is_literal().into())
Some(self.eval_expression(e, tuple, options)?.is_literal().into())
}
PlanExpression::IsNumeric(e) => Some(
match self.eval_expression(e, tuple)? {
match self.eval_expression(e, tuple, options)? {
EncodedTerm::FloatLiteral(_)
| EncodedTerm::DoubleLiteral(_)
| EncodedTerm::IntegerLiteral(_)
@ -1261,24 +1280,24 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
),
PlanExpression::Regex(text, pattern, flags) => {
let regex = self.compile_pattern(
self.eval_expression(pattern, tuple)?,
self.eval_expression(pattern, tuple, options)?,
if let Some(flags) = flags {
Some(self.eval_expression(flags, tuple)?)
Some(self.eval_expression(flags, tuple, options)?)
} else {
None
},
)?;
let text = self.to_string(self.eval_expression(text, tuple)?)?;
let text = self.to_string(self.eval_expression(text, tuple, options)?)?;
Some(regex.is_match(&text).into())
}
PlanExpression::BooleanCast(e) => match self.eval_expression(e, tuple)? {
PlanExpression::BooleanCast(e) => match self.eval_expression(e, tuple, options)? {
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)? {
PlanExpression::DoubleCast(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::FloatLiteral(value) => Some(value.to_f64()?.into()),
EncodedTerm::DoubleLiteral(value) => Some(value.to_f64()?.into()),
EncodedTerm::IntegerLiteral(value) => Some(value.to_f64()?.into()),
@ -1291,7 +1310,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
_ => None,
},
PlanExpression::FloatCast(e) => match self.eval_expression(e, tuple)? {
PlanExpression::FloatCast(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::FloatLiteral(value) => Some(value.to_f32()?.into()),
EncodedTerm::DoubleLiteral(value) => Some(value.to_f32()?.into()),
EncodedTerm::IntegerLiteral(value) => Some(value.to_f32()?.into()),
@ -1304,7 +1323,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
_ => None,
},
PlanExpression::IntegerCast(e) => match self.eval_expression(e, tuple)? {
PlanExpression::IntegerCast(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::FloatLiteral(value) => Some(value.to_i128()?.into()),
EncodedTerm::DoubleLiteral(value) => Some(value.to_i128()?.into()),
EncodedTerm::IntegerLiteral(value) => Some(value.to_i128()?.into()),
@ -1315,7 +1334,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
_ => None,
},
PlanExpression::DecimalCast(e) => match self.eval_expression(e, tuple)? {
PlanExpression::DecimalCast(e) => match self.eval_expression(e, tuple, options)? {
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()),
@ -1333,7 +1352,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
_ => None,
},
PlanExpression::DateCast(e) => match self.eval_expression(e, tuple)? {
PlanExpression::DateCast(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::DateLiteral(value) => Some(value.into()),
EncodedTerm::NaiveDateLiteral(value) => Some(value.into()),
EncodedTerm::DateTimeLiteral(value) => Some(value.date().into()),
@ -1343,7 +1362,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
_ => None,
},
PlanExpression::TimeCast(e) => match self.eval_expression(e, tuple)? {
PlanExpression::TimeCast(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::NaiveTimeLiteral(value) => Some(value.into()),
EncodedTerm::DateTimeLiteral(value) => Some(value.time().into()),
EncodedTerm::NaiveDateTimeLiteral(value) => Some(value.time().into()),
@ -1352,7 +1371,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
_ => None,
},
PlanExpression::DateTimeCast(e) => match self.eval_expression(e, tuple)? {
PlanExpression::DateTimeCast(e) => match self.eval_expression(e, tuple, options)? {
EncodedTerm::DateTimeLiteral(value) => Some(value.into()),
EncodedTerm::NaiveDateTimeLiteral(value) => Some(value.into()),
EncodedTerm::StringLiteral { value_id } => {
@ -1361,7 +1380,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
_ => None,
},
PlanExpression::StringCast(e) => Some(EncodedTerm::StringLiteral {
value_id: self.to_string_id(self.eval_expression(e, tuple)?)?,
value_id: self.to_string_id(self.eval_expression(e, tuple, options)?)?,
}),
}
}
@ -1526,15 +1545,16 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
regex_builder.build().ok()
}
fn parse_numeric_operands(
&self,
fn parse_numeric_operands<'b>(
&'b self,
e1: &PlanExpression,
e2: &PlanExpression,
tuple: &[Option<EncodedTerm>],
options: &QueryOptions<'b>
) -> Option<NumericBinaryOperands> {
NumericBinaryOperands::new(
self.eval_expression(&e1, tuple)?,
self.eval_expression(&e2, tuple)?,
self.eval_expression(&e1, tuple, options)?,
self.eval_expression(&e2, tuple, options)?,
)
}
@ -1674,15 +1694,16 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
}
}
fn cmp_according_to_expression(
&self,
fn cmp_according_to_expression<'b>(
&'b self,
tuple_a: &[Option<EncodedTerm>],
tuple_b: &[Option<EncodedTerm>],
expression: &PlanExpression,
options: &QueryOptions<'b>
) -> Ordering {
self.cmp_terms(
self.eval_expression(expression, tuple_a),
self.eval_expression(expression, tuple_b),
self.eval_expression(expression, tuple_a, options),
self.eval_expression(expression, tuple_b, options),
)
}
@ -1793,12 +1814,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
)
}
fn hash<H: Digest>(
&self,
fn hash<'b, H: Digest>(
&'b self,
arg: &PlanExpression,
tuple: &[Option<EncodedTerm>],
options: &QueryOptions<'b>
) -> Option<EncodedTerm> {
let input = self.to_simple_string(self.eval_expression(arg, tuple)?)?;
let input = self.to_simple_string(self.eval_expression(arg, tuple, options)?)?;
let hash = hex::encode(H::new().chain(&input as &str).result());
self.build_string_literal(&hash)
}
@ -2067,6 +2089,7 @@ 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> {
@ -2078,7 +2101,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.current_right = self.eval.eval_plan(self.right_plan, left_tuple.clone(), self.options);
if let Some(right_tuple) = self.current_right.next() {
Some(right_tuple)
} else {
@ -2132,6 +2155,7 @@ 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> {
@ -2147,13 +2171,13 @@ impl<'a, S: StoreConnection> Iterator for UnionIterator<'a, S> {
}
self.current_iterator = self
.eval
.eval_plan(&self.plans[self.current_plan], self.input.clone());
.eval_plan(&self.plans[self.current_plan], self.input.clone(), self.options);
self.current_plan += 1;
}
}
}
struct ConstructIterator<'a, S: StoreConnection> {
struct ConstructIterator<'a, S: StoreConnection + 'a> {
eval: &'a SimpleEvaluator<S>,
iter: EncodedTuplesIterator<'a>,
template: &'a [TripleTemplate],
@ -2161,7 +2185,7 @@ struct ConstructIterator<'a, S: StoreConnection> {
bnodes: Vec<BlankNode>,
}
impl<'a, S: StoreConnection> Iterator for ConstructIterator<'a, S> {
impl<'a, S: StoreConnection + 'a> Iterator for ConstructIterator<'a, S> {
type Item = Result<Triple>;
fn next(&mut self) -> Option<Result<Triple>> {
@ -2230,7 +2254,7 @@ struct DescribeIterator<'a, S: StoreConnection + 'a> {
quads: Box<dyn Iterator<Item = Result<EncodedQuad>> + 'a>,
}
impl<'a, S: StoreConnection> Iterator for DescribeIterator<'a, S> {
impl<'a, S: StoreConnection + 'a> Iterator for DescribeIterator<'a, S> {
type Item = Result<Triple>;
fn next(&mut self) -> Option<Result<Triple>> {

@ -9,6 +9,7 @@ mod plan;
mod plan_builder;
mod xml_results;
use crate::model::NamedNode;
use crate::sparql::algebra::QueryVariants;
use crate::sparql::eval::SimpleEvaluator;
use crate::sparql::parser::read_sparql_query;
@ -19,6 +20,7 @@ use crate::store::StoreConnection;
use crate::Result;
use std::fmt;
pub use crate::sparql::algebra::GraphPattern;
pub use crate::sparql::model::BindingsIterator;
pub use crate::sparql::model::QueryResult;
pub use crate::sparql::model::QueryResultSyntax;
@ -27,7 +29,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(&self) -> Result<QueryResult>;
fn exec<'a>(&'a self, options: &'a QueryOptions<'a>) -> Result<QueryResult<'a>>;
}
/// An implementation of `PreparedQuery` for internal use
@ -115,32 +117,37 @@ impl<S: StoreConnection> SimplePreparedQuery<S> {
}
impl<S: StoreConnection> PreparedQuery for SimplePreparedQuery<S> {
fn exec(&self) -> Result<QueryResult<'_>> {
fn exec<'a>(&'a self, options: &'a QueryOptions<'a>) -> Result<QueryResult<'a>> {
match &self.0 {
SimplePreparedQueryAction::Select {
plan,
variables,
evaluator,
} => evaluator.evaluate_select_plan(&plan, &variables),
} => evaluator.evaluate_select_plan(&plan, &variables, options),
SimplePreparedQueryAction::Ask { plan, evaluator } => {
evaluator.evaluate_ask_plan(&plan)
evaluator.evaluate_ask_plan(&plan, options)
}
SimplePreparedQueryAction::Construct {
plan,
construct,
evaluator,
} => evaluator.evaluate_construct_plan(&plan, &construct),
} => evaluator.evaluate_construct_plan(&plan, &construct, &options),
SimplePreparedQueryAction::Describe { plan, evaluator } => {
evaluator.evaluate_describe_plan(&plan)
evaluator.evaluate_describe_plan(&plan, &options)
}
}
}
}
pub trait ServiceHandler {
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
pub struct QueryOptions<'a> {
pub(crate) base_iri: Option<&'a str>,
pub(crate) default_graph_as_union: bool,
pub(crate) service_handler: Option<Box<dyn ServiceHandler>>,
}
impl<'a> Default for QueryOptions<'a> {
@ -148,6 +155,7 @@ impl<'a> Default for QueryOptions<'a> {
Self {
base_iri: None,
default_graph_as_union: false,
service_handler: None as Option<Box<dyn ServiceHandler>>,
}
}
}

Loading…
Cancel
Save