diff --git a/lib/src/sparql/algebra.rs b/lib/src/sparql/algebra.rs index 9ce76710..7898c822 100644 --- a/lib/src/sparql/algebra.rs +++ b/lib/src/sparql/algebra.rs @@ -1,4 +1,8 @@ -//! [SPARQL 1.1 Query Algebra](https://www.w3.org/TR/sparql11-query/#sparqlQuery) AST +//! [SPARQL 1.1 Query Algebra](https://www.w3.org/TR/sparql11-query/#sparqlQuery) +//! +//! The root type for SPARQL queries is [`Query`] and the root type for updates is [`Update`]. +//! +//! Warning: this implementation is an unstable work in progress use crate::model::*; use crate::sparql::model::*; @@ -28,7 +32,46 @@ use std::str::FromStr; /// # Result::Ok::<_, Box>(()) /// ``` #[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub struct Query(pub(crate) QueryVariants); +pub enum Query { + /// [SELECT](https://www.w3.org/TR/sparql11-query/#select) + Select { + /// The [query dataset specification](https://www.w3.org/TR/sparql11-query/#specifyingDataset) + dataset: QueryDataset, + /// The query selection graph pattern + pattern: GraphPattern, + /// The query base IRI + base_iri: Option>, + }, + /// [CONSTRUCT](https://www.w3.org/TR/sparql11-query/#construct) + Construct { + /// The query construction template + template: Vec, + /// The [query dataset specification](https://www.w3.org/TR/sparql11-query/#specifyingDataset) + dataset: QueryDataset, + /// The query selection graph pattern + pattern: GraphPattern, + /// The query base IRI + base_iri: Option>, + }, + /// [DESCRIBE](https://www.w3.org/TR/sparql11-query/#describe) + Describe { + /// The [query dataset specification](https://www.w3.org/TR/sparql11-query/#specifyingDataset) + dataset: QueryDataset, + /// The query selection graph pattern + pattern: GraphPattern, + /// The query base IRI + base_iri: Option>, + }, + /// [ASK](https://www.w3.org/TR/sparql11-query/#ask) + Ask { + /// The [query dataset specification](https://www.w3.org/TR/sparql11-query/#specifyingDataset) + dataset: QueryDataset, + /// The query selection graph pattern + pattern: Rc, + /// The query base IRI + base_iri: Option>, + }, +} impl Query { /// Parses a SPARQL query with an optional base IRI to resolve relative IRIs in the query @@ -38,28 +81,98 @@ impl Query { /// Returns [the query dataset specification](https://www.w3.org/TR/sparql11-query/#specifyingDataset) pub fn dataset(&self) -> &QueryDataset { - match &self.0 { - QueryVariants::Select { dataset, .. } => dataset, - QueryVariants::Construct { dataset, .. } => dataset, - QueryVariants::Describe { dataset, .. } => dataset, - QueryVariants::Ask { dataset, .. } => dataset, + match self { + Query::Select { dataset, .. } => dataset, + Query::Construct { dataset, .. } => dataset, + Query::Describe { dataset, .. } => dataset, + Query::Ask { dataset, .. } => dataset, } } /// Returns [the query dataset specification](https://www.w3.org/TR/sparql11-query/#specifyingDataset) pub fn dataset_mut(&mut self) -> &mut QueryDataset { - match &mut self.0 { - QueryVariants::Select { dataset, .. } => dataset, - QueryVariants::Construct { dataset, .. } => dataset, - QueryVariants::Describe { dataset, .. } => dataset, - QueryVariants::Ask { dataset, .. } => dataset, + match self { + Query::Select { dataset, .. } => dataset, + Query::Construct { dataset, .. } => dataset, + Query::Describe { dataset, .. } => dataset, + Query::Ask { dataset, .. } => dataset, } } } impl fmt::Display for Query { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) + match self { + Query::Select { + dataset, + pattern, + base_iri, + } => { + if let Some(base_iri) = base_iri { + writeln!(f, "BASE <{}>", base_iri)?; + } + write!(f, "{}", SparqlGraphRootPattern { pattern, dataset }) + } + Query::Construct { + template, + dataset, + pattern, + base_iri, + } => { + if let Some(base_iri) = base_iri { + writeln!(f, "BASE <{}>", base_iri)?; + } + write!(f, "CONSTRUCT {{ ")?; + for triple in template.iter() { + write!(f, "{} ", SparqlTriplePattern(triple))?; + } + write!( + f, + "}}{} WHERE {{ {} }}", + dataset, + SparqlGraphRootPattern { + pattern, + dataset: &QueryDataset::default() + } + ) + } + Query::Describe { + dataset, + pattern, + base_iri, + } => { + if let Some(base_iri) = base_iri { + writeln!(f, "BASE <{}>", base_iri.as_str())?; + } + write!( + f, + "DESCRIBE *{} WHERE {{ {} }}", + dataset, + SparqlGraphRootPattern { + pattern, + dataset: &QueryDataset::default() + } + ) + } + Query::Ask { + dataset, + pattern, + base_iri, + } => { + if let Some(base_iri) = base_iri { + writeln!(f, "BASE <{}>", base_iri)?; + } + write!( + f, + "ASK{} WHERE {{ {} }}", + dataset, + SparqlGraphRootPattern { + pattern, + dataset: &QueryDataset::default() + } + ) + } + } } } @@ -100,8 +213,10 @@ impl<'a> TryFrom<&'a String> for Query { /// ``` #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct Update { - pub(crate) base_iri: Option>>, - pub(crate) operations: Vec, + /// The update base IRI + pub base_iri: Option>, + /// The update operations + pub operations: Vec, } impl Update { @@ -147,6 +262,7 @@ impl<'a> TryFrom<&'a String> for Update { } } +/// The union of [`NamedNode`]s and [`Variable`]s #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum NamedNodeOrVariable { NamedNode(NamedNode), @@ -168,18 +284,13 @@ impl From for NamedNodeOrVariable { } } -impl From> for NamedNodeOrVariable { - fn from(node: NamedNodeRef<'_>) -> Self { - NamedNodeOrVariable::NamedNode(node.into()) - } -} - impl From for NamedNodeOrVariable { fn from(var: Variable) -> Self { NamedNodeOrVariable::Variable(var) } } +/// The union of [`Term`]s and [`Variable`]s #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum TermOrVariable { Term(Term), @@ -201,12 +312,6 @@ impl From for TermOrVariable { } } -impl From> for TermOrVariable { - fn from(node: NamedNodeRef<'_>) -> Self { - TermOrVariable::Term(node.into()) - } -} - impl From for TermOrVariable { fn from(node: BlankNode) -> Self { TermOrVariable::Term(node.into()) @@ -240,43 +345,7 @@ impl From for TermOrVariable { } } -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub struct StaticBindings { - variables: Vec, - values: Vec>>, -} - -impl StaticBindings { - pub fn new(variables: Vec, values: Vec>>) -> Self { - Self { variables, values } - } - - pub fn variables(&self) -> &[Variable] { - &*self.variables - } - - pub fn variables_iter(&self) -> impl Iterator { - self.variables.iter() - } - - pub fn values_iter(&self) -> impl Iterator>> { - self.values.iter() - } - - pub fn is_empty(&self) -> bool { - self.values.is_empty() - } -} - -impl Default for StaticBindings { - fn default() -> Self { - Self { - variables: Vec::default(), - values: Vec::default(), - } - } -} - +/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct TriplePattern { pub subject: TermOrVariable, @@ -285,7 +354,7 @@ pub struct TriplePattern { } impl TriplePattern { - pub fn new( + pub(crate) fn new( subject: impl Into, predicate: impl Into, object: impl Into, @@ -300,10 +369,27 @@ impl TriplePattern { impl fmt::Display for TriplePattern { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} {} {} .", self.subject, self.predicate, self.object) + write!( + f, + "(triple {} {} {})", + self.subject, self.predicate, self.object + ) + } +} + +struct SparqlTriplePattern<'a>(&'a TriplePattern); + +impl<'a> fmt::Display for SparqlTriplePattern<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{} {} {} .", + self.0.subject, self.0.predicate, self.0.object + ) } } +/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) in a specific graph #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct QuadPattern { pub subject: TermOrVariable, @@ -313,7 +399,7 @@ pub struct QuadPattern { } impl QuadPattern { - pub fn new( + pub(crate) fn new( subject: impl Into, predicate: impl Into, object: impl Into, @@ -333,72 +419,96 @@ impl fmt::Display for QuadPattern { if let Some(graph_name) = &self.graph_name { write!( f, - "GRAPH {} {{ {} {} {} }}", + "(graph {} (triple {} {} {}))", graph_name, self.subject, self.predicate, self.object ) } else { - write!(f, "{} {} {} .", self.subject, self.predicate, self.object) + write!( + f, + "(triple {} {} {})", + self.subject, self.predicate, self.object + ) } } } +struct SparqlQuadPattern<'a>(&'a QuadPattern); + +impl<'a> fmt::Display for SparqlQuadPattern<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(graph_name) = &self.0.graph_name { + write!( + f, + "GRAPH {} {{ {} {} {} }}", + graph_name, self.0.subject, self.0.predicate, self.0.object + ) + } else { + write!( + f, + "{} {} {} .", + self.0.subject, self.0.predicate, self.0.object + ) + } + } +} + +/// A [property path expression](https://www.w3.org/TR/sparql11-query/#defn_PropertyPathExpr) #[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub enum PropertyPath { - PredicatePath(NamedNode), - InversePath(Box), - SequencePath(Box, Box), - AlternativePath(Box, Box), - ZeroOrMorePath(Box), - OneOrMorePath(Box), - ZeroOrOnePath(Box), +pub enum PropertyPathExpression { + NamedNode(NamedNode), + Reverse(Box), + Sequence(Box, Box), + Alternative(Box, Box), + ZeroOrMore(Box), + OneOrMore(Box), + ZeroOrOne(Box), NegatedPropertySet(Vec), } -impl fmt::Display for PropertyPath { +impl fmt::Display for PropertyPathExpression { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - PropertyPath::PredicatePath(p) => write!(f, "link({})", p), - PropertyPath::InversePath(p) => write!(f, "inv({})", p), - PropertyPath::AlternativePath(a, b) => write!(f, "alt({}, {})", a, b), - PropertyPath::SequencePath(a, b) => write!(f, "seq({}, {})", a, b), - PropertyPath::ZeroOrMorePath(p) => write!(f, "ZeroOrMorePath({})", p), - PropertyPath::OneOrMorePath(p) => write!(f, "OneOrMorePath({})", p), - PropertyPath::ZeroOrOnePath(p) => write!(f, "ZeroOrOnePath({})", p), - PropertyPath::NegatedPropertySet(p) => write!( - f, - "NPS({{ {} }})", - p.iter() - .map(|v| v.to_string()) - .collect::>() - .join(" ") - ), + PropertyPathExpression::NamedNode(p) => p.fmt(f), + PropertyPathExpression::Reverse(p) => write!(f, "(reverse {})", p), + PropertyPathExpression::Alternative(a, b) => write!(f, "(alt {} {})", a, b), + PropertyPathExpression::Sequence(a, b) => write!(f, "(seq {} {})", a, b), + PropertyPathExpression::ZeroOrMore(p) => write!(f, "(path* {})", p), + PropertyPathExpression::OneOrMore(p) => write!(f, "(path+ {})", p), + PropertyPathExpression::ZeroOrOne(p) => write!(f, "(path? {})", p), + PropertyPathExpression::NegatedPropertySet(p) => { + write!(f, "(notoneof ")?; + for p in p { + write!(f, " {}", p)?; + } + write!(f, ")") + } } } } -struct SparqlPropertyPath<'a>(&'a PropertyPath); +struct SparqlPropertyPath<'a>(&'a PropertyPathExpression); impl<'a> fmt::Display for SparqlPropertyPath<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { - PropertyPath::PredicatePath(p) => write!(f, "{}", p), - PropertyPath::InversePath(p) => write!(f, "^{}", SparqlPropertyPath(&*p)), - PropertyPath::SequencePath(a, b) => write!( + PropertyPathExpression::NamedNode(p) => p.fmt(f), + PropertyPathExpression::Reverse(p) => write!(f, "^{}", SparqlPropertyPath(&*p)), + PropertyPathExpression::Sequence(a, b) => write!( f, "({} / {})", SparqlPropertyPath(&*a), SparqlPropertyPath(&*b) ), - PropertyPath::AlternativePath(a, b) => write!( + PropertyPathExpression::Alternative(a, b) => write!( f, "({} | {})", SparqlPropertyPath(&*a), SparqlPropertyPath(&*b) ), - PropertyPath::ZeroOrMorePath(p) => write!(f, "{}*", SparqlPropertyPath(&*p)), - PropertyPath::OneOrMorePath(p) => write!(f, "{}+", SparqlPropertyPath(&*p)), - PropertyPath::ZeroOrOnePath(p) => write!(f, "{}?", SparqlPropertyPath(&*p)), - PropertyPath::NegatedPropertySet(p) => write!( + PropertyPathExpression::ZeroOrMore(p) => write!(f, "{}*", SparqlPropertyPath(&*p)), + PropertyPathExpression::OneOrMore(p) => write!(f, "{}+", SparqlPropertyPath(&*p)), + PropertyPathExpression::ZeroOrOne(p) => write!(f, "{}?", SparqlPropertyPath(&*p)), + PropertyPathExpression::NegatedPropertySet(p) => write!( f, "!({})", p.iter() @@ -410,132 +520,58 @@ impl<'a> fmt::Display for SparqlPropertyPath<'a> { } } -impl From for PropertyPath { +impl From for PropertyPathExpression { fn from(p: NamedNode) -> Self { - PropertyPath::PredicatePath(p) - } -} - -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub struct PathPattern { - pub subject: TermOrVariable, - pub path: PropertyPath, - pub object: TermOrVariable, -} - -impl fmt::Display for PathPattern { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Path({} {} {})", self.subject, self.path, self.object) - } -} - -impl PathPattern { - pub fn new( - subject: impl Into, - path: impl Into, - object: impl Into, - ) -> Self { - Self { - subject: subject.into(), - path: path.into(), - object: object.into(), - } - } -} - -struct SparqlPathPattern<'a>(&'a PathPattern); - -impl<'a> fmt::Display for SparqlPathPattern<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{} {} {} .", - self.0.subject, - SparqlPropertyPath(&self.0.path), - self.0.object - ) - } -} - -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub enum TripleOrPathPattern { - Triple(TriplePattern), - Path(PathPattern), -} - -impl TripleOrPathPattern { - pub(crate) fn subject(&self) -> &TermOrVariable { - match self { - TripleOrPathPattern::Triple(t) => &t.subject, - TripleOrPathPattern::Path(t) => &t.subject, - } - } - - pub(crate) fn object(&self) -> &TermOrVariable { - match self { - TripleOrPathPattern::Triple(t) => &t.object, - TripleOrPathPattern::Path(t) => &t.object, - } - } -} - -impl<'a> fmt::Display for TripleOrPathPattern { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TripleOrPathPattern::Triple(tp) => write!(f, "{}", tp), - TripleOrPathPattern::Path(ppp) => write!(f, "{}", ppp), - } - } -} - -impl From for TripleOrPathPattern { - fn from(tp: TriplePattern) -> Self { - TripleOrPathPattern::Triple(tp) - } -} - -impl From for TripleOrPathPattern { - fn from(ppp: PathPattern) -> Self { - TripleOrPathPattern::Path(ppp) - } -} - -struct SparqlTripleOrPathPattern<'a>(&'a TripleOrPathPattern); - -impl<'a> fmt::Display for SparqlTripleOrPathPattern<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - TripleOrPathPattern::Triple(tp) => write!(f, "{}", tp), - TripleOrPathPattern::Path(ppp) => write!(f, "{}", SparqlPathPattern(ppp)), - } + PropertyPathExpression::NamedNode(p) } } +/// An [expression](https://www.w3.org/TR/sparql11-query/#expressions) #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum Expression { NamedNode(NamedNode), Literal(Literal), Variable(Variable), + /// [Logical-or](https://www.w3.org/TR/sparql11-query/#func-logical-or) Or(Box, Box), + /// [Logical-and](https://www.w3.org/TR/sparql11-query/#func-logical-and) And(Box, Box), + /// [RDFterm-equal](https://www.w3.org/TR/sparql11-query/#func-RDFterm-equal) and all the XSD equalities Equal(Box, Box), - NotEqual(Box, Box), + /// [sameTerm](https://www.w3.org/TR/sparql11-query/#func-sameTerm) + SameTerm(Box, Box), + /// [op:numeric-greater-than](https://www.w3.org/TR/xpath-functions/#func-numeric-greater-than) and other XSD greater than operators Greater(Box, Box), - GreaterOrEq(Box, Box), - Lower(Box, Box), - LowerOrEq(Box, Box), + GreaterOrEqual(Box, Box), + /// [op:numeric-less-than](https://www.w3.org/TR/xpath-functions/#func-numeric-less-than) and other XSD greater than operators + Less(Box, Box), + LessOrEqual(Box, Box), + /// [IN](https://www.w3.org/TR/sparql11-query/#func-in) In(Box, Vec), - NotIn(Box, Vec), + /// [op:numeric-add](https://www.w3.org/TR/xpath-functions/#func-numeric-add) and other XSD additions Add(Box, Box), - Sub(Box, Box), - Mul(Box, Box), - Div(Box, Box), + /// [op:numeric-subtract](https://www.w3.org/TR/xpath-functions/#func-numeric-subtract) and other XSD subtractions + Subtract(Box, Box), + /// [op:numeric-multiply](https://www.w3.org/TR/xpath-functions/#func-numeric-multiply) and other XSD multiplications + Multiply(Box, Box), + /// [op:numeric-divide](https://www.w3.org/TR/xpath-functions/#func-numeric-divide) and other XSD divides + Divide(Box, Box), + /// [op:numeric-unary-plus](https://www.w3.org/TR/xpath-functions/#func-numeric-unary-plus) and other XSD unary plus UnaryPlus(Box), + /// [op:numeric-unary-minus](https://www.w3.org/TR/xpath-functions/#func-numeric-unary-minus) and other XSD unary minus UnaryMinus(Box), - UnaryNot(Box), - FunctionCall(Function, Vec), + /// [fn:not](https://www.w3.org/TR/xpath-functions/#func-not) + Not(Box), + /// [EXISTS](https://www.w3.org/TR/sparql11-query/#func-filter-exists) Exists(Box), + /// [BOUND](https://www.w3.org/TR/sparql11-query/#func-bound) Bound(Variable), + /// [IF](https://www.w3.org/TR/sparql11-query/#func-if) + If(Box, Box, Box), + /// [COALESCE](https://www.w3.org/TR/sparql11-query/#func-coalesce) + Coalesce(Vec), + /// A regular function call + FunctionCall(Function, Vec), } impl fmt::Display for Expression { @@ -544,53 +580,45 @@ impl fmt::Display for Expression { Expression::NamedNode(node) => node.fmt(f), Expression::Literal(l) => l.fmt(f), Expression::Variable(var) => var.fmt(f), - Expression::Or(a, b) => write!(f, "({} || {})", a, b), - Expression::And(a, b) => write!(f, "({} && {})", a, b), - Expression::Equal(a, b) => write!(f, "({} = {})", a, b), - Expression::NotEqual(a, b) => write!(f, "({} != {})", a, b), - Expression::Greater(a, b) => write!(f, "({} > {})", a, b), - Expression::GreaterOrEq(a, b) => write!(f, "({} >= {})", a, b), - Expression::Lower(a, b) => write!(f, "({} < {})", a, b), - Expression::LowerOrEq(a, b) => write!(f, "({} <= {})", a, b), - Expression::In(a, b) => write!( - f, - "({} IN ({}))", - a, - b.iter() - .map(|v| v.to_string()) - .collect::>() - .join(", ") - ), - Expression::NotIn(a, b) => write!( - f, - "({} NOT IN ({}))", - a, - b.iter() - .map(|v| v.to_string()) - .collect::>() - .join(", ") - ), - Expression::Add(a, b) => write!(f, "{} + {}", a, b), - Expression::Sub(a, b) => write!(f, "{} - {}", a, b), - Expression::Mul(a, b) => write!(f, "{} * {}", a, b), - Expression::Div(a, b) => write!(f, "{} / {}", a, b), - Expression::UnaryPlus(e) => write!(f, "+{}", e), - Expression::UnaryMinus(e) => write!(f, "-{}", e), - Expression::UnaryNot(e) => write!(f, "!{}", e), + Expression::Or(a, b) => write!(f, "(|| {} {})", a, b), + Expression::And(a, b) => write!(f, "(&& {} {})", a, b), + Expression::Equal(a, b) => write!(f, "(= {} {})", a, b), + Expression::SameTerm(a, b) => write!(f, "(sameTerm {} {})", a, b), + Expression::Greater(a, b) => write!(f, "(> {} {})", a, b), + Expression::GreaterOrEqual(a, b) => write!(f, "(>= {} {})", a, b), + Expression::Less(a, b) => write!(f, "(< {} {})", a, b), + Expression::LessOrEqual(a, b) => write!(f, "(<= {} {})", a, b), + Expression::In(a, b) => { + write!(f, "(in {}", a)?; + for p in b { + write!(f, " {}", p)?; + } + write!(f, ")") + } + Expression::Add(a, b) => write!(f, "(+ {} {})", a, b), + Expression::Subtract(a, b) => write!(f, "(- {} {})", a, b), + Expression::Multiply(a, b) => write!(f, "(* {} {})", a, b), + Expression::Divide(a, b) => write!(f, "(/ {} {})", a, b), + Expression::UnaryPlus(e) => write!(f, "(+ {})", e), + Expression::UnaryMinus(e) => write!(f, "(- {})", e), + Expression::Not(e) => write!(f, "(! {})", e), Expression::FunctionCall(function, parameters) => { - write!(f, "{}(", function)?; - let mut cont = false; + write!(f, "({}", function)?; for p in parameters { - if cont { - write!(f, ", ")?; - } - p.fmt(f)?; - cont = true; + write!(f, " {}", p)?; + } + write!(f, ")") + } + Expression::Exists(p) => write!(f, "(exists {})", p), + Expression::Bound(v) => write!(f, "(bound {})", v), + Expression::If(a, b, c) => write!(f, "(if {} {} {})", a, b, c), + Expression::Coalesce(parameters) => { + write!(f, "(coalesce")?; + for p in parameters { + write!(f, " {}", p)?; } write!(f, ")") } - Expression::Exists(p) => write!(f, "EXISTS {{ {} }}", p), - Expression::Bound(v) => write!(f, "BOUND({})", v), } } } @@ -636,84 +664,93 @@ impl<'a> fmt::Display for SparqlExpression<'a> { Expression::Equal(a, b) => { write!(f, "({} = {})", SparqlExpression(&*a), SparqlExpression(&*b)) } - Expression::NotEqual(a, b) => write!( - f, - "({} != {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), + Expression::SameTerm(a, b) => { + write!( + f, + "sameTerm({}, {})", + SparqlExpression(&*a), + SparqlExpression(&*b) + ) + } Expression::Greater(a, b) => { write!(f, "({} > {})", SparqlExpression(&*a), SparqlExpression(&*b)) } - Expression::GreaterOrEq(a, b) => write!( + Expression::GreaterOrEqual(a, b) => write!( f, "({} >= {})", SparqlExpression(&*a), SparqlExpression(&*b) ), - Expression::Lower(a, b) => { + Expression::Less(a, b) => { write!(f, "({} < {})", SparqlExpression(&*a), SparqlExpression(&*b)) } - Expression::LowerOrEq(a, b) => write!( + Expression::LessOrEqual(a, b) => write!( f, "({} <= {})", SparqlExpression(&*a), SparqlExpression(&*b) ), - Expression::In(a, b) => write!( - f, - "({} IN ({}))", - a, - b.iter() - .map(|v| SparqlExpression(v).to_string()) - .collect::>() - .join(", ") - ), - Expression::NotIn(a, b) => write!( - f, - "({} NOT IN ({}))", - a, - b.iter() - .map(|v| SparqlExpression(v).to_string()) - .collect::>() - .join(", ") - ), + Expression::In(a, b) => { + write!(f, "({} IN ", SparqlExpression(&*a))?; + write_arg_list(b.iter().map(|p| SparqlExpression(&*p)), f)?; + write!(f, ")") + } Expression::Add(a, b) => { write!(f, "{} + {}", SparqlExpression(&*a), SparqlExpression(&*b)) } - Expression::Sub(a, b) => { + Expression::Subtract(a, b) => { write!(f, "{} - {}", SparqlExpression(&*a), SparqlExpression(&*b)) } - Expression::Mul(a, b) => { + Expression::Multiply(a, b) => { write!(f, "{} * {}", SparqlExpression(&*a), SparqlExpression(&*b)) } - Expression::Div(a, b) => { + Expression::Divide(a, b) => { write!(f, "{} / {}", SparqlExpression(&*a), SparqlExpression(&*b)) } Expression::UnaryPlus(e) => write!(f, "+{}", SparqlExpression(&*e)), Expression::UnaryMinus(e) => write!(f, "-{}", SparqlExpression(&*e)), - Expression::UnaryNot(e) => match e.as_ref() { + Expression::Not(e) => match e.as_ref() { Expression::Exists(p) => write!(f, "NOT EXISTS {{ {} }}", SparqlGraphPattern(&*p)), - e => write!(f, "!{}", e), + e => write!(f, "!{}", SparqlExpression(&*e)), }, Expression::FunctionCall(function, parameters) => { - write!(f, "{}(", function)?; - let mut cont = false; - for p in parameters { - if cont { - write!(f, ", ")?; - } - SparqlExpression(&*p).fmt(f)?; - cont = true; - } - write!(f, ")") + write!(f, "{}", function)?; + write_arg_list(parameters.iter().map(|p| SparqlExpression(&*p)), f) } Expression::Bound(v) => write!(f, "BOUND({})", v), Expression::Exists(p) => write!(f, "EXISTS {{ {} }}", SparqlGraphPattern(&*p)), + Expression::If(a, b, c) => write!( + f, + "IF({}, {}, {})", + SparqlExpression(&*a), + SparqlExpression(&*b), + SparqlExpression(&*c) + ), + Expression::Coalesce(parameters) => { + write!(f, "COALESCE")?; + write_arg_list(parameters.iter().map(|p| SparqlExpression(&*p)), f) + } } } } +fn write_arg_list( + params: impl IntoIterator, + f: &mut fmt::Formatter<'_>, +) -> fmt::Result { + write!(f, "(")?; + let mut cont = false; + for p in params { + if cont { + write!(f, ", ")?; + } + p.fmt(f)?; + cont = true; + } + write!(f, ")") +} + +/// A function name #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum Function { Str, @@ -755,11 +792,8 @@ pub enum Function { SHA256, SHA384, SHA512, - Coalesce, - If, StrLang, StrDT, - SameTerm, IsIRI, IsBlank, IsLiteral, @@ -810,11 +844,8 @@ impl fmt::Display for Function { Function::SHA256 => write!(f, "SHA256"), Function::SHA384 => write!(f, "SHA384"), Function::SHA512 => write!(f, "SHA512"), - Function::Coalesce => write!(f, "COALESCE"), - Function::If => write!(f, "IF"), Function::StrLang => write!(f, "STRLANG"), Function::StrDT => write!(f, "STRDT"), - Function::SameTerm => write!(f, "sameTerm"), Function::IsIRI => write!(f, "isIRI"), Function::IsBlank => write!(f, "isBLANK"), Function::IsLiteral => write!(f, "isLITERAL"), @@ -825,102 +856,204 @@ impl fmt::Display for Function { } } +/// A SPARQL query [graph pattern](https://www.w3.org/TR/sparql11-query/#sparqlQuery) #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum GraphPattern { - BGP(Vec), - Join(Box, Box), - LeftJoin(Box, Box, Option), - Filter(Expression, Box), - Union(Box, Box), - Graph(NamedNodeOrVariable, Box), - Extend(Box, Variable, Expression), - Minus(Box, Box), - Service(NamedNodeOrVariable, Box, bool), - AggregateJoin(GroupPattern, Vec<(Aggregation, Variable)>), - Data(StaticBindings), - OrderBy(Box, Vec), - Project(Box, Vec), - Distinct(Box), - Reduced(Box), - Slice(Box, usize, Option), + /// A [basic graph pattern](https://www.w3.org/TR/sparql11-query/#defn_BasicGraphPattern) + BGP(Vec), + /// A [property path pattern](https://www.w3.org/TR/sparql11-query/#defn_evalPP_predicate) + Path { + subject: TermOrVariable, + path: PropertyPathExpression, + object: TermOrVariable, + }, + /// [Join](https://www.w3.org/TR/sparql11-query/#defn_algJoin) + Join { + left: Box, + right: Box, + }, + /// [LeftJoin](https://www.w3.org/TR/sparql11-query/#defn_algLeftJoin) + LeftJoin { + left: Box, + right: Box, + expr: Option, + }, + /// [Filter](https://www.w3.org/TR/sparql11-query/#defn_algFilter) + Filter { + expr: Expression, + inner: Box, + }, + /// [Union](https://www.w3.org/TR/sparql11-query/#defn_algUnion) + Union { + left: Box, + right: Box, + }, + Graph { + graph_name: NamedNodeOrVariable, + inner: Box, + }, + /// [Extend](https://www.w3.org/TR/sparql11-query/#defn_extend) + Extend { + inner: Box, + var: Variable, + expr: Expression, + }, + /// [Minus](https://www.w3.org/TR/sparql11-query/#defn_algMinus) + Minus { + left: Box, + right: Box, + }, + /// A table used to provide inline values + Table { + variables: Vec, + rows: Vec>>, + }, + /// [OrderBy](https://www.w3.org/TR/sparql11-query/#defn_algOrdered) + OrderBy { + inner: Box, + condition: Vec, + }, + /// [Project](https://www.w3.org/TR/sparql11-query/#defn_algProjection) + Project { + inner: Box, + projection: Vec, + }, + /// [Distinct](https://www.w3.org/TR/sparql11-query/#defn_algDistinct) + Distinct { inner: Box }, + /// [Reduced](https://www.w3.org/TR/sparql11-query/#defn_algReduced) + Reduced { inner: Box }, + /// [Slice](https://www.w3.org/TR/sparql11-query/#defn_algSlice) + Slice { + inner: Box, + start: usize, + length: Option, + }, + /// [Group](https://www.w3.org/TR/sparql11-federated-query/#aggregateAlgebra) + Group { + inner: Box, + by: Vec, + aggregates: Vec<(Variable, SetFunction)>, + }, + /// [Service](https://www.w3.org/TR/sparql11-federated-query/#defn_evalService) + Service { + name: NamedNodeOrVariable, + pattern: Box, + silent: bool, + }, } impl fmt::Display for GraphPattern { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - GraphPattern::BGP(p) => write!( - f, - "BGP({})", - p.iter() - .map(|v| v.to_string()) - .collect::>() - .join(" ") - ), - GraphPattern::Join(a, b) => write!(f, "Join({}, {})", a, b), - GraphPattern::LeftJoin(a, b, e) => { - if let Some(e) = e { - write!(f, "LeftJoin({}, {}, {})", a, b, e) + GraphPattern::BGP(p) => { + write!(f, "(bgp")?; + for pattern in p { + write!(f, " {}", pattern)?; + } + write!(f, ")") + } + GraphPattern::Path { + subject, + path, + object, + } => write!(f, "(path {} {} {})", subject, path, object), + GraphPattern::Join { left, right } => write!(f, "(join {} {})", left, right), + GraphPattern::LeftJoin { left, right, expr } => { + if let Some(expr) = expr { + write!(f, "(leftjoin {} {} {})", left, right, expr) } else { - write!(f, "LeftJoin({}, {})", a, b) + write!(f, "(leftjoin {} {})", left, right) } } - GraphPattern::Filter(e, p) => write!(f, "Filter({}, {})", e, p), - GraphPattern::Union(a, b) => write!(f, "Union({}, {})", a, b), - GraphPattern::Graph(g, p) => write!(f, "Graph({}, {})", g, p), - GraphPattern::Extend(p, v, e) => write!(f, "Extend({}), {}, {})", p, v, e), - GraphPattern::Minus(a, b) => write!(f, "Minus({}, {})", a, b), - GraphPattern::Service(n, p, s) => write!(f, "Service({}, {}, {})", n, p, s), - GraphPattern::AggregateJoin(g, a) => write!( + GraphPattern::Filter { expr, inner } => write!(f, "(filter {} {})", expr, inner), + GraphPattern::Union { left, right } => write!(f, "(union {} {})", left, right), + GraphPattern::Graph { graph_name, inner } => { + write!(f, "(graph {} {})", graph_name, inner) + } + GraphPattern::Extend { inner, var, expr } => { + write!(f, "(extend ({} {}) {})", var, expr, inner) + } + GraphPattern::Minus { left, right } => write!(f, "(minus {} {})", left, right), + GraphPattern::Service { + name, + pattern, + silent, + } => { + if *silent { + write!(f, "(service silent {} {})", name, pattern) + } else { + write!(f, "(service {} {})", name, pattern) + } + } + GraphPattern::Group { + inner, + by, + aggregates, + } => write!( f, - "AggregateJoin({}, {})", - g, - a.iter() - .map(|(a, v)| format!("{}: {}", v, a)) + "(group ({}) ({}) {})", + by.iter() + .map(|v| v.as_str()) + .collect::>() + .join(" "), + aggregates + .iter() + .map(|(a, v)| format!("({} {})", v, a)) .collect::>() - .join(", ") + .join(" "), + inner ), - GraphPattern::Data(bs) => { - let variables = bs.variables(); - write!(f, "{{ ")?; - for values in bs.values_iter() { - write!(f, "{{")?; - for i in 0..values.len() { - if let Some(ref val) = values[i] { - write!(f, " {} \u{2192} {} ", variables[i], val)?; + GraphPattern::Table { variables, rows } => { + write!(f, "(table (vars")?; + for var in variables { + write!(f, " {}", var)?; + } + write!(f, ")")?; + for row in rows { + write!(f, " (row")?; + for (value, var) in row.iter().zip(variables) { + if let Some(value) = value { + write!(f, " ({} {})", var, value)?; } } - write!(f, "}}")?; + write!(f, ")")?; } - write!(f, "}}") + write!(f, ")") } - GraphPattern::OrderBy(l, o) => write!( + GraphPattern::OrderBy { inner, condition } => write!( f, - "OrderBy({}, ({}))", - l, - o.iter() + "(order ({}) {})", + condition + .iter() .map(|c| c.to_string()) .collect::>() - .join(", ") + .join(" "), + inner ), - GraphPattern::Project(l, pv) => write!( + GraphPattern::Project { inner, projection } => write!( f, - "Project({}, ({}))", - l, - pv.iter() + "(project ({}) {})", + projection + .iter() .map(|v| v.to_string()) .collect::>() - .join(", ") + .join(" "), + inner ), - GraphPattern::Distinct(l) => write!(f, "Distinct({})", l), - GraphPattern::Reduced(l) => write!(f, "Reduce({})", l), - GraphPattern::Slice(l, start, length) => write!( + GraphPattern::Distinct { inner } => write!(f, "(distinct {})", inner), + GraphPattern::Reduced { inner } => write!(f, "(reduced {})", inner), + GraphPattern::Slice { + inner, + start, + length, + } => write!( f, - "Slice({}, {}, {})", - l, + "(slice {} {} {})", start, length .map(|l| l.to_string()) - .unwrap_or_else(|| '?'.to_string()) + .unwrap_or_else(|| '_'.to_string()), + inner ), } } @@ -932,12 +1065,6 @@ impl Default for GraphPattern { } } -impl From for GraphPattern { - fn from(p: TripleOrPathPattern) -> Self { - GraphPattern::BGP(vec![p]) - } -} - impl GraphPattern { pub fn visible_variables(&self) -> BTreeSet<&Variable> { let mut vars = BTreeSet::default(); @@ -949,65 +1076,58 @@ impl GraphPattern { match self { GraphPattern::BGP(p) => { for pattern in p { - match pattern { - TripleOrPathPattern::Triple(tp) => { - if let TermOrVariable::Variable(ref s) = tp.subject { - vars.insert(s); - } - if let NamedNodeOrVariable::Variable(ref p) = tp.predicate { - vars.insert(p); - } - if let TermOrVariable::Variable(ref o) = tp.object { - vars.insert(o); - } - } - TripleOrPathPattern::Path(ppp) => { - if let TermOrVariable::Variable(ref s) = ppp.subject { - vars.insert(s); - } - if let TermOrVariable::Variable(ref o) = ppp.object { - vars.insert(o); - } - } + if let TermOrVariable::Variable(s) = &pattern.subject { + vars.insert(s); + } + if let NamedNodeOrVariable::Variable(p) = &pattern.predicate { + vars.insert(p); + } + if let TermOrVariable::Variable(o) = &pattern.object { + vars.insert(o); } } } - GraphPattern::Join(a, b) => { - a.add_visible_variables(vars); - b.add_visible_variables(vars); - } - GraphPattern::LeftJoin(a, b, _) => { - a.add_visible_variables(vars); - b.add_visible_variables(vars); + GraphPattern::Path { + subject, object, .. + } => { + if let TermOrVariable::Variable(s) = subject { + vars.insert(s); + } + if let TermOrVariable::Variable(o) = object { + vars.insert(o); + } } - GraphPattern::Filter(_, p) => p.add_visible_variables(vars), - GraphPattern::Union(a, b) => { - a.add_visible_variables(vars); - b.add_visible_variables(vars); + GraphPattern::Join { left, right } + | GraphPattern::LeftJoin { left, right, .. } + | GraphPattern::Union { left, right } => { + left.add_visible_variables(vars); + right.add_visible_variables(vars); } - GraphPattern::Graph(g, p) => { - if let NamedNodeOrVariable::Variable(ref g) = g { + GraphPattern::Filter { inner, .. } => inner.add_visible_variables(vars), + GraphPattern::Graph { graph_name, inner } => { + if let NamedNodeOrVariable::Variable(ref g) = graph_name { vars.insert(g); } - p.add_visible_variables(vars); + inner.add_visible_variables(vars); } - GraphPattern::Extend(p, v, _) => { - vars.insert(v); - p.add_visible_variables(vars); + GraphPattern::Extend { inner, var, .. } => { + vars.insert(var); + inner.add_visible_variables(vars); } - GraphPattern::Minus(a, _) => a.add_visible_variables(vars), - GraphPattern::Service(_, p, _) => p.add_visible_variables(vars), - GraphPattern::AggregateJoin(_, a) => { - for (_, v) in a { + GraphPattern::Minus { left, .. } => left.add_visible_variables(vars), + GraphPattern::Service { pattern, .. } => pattern.add_visible_variables(vars), + GraphPattern::Group { by, aggregates, .. } => { + vars.extend(by); + for (v, _) in aggregates { vars.insert(v); } } - GraphPattern::Data(b) => vars.extend(b.variables_iter()), - GraphPattern::OrderBy(l, _) => l.add_visible_variables(vars), - GraphPattern::Project(_, pv) => vars.extend(pv.iter()), - GraphPattern::Distinct(l) => l.add_visible_variables(vars), - GraphPattern::Reduced(l) => l.add_visible_variables(vars), - GraphPattern::Slice(l, _, _) => l.add_visible_variables(vars), + GraphPattern::Table { variables, .. } => vars.extend(variables), + GraphPattern::Project { projection, .. } => vars.extend(projection.iter()), + GraphPattern::OrderBy { inner, .. } + | GraphPattern::Distinct { inner } + | GraphPattern::Reduced { inner } + | GraphPattern::Slice { inner, .. } => inner.add_visible_variables(vars), } } } @@ -1019,102 +1139,126 @@ impl<'a> fmt::Display for SparqlGraphPattern<'a> { match self.0 { GraphPattern::BGP(p) => { for pattern in p { - write!(f, "{}", SparqlTripleOrPathPattern(pattern))? + write!(f, "{}", SparqlTriplePattern(pattern))? } Ok(()) } - GraphPattern::Join(a, b) => write!( + GraphPattern::Path { + subject, + path, + object, + } => write!(f, "{} {} {} .", subject, SparqlPropertyPath(path), object), + GraphPattern::Join { left, right } => write!( f, - "{{ {} }} {{ {} }}", - SparqlGraphPattern(&*a), - SparqlGraphPattern(&*b) + "{} {}", + SparqlGraphPattern(&*left), + SparqlGraphPattern(&*right) ), - GraphPattern::LeftJoin(a, b, e) => { - if let Some(e) = e { + GraphPattern::LeftJoin { left, right, expr } => { + if let Some(expr) = expr { write!( f, "{} OPTIONAL {{ {} FILTER({}) }}", - SparqlGraphPattern(&*a), - SparqlGraphPattern(&*b), - SparqlExpression(e) + SparqlGraphPattern(&*left), + SparqlGraphPattern(&*right), + SparqlExpression(expr) ) } else { write!( f, "{} OPTIONAL {{ {} }}", - SparqlGraphPattern(&*a), - SparqlGraphPattern(&*b) + SparqlGraphPattern(&*left), + SparqlGraphPattern(&*right) ) } } - GraphPattern::Filter(e, p) => write!( + GraphPattern::Filter { expr, inner } => write!( f, "{} FILTER({})", - SparqlGraphPattern(&*p), - SparqlExpression(e) + SparqlGraphPattern(&*inner), + SparqlExpression(expr) ), - GraphPattern::Union(a, b) => write!( + GraphPattern::Union { left, right } => write!( f, "{{ {} }} UNION {{ {} }}", - SparqlGraphPattern(&*a), - SparqlGraphPattern(&*b), + SparqlGraphPattern(&*left), + SparqlGraphPattern(&*right), ), - GraphPattern::Graph(g, p) => { - write!(f, "GRAPH {} {{ {} }}", g, SparqlGraphPattern(&*p),) + GraphPattern::Graph { graph_name, inner } => { + write!( + f, + "GRAPH {} {{ {} }}", + graph_name, + SparqlGraphPattern(&*inner) + ) } - GraphPattern::Extend(p, v, e) => write!( + GraphPattern::Extend { inner, var, expr } => write!( f, "{} BIND({} AS {})", - SparqlGraphPattern(&*p), - SparqlExpression(e), - v + SparqlGraphPattern(&*inner), + SparqlExpression(expr), + var ), - GraphPattern::Minus(a, b) => write!( + GraphPattern::Minus { left, right } => write!( f, "{} MINUS {{ {} }}", - SparqlGraphPattern(&*a), - SparqlGraphPattern(&*b) + SparqlGraphPattern(&*left), + SparqlGraphPattern(&*right) ), - GraphPattern::Service(n, p, s) => { - if *s { - write!(f, "SERVICE SILENT {} {{ {} }}", n, SparqlGraphPattern(&*p)) + GraphPattern::Service { + name, + pattern, + silent, + } => { + if *silent { + write!( + f, + "SERVICE SILENT {} {{ {} }}", + name, + SparqlGraphPattern(&*pattern) + ) } else { - write!(f, "SERVICE {} {{ {} }}", n, SparqlGraphPattern(&*p)) + write!( + f, + "SERVICE {} {{ {} }}", + name, + SparqlGraphPattern(&*pattern) + ) } } - GraphPattern::Data(bs) => { - if bs.is_empty() { - Ok(()) - } else { - write!(f, "VALUES ( ")?; - for var in bs.variables() { - write!(f, "{} ", var)?; - } - write!(f, ") {{ ")?; - for values in bs.values_iter() { - write!(f, "( ")?; - for val in values { - match val { - Some(val) => write!(f, "{} ", val), - None => write!(f, "UNDEF "), - }?; - } - write!(f, ") ")?; + GraphPattern::Table { variables, rows } => { + write!(f, "VALUES ( ")?; + for var in variables { + write!(f, "{} ", var)?; + } + write!(f, ") {{ ")?; + for row in rows { + write!(f, "( ")?; + for val in row { + match val { + Some(val) => write!(f, "{} ", val), + None => write!(f, "UNDEF "), + }?; } - write!(f, " }}") + write!(f, ") ")?; } + write!(f, " }}") } - GraphPattern::AggregateJoin(GroupPattern(group, p), agg) => write!( + GraphPattern::Group { + inner, + by, + aggregates, + } => write!( f, "{{ SELECT {} WHERE {{ {} }} GROUP BY {} }}", - agg.iter() - .map(|(a, v)| format!("({} AS {})", SparqlAggregation(a), v)) - .chain(group.iter().map(|e| e.to_string())) + aggregates + .iter() + .map(|(v, a)| format!("({} AS {})", SparqlAggregation(a), v)) + .chain(by.iter().map(|e| e.to_string())) .collect::>() .join(" "), - SparqlGraphPattern(&*p), - group - .iter() + SparqlGraphPattern(&*inner), + by.iter() .map(|e| format!("({})", e.to_string())) .collect::>() .join(" ") @@ -1123,7 +1267,7 @@ impl<'a> fmt::Display for SparqlGraphPattern<'a> { f, "{{ {} }}", SparqlGraphRootPattern { - algebra: p, + pattern: p, dataset: &QueryDataset::default() } ), @@ -1132,7 +1276,7 @@ impl<'a> fmt::Display for SparqlGraphPattern<'a> { } struct SparqlGraphRootPattern<'a> { - algebra: &'a GraphPattern, + pattern: &'a GraphPattern, dataset: &'a QueryDataset, } @@ -1145,29 +1289,33 @@ impl<'a> fmt::Display for SparqlGraphRootPattern<'a> { let mut length = None; let mut project: &[Variable] = &[]; - let mut child = self.algebra; + let mut child = self.pattern; loop { match child { - GraphPattern::OrderBy(l, o) => { - order = Some(o); - child = &*l; + GraphPattern::OrderBy { inner, condition } => { + order = Some(condition); + child = &*inner; } - GraphPattern::Project(l, pv) if project.is_empty() => { - project = pv; - child = &*l; + GraphPattern::Project { inner, projection } if project.is_empty() => { + project = projection; + child = &*inner; } - GraphPattern::Distinct(l) => { + GraphPattern::Distinct { inner } => { distinct = true; - child = &*l; + child = &*inner; } - GraphPattern::Reduced(l) => { + GraphPattern::Reduced { inner } => { reduced = true; - child = &*l; + child = &*inner; } - GraphPattern::Slice(l, s, len) => { + GraphPattern::Slice { + inner, + start: s, + length: l, + } => { start = *s; - length = *len; - child = l; + length = *l; + child = inner; } p => { write!(f, "SELECT ")?; @@ -1208,24 +1356,6 @@ impl<'a> fmt::Display for SparqlGraphRootPattern<'a> { } } -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub struct GroupPattern(pub Vec, pub Box); - -impl fmt::Display for GroupPattern { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Group(({}), {})", - self.0 - .iter() - .map(|c| c.to_string()) - .collect::>() - .join(", "), - self.1 - ) - } -} - fn build_sparql_select_arguments(args: &[Variable]) -> String { if args.is_empty() { "*".to_owned() @@ -1237,169 +1367,197 @@ fn build_sparql_select_arguments(args: &[Variable]) -> String { } } +/// A set function used in aggregates (c.f. [`GraphPattern::Group`]) #[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub enum Aggregation { - Count(Option>, bool), - Sum(Box, bool), - Min(Box, bool), - Max(Box, bool), - Avg(Box, bool), - Sample(Box, bool), - GroupConcat(Box, bool, Option), +pub enum SetFunction { + /// [Count](https://www.w3.org/TR/sparql11-query/#defn_aggCount) + Count { + expr: Option>, + distinct: bool, + }, + /// [Sum](https://www.w3.org/TR/sparql11-query/#defn_aggSum) + Sum { + expr: Box, + distinct: bool, + }, + /// [Avg](https://www.w3.org/TR/sparql11-query/#defn_aggAvg) + Avg { + expr: Box, + distinct: bool, + }, + /// [Min](https://www.w3.org/TR/sparql11-query/#defn_aggMin) + Min { + expr: Box, + distinct: bool, + }, + /// [Max](https://www.w3.org/TR/sparql11-query/#defn_aggMax) + Max { + expr: Box, + distinct: bool, + }, + /// [GroupConcat](https://www.w3.org/TR/sparql11-query/#defn_aggGroupConcat) + GroupConcat { + expr: Box, + distinct: bool, + separator: Option, + }, + /// [Sample](https://www.w3.org/TR/sparql11-query/#defn_aggSample) + Sample { + expr: Box, + distinct: bool, + }, } -impl fmt::Display for Aggregation { +impl fmt::Display for SetFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Aggregation::Count(e, distinct) => { + SetFunction::Count { expr, distinct } => { if *distinct { - if let Some(ex) = e { - write!(f, "COUNT(DISTINCT {})", ex) + if let Some(expr) = expr { + write!(f, "(count distinct {})", expr) } else { - write!(f, "COUNT(DISTINCT *)") + write!(f, "(count distinct)") } - } else if let Some(ex) = e { - write!(f, "COUNT({})", ex) + } else if let Some(expr) = expr { + write!(f, "(count {})", expr) } else { - write!(f, "COUNT(*)") + write!(f, "(count)") } } - Aggregation::Sum(e, distinct) => { + SetFunction::Sum { expr, distinct } => { if *distinct { - write!(f, "Aggregation(Distinct({}), Sum, {{}})", e) + write!(f, "(sum distinct {})", expr) } else { - write!(f, "Aggregation({}, Sum, {{}})", e) + write!(f, "(sum {})", expr) } } - Aggregation::Min(e, distinct) => { + SetFunction::Avg { expr, distinct } => { if *distinct { - write!(f, "Aggregation(Distinct({}), Min, {{}})", e) + write!(f, "(avg distinct {})", expr) } else { - write!(f, "Aggregation({}, Min, {{}})", e) + write!(f, "(avg {})", expr) } } - Aggregation::Max(e, distinct) => { + SetFunction::Min { expr, distinct } => { if *distinct { - write!(f, "Aggregation(Distinct({}), Max, {{}})", e) + write!(f, "(min distinct {})", expr) } else { - write!(f, "Aggregation({}, Max, {{}})", e) + write!(f, "(min {})", expr) } } - Aggregation::Avg(e, distinct) => { + SetFunction::Max { expr, distinct } => { if *distinct { - write!(f, "Aggregation(Distinct({}), Avg, {{}})", e) + write!(f, "(max distinct {})", expr) } else { - write!(f, "Aggregation({}, Avg, {{}})", e) + write!(f, "(max {})", expr) } } - Aggregation::Sample(e, distinct) => { + SetFunction::Sample { expr, distinct } => { if *distinct { - write!(f, "Aggregation(Distinct({}), Sum, {{}})", e) + write!(f, "(sample distinct {})", expr) } else { - write!(f, "Aggregation({}, Sample, {{}})", e) + write!(f, "(sample {})", expr) } } - Aggregation::GroupConcat(e, distinct, sep) => { + SetFunction::GroupConcat { + expr, + distinct, + separator, + } => { if *distinct { - if let Some(s) = sep { - write!( - f, - "Aggregation(Distinct({}), GroupConcat, {{\"separator\" \u{2192} {}}})", - e, - fmt_str(s) - ) + if let Some(separator) = separator { + write!(f, "(group_concat distinct {} {})", expr, fmt_str(separator)) } else { - write!(f, "Aggregation(Distinct({}), GroupConcat, {{}})", e) + write!(f, "(group_concat distinct {})", expr) } - } else if let Some(s) = sep { - write!( - f, - "Aggregation({}, GroupConcat, {{\"separator\" \u{2192} {}}})", - e, - fmt_str(s) - ) + } else if let Some(separator) = separator { + write!(f, "(group_concat {} {})", expr, fmt_str(separator)) } else { - write!(f, "Aggregation(Distinct({}), GroupConcat, {{}})", e) + write!(f, "(group_concat {})", expr) } } } } } -struct SparqlAggregation<'a>(&'a Aggregation); +struct SparqlAggregation<'a>(&'a SetFunction); impl<'a> fmt::Display for SparqlAggregation<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { - Aggregation::Count(e, distinct) => { + SetFunction::Count { expr, distinct } => { if *distinct { - if let Some(e) = e { - write!(f, "COUNT(DISTINCT {})", SparqlExpression(e)) + if let Some(expr) = expr { + write!(f, "COUNT(DISTINCT {})", SparqlExpression(expr)) } else { write!(f, "COUNT(DISTINCT *)") } - } else if let Some(e) = e { - write!(f, "COUNT({})", SparqlExpression(e)) + } else if let Some(expr) = expr { + write!(f, "COUNT({})", SparqlExpression(expr)) } else { write!(f, "COUNT(*)") } } - Aggregation::Sum(e, distinct) => { + SetFunction::Sum { expr, distinct } => { if *distinct { - write!(f, "SUM(DISTINCT {})", SparqlExpression(e)) + write!(f, "SUM(DISTINCT {})", SparqlExpression(expr)) } else { - write!(f, "SUM({})", SparqlExpression(e)) + write!(f, "SUM({})", SparqlExpression(expr)) } } - Aggregation::Min(e, distinct) => { + SetFunction::Min { expr, distinct } => { if *distinct { - write!(f, "MIN(DISTINCT {})", SparqlExpression(e)) + write!(f, "MIN(DISTINCT {})", SparqlExpression(expr)) } else { - write!(f, "MIN({})", SparqlExpression(e)) + write!(f, "MIN({})", SparqlExpression(expr)) } } - Aggregation::Max(e, distinct) => { + SetFunction::Max { expr, distinct } => { if *distinct { - write!(f, "MAX(DISTINCT {})", SparqlExpression(e)) + write!(f, "MAX(DISTINCT {})", SparqlExpression(expr)) } else { - write!(f, "MAX({})", SparqlExpression(e)) + write!(f, "MAX({})", SparqlExpression(expr)) } } - Aggregation::Avg(e, distinct) => { + SetFunction::Avg { expr, distinct } => { if *distinct { - write!(f, "AVG(DISTINCT {})", SparqlExpression(e)) + write!(f, "AVG(DISTINCT {})", SparqlExpression(expr)) } else { - write!(f, "AVG({})", SparqlExpression(e)) + write!(f, "AVG({})", SparqlExpression(expr)) } } - Aggregation::Sample(e, distinct) => { + SetFunction::Sample { expr, distinct } => { if *distinct { - write!(f, "SAMPLE(DISTINCT {})", SparqlExpression(e)) + write!(f, "SAMPLE(DISTINCT {})", SparqlExpression(expr)) } else { - write!(f, "SAMPLE({})", SparqlExpression(e)) + write!(f, "SAMPLE({})", SparqlExpression(expr)) } } - Aggregation::GroupConcat(e, distinct, sep) => { + SetFunction::GroupConcat { + expr, + distinct, + separator, + } => { if *distinct { - if let Some(sep) = sep { + if let Some(separator) = separator { write!( f, "GROUP_CONCAT(DISTINCT {}; SEPARATOR = {})", - SparqlExpression(e), - fmt_str(sep) + SparqlExpression(expr), + fmt_str(separator) ) } else { - write!(f, "GROUP_CONCAT(DISTINCT {})", SparqlExpression(e)) + write!(f, "GROUP_CONCAT(DISTINCT {})", SparqlExpression(expr)) } - } else if let Some(sep) = sep { + } else if let Some(separator) = separator { write!( f, "GROUP_CONCAT({}; SEPARATOR = {})", - SparqlExpression(e), - fmt_str(sep) + SparqlExpression(expr), + fmt_str(separator) ) } else { - write!(f, "GROUP_CONCAT({})", SparqlExpression(e)) + write!(f, "GROUP_CONCAT({})", SparqlExpression(expr)) } } } @@ -1410,27 +1568,24 @@ fn fmt_str(value: &str) -> rio::Literal<'_> { rio::Literal::Simple { value } } +/// An ordering comparator used by [`GraphPattern::OrderBy`] #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum OrderComparator { + /// Ascending order Asc(Expression), + /// Descending order Desc(Expression), } impl fmt::Display for OrderComparator { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - OrderComparator::Asc(e) => write!(f, "ASC({})", e), - OrderComparator::Desc(e) => write!(f, "DESC({})", e), + OrderComparator::Asc(e) => write!(f, "(asc {})", e), + OrderComparator::Desc(e) => write!(f, "(desc {})", e), } } } -impl From for OrderComparator { - fn from(e: Expression) -> Self { - OrderComparator::Asc(e) - } -} - struct SparqlOrderComparator<'a>(&'a OrderComparator); impl<'a> fmt::Display for SparqlOrderComparator<'a> { @@ -1546,107 +1701,6 @@ impl fmt::Display for QueryDataset { } } -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub enum QueryVariants { - Select { - dataset: QueryDataset, - algebra: Rc, - base_iri: Option>>, - }, - Construct { - construct: Rc>, - dataset: QueryDataset, - algebra: Rc, - base_iri: Option>>, - }, - Describe { - dataset: QueryDataset, - algebra: Rc, - base_iri: Option>>, - }, - Ask { - dataset: QueryDataset, - algebra: Rc, - base_iri: Option>>, - }, -} - -impl fmt::Display for QueryVariants { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - QueryVariants::Select { - dataset, - algebra, - base_iri, - } => { - if let Some(base_iri) = base_iri { - writeln!(f, "BASE <{}>", base_iri)?; - } - write!(f, "{}", SparqlGraphRootPattern { algebra, dataset }) - } - QueryVariants::Construct { - construct, - dataset, - algebra, - base_iri, - } => { - if let Some(base_iri) = base_iri { - writeln!(f, "BASE <{}>", base_iri)?; - } - write!(f, "CONSTRUCT {{ ")?; - for triple in construct.iter() { - write!(f, "{} ", triple)?; - } - write!( - f, - "}}{} WHERE {{ {} }}", - dataset, - SparqlGraphRootPattern { - algebra, - dataset: &QueryDataset::default() - } - ) - } - QueryVariants::Describe { - dataset, - algebra, - base_iri, - } => { - if let Some(base_iri) = base_iri { - writeln!(f, "BASE <{}>", base_iri.as_str())?; - } - write!( - f, - "DESCRIBE *{} WHERE {{ {} }}", - dataset, - SparqlGraphRootPattern { - algebra, - dataset: &QueryDataset::default() - } - ) - } - QueryVariants::Ask { - dataset, - algebra, - base_iri, - } => { - if let Some(base_iri) = base_iri { - writeln!(f, "BASE <{}>", base_iri)?; - } - write!( - f, - "ASK{} WHERE {{ {} }}", - dataset, - SparqlGraphRootPattern { - algebra, - dataset: &QueryDataset::default() - } - ) - } - } - } -} - /// The [graph update operations](https://www.w3.org/TR/sparql11-update/#formalModelGraphUpdate) #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum GraphUpdateOperation { @@ -1659,7 +1713,7 @@ pub enum GraphUpdateOperation { delete: Vec, insert: Vec, using: QueryDataset, - algebra: GraphPattern, + pattern: Box, }, /// [load](https://www.w3.org/TR/sparql11-update/#def_loadoperation) Load { @@ -1681,14 +1735,14 @@ impl fmt::Display for GraphUpdateOperation { GraphUpdateOperation::InsertData { data } => { writeln!(f, "INSERT DATA {{")?; for quad in data { - writeln!(f, "\t{}", quad)?; + writeln!(f, "\t{}", SparqlQuadPattern(quad))?; } write!(f, "}}") } GraphUpdateOperation::DeleteData { data } => { writeln!(f, "DELETE DATA {{")?; for quad in data { - writeln!(f, "\t{}", quad)?; + writeln!(f, "\t{}", SparqlQuadPattern(quad))?; } write!(f, "}}") } @@ -1696,19 +1750,19 @@ impl fmt::Display for GraphUpdateOperation { delete, insert, using, - algebra, + pattern, } => { if !delete.is_empty() { writeln!(f, "DELETE {{")?; for quad in delete { - writeln!(f, "\t{}", quad)?; + writeln!(f, "\t{}", SparqlQuadPattern(quad))?; } writeln!(f, "}}")?; } if !insert.is_empty() { writeln!(f, "INSERT {{")?; for quad in insert { - writeln!(f, "\t{}", quad)?; + writeln!(f, "\t{}", SparqlQuadPattern(quad))?; } writeln!(f, "}}")?; } @@ -1728,7 +1782,7 @@ impl fmt::Display for GraphUpdateOperation { f, "WHERE {{ {} }}", SparqlGraphRootPattern { - algebra, + pattern, dataset: &QueryDataset::default() } ) @@ -1769,6 +1823,9 @@ impl fmt::Display for GraphUpdateOperation { } } +/// A target RDF graph for update operations +/// +/// Could be a specific graph, all named graphs or the complete dataset. #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum GraphTarget { NamedNode(NamedNode), @@ -1793,54 +1850,3 @@ impl From for GraphTarget { Self::NamedNode(node) } } - -impl From> for GraphTarget { - fn from(node: NamedNodeRef<'_>) -> Self { - Self::NamedNode(node.into()) - } -} - -impl From for GraphTarget { - fn from(graph: NamedOrDefaultGraphTarget) -> Self { - match graph { - NamedOrDefaultGraphTarget::NamedNode(node) => Self::NamedNode(node), - NamedOrDefaultGraphTarget::DefaultGraph => Self::DefaultGraph, - } - } -} - -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub enum NamedOrDefaultGraphTarget { - NamedNode(NamedNode), - DefaultGraph, -} - -impl fmt::Display for NamedOrDefaultGraphTarget { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::NamedNode(node) => write!(f, "GRAPH {}", node), - Self::DefaultGraph => write!(f, "DEFAULT"), - } - } -} - -impl From for NamedOrDefaultGraphTarget { - fn from(node: NamedNode) -> Self { - Self::NamedNode(node) - } -} - -impl From> for NamedOrDefaultGraphTarget { - fn from(node: NamedNodeRef<'_>) -> Self { - Self::NamedNode(node.into()) - } -} - -impl From for Option { - fn from(graph: NamedOrDefaultGraphTarget) -> Self { - match graph { - NamedOrDefaultGraphTarget::NamedNode(node) => Some(node.into()), - NamedOrDefaultGraphTarget::DefaultGraph => None, - } - } -} diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index bda91208..e5772ec8 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -2,7 +2,7 @@ use crate::model::vocab::{rdf, xsd}; use crate::model::xsd::*; use crate::model::Triple; use crate::model::{BlankNode, LiteralRef, NamedNodeRef}; -use crate::sparql::algebra::{GraphPattern, Query, QueryDataset, QueryVariants}; +use crate::sparql::algebra::{GraphPattern, Query, QueryDataset}; use crate::sparql::error::EvaluationError; use crate::sparql::model::*; use crate::sparql::plan::*; @@ -134,25 +134,22 @@ where service_name, graph_pattern, .. - } => match self.evaluate_service( - service_name, - graph_pattern.clone(), - variables.clone(), - &from, - ) { - Ok(result) => Box::new(result.flat_map(move |binding| { - binding - .map(|binding| binding.combine_with(&from)) - .transpose() - })), - Err(e) => { - if *silent { - Box::new(once(Ok(from))) - } else { - Box::new(once(Err(e))) + } => { + match self.evaluate_service(service_name, graph_pattern, variables.clone(), &from) { + Ok(result) => Box::new(result.flat_map(move |binding| { + binding + .map(|binding| binding.combine_with(&from)) + .transpose() + })), + Err(e) => { + if *silent { + Box::new(once(Ok(from))) + } else { + Box::new(once(Err(e))) + } } } - }, + } PlanNode::QuadPatternJoin { child, subject, @@ -516,7 +513,7 @@ where fn evaluate_service( &self, service_name: &PatternValue, - graph_pattern: Rc, + graph_pattern: &GraphPattern, variables: Rc>, from: &EncodedTuple, ) -> Result, EvaluationError> { @@ -525,11 +522,11 @@ where get_pattern_value(service_name, from) .ok_or_else(|| EvaluationError::msg("The SERVICE name is not bound"))?, )?, - Query(QueryVariants::Select { + Query::Select { dataset: QueryDataset::default(), - algebra: graph_pattern, - base_iri: self.base_iri.clone(), - }), + pattern: graph_pattern.clone(), + base_iri: self.base_iri.as_ref().map(|iri| iri.as_ref().clone()), + }, )? { Ok(self.encode_bindings(variables, iter)) } else { @@ -589,13 +586,13 @@ where graph_name: EncodedTerm, ) -> Box, EvaluationError>>> { match path { - PlanPropertyPath::PredicatePath(p) => Box::new( + PlanPropertyPath::Path(p) => Box::new( self.dataset .encoded_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), - PlanPropertyPath::SequencePath(a, b) => { + PlanPropertyPath::Reverse(p) => self.eval_path_to(p, start, graph_name), + PlanPropertyPath::Sequence(a, b) => { let eval = self.clone(); let b = b.clone(); Box::new( @@ -603,18 +600,18 @@ where .flat_map_ok(move |middle| eval.eval_path_from(&b, middle, graph_name)), ) } - PlanPropertyPath::AlternativePath(a, b) => Box::new( + PlanPropertyPath::Alternative(a, b) => Box::new( self.eval_path_from(a, start, graph_name) .chain(self.eval_path_from(b, start, graph_name)), ), - PlanPropertyPath::ZeroOrMorePath(p) => { + PlanPropertyPath::ZeroOrMore(p) => { let eval = self.clone(); let p = p.clone(); Box::new(transitive_closure(Some(Ok(start)), move |e| { eval.eval_path_from(&p, e, graph_name) })) } - PlanPropertyPath::OneOrMorePath(p) => { + PlanPropertyPath::OneOrMore(p) => { let eval = self.clone(); let p = p.clone(); Box::new(transitive_closure( @@ -622,7 +619,7 @@ where move |e| eval.eval_path_from(&p, e, graph_name), )) } - PlanPropertyPath::ZeroOrOnePath(p) => Box::new(hash_deduplicate( + PlanPropertyPath::ZeroOrOne(p) => Box::new(hash_deduplicate( once(Ok(start)).chain(self.eval_path_from(p, start, graph_name)), )), PlanPropertyPath::NegatedPropertySet(ps) => { @@ -652,13 +649,13 @@ where graph_name: EncodedTerm, ) -> Box, EvaluationError>>> { match path { - PlanPropertyPath::PredicatePath(p) => Box::new( + PlanPropertyPath::Path(p) => Box::new( self.dataset .encoded_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), - PlanPropertyPath::SequencePath(a, b) => { + PlanPropertyPath::Reverse(p) => self.eval_path_from(p, end, graph_name), + PlanPropertyPath::Sequence(a, b) => { let eval = self.clone(); let a = a.clone(); Box::new( @@ -666,18 +663,18 @@ where .flat_map_ok(move |middle| eval.eval_path_to(&a, middle, graph_name)), ) } - PlanPropertyPath::AlternativePath(a, b) => Box::new( + PlanPropertyPath::Alternative(a, b) => Box::new( self.eval_path_to(a, end, graph_name) .chain(self.eval_path_to(b, end, graph_name)), ), - PlanPropertyPath::ZeroOrMorePath(p) => { + PlanPropertyPath::ZeroOrMore(p) => { let eval = self.clone(); let p = p.clone(); Box::new(transitive_closure(Some(Ok(end)), move |e| { eval.eval_path_to(&p, e, graph_name) })) } - PlanPropertyPath::OneOrMorePath(p) => { + PlanPropertyPath::OneOrMore(p) => { let eval = self.clone(); let p = p.clone(); Box::new(transitive_closure( @@ -685,7 +682,7 @@ where move |e| eval.eval_path_to(&p, e, graph_name), )) } - PlanPropertyPath::ZeroOrOnePath(p) => Box::new(hash_deduplicate( + PlanPropertyPath::ZeroOrOne(p) => Box::new(hash_deduplicate( once(Ok(end)).chain(self.eval_path_to(p, end, graph_name)), )), PlanPropertyPath::NegatedPropertySet(ps) => { @@ -718,16 +715,16 @@ where >, > { match path { - PlanPropertyPath::PredicatePath(p) => Box::new( + PlanPropertyPath::Path(p) => Box::new( self.dataset .encoded_quads_for_pattern(None, Some(*p), None, Some(graph_name)) .map(|t| t.map(|t| (t.subject, t.object))), ), - PlanPropertyPath::InversePath(p) => Box::new( + PlanPropertyPath::Reverse(p) => Box::new( self.eval_open_path(p, graph_name) .map(|t| t.map(|(s, o)| (o, s))), ), - PlanPropertyPath::SequencePath(a, b) => { + PlanPropertyPath::Sequence(a, b) => { let eval = self.clone(); let b = b.clone(); Box::new( @@ -738,11 +735,11 @@ where }), ) } - PlanPropertyPath::AlternativePath(a, b) => Box::new( + PlanPropertyPath::Alternative(a, b) => Box::new( self.eval_open_path(a, graph_name) .chain(self.eval_open_path(b, graph_name)), ), - PlanPropertyPath::ZeroOrMorePath(p) => { + PlanPropertyPath::ZeroOrMore(p) => { let eval = self.clone(); let p = p.clone(); Box::new(transitive_closure( @@ -753,7 +750,7 @@ where }, )) } - PlanPropertyPath::OneOrMorePath(p) => { + PlanPropertyPath::OneOrMore(p) => { let eval = self.clone(); let p = p.clone(); Box::new(transitive_closure( @@ -764,7 +761,7 @@ where }, )) } - PlanPropertyPath::ZeroOrOnePath(p) => Box::new(hash_deduplicate( + PlanPropertyPath::ZeroOrOne(p) => Box::new(hash_deduplicate( self.get_subject_or_object_identity_pairs(graph_name) .chain(self.eval_open_path(p, graph_name)), )), @@ -845,11 +842,6 @@ where 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)?; - 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)?, @@ -857,7 +849,7 @@ where )? == Ordering::Greater) .into(), ), - PlanExpression::GreaterOrEq(a, b) => Some( + PlanExpression::GreaterOrEqual(a, b) => Some( match self.partial_cmp_literals( self.eval_expression(a, tuple)?, self.eval_expression(b, tuple)?, @@ -867,14 +859,14 @@ where } .into(), ), - PlanExpression::Lower(a, b) => Some( + PlanExpression::Less(a, b) => Some( (self.partial_cmp_literals( self.eval_expression(a, tuple)?, self.eval_expression(b, tuple)?, )? == Ordering::Less) .into(), ), - PlanExpression::LowerOrEq(a, b) => Some( + PlanExpression::LessOrEqual(a, b) => Some( match self.partial_cmp_literals( self.eval_expression(a, tuple)?, self.eval_expression(b, tuple)?, @@ -938,46 +930,52 @@ where } _ => None, }, - 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(), - NumericBinaryOperands::DateTime(v1, v2) => v1.checked_sub(v2)?.into(), - NumericBinaryOperands::Date(v1, v2) => v1.checked_sub(v2)?.into(), - NumericBinaryOperands::Time(v1, v2) => v1.checked_sub(v2)?.into(), - NumericBinaryOperands::Duration(v1, v2) => v1.checked_sub(v2)?.into(), - NumericBinaryOperands::YearMonthDuration(v1, v2) => v1.checked_sub(v2)?.into(), - NumericBinaryOperands::DayTimeDuration(v1, v2) => v1.checked_sub(v2)?.into(), - NumericBinaryOperands::DateTimeDuration(v1, v2) => { - v1.checked_sub_duration(v2)?.into() - } - NumericBinaryOperands::DateTimeYearMonthDuration(v1, v2) => { - v1.checked_sub_year_month_duration(v2)?.into() - } - NumericBinaryOperands::DateTimeDayTimeDuration(v1, v2) => { - v1.checked_sub_day_time_duration(v2)?.into() - } - NumericBinaryOperands::DateDuration(v1, v2) => v1.checked_sub_duration(v2)?.into(), - NumericBinaryOperands::DateYearMonthDuration(v1, v2) => { - v1.checked_sub_year_month_duration(v2)?.into() - } - NumericBinaryOperands::DateDayTimeDuration(v1, v2) => { - v1.checked_sub_day_time_duration(v2)?.into() - } - NumericBinaryOperands::TimeDuration(v1, v2) => v1.checked_sub_duration(v2)?.into(), - NumericBinaryOperands::TimeDayTimeDuration(v1, v2) => { - v1.checked_sub_day_time_duration(v2)?.into() - } - }), - PlanExpression::Mul(a, b) => match self.parse_numeric_operands(a, b, tuple)? { + PlanExpression::Subtract(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(), + NumericBinaryOperands::DateTime(v1, v2) => v1.checked_sub(v2)?.into(), + NumericBinaryOperands::Date(v1, v2) => v1.checked_sub(v2)?.into(), + NumericBinaryOperands::Time(v1, v2) => v1.checked_sub(v2)?.into(), + NumericBinaryOperands::Duration(v1, v2) => v1.checked_sub(v2)?.into(), + NumericBinaryOperands::YearMonthDuration(v1, v2) => v1.checked_sub(v2)?.into(), + NumericBinaryOperands::DayTimeDuration(v1, v2) => v1.checked_sub(v2)?.into(), + NumericBinaryOperands::DateTimeDuration(v1, v2) => { + v1.checked_sub_duration(v2)?.into() + } + NumericBinaryOperands::DateTimeYearMonthDuration(v1, v2) => { + v1.checked_sub_year_month_duration(v2)?.into() + } + NumericBinaryOperands::DateTimeDayTimeDuration(v1, v2) => { + v1.checked_sub_day_time_duration(v2)?.into() + } + NumericBinaryOperands::DateDuration(v1, v2) => { + v1.checked_sub_duration(v2)?.into() + } + NumericBinaryOperands::DateYearMonthDuration(v1, v2) => { + v1.checked_sub_year_month_duration(v2)?.into() + } + NumericBinaryOperands::DateDayTimeDuration(v1, v2) => { + v1.checked_sub_day_time_duration(v2)?.into() + } + NumericBinaryOperands::TimeDuration(v1, v2) => { + v1.checked_sub_duration(v2)?.into() + } + NumericBinaryOperands::TimeDayTimeDuration(v1, v2) => { + v1.checked_sub_day_time_duration(v2)?.into() + } + }) + } + PlanExpression::Multiply(a, b) => match self.parse_numeric_operands(a, b, tuple)? { NumericBinaryOperands::Float(v1, v2) => Some((v1 * v2).into()), NumericBinaryOperands::Double(v1, v2) => Some((v1 * v2).into()), NumericBinaryOperands::Integer(v1, v2) => Some(v1.checked_mul(v2)?.into()), NumericBinaryOperands::Decimal(v1, v2) => Some(v1.checked_mul(v2)?.into()), _ => None, }, - PlanExpression::Div(a, b) => match self.parse_numeric_operands(a, b, tuple)? { + PlanExpression::Divide(a, b) => match self.parse_numeric_operands(a, b, tuple)? { NumericBinaryOperands::Float(v1, v2) => Some((v1 / v2).into()), NumericBinaryOperands::Double(v1, v2) => Some((v1 / v2).into()), NumericBinaryOperands::Integer(v1, v2) => { @@ -1006,7 +1004,7 @@ where EncodedTerm::DayTimeDurationLiteral(value) => Some((-value).into()), _ => None, }, - PlanExpression::UnaryNot(e) => self + PlanExpression::Not(e) => self .to_bool(self.eval_expression(e, tuple)?) .map(|v| (!v).into()), PlanExpression::Str(e) => { diff --git a/lib/src/sparql/mod.rs b/lib/src/sparql/mod.rs index f7242203..2bd617a7 100644 --- a/lib/src/sparql/mod.rs +++ b/lib/src/sparql/mod.rs @@ -2,7 +2,7 @@ //! //! Stores execute SPARQL. See [`MemoryStore`](super::store::memory::MemoryStore::query()) for an example. -mod algebra; +pub mod algebra; mod csv_results; mod dataset; mod error; @@ -17,7 +17,6 @@ mod service; mod update; mod xml_results; -use crate::sparql::algebra::QueryVariants; pub use crate::sparql::algebra::{Query, Update}; use crate::sparql::dataset::DatasetView; pub use crate::sparql::error::EvaluationError; @@ -44,48 +43,64 @@ pub(crate) fn evaluate_query( query: impl TryInto>, options: QueryOptions, ) -> Result { - match query.try_into().map_err(|e| e.into())?.0 { - QueryVariants::Select { - algebra, + match query.try_into().map_err(|e| e.into())? { + Query::Select { + pattern, base_iri, dataset, } => { let dataset = DatasetView::new(store, &dataset)?; - let (plan, variables) = PlanBuilder::build(&dataset, &algebra)?; - SimpleEvaluator::new(Rc::new(dataset), base_iri, options.service_handler) - .evaluate_select_plan(&plan, Rc::new(variables)) + let (plan, variables) = PlanBuilder::build(&dataset, &pattern)?; + SimpleEvaluator::new( + Rc::new(dataset), + base_iri.map(Rc::new), + options.service_handler, + ) + .evaluate_select_plan(&plan, Rc::new(variables)) } - QueryVariants::Ask { - algebra, + Query::Ask { + pattern, base_iri, dataset, } => { let dataset = DatasetView::new(store, &dataset)?; - let (plan, _) = PlanBuilder::build(&dataset, &algebra)?; - SimpleEvaluator::new(Rc::new(dataset), base_iri, options.service_handler) - .evaluate_ask_plan(&plan) + let (plan, _) = PlanBuilder::build(&dataset, &pattern)?; + SimpleEvaluator::new( + Rc::new(dataset), + base_iri.map(Rc::new), + options.service_handler, + ) + .evaluate_ask_plan(&plan) } - QueryVariants::Construct { - construct, - algebra, + Query::Construct { + template, + pattern, base_iri, dataset, } => { let dataset = DatasetView::new(store, &dataset)?; - let (plan, variables) = PlanBuilder::build(&dataset, &algebra)?; - let construct = PlanBuilder::build_graph_template(&dataset, &construct, variables)?; - SimpleEvaluator::new(Rc::new(dataset), base_iri, options.service_handler) - .evaluate_construct_plan(&plan, construct) + let (plan, variables) = PlanBuilder::build(&dataset, &pattern)?; + let construct = PlanBuilder::build_graph_template(&dataset, &template, variables)?; + SimpleEvaluator::new( + Rc::new(dataset), + base_iri.map(Rc::new), + options.service_handler, + ) + .evaluate_construct_plan(&plan, construct) } - QueryVariants::Describe { - algebra, + Query::Describe { + pattern, base_iri, dataset, } => { let dataset = DatasetView::new(store, &dataset)?; - let (plan, _) = PlanBuilder::build(&dataset, &algebra)?; - SimpleEvaluator::new(Rc::new(dataset), base_iri, options.service_handler) - .evaluate_describe_plan(&plan) + let (plan, _) = PlanBuilder::build(&dataset, &pattern)?; + SimpleEvaluator::new( + Rc::new(dataset), + base_iri.map(Rc::new), + options.service_handler, + ) + .evaluate_describe_plan(&plan) } } } @@ -135,7 +150,7 @@ pub(crate) fn evaluate_update< >( read: R, write: &mut W, - update: &Update, + update: Update, ) -> Result<(), EvaluationError> where io::Error: From>, @@ -143,7 +158,7 @@ where SimpleUpdateEvaluator::new( read, write, - update.base_iri.clone(), + update.base_iri.map(Rc::new), Rc::new(EmptyServiceHandler), ) .eval_all(&update.operations) diff --git a/lib/src/sparql/parser.rs b/lib/src/sparql/parser.rs index bb38e4d3..2aa39167 100644 --- a/lib/src/sparql/parser.rs +++ b/lib/src/sparql/parser.rs @@ -18,45 +18,41 @@ use std::{char, fmt}; pub fn parse_query(query: &str, base_iri: Option<&str>) -> Result { let mut state = ParserState { base_iri: if let Some(base_iri) = base_iri { - Some(Rc::new(Iri::parse(base_iri.to_owned()).map_err(|e| { - ParseError { - inner: ParseErrorKind::InvalidBaseIri(e), - } - })?)) + Some(Iri::parse(base_iri.to_owned()).map_err(|e| ParseError { + inner: ParseErrorKind::InvalidBaseIri(e), + })?) } else { None }, namespaces: HashMap::default(), used_bnodes: HashSet::default(), currently_used_bnodes: HashSet::default(), - aggregations: Vec::default(), + aggregates: Vec::default(), }; - Ok(Query( + Ok( parser::QueryUnit(&unescape_unicode_codepoints(query), &mut state).map_err(|e| { ParseError { inner: ParseErrorKind::Parser(e), } })?, - )) + ) } /// Parses a SPARQL update with an optional base IRI to resolve relative IRIs in the query pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result { let mut state = ParserState { base_iri: if let Some(base_iri) = base_iri { - Some(Rc::new(Iri::parse(base_iri.to_owned()).map_err(|e| { - ParseError { - inner: ParseErrorKind::InvalidBaseIri(e), - } - })?)) + Some(Iri::parse(base_iri.to_owned()).map_err(|e| ParseError { + inner: ParseErrorKind::InvalidBaseIri(e), + })?) } else { None }, namespaces: HashMap::default(), used_bnodes: HashSet::default(), currently_used_bnodes: HashSet::default(), - aggregations: Vec::default(), + aggregates: Vec::default(), }; let operations = @@ -131,7 +127,7 @@ impl From> for FocusedTriplePattern> { #[derive(Clone)] enum VariableOrPropertyPath { Variable(Variable), - PropertyPath(PropertyPath), + PropertyPath(PropertyPathExpression), } impl From for VariableOrPropertyPath { @@ -140,8 +136,8 @@ impl From for VariableOrPropertyPath { } } -impl From for VariableOrPropertyPath { - fn from(path: PropertyPath) -> Self { +impl From for VariableOrPropertyPath { + fn from(path: PropertyPathExpression) -> Self { VariableOrPropertyPath::PropertyPath(path) } } @@ -157,22 +153,68 @@ fn add_to_triple_or_path_patterns( patterns.push(TriplePattern::new(subject, p, object).into()) } VariableOrPropertyPath::PropertyPath(p) => match p { - PropertyPath::PredicatePath(p) => { + PropertyPathExpression::NamedNode(p) => { patterns.push(TriplePattern::new(subject, p, object).into()) } - PropertyPath::InversePath(p) => { + PropertyPathExpression::Reverse(p) => { add_to_triple_or_path_patterns(object, *p, subject, patterns) } - PropertyPath::SequencePath(a, b) => { + PropertyPathExpression::Sequence(a, b) => { let middle = BlankNode::default(); add_to_triple_or_path_patterns(subject, *a, middle.clone().into(), patterns); add_to_triple_or_path_patterns(middle.into(), *b, object, patterns); } - p => patterns.push(PathPattern::new(subject, p, object).into()), + path => patterns.push(TripleOrPathPattern::Path { + subject, + path, + object, + }), }, } } +fn build_bgp(patterns: Vec) -> GraphPattern { + let mut bgp = Vec::with_capacity(patterns.len()); + let mut paths = Vec::with_capacity(patterns.len()); + for pattern in patterns { + match pattern { + TripleOrPathPattern::Triple(t) => bgp.push(t), + TripleOrPathPattern::Path { + subject, + path, + object, + } => paths.push((subject, path, object)), + } + } + let mut graph_pattern = GraphPattern::BGP(bgp); + for (subject, path, object) in paths { + graph_pattern = new_join( + graph_pattern, + GraphPattern::Path { + subject, + path, + object, + }, + ) + } + graph_pattern +} + +enum TripleOrPathPattern { + Triple(TriplePattern), + Path { + subject: TermOrVariable, + path: PropertyPathExpression, + object: TermOrVariable, + }, +} + +impl From for TripleOrPathPattern { + fn from(tp: TriplePattern) -> Self { + TripleOrPathPattern::Triple(tp) + } +} + struct FocusedTripleOrPathPattern { focus: F, patterns: Vec, @@ -239,14 +281,29 @@ fn new_join(l: GraphPattern, r: GraphPattern) -> GraphPattern { //Merge BGPs match (l, r) { (GraphPattern::BGP(mut pl), GraphPattern::BGP(pr)) => { - pl.extend_from_slice(&pr); + pl.extend(pr); GraphPattern::BGP(pl) } - (GraphPattern::Graph(g1, l), GraphPattern::Graph(g2, r)) if g1 == g2 => { + ( + GraphPattern::Graph { + graph_name: g1, + inner: l, + }, + GraphPattern::Graph { + graph_name: g2, + inner: r, + }, + ) if g1 == g2 => { // We merge identical graphs - GraphPattern::Graph(g1, Box::new(new_join(*l, *r))) + GraphPattern::Graph { + graph_name: g1, + inner: Box::new(new_join(*l, *r)), + } } - (l, r) => GraphPattern::Join(Box::new(l), Box::new(r)), + (l, r) => GraphPattern::Join { + left: Box::new(l), + right: Box::new(r), + }, } } @@ -299,8 +356,8 @@ fn build_select( let mut p = wher; //GROUP BY - let aggregations = state.aggregations.pop().unwrap_or_else(Vec::default); - if group.is_none() && !aggregations.is_empty() { + let aggregates = state.aggregates.pop().unwrap_or_else(Vec::default); + if group.is_none() && !aggregates.is_empty() { let const_variable = Variable::new_random(); group = Some(( vec![const_variable.clone()], @@ -309,16 +366,26 @@ fn build_select( } if let Some((clauses, binds)) = group { - for (e, v) in binds { - p = GraphPattern::Extend(Box::new(p), v, e); - } - let g = GroupPattern(clauses, Box::new(p)); - p = GraphPattern::AggregateJoin(g, aggregations); + for (expr, var) in binds { + p = GraphPattern::Extend { + inner: Box::new(p), + var, + expr, + }; + } + p = GraphPattern::Group { + inner: Box::new(p), + by: clauses, + aggregates, + }; } //HAVING - if let Some(ex) = having { - p = GraphPattern::Filter(ex, Box::new(p)); + if let Some(expr) = having { + p = GraphPattern::Filter { + expr, + inner: Box::new(p), + }; } //VALUES @@ -333,11 +400,15 @@ fn build_select( for sel_item in sel_items { match sel_item { SelectionMember::Variable(v) => pv.push(v), - SelectionMember::Expression(e, v) => { + SelectionMember::Expression(expr, v) => { if pv.contains(&v) { //TODO: fail } else { - p = GraphPattern::Extend(Box::new(p), v.clone(), e); + p = GraphPattern::Extend { + inner: Box::new(p), + var: v.clone(), + expr, + }; pv.push(v); } } @@ -351,50 +422,58 @@ fn build_select( let mut m = p; //ORDER BY - if let Some(order) = order_by { - m = GraphPattern::OrderBy(Box::new(m), order); + if let Some(condition) = order_by { + m = GraphPattern::OrderBy { + inner: Box::new(m), + condition, + }; } //PROJECT - m = GraphPattern::Project(Box::new(m), pv); + m = GraphPattern::Project { + inner: Box::new(m), + projection: pv, + }; match select.option { - SelectionOption::Distinct => m = GraphPattern::Distinct(Box::new(m)), - SelectionOption::Reduced => m = GraphPattern::Reduced(Box::new(m)), + SelectionOption::Distinct => m = GraphPattern::Distinct { inner: Box::new(m) }, + SelectionOption::Reduced => m = GraphPattern::Reduced { inner: Box::new(m) }, SelectionOption::Default => (), } //OFFSET LIMIT - if let Some((offset, limit)) = offset_limit { - m = GraphPattern::Slice(Box::new(m), offset, limit) + if let Some((start, length)) = offset_limit { + m = GraphPattern::Slice { + inner: Box::new(m), + start, + length, + } } m } -fn copy_graph( - from: NamedOrDefaultGraphTarget, - to: impl Into>, -) -> GraphUpdateOperation { +fn copy_graph(from: Option, to: Option) -> GraphUpdateOperation { let bgp = GraphPattern::BGP(vec![TriplePattern::new( Variable::new_unchecked("s"), Variable::new_unchecked("p"), Variable::new_unchecked("o"), - ) - .into()]); + )]); GraphUpdateOperation::DeleteInsert { delete: Vec::new(), insert: vec![QuadPattern::new( Variable::new_unchecked("s"), Variable::new_unchecked("p"), Variable::new_unchecked("o"), - to.into(), + to, )], using: QueryDataset::default(), - algebra: match from { - NamedOrDefaultGraphTarget::NamedNode(from) => { - GraphPattern::Graph(from.into(), Box::new(bgp)) + pattern: Box::new(if let Some(from) = from { + GraphPattern::Graph { + graph_name: from.into(), + inner: Box::new(bgp), } - NamedOrDefaultGraphTarget::DefaultGraph => bgp, - }, + } else { + bgp + }), } } @@ -404,11 +483,11 @@ enum Either { } pub struct ParserState { - base_iri: Option>>, + base_iri: Option>, namespaces: HashMap, used_bnodes: HashSet, currently_used_bnodes: HashSet, - aggregations: Vec>, + aggregates: Vec>, } impl ParserState { @@ -420,15 +499,15 @@ impl ParserState { } } - fn new_aggregation(&mut self, agg: Aggregation) -> Result { - let aggregations = self.aggregations.last_mut().ok_or("Unexpected aggregate")?; - Ok(aggregations + fn new_aggregation(&mut self, agg: SetFunction) -> Result { + let aggregates = self.aggregates.last_mut().ok_or("Unexpected aggregate")?; + Ok(aggregates .iter() - .find_map(|(a, v)| if a == &agg { Some(v) } else { None }) + .find_map(|(v, a)| if a == &agg { Some(v) } else { None }) .cloned() .unwrap_or_else(|| { let new_var = Variable::new_random(); - aggregations.push((agg, new_var.clone())); + aggregates.push((new_var.clone(), agg)); new_var })) } @@ -642,10 +721,10 @@ parser! { //See https://www.w3.org/TR/turtle/#sec-grammar grammar parser(state: &mut ParserState) for str { //[1] - pub rule QueryUnit() -> QueryVariants = Query() + pub rule QueryUnit() -> Query = Query() //[2] - rule Query() -> QueryVariants = _ Prologue() _ q:(SelectQuery() / ConstructQuery() / DescribeQuery() / AskQuery()) _ { + rule Query() -> Query = _ Prologue() _ q:(SelectQuery() / ConstructQuery() / DescribeQuery() / AskQuery()) _ { q } @@ -657,7 +736,7 @@ parser! { //[5] rule BaseDecl() = i("BASE") _ i:IRIREF() { - state.base_iri = Some(Rc::new(i)) + state.base_iri = Some(i) } //[6] @@ -666,10 +745,10 @@ parser! { } //[7] - rule SelectQuery() -> QueryVariants = s:SelectClause() _ d:DatasetClauses() _ w:WhereClause() _ g:GroupClause()? _ h:HavingClause()? _ o:OrderClause()? _ l:LimitOffsetClauses()? _ v:ValuesClause() { - QueryVariants::Select { + rule SelectQuery() -> Query = s:SelectClause() _ d:DatasetClauses() _ w:WhereClause() _ g:GroupClause()? _ h:HavingClause()? _ o:OrderClause()? _ l:LimitOffsetClauses()? _ v:ValuesClause() { + Query::Select { dataset: d, - algebra: Rc::new(build_select(s, w, g, h, o, l, v, state)), + pattern: build_select(s, w, g, h, o, l, v, state), base_iri: state.base_iri.clone() } } @@ -687,7 +766,7 @@ parser! { } } rule Selection_init() = { - state.aggregations.push(Vec::default()) + state.aggregates.push(Vec::default()) } rule SelectClause_option() -> SelectionOption = i("DISTINCT") { SelectionOption::Distinct } / @@ -701,24 +780,24 @@ parser! { "(" _ e:Expression() _ i("AS") _ v:Var() _ ")" _ { SelectionMember::Expression(e, v) } //[10] - rule ConstructQuery() -> QueryVariants = + rule ConstructQuery() -> Query = i("CONSTRUCT") _ c:ConstructTemplate() _ d:DatasetClauses() _ w:WhereClause() _ g:GroupClause()? _ h:HavingClause()? _ o:OrderClause()? _ l:LimitOffsetClauses()? _ v:ValuesClause() { - QueryVariants::Construct { - construct: Rc::new(c), + Query::Construct { + template: c, dataset: d, - algebra: Rc::new(build_select(Selection::default(), w, g, h, o, l, v, state)), + pattern: build_select(Selection::default(), w, g, h, o, l, v, state), base_iri: state.base_iri.clone() } } / i("CONSTRUCT") _ d:DatasetClauses() _ i("WHERE") _ "{" _ c:ConstructQuery_optional_triple_template() _ "}" _ g:GroupClause()? _ h:HavingClause()? _ o:OrderClause()? _ l:LimitOffsetClauses()? _ v:ValuesClause() { - QueryVariants::Construct { - construct: Rc::new(c.clone()), + Query::Construct { + template: c.clone(), dataset: d, - algebra: Rc::new(build_select( + pattern: build_select( Selection::default(), - GraphPattern::BGP(c.into_iter().map(TripleOrPathPattern::from).collect()), + GraphPattern::BGP(c), g, h, o, l, v, state - )), + ), base_iri: state.base_iri.clone() } } @@ -726,34 +805,34 @@ parser! { rule ConstructQuery_optional_triple_template() -> Vec = TriplesTemplate() / { Vec::default() } //[11] - rule DescribeQuery() -> QueryVariants = + rule DescribeQuery() -> Query = i("DESCRIBE") _ "*" _ d:DatasetClauses() w:WhereClause()? _ g:GroupClause()? _ h:HavingClause()? _ o:OrderClause()? _ l:LimitOffsetClauses()? _ v:ValuesClause() { - QueryVariants::Describe { + Query::Describe { dataset: d, - algebra: Rc::new(build_select(Selection::default(), w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state)), + pattern: build_select(Selection::default(), w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state), base_iri: state.base_iri.clone() } } / i("DESCRIBE") _ p:DescribeQuery_item()+ _ d:DatasetClauses() w:WhereClause()? _ g:GroupClause()? _ h:HavingClause()? _ o:OrderClause()? _ l:LimitOffsetClauses()? _ v:ValuesClause() { - QueryVariants::Describe { + Query::Describe { dataset: d, - algebra: Rc::new(build_select(Selection { + pattern: build_select(Selection { option: SelectionOption::Default, variables: Some(p.into_iter().map(|var_or_iri| match var_or_iri { NamedNodeOrVariable::NamedNode(n) => SelectionMember::Expression(n.into(), Variable::new_random()), NamedNodeOrVariable::Variable(v) => SelectionMember::Variable(v) }).collect()) - }, w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state)), + }, w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state), base_iri: state.base_iri.clone() } } rule DescribeQuery_item() -> NamedNodeOrVariable = i:VarOrIri() _ { i } //[12] - rule AskQuery() -> QueryVariants = i("ASK") _ d:DatasetClauses() w:WhereClause() _ g:GroupClause()? _ h:HavingClause()? _ o:OrderClause()? _ l:LimitOffsetClauses()? _ v:ValuesClause() { - QueryVariants::Ask { + rule AskQuery() -> Query = i("ASK") _ d:DatasetClauses() w:WhereClause() _ g:GroupClause()? _ h:HavingClause()? _ o:OrderClause()? _ l:LimitOffsetClauses()? _ v:ValuesClause() { + Query::Ask { dataset: d, - algebra: Rc::new(build_select(Selection::default(), w, g, h, o, l, v, state)), + pattern: Rc::new(build_select(Selection::default(), w, g, h, o, l, v, state)), base_iri: state.base_iri.clone() } } @@ -837,8 +916,8 @@ parser! { rule OrderCondition() -> OrderComparator = i("ASC") _ e: BrackettedExpression() { OrderComparator::Asc(e) } / i("DESC") _ e: BrackettedExpression() { OrderComparator::Desc(e) } / - e: Constraint() { e.into() } / - v: Var() { Expression::from(v).into() } + e: Constraint() { OrderComparator::Asc(e) } / + v: Var() { OrderComparator::Asc(Expression::from(v)) } //[25] rule LimitOffsetClauses() -> (usize, Option) = @@ -895,8 +974,8 @@ parser! { if from == to { Vec::new() // identity case } else { - let bgp = GraphPattern::BGP(vec![TriplePattern::new(Variable::new_unchecked("s"), Variable::new_unchecked("p"), Variable::new_unchecked("o")).into()]); - vec![copy_graph(from, to)] + let bgp = GraphPattern::BGP(vec![TriplePattern::new(Variable::new_unchecked("s"), Variable::new_unchecked("p"), Variable::new_unchecked("o"))]); + vec![copy_graph(from, to.map(NamedNodeOrVariable::NamedNode))] } } @@ -906,8 +985,8 @@ parser! { if from == to { Vec::new() // identity case } else { - let bgp = GraphPattern::BGP(vec![TriplePattern::new(Variable::new_unchecked("s"), Variable::new_unchecked("p"), Variable::new_unchecked("o")).into()]); - vec![GraphUpdateOperation::Drop { silent, graph: to.clone().into() }, copy_graph(from.clone(), to), GraphUpdateOperation::Drop { silent, graph: from.into() }] + let bgp = GraphPattern::BGP(vec![TriplePattern::new(Variable::new_unchecked("s"), Variable::new_unchecked("p"), Variable::new_unchecked("o"))]); + vec![GraphUpdateOperation::Drop { silent, graph: to.clone().map_or(GraphTarget::DefaultGraph, GraphTarget::NamedNode) }, copy_graph(from.clone(), to.map(NamedNodeOrVariable::NamedNode)), GraphUpdateOperation::Drop { silent, graph: from.map_or(GraphTarget::DefaultGraph, GraphTarget::NamedNode) }] } } @@ -917,8 +996,8 @@ parser! { if from == to { Vec::new() // identity case } else { - let bgp = GraphPattern::BGP(vec![TriplePattern::new(Variable::new_unchecked("s"), Variable::new_unchecked("p"), Variable::new_unchecked("o")).into()]); - vec![GraphUpdateOperation::Drop { silent, graph: to.clone().into() }, copy_graph(from, to)] + let bgp = GraphPattern::BGP(vec![TriplePattern::new(Variable::new_unchecked("s"), Variable::new_unchecked("p"), Variable::new_unchecked("o"))]); + vec![GraphUpdateOperation::Drop { silent, graph: to.clone().map_or(GraphTarget::DefaultGraph, GraphTarget::NamedNode) }, copy_graph(from, to.map(NamedNodeOrVariable::NamedNode))] } } @@ -934,10 +1013,10 @@ parser! { //[40] rule DeleteWhere() -> Vec = i("DELETE") _ i("WHERE") _ d:QuadData() { - let algebra = d.iter().map(|q| { - let bgp = GraphPattern::BGP(vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone()).into()]); + let pattern = d.iter().map(|q| { + let bgp = GraphPattern::BGP(vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone())]); if let Some(graph_name) = &q.graph_name { - GraphPattern::Graph(graph_name.clone(), Box::new(bgp)) + GraphPattern::Graph { graph_name: graph_name.clone(), inner: Box::new(bgp) } } else { bgp } @@ -946,16 +1025,16 @@ parser! { delete: d, insert: Vec::new(), using: QueryDataset::default(), - algebra + pattern: Box::new(pattern) }] } //[41] - rule Modify() -> Vec = with:Modify_with()? _ Modify_clear() c:Modify_clauses() _ u:(UsingClause() ** (_)) _ i("WHERE") _ algebra:GroupGraphPattern() { + rule Modify() -> Vec = with:Modify_with()? _ Modify_clear() c:Modify_clauses() _ u:(UsingClause() ** (_)) _ i("WHERE") _ pattern:GroupGraphPattern() { let (delete, insert) = c; let mut delete = delete.unwrap_or_else(Vec::new); let mut insert = insert.unwrap_or_else(Vec::new); - let mut algebra = algebra; + let mut pattern = pattern; if let Some(with) = with { // We inject WITH everywhere @@ -969,7 +1048,7 @@ parser! { } else { q }).collect(); - algebra = GraphPattern::Graph(with.into(), Box::new(algebra)); + pattern = GraphPattern::Graph { graph_name: with.into(), inner: Box::new(pattern) }; } let mut using = QueryDataset::default(); @@ -992,7 +1071,7 @@ parser! { delete, insert, using, - algebra + pattern: Box::new(pattern) }] } rule Modify_with() -> NamedNode = i("WITH") _ i:iri() _ { i } @@ -1022,10 +1101,10 @@ parser! { } //[45] - rule GraphOrDefault() -> NamedOrDefaultGraphTarget = i("DEFAULT") { - NamedOrDefaultGraphTarget::DefaultGraph + rule GraphOrDefault() -> Option = i("DEFAULT") { + None } / (i("GRAPH") _)? g:iri() { - NamedOrDefaultGraphTarget::NamedNode(g) + Some(g) } //[46] @@ -1061,7 +1140,7 @@ parser! { rule TriplesTemplate() -> Vec = h:TriplesSameSubject() _ t:TriplesTemplate_tail()? { let mut triples = h; if let Some(l) = t { - triples.extend_from_slice(&l) + triples.extend(l) } triples } @@ -1076,22 +1155,22 @@ parser! { //[54] rule GroupGraphPatternSub() -> GraphPattern = a:TriplesBlock()? _ b:GroupGraphPatternSub_item()* { - let mut p = a.map_or_else(Vec::default, |v| vec![PartialGraphPattern::Other(GraphPattern::BGP(v))]); + let mut p = a.map_or_else(Vec::default, |v| vec![PartialGraphPattern::Other(build_bgp(v))]); for v in b { - p.extend_from_slice(&v) + p.extend(v) } let mut filter: Option = None; let mut g = GraphPattern::default(); for e in p { match e { PartialGraphPattern::Optional(p, f) => { - g = GraphPattern::LeftJoin(Box::new(g), Box::new(p), f) + g = GraphPattern::LeftJoin { left: Box::new(g), right: Box::new(p), expr: f } } PartialGraphPattern::Minus(p) => { - g = GraphPattern::Minus(Box::new(g), Box::new(p)) + g = GraphPattern::Minus { left: Box::new(g), right: Box::new(p) } } PartialGraphPattern::Bind(expr, var) => { - g = GraphPattern::Extend(Box::new(g), var, expr) + g = GraphPattern::Extend { inner: Box::new(g), var, expr } } PartialGraphPattern::Filter(expr) => filter = Some(if let Some(f) = filter { Expression::And(Box::new(f), Box::new(expr)) @@ -1106,8 +1185,8 @@ parser! { state.used_bnodes.extend(state.currently_used_bnodes.iter().cloned()); state.currently_used_bnodes.clear(); - if let Some(filter) = filter { - GraphPattern::Filter(filter, Box::new(g)) + if let Some(expr) = filter { + GraphPattern::Filter { expr, inner: Box::new(g) } } else { g } @@ -1115,7 +1194,7 @@ parser! { rule GroupGraphPatternSub_item() -> Vec = a:GraphPatternNotTriples() _ ("." _)? b:TriplesBlock()? _ { let mut result = vec![a]; if let Some(v) = b { - result.push(PartialGraphPattern::Other(GraphPattern::BGP(v))); + result.push(PartialGraphPattern::Other(build_bgp(v))); } result } @@ -1124,7 +1203,7 @@ parser! { rule TriplesBlock() -> Vec = h:TriplesSameSubjectPath() _ t:TriplesBlock_tail()? { let mut triples = h; if let Some(l) = t { - triples.extend_from_slice(&l) + triples.extend(l) } triples } @@ -1137,22 +1216,22 @@ parser! { //[57] rule OptionalGraphPattern() -> PartialGraphPattern = i("OPTIONAL") _ p:GroupGraphPattern() { - if let GraphPattern::Filter(f, p) = p { - PartialGraphPattern::Optional(*p, Some(f)) + if let GraphPattern::Filter { expr, inner } = p { + PartialGraphPattern::Optional(*inner, Some(expr)) } else { PartialGraphPattern::Optional(p, None) } } //[58] - rule GraphGraphPattern() -> PartialGraphPattern = i("GRAPH") _ g:VarOrIri() _ p:GroupGraphPattern() { - PartialGraphPattern::Other(GraphPattern::Graph(g, Box::new(p))) + rule GraphGraphPattern() -> PartialGraphPattern = i("GRAPH") _ graph_name:VarOrIri() _ p:GroupGraphPattern() { + PartialGraphPattern::Other(GraphPattern::Graph { graph_name, inner: Box::new(p) }) } //[59] rule ServiceGraphPattern() -> PartialGraphPattern = - i("SERVICE") _ i("SILENT") _ s:VarOrIri() _ p:GroupGraphPattern() { PartialGraphPattern::Other(GraphPattern::Service(s, Box::new(p), true)) } / - i("SERVICE") _ s:VarOrIri() _ p:GroupGraphPattern() { PartialGraphPattern::Other(GraphPattern::Service(s, Box::new(p), false)) } + i("SERVICE") _ i("SILENT") _ name:VarOrIri() _ p:GroupGraphPattern() { PartialGraphPattern::Other(GraphPattern::Service { name, pattern: Box::new(p), silent: true }) } / + i("SERVICE") _ name:VarOrIri() _ p:GroupGraphPattern() { PartialGraphPattern::Other(GraphPattern::Service{ name, pattern: Box::new(p), silent: true }) } //[60] rule Bind() -> PartialGraphPattern = i("BIND") _ "(" _ e:Expression() _ i("AS") _ v:Var() _ ")" { @@ -1164,18 +1243,18 @@ parser! { //[62] rule DataBlock() -> GraphPattern = l:(InlineDataOneVar() / InlineDataFull()) { - GraphPattern::Data(l) + GraphPattern::Table { variables: l.0, rows: l.1 } } //[63] - rule InlineDataOneVar() -> StaticBindings = var:Var() _ "{" _ d:InlineDataOneVar_value()* "}" { - StaticBindings::new(vec![var], d) + rule InlineDataOneVar() -> (Vec, Vec>>) = var:Var() _ "{" _ d:InlineDataOneVar_value()* "}" { + (vec![var], d) } rule InlineDataOneVar_value() -> Vec> = t:DataBlockValue() _ { vec![t] } //[64] - rule InlineDataFull() -> StaticBindings = "(" _ vars:InlineDataFull_var()* _ ")" _ "{" _ val:InlineDataFull_values()* "}" { - StaticBindings::new(vars, val) + rule InlineDataFull() -> (Vec, Vec>>) = "(" _ vars:InlineDataFull_var()* _ ")" _ "{" _ val:InlineDataFull_values()* "}" { + (vars, val) } rule InlineDataFull_var() -> Variable = v:Var() _ { v } rule InlineDataFull_values() -> Vec> = "(" _ v:InlineDataFull_value()* _ ")" _ { v } @@ -1197,7 +1276,7 @@ parser! { //[67] rule GroupOrUnionGraphPattern() -> PartialGraphPattern = p:GroupOrUnionGraphPattern_item() **<1,> (i("UNION") _) {? not_empty_fold(p.into_iter(), |a, b| { - GraphPattern::Union(Box::new(a), Box::new(b)) + GraphPattern::Union { left: Box::new(a), right: Box::new(b) } }).map(PartialGraphPattern::Other) } rule GroupOrUnionGraphPattern_item() -> GraphPattern = p:GroupGraphPattern() _ { p } @@ -1249,7 +1328,7 @@ parser! { } / s:TriplesNode() _ po:PropertyList() { let mut patterns = s.patterns; - patterns.extend_from_slice(&po.patterns); + patterns.extend(po.patterns); for (p, os) in po.focus { for o in os { patterns.push(TriplePattern::new(s.focus.clone(), p.clone(), o)) @@ -1267,7 +1346,7 @@ parser! { rule PropertyListNotEmpty() -> FocusedTriplePattern)>> = l:PropertyListNotEmpty_item() **<1,> (";" _) { l.into_iter().fold(FocusedTriplePattern::)>>::default(), |mut a, b| { a.focus.push(b.focus); - a.patterns.extend_from_slice(&b.patterns); + a.patterns.extend(b.patterns); a }) } @@ -1279,7 +1358,7 @@ parser! { } //[78] - rule Verb() -> NamedNodeOrVariable = VarOrIri() / "a" { rdf::TYPE.into() } + rule Verb() -> NamedNodeOrVariable = VarOrIri() / "a" { rdf::TYPE.into_owned().into() } //[79] rule ObjectList() -> FocusedTriplePattern> = o:ObjectList_item() **<1,> ("," _) { @@ -1307,7 +1386,7 @@ parser! { } / s:TriplesNodePath() _ po:PropertyListPath() { let mut patterns = s.patterns; - patterns.extend_from_slice(&po.patterns); + patterns.extend(po.patterns); for (p, os) in po.focus { for o in os { add_to_triple_or_path_patterns(s.focus.clone(), p.clone(), o, &mut patterns); @@ -1356,7 +1435,7 @@ parser! { rule ObjectListPath() -> FocusedTripleOrPathPattern> = o:ObjectPath_item() **<1,> ("," _) { o.into_iter().fold(FocusedTripleOrPathPattern::>::default(), |mut a, b| { a.focus.push(b.focus); - a.patterns.extend_from_slice(&b.patterns); + a.patterns.extend(b.patterns); a }) } @@ -1366,45 +1445,45 @@ parser! { rule ObjectPath() -> FocusedTripleOrPathPattern = GraphNodePath() //[88] - rule Path() -> PropertyPath = PathAlternative() + rule Path() -> PropertyPathExpression = PathAlternative() //[89] - rule PathAlternative() -> PropertyPath = p:PathAlternative_item() **<1,> ("|" _) {? + rule PathAlternative() -> PropertyPathExpression = p:PathAlternative_item() **<1,> ("|" _) {? not_empty_fold(p.into_iter(), |a, b| { - PropertyPath::AlternativePath(Box::new(a), Box::new(b)) + PropertyPathExpression::Alternative(Box::new(a), Box::new(b)) }) } - rule PathAlternative_item() -> PropertyPath = p:PathSequence() _ { p } + rule PathAlternative_item() -> PropertyPathExpression = p:PathSequence() _ { p } //[90] - rule PathSequence() -> PropertyPath = p:PathSequence_item() **<1,> ("/" _) {? + rule PathSequence() -> PropertyPathExpression = p:PathSequence_item() **<1,> ("/" _) {? not_empty_fold(p.into_iter(), |a, b| { - PropertyPath::SequencePath(Box::new(a), Box::new(b)) + PropertyPathExpression::Sequence(Box::new(a), Box::new(b)) }) } - rule PathSequence_item() -> PropertyPath = p:PathEltOrInverse() _ { p } + rule PathSequence_item() -> PropertyPathExpression = p:PathEltOrInverse() _ { p } //[91] - rule PathElt() -> PropertyPath = - p:PathPrimary() "?" { PropertyPath::ZeroOrOnePath(Box::new(p)) } / //TODO: allow space before "?" - p:PathPrimary() _ "*" { PropertyPath::ZeroOrMorePath(Box::new(p)) } / - p:PathPrimary() _ "+" { PropertyPath::OneOrMorePath(Box::new(p)) } / + rule PathElt() -> PropertyPathExpression = + p:PathPrimary() "?" { PropertyPathExpression::ZeroOrOne(Box::new(p)) } / //TODO: allow space before "?" + p:PathPrimary() _ "*" { PropertyPathExpression::ZeroOrMore(Box::new(p)) } / + p:PathPrimary() _ "+" { PropertyPathExpression::OneOrMore(Box::new(p)) } / PathPrimary() //[92] - rule PathEltOrInverse() -> PropertyPath = - "^" _ p:PathElt() { PropertyPath::InversePath(Box::new(p)) } / + rule PathEltOrInverse() -> PropertyPathExpression = + "^" _ p:PathElt() { PropertyPathExpression::Reverse(Box::new(p)) } / PathElt() //[94] - rule PathPrimary() -> PropertyPath = + rule PathPrimary() -> PropertyPathExpression = v:iri() { v.into() } / - "a" { NamedNode::from(rdf::TYPE).into() } / + "a" { rdf::TYPE.into_owned().into() } / "!" _ p:PathNegatedPropertySet() { p } / "(" _ p:Path() _ ")" { p } //[95] - rule PathNegatedPropertySet() -> PropertyPath = + rule PathNegatedPropertySet() -> PropertyPathExpression = "(" _ p:PathNegatedPropertySet_item() **<1,> ("|" _) ")" { let mut direct = Vec::default(); let mut inverse = Vec::default(); @@ -1415,20 +1494,20 @@ parser! { } } if inverse.is_empty() { - PropertyPath::NegatedPropertySet(direct) + PropertyPathExpression::NegatedPropertySet(direct) } else if direct.is_empty() { - PropertyPath::InversePath(Box::new(PropertyPath::NegatedPropertySet(inverse))) + PropertyPathExpression::Reverse(Box::new(PropertyPathExpression::NegatedPropertySet(inverse))) } else { - PropertyPath::AlternativePath( - Box::new(PropertyPath::NegatedPropertySet(direct)), - Box::new(PropertyPath::InversePath(Box::new(PropertyPath::NegatedPropertySet(inverse)))) + PropertyPathExpression::Alternative( + Box::new(PropertyPathExpression::NegatedPropertySet(direct)), + Box::new(PropertyPathExpression::Reverse(Box::new(PropertyPathExpression::NegatedPropertySet(inverse)))) ) } } / p:PathOneInPropertySet() { match p { - Either::Left(a) => PropertyPath::NegatedPropertySet(vec![a]), - Either::Right(b) => PropertyPath::InversePath(Box::new(PropertyPath::NegatedPropertySet(vec![b]))), + Either::Left(a) => PropertyPathExpression::NegatedPropertySet(vec![a]), + Either::Right(b) => PropertyPathExpression::Reverse(Box::new(PropertyPathExpression::NegatedPropertySet(vec![b]))), } } rule PathNegatedPropertySet_item() -> Either = p:PathOneInPropertySet() _ { p } @@ -1436,9 +1515,9 @@ parser! { //[96] rule PathOneInPropertySet() -> Either = "^" _ v:iri() { Either::Right(v) } / - "^" _ "a" { Either::Right(rdf::TYPE.into()) } / + "^" _ "a" { Either::Right(rdf::TYPE.into_owned()) } / v:iri() { Either::Left(v) } / - "a" { Either::Left(rdf::TYPE.into()) } + "a" { Either::Left(rdf::TYPE.into_owned()) } //[98] rule TriplesNode() -> FocusedTriplePattern = Collection() / BlankNodePropertyList() @@ -1479,11 +1558,11 @@ parser! { //[102] rule Collection() -> FocusedTriplePattern = "(" _ o:Collection_item()+ ")" { let mut patterns: Vec = Vec::default(); - let mut current_list_node = TermOrVariable::from(rdf::NIL); + let mut current_list_node = TermOrVariable::from(rdf::NIL.into_owned()); for objWithPatterns in o.into_iter().rev() { let new_blank_node = TermOrVariable::from(BlankNode::default()); - patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::FIRST, objWithPatterns.focus.clone())); - patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::REST, current_list_node)); + patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::FIRST.into_owned(), objWithPatterns.focus.clone())); + patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::REST.into_owned(), current_list_node)); current_list_node = new_blank_node; patterns.extend_from_slice(&objWithPatterns.patterns); } @@ -1497,13 +1576,13 @@ parser! { //[103] rule CollectionPath() -> FocusedTripleOrPathPattern = "(" _ o:CollectionPath_item()+ _ ")" { let mut patterns: Vec = Vec::default(); - let mut current_list_node = TermOrVariable::from(rdf::NIL); + let mut current_list_node = TermOrVariable::from(rdf::NIL.into_owned()); for objWithPatterns in o.into_iter().rev() { let new_blank_node = TermOrVariable::from(BlankNode::default()); - patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::FIRST, objWithPatterns.focus.clone()).into()); - patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::REST, current_list_node).into()); + patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::FIRST.into_owned(), objWithPatterns.focus.clone()).into()); + patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::REST.into_owned(), current_list_node).into()); current_list_node = new_blank_node; - patterns.extend_from_slice(&objWithPatterns.patterns); + patterns.extend(objWithPatterns.patterns); } FocusedTripleOrPathPattern { focus: current_list_node, @@ -1565,13 +1644,13 @@ parser! { //[114] rule RelationalExpression() -> Expression = a:NumericExpression() _ o: RelationalExpression_inner()? { match o { Some(("=", Some(b), None)) => Expression::Equal(Box::new(a), Box::new(b)), - Some(("!=", Some(b), None)) => Expression::NotEqual(Box::new(a), Box::new(b)), + Some(("!=", Some(b), None)) => Expression::Not(Box::new(Expression::Equal(Box::new(a), Box::new(b)))), Some((">", Some(b), None)) => Expression::Greater(Box::new(a), Box::new(b)), - Some((">=", Some(b), None)) => Expression::GreaterOrEq(Box::new(a), Box::new(b)), - Some(("<", Some(b), None)) => Expression::Lower(Box::new(a), Box::new(b)), - Some(("<=", Some(b), None)) => Expression::LowerOrEq(Box::new(a), Box::new(b)), + Some((">=", Some(b), None)) => Expression::GreaterOrEqual(Box::new(a), Box::new(b)), + Some(("<", Some(b), None)) => Expression::Less(Box::new(a), Box::new(b)), + Some(("<=", Some(b), None)) => Expression::LessOrEqual(Box::new(a), Box::new(b)), Some(("IN", None, Some(l))) => Expression::In(Box::new(a), l), - Some(("NOT IN", None, Some(l))) => Expression::NotIn(Box::new(a), l), + Some(("NOT IN", None, Some(l))) => Expression::Not(Box::new(Expression::In(Box::new(a), l))), Some(_) => unreachable!(), None => a } } @@ -1586,7 +1665,7 @@ parser! { //[116] rule AdditiveExpression() -> Expression = a:MultiplicativeExpression() _ o:AdditiveExpression_inner()? { match o { Some(("+", b)) => Expression::Add(Box::new(a), Box::new(b)), - Some(("-", b)) => Expression::Sub(Box::new(a), Box::new(b)), + Some(("-", b)) => Expression::Subtract(Box::new(a), Box::new(b)), Some(_) => unreachable!(), None => a, } } @@ -1596,8 +1675,8 @@ parser! { //[117] rule MultiplicativeExpression() -> Expression = a:UnaryExpression() _ o: MultiplicativeExpression_inner()? { match o { - Some(("*", b)) => Expression::Mul(Box::new(a), Box::new(b)), - Some(("/", b)) => Expression::Div(Box::new(a), Box::new(b)), + Some(("*", b)) => Expression::Multiply(Box::new(a), Box::new(b)), + Some(("/", b)) => Expression::Divide(Box::new(a), Box::new(b)), Some(_) => unreachable!(), None => a } } @@ -1607,7 +1686,7 @@ parser! { //[118] rule UnaryExpression() -> Expression = s: $("!" / "+" / "-")? _ e:PrimaryExpression() { match s { - Some("!") => Expression::UnaryNot(Box::new(e)), + Some("!") => Expression::Not(Box::new(e)), Some("+") => Expression::UnaryPlus(Box::new(e)), Some("-") => Expression::UnaryMinus(Box::new(e)), Some(_) => unreachable!(), @@ -1671,11 +1750,11 @@ parser! { i("SHA256") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::SHA256, vec![e]) } / i("SHA384") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::SHA384, vec![e]) } / i("SHA512") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::SHA512, vec![e]) } / - i("COALESCE") e:ExpressionList() { Expression::FunctionCall(Function::Coalesce, e) } / - i("IF") _ "(" _ a:Expression() _ "," _ b:Expression() _ "," _ c:Expression() _ ")" { Expression::FunctionCall(Function::If, vec![a, b, c]) } / + i("COALESCE") e:ExpressionList() { Expression::Coalesce(e) } / + i("IF") _ "(" _ a:Expression() _ "," _ b:Expression() _ "," _ c:Expression() _ ")" { Expression::If(Box::new(a), Box::new(b), Box::new(c)) } / i("STRLANG") _ "(" _ a:Expression() _ "," _ b:Expression() _ ")" { Expression::FunctionCall(Function::StrLang, vec![a, b]) } / i("STRDT") _ "(" _ a:Expression() _ "," _ b:Expression() _ ")" { Expression::FunctionCall(Function::StrDT, vec![a, b]) } / - i("sameTerm") "(" _ a:Expression() _ "," _ b:Expression() _ ")" { Expression::FunctionCall(Function::SameTerm, vec![a, b]) } / + i("sameTerm") "(" _ a:Expression() _ "," _ b:Expression() _ ")" { Expression::SameTerm(Box::new(a), Box::new(b)) } / (i("isIRI") / i("isURI")) _ "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::IsIRI, vec![e]) } / i("isBLANK") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::IsBlank, vec![e]) } / i("isLITERAL") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::IsLiteral, vec![e]) } / @@ -1704,28 +1783,28 @@ parser! { rule ExistsFunc() -> Expression = i("EXISTS") _ p:GroupGraphPattern() { Expression::Exists(Box::new(p)) } //[126] - rule NotExistsFunc() -> Expression = i("NOT") _ i("EXISTS") _ p:GroupGraphPattern() { Expression::UnaryNot(Box::new(Expression::Exists(Box::new(p)))) } + rule NotExistsFunc() -> Expression = i("NOT") _ i("EXISTS") _ p:GroupGraphPattern() { Expression::Not(Box::new(Expression::Exists(Box::new(p)))) } //[127] - rule Aggregate() -> Aggregation = - i("COUNT") _ "(" _ i("DISTINCT") _ "*" _ ")" { Aggregation::Count(None, true) } / - i("COUNT") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { Aggregation::Count(Some(Box::new(e)), true) } / - i("COUNT") _ "(" _ "*" _ ")" { Aggregation::Count(None, false) } / - i("COUNT") _ "(" _ e:Expression() _ ")" { Aggregation::Count(Some(Box::new(e)), false) } / - i("SUM") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { Aggregation::Sum(Box::new(e), true) } / - i("SUM") _ "(" _ e:Expression() _ ")" { Aggregation::Sum(Box::new(e), false) } / - i("MIN") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { Aggregation::Min(Box::new(e), true) } / - i("MIN") _ "(" _ e:Expression() _ ")" { Aggregation::Min(Box::new(e), false) } / - i("MAX") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { Aggregation::Max(Box::new(e), true) } / - i("MAX") _ "(" _ e:Expression() _ ")" { Aggregation::Max(Box::new(e), false) } / - i("AVG") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { Aggregation::Avg(Box::new(e), true) } / - i("AVG") _ "(" _ e:Expression() _ ")" { Aggregation::Avg(Box::new(e), false) } / - i("SAMPLE") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { Aggregation::Sample(Box::new(e), true) } / - i("SAMPLE") _ "(" _ e:Expression() _ ")" { Aggregation::Sample(Box::new(e), false) } / - i("GROUP_CONCAT") _ "(" _ i("DISTINCT") _ e:Expression() _ ";" _ i("SEPARATOR") _ "=" _ s:String() _ ")" { Aggregation::GroupConcat(Box::new(e), true, Some(s)) } / - i("GROUP_CONCAT") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { Aggregation::GroupConcat(Box::new(e), true, None) } / - i("GROUP_CONCAT") _ "(" _ e:Expression() _ ";" _ i("SEPARATOR") _ "=" _ s:String() _ ")" { Aggregation::GroupConcat(Box::new(e), true, Some(s)) } / - i("GROUP_CONCAT") _ "(" _ e:Expression() _ ")" { Aggregation::GroupConcat(Box::new(e), false, None) } + rule Aggregate() -> SetFunction = + i("COUNT") _ "(" _ i("DISTINCT") _ "*" _ ")" { SetFunction::Count { expr: None, distinct: true } } / + i("COUNT") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { SetFunction::Count { expr: Some(Box::new(e)), distinct: true } } / + i("COUNT") _ "(" _ "*" _ ")" { SetFunction::Count { expr: None, distinct: false } } / + i("COUNT") _ "(" _ e:Expression() _ ")" { SetFunction::Count { expr: Some(Box::new(e)), distinct: false } } / + i("SUM") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { SetFunction::Sum { expr: Box::new(e), distinct: true } } / + i("SUM") _ "(" _ e:Expression() _ ")" { SetFunction::Sum { expr: Box::new(e), distinct: false } } / + i("MIN") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { SetFunction::Min { expr: Box::new(e), distinct: true } } / + i("MIN") _ "(" _ e:Expression() _ ")" { SetFunction::Min { expr: Box::new(e), distinct: false } } / + i("MAX") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { SetFunction::Max { expr: Box::new(e), distinct: true } } / + i("MAX") _ "(" _ e:Expression() _ ")" { SetFunction::Max { expr: Box::new(e), distinct: false } } / + i("AVG") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { SetFunction::Avg { expr: Box::new(e), distinct: true } } / + i("AVG") _ "(" _ e:Expression() _ ")" { SetFunction::Avg { expr: Box::new(e), distinct: false } } / + i("SAMPLE") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { SetFunction::Sample { expr: Box::new(e), distinct: true } } / + i("SAMPLE") _ "(" _ e:Expression() _ ")" { SetFunction::Sample { expr: Box::new(e), distinct: false } } / + i("GROUP_CONCAT") _ "(" _ i("DISTINCT") _ e:Expression() _ ";" _ i("SEPARATOR") _ "=" _ s:String() _ ")" { SetFunction::GroupConcat { expr: Box::new(e), distinct: true, separator: Some(s) } } / + i("GROUP_CONCAT") _ "(" _ i("DISTINCT") _ e:Expression() _ ")" { SetFunction::GroupConcat { expr: Box::new(e), distinct: true, separator: None } } / + i("GROUP_CONCAT") _ "(" _ e:Expression() _ ";" _ i("SEPARATOR") _ "=" _ s:String() _ ")" { SetFunction::GroupConcat { expr: Box::new(e), distinct: true, separator: Some(s) } } / + i("GROUP_CONCAT") _ "(" _ e:Expression() _ ")" { SetFunction::GroupConcat { expr: Box::new(e), distinct: false, separator: None } } //[128] rule iriOrFunction() -> Expression = i: iri() _ a: ArgList()? { diff --git a/lib/src/sparql/plan.rs b/lib/src/sparql/plan.rs index 2e54f268..ed99f67f 100644 --- a/lib/src/sparql/plan.rs +++ b/lib/src/sparql/plan.rs @@ -216,19 +216,18 @@ pub enum PlanExpression { Or(Box>, Box>), And(Box>, Box>), Equal(Box>, Box>), - NotEqual(Box>, Box>), Greater(Box>, Box>), - GreaterOrEq(Box>, Box>), - Lower(Box>, Box>), - LowerOrEq(Box>, Box>), + GreaterOrEqual(Box>, Box>), + Less(Box>, Box>), + LessOrEqual(Box>, Box>), In(Box>, Vec>), Add(Box>, Box>), - Sub(Box>, Box>), - Mul(Box>, Box>), - Div(Box>, Box>), + Subtract(Box>, Box>), + Multiply(Box>, Box>), + Divide(Box>, Box>), UnaryPlus(Box>), UnaryMinus(Box>), - UnaryNot(Box>), + Not(Box>), Str(Box>), Lang(Box>), LangMatches(Box>, Box>), @@ -324,7 +323,7 @@ impl PlanExpression { | PlanExpression::BNode(None) => (), PlanExpression::UnaryPlus(e) | PlanExpression::UnaryMinus(e) - | PlanExpression::UnaryNot(e) + | PlanExpression::Not(e) | PlanExpression::BNode(Some(e)) | PlanExpression::Str(e) | PlanExpression::Lang(e) @@ -370,15 +369,14 @@ impl PlanExpression { PlanExpression::Or(a, b) | PlanExpression::And(a, b) | PlanExpression::Equal(a, b) - | PlanExpression::NotEqual(a, b) | PlanExpression::Greater(a, b) - | PlanExpression::GreaterOrEq(a, b) - | PlanExpression::Lower(a, b) - | PlanExpression::LowerOrEq(a, b) + | PlanExpression::GreaterOrEqual(a, b) + | PlanExpression::Less(a, b) + | PlanExpression::LessOrEqual(a, b) | PlanExpression::Add(a, b) - | PlanExpression::Sub(a, b) - | PlanExpression::Mul(a, b) - | PlanExpression::Div(a, b) + | PlanExpression::Subtract(a, b) + | PlanExpression::Multiply(a, b) + | PlanExpression::Divide(a, b) | PlanExpression::LangMatches(a, b) | PlanExpression::Contains(a, b) | PlanExpression::StrStarts(a, b) @@ -446,13 +444,13 @@ pub enum PlanAggregationFunction { #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum PlanPropertyPath { - PredicatePath(EncodedTerm), - InversePath(Rc>), - SequencePath(Rc>, Rc>), - AlternativePath(Rc>, Rc>), - ZeroOrMorePath(Rc>), - OneOrMorePath(Rc>), - ZeroOrOnePath(Rc>), + Path(EncodedTerm), + Reverse(Rc>), + Sequence(Rc>, Rc>), + Alternative(Rc>, Rc>), + ZeroOrMore(Rc>), + OneOrMore(Rc>), + ZeroOrOne(Rc>), NegatedPropertySet(Rc>>), } diff --git a/lib/src/sparql/plan_builder.rs b/lib/src/sparql/plan_builder.rs index 46102950..447e5973 100644 --- a/lib/src/sparql/plan_builder.rs +++ b/lib/src/sparql/plan_builder.rs @@ -41,22 +41,54 @@ impl> PlanBuilder { ) -> Result, EvaluationError> { Ok(match pattern { GraphPattern::BGP(p) => self.build_for_bgp(p, variables, graph_name)?, - GraphPattern::Join(a, b) => PlanNode::Join { - left: Rc::new(self.build_for_graph_pattern(a, variables, graph_name)?), - right: Rc::new(self.build_for_graph_pattern(b, variables, graph_name)?), + GraphPattern::Path { + subject, + path, + object, + } => PlanNode::PathPatternJoin { + child: Rc::new(PlanNode::Init), + subject: self.pattern_value_from_term_or_variable(subject, variables)?, + path: Rc::new(self.build_for_path(path)?), + object: self.pattern_value_from_term_or_variable(object, variables)?, + graph_name, }, - GraphPattern::LeftJoin(a, b, e) => { - let left = self.build_for_graph_pattern(a, variables, graph_name)?; - let right = self.build_for_graph_pattern(b, variables, graph_name)?; + GraphPattern::Join { left, right } => { + //TODO: improve + if let GraphPattern::Path { + subject, + path, + object, + } = right.as_ref() + { + let left = self.build_for_graph_pattern(left, variables, graph_name)?; + PlanNode::PathPatternJoin { + child: Rc::new(left), + subject: self.pattern_value_from_term_or_variable(subject, variables)?, + path: Rc::new(self.build_for_path(path)?), + object: self.pattern_value_from_term_or_variable(object, variables)?, + graph_name, + } + } else { + PlanNode::Join { + left: Rc::new(self.build_for_graph_pattern(left, variables, graph_name)?), + right: Rc::new(self.build_for_graph_pattern(right, variables, graph_name)?), + } + } + } + GraphPattern::LeftJoin { left, right, expr } => { + let left = self.build_for_graph_pattern(left, variables, graph_name)?; + let right = self.build_for_graph_pattern(right, variables, graph_name)?; let mut possible_problem_vars = BTreeSet::new(); self.add_left_join_problematic_variables(&right, &mut possible_problem_vars); //We add the extra filter if needed - let right = if let Some(e) = e { + let right = if let Some(expr) = expr { PlanNode::Filter { child: Rc::new(right), - expression: Rc::new(self.build_for_expression(e, variables, graph_name)?), + expression: Rc::new( + self.build_for_expression(expr, variables, graph_name)?, + ), } } else { right @@ -68,20 +100,20 @@ impl> PlanBuilder { possible_problem_vars: Rc::new(possible_problem_vars.into_iter().collect()), } } - GraphPattern::Filter(e, p) => PlanNode::Filter { - child: Rc::new(self.build_for_graph_pattern(p, variables, graph_name)?), - expression: Rc::new(self.build_for_expression(e, variables, graph_name)?), + GraphPattern::Filter { expr, inner } => PlanNode::Filter { + child: Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?), + expression: Rc::new(self.build_for_expression(expr, variables, graph_name)?), }, - GraphPattern::Union(a, b) => { + GraphPattern::Union { left, right } => { //We flatten the UNIONs - let mut stack: Vec<&GraphPattern> = vec![a, b]; + let mut stack: Vec<&GraphPattern> = vec![left, right]; let mut children = vec![]; loop { match stack.pop() { None => break, - Some(GraphPattern::Union(a, b)) => { - stack.push(a); - stack.push(b); + Some(GraphPattern::Union { left, right }) => { + stack.push(left); + stack.push(right); } Some(p) => children.push(Rc::new( self.build_for_graph_pattern(p, variables, graph_name)?, @@ -90,44 +122,54 @@ impl> PlanBuilder { } PlanNode::Union { children } } - GraphPattern::Graph(g, p) => { - let graph_name = self.pattern_value_from_named_node_or_variable(g, variables)?; - self.build_for_graph_pattern(p, variables, graph_name)? + GraphPattern::Graph { graph_name, inner } => { + let graph_name = + self.pattern_value_from_named_node_or_variable(graph_name, variables)?; + self.build_for_graph_pattern(inner, variables, graph_name)? } - GraphPattern::Extend(p, v, e) => PlanNode::Extend { - child: Rc::new(self.build_for_graph_pattern(p, variables, graph_name)?), - position: variable_key(variables, v), - expression: Rc::new(self.build_for_expression(e, variables, graph_name)?), + GraphPattern::Extend { inner, var, expr } => PlanNode::Extend { + child: Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?), + position: variable_key(variables, var), + expression: Rc::new(self.build_for_expression(expr, variables, graph_name)?), }, - GraphPattern::Minus(a, b) => PlanNode::AntiJoin { - left: Rc::new(self.build_for_graph_pattern(a, variables, graph_name)?), - right: Rc::new(self.build_for_graph_pattern(b, variables, graph_name)?), + GraphPattern::Minus { left, right } => PlanNode::AntiJoin { + left: Rc::new(self.build_for_graph_pattern(left, variables, graph_name)?), + right: Rc::new(self.build_for_graph_pattern(right, variables, graph_name)?), }, - GraphPattern::Service(n, p, s) => { + GraphPattern::Service { + name, + pattern, + silent, + } => { // 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 child = self.build_for_graph_pattern(pattern, variables, graph_name)?; + let service_name = + self.pattern_value_from_named_node_or_variable(name, variables)?; PlanNode::Service { service_name, variables: Rc::new(variables.clone()), child: Rc::new(child), - graph_pattern: Rc::new(*p.clone()), - silent: *s, + graph_pattern: Rc::new(*pattern.clone()), + silent: *silent, } } - GraphPattern::AggregateJoin(GroupPattern(key, p), aggregates) => { - let mut inner_variables = key.clone(); + GraphPattern::Group { + inner, + by, + aggregates, + } => { + let mut inner_variables = by.clone(); let inner_graph_name = self.convert_pattern_value_id(graph_name, variables, &mut inner_variables); PlanNode::Aggregate { child: Rc::new(self.build_for_graph_pattern( - p, + inner, &mut inner_variables, inner_graph_name, )?), key_mapping: Rc::new( - key.iter() + by.iter() .map(|k| { ( variable_key(&mut inner_variables, k), @@ -139,7 +181,7 @@ impl> PlanBuilder { aggregates: Rc::new( aggregates .iter() - .map(|(a, v)| { + .map(|(v, a)| { Ok(( self.build_for_aggregate(a, &mut inner_variables, graph_name)?, variable_key(variables, v), @@ -149,11 +191,14 @@ impl> PlanBuilder { ), } } - GraphPattern::Data(bs) => PlanNode::StaticBindings { - tuples: self.encode_bindings(bs, variables)?, + GraphPattern::Table { + variables: table_variables, + rows, + } => PlanNode::StaticBindings { + tuples: self.encode_bindings(table_variables, rows, variables)?, }, - GraphPattern::OrderBy(l, o) => { - let by: Result, EvaluationError> = o + GraphPattern::OrderBy { inner, condition } => { + let condition: Result, EvaluationError> = condition .iter() .map(|comp| match comp { OrderComparator::Asc(e) => Ok(Comparator::Asc( @@ -165,22 +210,22 @@ impl> PlanBuilder { }) .collect(); PlanNode::Sort { - child: Rc::new(self.build_for_graph_pattern(l, variables, graph_name)?), - by: by?, + child: Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?), + by: condition?, } } - GraphPattern::Project(l, new_variables) => { - let mut inner_variables = new_variables.clone(); + GraphPattern::Project { inner, projection } => { + let mut inner_variables = projection.clone(); let inner_graph_name = self.convert_pattern_value_id(graph_name, variables, &mut inner_variables); PlanNode::Project { child: Rc::new(self.build_for_graph_pattern( - l, + inner, &mut inner_variables, inner_graph_name, )?), mapping: Rc::new( - new_variables + projection .iter() .enumerate() .map(|(new_variable, variable)| { @@ -190,12 +235,18 @@ impl> PlanBuilder { ), } } - GraphPattern::Distinct(l) => PlanNode::HashDeduplicate { - child: Rc::new(self.build_for_graph_pattern(l, variables, graph_name)?), + GraphPattern::Distinct { inner } => PlanNode::HashDeduplicate { + child: Rc::new(self.build_for_graph_pattern(inner, variables, graph_name)?), }, - GraphPattern::Reduced(l) => self.build_for_graph_pattern(l, variables, graph_name)?, - GraphPattern::Slice(l, start, length) => { - let mut plan = self.build_for_graph_pattern(l, variables, graph_name)?; + GraphPattern::Reduced { inner } => { + self.build_for_graph_pattern(inner, variables, graph_name)? + } + GraphPattern::Slice { + inner, + start, + length, + } => { + let mut plan = self.build_for_graph_pattern(inner, variables, graph_name)?; if *start > 0 { plan = PlanNode::Skip { child: Rc::new(plan), @@ -215,30 +266,19 @@ impl> PlanBuilder { fn build_for_bgp( &mut self, - p: &[TripleOrPathPattern], + p: &[TriplePattern], variables: &mut Vec, graph_name: PatternValue, ) -> Result, EvaluationError> { let mut plan = PlanNode::Init; for pattern in sort_bgp(p) { - plan = match pattern { - TripleOrPathPattern::Triple(pattern) => PlanNode::QuadPatternJoin { - child: Rc::new(plan), - subject: self - .pattern_value_from_term_or_variable(&pattern.subject, variables)?, - predicate: self - .pattern_value_from_named_node_or_variable(&pattern.predicate, variables)?, - object: self.pattern_value_from_term_or_variable(&pattern.object, variables)?, - graph_name, - }, - TripleOrPathPattern::Path(pattern) => PlanNode::PathPatternJoin { - child: Rc::new(plan), - subject: self - .pattern_value_from_term_or_variable(&pattern.subject, variables)?, - path: Rc::new(self.build_for_path(&pattern.path)?), - object: self.pattern_value_from_term_or_variable(&pattern.object, variables)?, - graph_name, - }, + plan = PlanNode::QuadPatternJoin { + child: Rc::new(plan), + subject: self.pattern_value_from_term_or_variable(&pattern.subject, variables)?, + predicate: self + .pattern_value_from_named_node_or_variable(&pattern.predicate, variables)?, + object: self.pattern_value_from_term_or_variable(&pattern.object, variables)?, + graph_name, } } Ok(plan) @@ -246,37 +286,39 @@ impl> PlanBuilder { fn build_for_path( &mut self, - path: &PropertyPath, + path: &PropertyPathExpression, ) -> Result, EvaluationError> { Ok(match path { - PropertyPath::PredicatePath(p) => { - PlanPropertyPath::PredicatePath(self.build_named_node(p)?) + PropertyPathExpression::NamedNode(p) => { + PlanPropertyPath::Path(self.build_named_node(p)?) } - PropertyPath::InversePath(p) => { - PlanPropertyPath::InversePath(Rc::new(self.build_for_path(p)?)) + PropertyPathExpression::Reverse(p) => { + PlanPropertyPath::Reverse(Rc::new(self.build_for_path(p)?)) } - PropertyPath::AlternativePath(a, b) => PlanPropertyPath::AlternativePath( + PropertyPathExpression::Alternative(a, b) => PlanPropertyPath::Alternative( Rc::new(self.build_for_path(a)?), Rc::new(self.build_for_path(b)?), ), - PropertyPath::SequencePath(a, b) => PlanPropertyPath::SequencePath( + PropertyPathExpression::Sequence(a, b) => PlanPropertyPath::Sequence( Rc::new(self.build_for_path(a)?), Rc::new(self.build_for_path(b)?), ), - PropertyPath::ZeroOrMorePath(p) => { - PlanPropertyPath::ZeroOrMorePath(Rc::new(self.build_for_path(p)?)) + PropertyPathExpression::ZeroOrMore(p) => { + PlanPropertyPath::ZeroOrMore(Rc::new(self.build_for_path(p)?)) } - PropertyPath::OneOrMorePath(p) => { - PlanPropertyPath::OneOrMorePath(Rc::new(self.build_for_path(p)?)) + PropertyPathExpression::OneOrMore(p) => { + PlanPropertyPath::OneOrMore(Rc::new(self.build_for_path(p)?)) } - PropertyPath::ZeroOrOnePath(p) => { - PlanPropertyPath::ZeroOrOnePath(Rc::new(self.build_for_path(p)?)) + PropertyPathExpression::ZeroOrOne(p) => { + PlanPropertyPath::ZeroOrOne(Rc::new(self.build_for_path(p)?)) + } + PropertyPathExpression::NegatedPropertySet(p) => { + PlanPropertyPath::NegatedPropertySet(Rc::new( + p.iter() + .map(|p| self.build_named_node(p)) + .collect::, _>>()?, + )) } - PropertyPath::NegatedPropertySet(p) => PlanPropertyPath::NegatedPropertySet(Rc::new( - p.iter() - .map(|p| self.build_named_node(p)) - .collect::, _>>()?, - )), }) } @@ -302,7 +344,7 @@ impl> PlanBuilder { Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), - Expression::NotEqual(a, b) => PlanExpression::NotEqual( + Expression::SameTerm(a, b) => PlanExpression::SameTerm( Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), @@ -310,15 +352,15 @@ impl> PlanBuilder { Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), - Expression::GreaterOrEq(a, b) => PlanExpression::GreaterOrEq( + Expression::GreaterOrEqual(a, b) => PlanExpression::GreaterOrEqual( Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), - Expression::Lower(a, b) => PlanExpression::Lower( + Expression::Less(a, b) => PlanExpression::Less( Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), - Expression::LowerOrEq(a, b) => PlanExpression::LowerOrEq( + Expression::LessOrEqual(a, b) => PlanExpression::LessOrEqual( Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), @@ -326,23 +368,19 @@ impl> PlanBuilder { Box::new(self.build_for_expression(e, variables, graph_name)?), self.expression_list(l, variables, graph_name)?, ), - Expression::NotIn(e, l) => PlanExpression::UnaryNot(Box::new(PlanExpression::In( - Box::new(self.build_for_expression(e, variables, graph_name)?), - self.expression_list(l, variables, graph_name)?, - ))), Expression::Add(a, b) => PlanExpression::Add( Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), - Expression::Sub(a, b) => PlanExpression::Sub( + Expression::Subtract(a, b) => PlanExpression::Subtract( Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), - Expression::Mul(a, b) => PlanExpression::Mul( + Expression::Multiply(a, b) => PlanExpression::Multiply( Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), - Expression::Div(a, b) => PlanExpression::Div( + Expression::Divide(a, b) => PlanExpression::Divide( Box::new(self.build_for_expression(a, variables, graph_name)?), Box::new(self.build_for_expression(b, variables, graph_name)?), ), @@ -352,7 +390,7 @@ impl> PlanBuilder { Expression::UnaryMinus(e) => PlanExpression::UnaryMinus(Box::new( self.build_for_expression(e, variables, graph_name)?, )), - Expression::UnaryNot(e) => PlanExpression::UnaryNot(Box::new( + Expression::Not(e) => PlanExpression::Not(Box::new( self.build_for_expression(e, variables, graph_name)?, )), Expression::FunctionCall(function, parameters) => match function { @@ -533,14 +571,6 @@ impl> PlanBuilder { variables, graph_name, )?)), - Function::Coalesce => PlanExpression::Coalesce( - self.expression_list(parameters, variables, graph_name)?, - ), - Function::If => PlanExpression::If( - Box::new(self.build_for_expression(¶meters[0], variables, graph_name)?), - Box::new(self.build_for_expression(¶meters[1], variables, graph_name)?), - Box::new(self.build_for_expression(¶meters[2], variables, graph_name)?), - ), Function::StrLang => PlanExpression::StrLang( Box::new(self.build_for_expression(¶meters[0], variables, graph_name)?), Box::new(self.build_for_expression(¶meters[1], variables, graph_name)?), @@ -549,10 +579,6 @@ impl> PlanBuilder { Box::new(self.build_for_expression(¶meters[0], variables, graph_name)?), Box::new(self.build_for_expression(¶meters[1], variables, graph_name)?), ), - Function::SameTerm => PlanExpression::SameTerm( - Box::new(self.build_for_expression(¶meters[0], variables, graph_name)?), - Box::new(self.build_for_expression(¶meters[1], variables, graph_name)?), - ), Function::IsIRI => PlanExpression::IsIRI(Box::new(self.build_for_expression( ¶meters[0], variables, @@ -685,9 +711,17 @@ impl> PlanBuilder { } }, Expression::Bound(v) => PlanExpression::Bound(variable_key(variables, v)), + Expression::If(a, b, c) => PlanExpression::If( + Box::new(self.build_for_expression(a, variables, graph_name)?), + Box::new(self.build_for_expression(b, variables, graph_name)?), + Box::new(self.build_for_expression(c, variables, graph_name)?), + ), Expression::Exists(n) => PlanExpression::Exists(Rc::new( self.build_for_graph_pattern(n, variables, graph_name)?, )), + Expression::Coalesce(parameters) => { + PlanExpression::Coalesce(self.expression_list(parameters, variables, graph_name)?) + } }) } @@ -761,19 +795,18 @@ impl> PlanBuilder { fn encode_bindings( &mut self, - bindings: &StaticBindings, + table_variables: &[Variable], + rows: &[Vec>], variables: &mut Vec, ) -> Result>, EvaluationError> { - let bindings_variables_keys = bindings - .variables() + let bindings_variables_keys = table_variables .iter() .map(|v| variable_key(variables, v)) .collect::>(); - bindings - .values_iter() - .map(move |values| { + rows.iter() + .map(move |row| { let mut result = EncodedTuple::with_capacity(variables.len()); - for (key, value) in values.iter().enumerate() { + for (key, value) in row.iter().enumerate() { if let Some(term) = value { result.set(bindings_variables_keys[key], self.build_term(term)?); } @@ -785,49 +818,53 @@ impl> PlanBuilder { fn build_for_aggregate( &mut self, - aggregate: &Aggregation, + aggregate: &SetFunction, variables: &mut Vec, graph_name: PatternValue, ) -> Result, EvaluationError> { Ok(match aggregate { - Aggregation::Count(e, distinct) => PlanAggregation { + SetFunction::Count { expr, distinct } => PlanAggregation { function: PlanAggregationFunction::Count, - parameter: match e { - Some(e) => Some(self.build_for_expression(e, variables, graph_name)?), + parameter: match expr { + Some(expr) => Some(self.build_for_expression(expr, variables, graph_name)?), None => None, }, distinct: *distinct, }, - Aggregation::Sum(e, distinct) => PlanAggregation { + SetFunction::Sum { expr, distinct } => PlanAggregation { function: PlanAggregationFunction::Sum, - parameter: Some(self.build_for_expression(e, variables, graph_name)?), + parameter: Some(self.build_for_expression(expr, variables, graph_name)?), distinct: *distinct, }, - Aggregation::Min(e, distinct) => PlanAggregation { + SetFunction::Min { expr, distinct } => PlanAggregation { function: PlanAggregationFunction::Min, - parameter: Some(self.build_for_expression(e, variables, graph_name)?), + parameter: Some(self.build_for_expression(expr, variables, graph_name)?), distinct: *distinct, }, - Aggregation::Max(e, distinct) => PlanAggregation { + SetFunction::Max { expr, distinct } => PlanAggregation { function: PlanAggregationFunction::Max, - parameter: Some(self.build_for_expression(e, variables, graph_name)?), + parameter: Some(self.build_for_expression(expr, variables, graph_name)?), distinct: *distinct, }, - Aggregation::Avg(e, distinct) => PlanAggregation { + SetFunction::Avg { expr, distinct } => PlanAggregation { function: PlanAggregationFunction::Avg, - parameter: Some(self.build_for_expression(e, variables, graph_name)?), + parameter: Some(self.build_for_expression(expr, variables, graph_name)?), distinct: *distinct, }, - Aggregation::Sample(e, distinct) => PlanAggregation { + SetFunction::Sample { expr, distinct } => PlanAggregation { function: PlanAggregationFunction::Sample, - parameter: Some(self.build_for_expression(e, variables, graph_name)?), + parameter: Some(self.build_for_expression(expr, variables, graph_name)?), distinct: *distinct, }, - Aggregation::GroupConcat(e, distinct, separator) => PlanAggregation { + SetFunction::GroupConcat { + expr, + distinct, + separator, + } => PlanAggregation { function: PlanAggregationFunction::GroupConcat { separator: Rc::new(separator.clone().unwrap_or_else(|| " ".to_string())), }, - parameter: Some(self.build_for_expression(e, variables, graph_name)?), + parameter: Some(self.build_for_expression(expr, variables, graph_name)?), distinct: *distinct, }, }) @@ -1041,7 +1078,7 @@ fn slice_key(slice: &[T], element: &T) -> Option { None } -fn sort_bgp(p: &[TripleOrPathPattern]) -> Vec<&TripleOrPathPattern> { +fn sort_bgp(p: &[TriplePattern]) -> Vec<&TriplePattern> { let mut assigned_variables = HashSet::default(); let mut assigned_blank_nodes = HashSet::default(); let mut new_p: Vec<_> = p.iter().collect(); @@ -1059,38 +1096,34 @@ fn sort_bgp(p: &[TripleOrPathPattern]) -> Vec<&TripleOrPathPattern> { } fn count_pattern_binds( - pattern: &TripleOrPathPattern, + pattern: &TriplePattern, assigned_variables: &HashSet<&Variable>, assigned_blank_nodes: &HashSet<&BlankNode>, ) -> u8 { let mut count = 12; - if let TermOrVariable::Variable(v) = pattern.subject() { + if let TermOrVariable::Variable(v) = &pattern.subject { if !assigned_variables.contains(v) { count -= 4; } - } else if let TermOrVariable::Term(Term::BlankNode(bnode)) = pattern.subject() { + } else if let TermOrVariable::Term(Term::BlankNode(bnode)) = &pattern.subject { if !assigned_blank_nodes.contains(bnode) { count -= 4; } } else { count -= 1; } - if let TripleOrPathPattern::Triple(t) = pattern { - if let NamedNodeOrVariable::Variable(v) = &t.predicate { - if !assigned_variables.contains(v) { - count -= 4; - } - } else { - count -= 1; + if let NamedNodeOrVariable::Variable(v) = &pattern.predicate { + if !assigned_variables.contains(v) { + count -= 4; } } else { - count -= 3; + count -= 1; } - if let TermOrVariable::Variable(v) = pattern.object() { + if let TermOrVariable::Variable(v) = &pattern.object { if !assigned_variables.contains(v) { count -= 4; } - } else if let TermOrVariable::Term(Term::BlankNode(bnode)) = pattern.object() { + } else if let TermOrVariable::Term(Term::BlankNode(bnode)) = &pattern.object { if !assigned_blank_nodes.contains(bnode) { count -= 4; } @@ -1101,23 +1134,21 @@ fn count_pattern_binds( } fn add_pattern_variables<'a>( - pattern: &'a TripleOrPathPattern, + pattern: &'a TriplePattern, variables: &mut HashSet<&'a Variable>, blank_nodes: &mut HashSet<&'a BlankNode>, ) { - if let TermOrVariable::Variable(v) = pattern.subject() { + if let TermOrVariable::Variable(v) = &pattern.subject { variables.insert(v); - } else if let TermOrVariable::Term(Term::BlankNode(bnode)) = pattern.subject() { + } else if let TermOrVariable::Term(Term::BlankNode(bnode)) = &pattern.subject { blank_nodes.insert(bnode); } - if let TripleOrPathPattern::Triple(t) = pattern { - if let NamedNodeOrVariable::Variable(v) = &t.predicate { - variables.insert(v); - } + if let NamedNodeOrVariable::Variable(v) = &pattern.predicate { + variables.insert(v); } - if let TermOrVariable::Variable(v) = pattern.object() { + if let TermOrVariable::Variable(v) = &pattern.object { variables.insert(v); - } else if let TermOrVariable::Term(Term::BlankNode(bnode)) = pattern.object() { + } else if let TermOrVariable::Term(Term::BlankNode(bnode)) = &pattern.object { blank_nodes.insert(bnode); } } diff --git a/lib/src/sparql/update.rs b/lib/src/sparql/update.rs index a2590140..a7e92ac6 100644 --- a/lib/src/sparql/update.rs +++ b/lib/src/sparql/update.rs @@ -69,8 +69,8 @@ where delete, insert, using, - algebra, - } => self.eval_delete_insert(delete, insert, using, algebra), + pattern, + } => self.eval_delete_insert(delete, insert, using, pattern), GraphUpdateOperation::Load { silent, from, to } => { if let Err(error) = self.eval_load(from, to) { if *silent { diff --git a/lib/src/store/memory.rs b/lib/src/store/memory.rs index 5f8e1dcb..08db8a33 100644 --- a/lib/src/store/memory.rs +++ b/lib/src/store/memory.rs @@ -238,7 +238,7 @@ impl MemoryStore { evaluate_update( self.clone(), &mut &*self, - &update.try_into().map_err(|e| e.into())?, + update.try_into().map_err(|e| e.into())?, ) } diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index 27591969..f104a7c1 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -220,7 +220,7 @@ impl RocksDbStore { evaluate_update( self.clone(), &mut writer, - &update.try_into().map_err(|e| e.into())?, + update.try_into().map_err(|e| e.into())?, )?; Ok(writer.apply()?) } diff --git a/lib/src/store/sled.rs b/lib/src/store/sled.rs index cec7902e..1edce28e 100644 --- a/lib/src/store/sled.rs +++ b/lib/src/store/sled.rs @@ -211,7 +211,7 @@ impl SledStore { evaluate_update( self.clone(), &mut &*self, - &update.try_into().map_err(|e| e.into())?, + update.try_into().map_err(|e| e.into())?, ) }