Adds RDF-star SPARQL functions

pull/171/head
Tpt 4 years ago
parent a97250dcce
commit dcaf3793d5
  1. 36
      lib/src/sparql/eval.rs
  2. 16
      lib/src/sparql/plan.rs
  3. 21
      lib/src/sparql/plan_builder.rs
  4. 14
      lib/src/storage/numeric_encoder.rs
  5. 10
      spargebra/src/algebra.rs
  6. 7
      spargebra/src/parser.rs

@ -1438,6 +1438,42 @@ impl SimpleEvaluator {
let text = self.to_string(&self.eval_expression(text, tuple)?)?; let text = self.to_string(&self.eval_expression(text, tuple)?)?;
Some(regex.is_match(&text).into()) Some(regex.is_match(&text).into())
} }
PlanExpression::Triple(s, p, o) => {
let s = self.eval_expression(s, tuple)?;
let p = self.eval_expression(p, tuple)?;
let o = self.eval_expression(o, tuple)?;
if !s.is_literal()
&& !s.is_default_graph()
&& p.is_named_node()
&& !o.is_default_graph()
{
Some(EncodedTriple::new(s, p, o).into())
} else {
None
}
}
PlanExpression::Subject(e) => {
if let EncodedTerm::Triple(t) = self.eval_expression(e, tuple)? {
Some(t.subject.clone())
} else {
None
}
}
PlanExpression::Predicate(e) => {
if let EncodedTerm::Triple(t) = self.eval_expression(e, tuple)? {
Some(t.predicate.clone())
} else {
None
}
}
PlanExpression::Object(e) => {
if let EncodedTerm::Triple(t) = self.eval_expression(e, tuple)? {
Some(t.object.clone())
} else {
None
}
}
PlanExpression::IsTriple(e) => Some(self.eval_expression(e, tuple)?.is_triple().into()),
PlanExpression::BooleanCast(e) => match self.eval_expression(e, tuple)? { PlanExpression::BooleanCast(e) => match self.eval_expression(e, tuple)? {
EncodedTerm::BooleanLiteral(value) => Some(value.into()), EncodedTerm::BooleanLiteral(value) => Some(value.into()),
EncodedTerm::FloatLiteral(value) => Some((value != 0. && !value.is_nan()).into()), EncodedTerm::FloatLiteral(value) => Some((value != 0. && !value.is_nan()).into()),

@ -295,6 +295,15 @@ pub enum PlanExpression {
Box<PlanExpression>, Box<PlanExpression>,
Option<Box<PlanExpression>>, Option<Box<PlanExpression>>,
), ),
Triple(
Box<PlanExpression>,
Box<PlanExpression>,
Box<PlanExpression>,
),
Subject(Box<PlanExpression>),
Predicate(Box<PlanExpression>),
Object(Box<PlanExpression>),
IsTriple(Box<PlanExpression>),
BooleanCast(Box<PlanExpression>), BooleanCast(Box<PlanExpression>),
DoubleCast(Box<PlanExpression>), DoubleCast(Box<PlanExpression>),
FloatCast(Box<PlanExpression>), FloatCast(Box<PlanExpression>),
@ -354,6 +363,10 @@ impl PlanExpression {
| PlanExpression::IsBlank(e) | PlanExpression::IsBlank(e)
| PlanExpression::IsLiteral(e) | PlanExpression::IsLiteral(e)
| PlanExpression::IsNumeric(e) | PlanExpression::IsNumeric(e)
| PlanExpression::IsTriple(e)
| PlanExpression::Subject(e)
| PlanExpression::Predicate(e)
| PlanExpression::Object(e)
| PlanExpression::BooleanCast(e) | PlanExpression::BooleanCast(e)
| PlanExpression::DoubleCast(e) | PlanExpression::DoubleCast(e)
| PlanExpression::FloatCast(e) | PlanExpression::FloatCast(e)
@ -394,7 +407,8 @@ impl PlanExpression {
PlanExpression::If(a, b, c) PlanExpression::If(a, b, c)
| PlanExpression::SubStr(a, b, Some(c)) | PlanExpression::SubStr(a, b, Some(c))
| PlanExpression::Regex(a, b, Some(c)) | PlanExpression::Regex(a, b, Some(c))
| PlanExpression::Replace(a, b, c, None) => { | PlanExpression::Replace(a, b, c, None)
| PlanExpression::Triple(a, b, c) => {
a.add_maybe_bound_variables(set); a.add_maybe_bound_variables(set);
b.add_maybe_bound_variables(set); b.add_maybe_bound_variables(set);
c.add_maybe_bound_variables(set); c.add_maybe_bound_variables(set);

@ -613,6 +613,27 @@ impl<'a> PlanBuilder<'a> {
None => None, None => None,
}, },
), ),
Function::Triple => PlanExpression::Triple(
Box::new(self.build_for_expression(&parameters[0], variables, graph_name)?),
Box::new(self.build_for_expression(&parameters[1], variables, graph_name)?),
Box::new(self.build_for_expression(&parameters[2], variables, graph_name)?),
),
Function::Subject => PlanExpression::Subject(Box::new(self.build_for_expression(
&parameters[0],
variables,
graph_name,
)?)),
Function::Predicate => PlanExpression::Predicate(Box::new(
self.build_for_expression(&parameters[0], variables, graph_name)?,
)),
Function::Object => PlanExpression::Object(Box::new(self.build_for_expression(
&parameters[0],
variables,
graph_name,
)?)),
Function::IsTriple => PlanExpression::IsTriple(Box::new(
self.build_for_expression(&parameters[0], variables, graph_name)?,
)),
Function::Custom(name) => { Function::Custom(name) => {
if name.iri == "http://www.w3.org/2001/XMLSchema#boolean" { if name.iri == "http://www.w3.org/2001/XMLSchema#boolean" {
self.build_cast( self.build_cast(

@ -340,6 +340,10 @@ impl EncodedTerm {
matches!(self, Self::DefaultGraph) matches!(self, Self::DefaultGraph)
} }
pub fn is_triple(&self) -> bool {
matches!(self, Self::Triple { .. })
}
pub fn on_each_id<E>( pub fn on_each_id<E>(
&self, &self,
callback: &mut impl FnMut(&StrHash) -> Result<(), E>, callback: &mut impl FnMut(&StrHash) -> Result<(), E>,
@ -484,6 +488,16 @@ pub struct EncodedTriple {
pub object: EncodedTerm, pub object: EncodedTerm,
} }
impl EncodedTriple {
pub fn new(subject: EncodedTerm, predicate: EncodedTerm, object: EncodedTerm) -> Self {
Self {
subject,
predicate,
object,
}
}
}
#[derive(Eq, PartialEq, Debug, Clone, Hash)] #[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct EncodedQuad { pub struct EncodedQuad {
pub subject: EncodedTerm, pub subject: EncodedTerm,

@ -404,6 +404,11 @@ pub enum Function {
IsLiteral, IsLiteral,
IsNumeric, IsNumeric,
Regex, Regex,
Triple,
Subject,
Predicate,
Object,
IsTriple,
Custom(NamedNode), Custom(NamedNode),
} }
@ -456,6 +461,11 @@ impl fmt::Display for Function {
Function::IsLiteral => write!(f, "isLITERAL"), Function::IsLiteral => write!(f, "isLITERAL"),
Function::IsNumeric => write!(f, "isNUMERIC"), Function::IsNumeric => write!(f, "isNUMERIC"),
Function::Regex => write!(f, "REGEX"), Function::Regex => write!(f, "REGEX"),
Function::Triple => write!(f, "TRIPLE"),
Function::Subject => write!(f, "SUBJECT"),
Function::Predicate => write!(f, "PREDICATE"),
Function::Object => write!(f, "OBJECT"),
Function::IsTriple => write!(f, "isTRIPLE"),
Function::Custom(iri) => iri.fmt(f), Function::Custom(iri) => iri.fmt(f),
} }
} }

@ -1872,7 +1872,12 @@ parser! {
i("isNUMERIC") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::IsNumeric, vec![e]) } / i("isNUMERIC") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::IsNumeric, vec![e]) } /
RegexExpression() / RegexExpression() /
ExistsFunc() / ExistsFunc() /
NotExistsFunc() NotExistsFunc() /
i("TRIPLE") "(" _ s:Expression() _ "," _ p:Expression() "," _ o:Expression() ")" { Expression::FunctionCall(Function::Triple, vec![s, p, o]) } /
i("SUBJECT") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::Subject, vec![e]) } /
i("PREDICATE") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::Predicate, vec![e]) } /
i("OBJECT") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::Object, vec![e]) } /
i("isTriple") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::IsTriple, vec![e]) }
//[122] //[122]
rule RegexExpression() -> Expression = rule RegexExpression() -> Expression =

Loading…
Cancel
Save