diff --git a/lib/src/sparql/algebra.rs b/lib/src/sparql/algebra.rs index 0fc7683d..a55f2ce7 100644 --- a/lib/src/sparql/algebra.rs +++ b/lib/src/sparql/algebra.rs @@ -474,7 +474,7 @@ pub enum Expression { IsNumericFunctionCall(Box), RegexFunctionCall(Box, Box, Option>), CustomFunctionCall(NamedNode, Vec), - ExistsFunctionCall(Box), + ExistsFunctionCall(Box), } impl fmt::Display for Expression { @@ -700,7 +700,7 @@ impl<'a> fmt::Display for SparqlExpression<'a> { Expression::UnaryMinusExpression(e) => write!(f, "-{}", SparqlExpression(&*e)), Expression::UnaryNotExpression(e) => match e.as_ref() { Expression::ExistsFunctionCall(p) => { - write!(f, "NOT EXISTS {{ {} }}", SparqlMultiSetPattern(&*p)) + write!(f, "NOT EXISTS {{ {} }}", SparqlGraphPattern(&*p)) } e => write!(f, "!{}", e), }, @@ -890,31 +890,36 @@ impl<'a> fmt::Display for SparqlExpression<'a> { .join(", ") ), Expression::ExistsFunctionCall(p) => { - write!(f, "EXISTS {{ {} }}", SparqlMultiSetPattern(&*p)) + write!(f, "EXISTS {{ {} }}", SparqlGraphPattern(&*p)) } } } } #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] -pub enum MultiSetPattern { +pub enum GraphPattern { BGP(Vec), - Join(Box, Box), - LeftJoin(Box, Box, Expression), - Filter(Expression, Box), - Union(Box, Box), - Graph(NamedNodeOrVariable, Box), - Extend(Box, Variable, Expression), - Minus(Box, Box), - ToMultiSet(Box), - Service(NamedNodeOrVariable, Box, bool), + Join(Box, Box), + LeftJoin(Box, Box, Expression), + Filter(Expression, Box), + Union(Box, Box), + Graph(NamedNodeOrVariable, Box), + Extend(Box, Variable, Expression), + Minus(Box, Box), + Service(NamedNodeOrVariable, Box, bool), AggregateJoin(GroupPattern, BTreeMap), + Data(StaticBindings), + OrderBy(Box, Vec), + Project(Box, Vec), + Distinct(Box), + Reduced(Box), + Slice(Box, usize, Option), } -impl fmt::Display for MultiSetPattern { +impl fmt::Display for GraphPattern { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - MultiSetPattern::BGP(p) => write!( + GraphPattern::BGP(p) => write!( f, "BGP({})", p.iter() @@ -922,16 +927,15 @@ impl fmt::Display for MultiSetPattern { .collect::>() .join(" . ") ), - MultiSetPattern::Join(a, b) => write!(f, "Join({}, {})", a, b), - MultiSetPattern::LeftJoin(a, b, e) => write!(f, "LeftJoin({}, {}, {})", a, b, e), - MultiSetPattern::Filter(e, p) => write!(f, "Filter({}, {})", e, p), - MultiSetPattern::Union(a, b) => write!(f, "Union({}, {})", a, b), - MultiSetPattern::Graph(g, p) => write!(f, "Graph({}, {})", g, p), - MultiSetPattern::Extend(p, v, e) => write!(f, "Extend({}), {}, {})", p, v, e), - MultiSetPattern::Minus(a, b) => write!(f, "Minus({}, {})", a, b), - MultiSetPattern::ToMultiSet(l) => write!(f, "{}", l), - MultiSetPattern::Service(n, p, s) => write!(f, "Service({}, {}, {})", n, p, s), - MultiSetPattern::AggregateJoin(g, a) => write!( + GraphPattern::Join(a, b) => write!(f, "Join({}, {})", a, b), + GraphPattern::LeftJoin(a, b, e) => write!(f, "LeftJoin({}, {}, {})", a, b, e), + 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!( f, "AggregateJoin({}, {})", g, @@ -940,29 +944,66 @@ impl fmt::Display for MultiSetPattern { .collect::>() .join(", ") ), + 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, " {} → {} ", variables[i], val)?; + } + } + write!(f, "}}")?; + } + write!(f, "}}") + } + GraphPattern::OrderBy(l, o) => write!( + f, + "OrderBy({}, ({}))", + l, + o.iter() + .map(|c| c.to_string()) + .collect::>() + .join(", ") + ), + GraphPattern::Project(l, pv) => write!( + f, + "Project({}, ({}))", + l, + pv.iter() + .map(|v| v.to_string()) + .collect::>() + .join(", ") + ), + GraphPattern::Distinct(l) => write!(f, "Distinct({})", l), + GraphPattern::Reduced(l) => write!(f, "Reduce({})", l), + GraphPattern::Slice(l, start, length) => write!( + f, + "Slice({}, {}, {})", + l, + start, + length + .map(|l| l.to_string()) + .unwrap_or_else(|| '?'.to_string()) + ), } } } -impl Default for MultiSetPattern { +impl Default for GraphPattern { fn default() -> Self { - MultiSetPattern::BGP(Vec::default()) + GraphPattern::BGP(Vec::default()) } } -impl From for MultiSetPattern { +impl From for GraphPattern { fn from(p: TripleOrPathPattern) -> Self { - MultiSetPattern::BGP(vec![p]) - } -} - -impl From for MultiSetPattern { - fn from(pattern: ListPattern) -> Self { - MultiSetPattern::ToMultiSet(Box::new(pattern)) + GraphPattern::BGP(vec![p]) } } -impl MultiSetPattern { +impl GraphPattern { pub fn visible_variables(&self) -> BTreeSet<&Variable> { let mut vars = BTreeSet::default(); self.add_visible_variables(&mut vars); @@ -971,7 +1012,7 @@ impl MultiSetPattern { fn add_visible_variables<'a>(&'a self, vars: &mut BTreeSet<&'a Variable>) { match self { - MultiSetPattern::BGP(p) => { + GraphPattern::BGP(p) => { for pattern in p { match pattern { TripleOrPathPattern::Triple(tp) => { @@ -996,28 +1037,33 @@ impl MultiSetPattern { } } } - MultiSetPattern::Join(a, b) => { + GraphPattern::Join(a, b) => { a.add_visible_variables(vars); b.add_visible_variables(vars); } - MultiSetPattern::LeftJoin(a, b, _) => { + GraphPattern::LeftJoin(a, b, _) => { a.add_visible_variables(vars); b.add_visible_variables(vars); } - MultiSetPattern::Filter(_, p) => p.add_visible_variables(vars), - MultiSetPattern::Union(a, b) => { + GraphPattern::Filter(_, p) => p.add_visible_variables(vars), + GraphPattern::Union(a, b) => { a.add_visible_variables(vars); b.add_visible_variables(vars); } - MultiSetPattern::Graph(_, p) => p.add_visible_variables(vars), - MultiSetPattern::Extend(p, v, _) => { + GraphPattern::Graph(_, p) => p.add_visible_variables(vars), + GraphPattern::Extend(p, v, _) => { p.add_visible_variables(vars); adds_if_has_name(vars, &v); } - MultiSetPattern::Minus(a, _) => a.add_visible_variables(vars), - MultiSetPattern::ToMultiSet(l) => l.add_visible_variables(vars), - MultiSetPattern::Service(_, p, _) => p.add_visible_variables(vars), - MultiSetPattern::AggregateJoin(_, a) => vars.extend(a.iter().map(|(_, v)| v)), + GraphPattern::Minus(a, _) => a.add_visible_variables(vars), + GraphPattern::Service(_, p, _) => p.add_visible_variables(vars), + GraphPattern::AggregateJoin(_, a) => vars.extend(a.iter().map(|(_, v)| 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), } } } @@ -1028,223 +1074,61 @@ fn adds_if_has_name<'a>(vars: &mut BTreeSet<&'a Variable>, var: &'a Variable) { } } -struct SparqlMultiSetPattern<'a>(&'a MultiSetPattern); +struct SparqlGraphPattern<'a>(&'a GraphPattern); -impl<'a> fmt::Display for SparqlMultiSetPattern<'a> { +impl<'a> fmt::Display for SparqlGraphPattern<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.0 { - MultiSetPattern::BGP(p) => { - if p.is_empty() { - Ok(()) - } else { - write!( - f, - "{}", - p.iter() - .map(|v| SparqlTripleOrPathPattern(v).to_string()) - .collect::>() - .join(" . ") - ) + GraphPattern::BGP(p) => { + for pattern in p { + write!(f, "{} .", SparqlTripleOrPathPattern(pattern))? } + Ok(()) } - MultiSetPattern::Join(a, b) => write!( - f, - "{} {}", - SparqlMultiSetPattern(&*a), - SparqlMultiSetPattern(&*b) - ), - MultiSetPattern::LeftJoin(a, b, e) => write!( + GraphPattern::Join(a, b) => { + write!(f, "{} {}", SparqlGraphPattern(&*a), SparqlGraphPattern(&*b)) + } + GraphPattern::LeftJoin(a, b, e) => write!( f, "{} OPTIONAL {{ {} FILTER({}) }}", - SparqlMultiSetPattern(&*a), - SparqlMultiSetPattern(&*b), + SparqlGraphPattern(&*a), + SparqlGraphPattern(&*b), SparqlExpression(e) ), - MultiSetPattern::Filter(e, p) => write!( + GraphPattern::Filter(e, p) => write!( f, "{} FILTER({})", - SparqlMultiSetPattern(&*p), + SparqlGraphPattern(&*p), SparqlExpression(e) ), - MultiSetPattern::Union(a, b) => write!( + GraphPattern::Union(a, b) => write!( f, "{{ {} }} UNION {{ {} }}", - SparqlMultiSetPattern(&*a), - SparqlMultiSetPattern(&*b) + SparqlGraphPattern(&*a), + SparqlGraphPattern(&*b), ), - MultiSetPattern::Graph(g, p) => { - write!(f, "GRAPH {} {{ {} }}", g, SparqlMultiSetPattern(&*p)) + GraphPattern::Graph(g, p) => { + write!(f, "GRAPH {} {{ {} }}", g, SparqlGraphPattern(&*p),) } - MultiSetPattern::Extend(p, v, e) => write!( + GraphPattern::Extend(p, v, e) => write!( f, "{} BIND({} AS {})", - SparqlMultiSetPattern(&*p), + SparqlGraphPattern(&*p), SparqlExpression(e), v ), - MultiSetPattern::Minus(a, b) => write!( + GraphPattern::Minus(a, b) => write!( f, "{} MINUS {{ {} }}", - SparqlMultiSetPattern(&*a), - SparqlMultiSetPattern(&*b) - ), - MultiSetPattern::ToMultiSet(l) => write!( - f, - "{{ {} }}", - SparqlListPattern { - algebra: &l, - dataset: &EMPTY_DATASET - } + SparqlGraphPattern(&*a), + SparqlGraphPattern(&*b) ), - MultiSetPattern::Service(n, p, s) => if *s { - write!( - f, - "SERVICE SILENT {} {{ {} }}", - n, - SparqlMultiSetPattern(&*p) - ) + GraphPattern::Service(n, p, s) => if *s { + write!(f, "SERVICE SILENT {} {{ {} }}", n, SparqlGraphPattern(&*p)) } else { - write!(f, "SERVICE {} {{ {} }}", n, SparqlMultiSetPattern(&*p)) + write!(f, "SERVICE {} {{ {} }}", n, SparqlGraphPattern(&*p)) }, - MultiSetPattern::AggregateJoin(GroupPattern(group, p), agg) => write!( - f, - "{{ SELECT {} WHERE {{ {} }} GROUP BY {} }}", - agg.iter() - .map(|(a, v)| format!("({} AS {})", SparqlAggregation(&a), v)) - .collect::>() - .join(" "), - SparqlMultiSetPattern(p), - group - .iter() - .map(|e| format!("({})", e.to_string())) - .collect::>() - .join(" ") - ), - } - } -} - -#[derive(Eq, PartialEq, Ord, PartialOrd, 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 - ) - } -} - -#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] -pub enum ListPattern { - Data(StaticBindings), - ToList(MultiSetPattern), - OrderBy(Box, Vec), - Project(Box, Vec), - Distinct(Box), - Reduced(Box), - Slice(Box, usize, Option), -} - -impl fmt::Display for ListPattern { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - ListPattern::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, " {} → {} ", variables[i], val)?; - } - } - write!(f, "}}")?; - } - write!(f, "}}") - } - ListPattern::ToList(l) => write!(f, "{}", l), - ListPattern::OrderBy(l, o) => write!( - f, - "OrderBy({}, ({}))", - l, - o.iter() - .map(|c| c.to_string()) - .collect::>() - .join(", ") - ), - ListPattern::Project(l, pv) => write!( - f, - "Project({}, ({}))", - l, - pv.iter() - .map(|v| v.to_string()) - .collect::>() - .join(", ") - ), - ListPattern::Distinct(l) => write!(f, "Distinct({})", l), - ListPattern::Reduced(l) => write!(f, "Reduce({})", l), - ListPattern::Slice(l, start, length) => write!( - f, - "Slice({}, {}, {})", - l, - start, - length - .map(|l| l.to_string()) - .unwrap_or_else(|| '?'.to_string()) - ), - } - } -} - -impl Default for ListPattern { - fn default() -> Self { - ListPattern::Data(StaticBindings::default()) - } -} - -impl From for ListPattern { - fn from(pattern: MultiSetPattern) -> Self { - ListPattern::ToList(pattern) - } -} - -impl ListPattern { - pub fn visible_variables<'a>(&'a self) -> BTreeSet<&'a Variable> { - let mut vars = BTreeSet::default(); - self.add_visible_variables(&mut vars); - vars - } - - fn add_visible_variables<'a>(&'a self, vars: &mut BTreeSet<&'a Variable>) { - match self { - ListPattern::Data(b) => vars.extend(b.variables_iter()), - ListPattern::ToList(p) => p.add_visible_variables(vars), - ListPattern::OrderBy(l, _) => l.add_visible_variables(vars), - ListPattern::Project(_, pv) => vars.extend(pv.iter()), - ListPattern::Distinct(l) => l.add_visible_variables(vars), - ListPattern::Reduced(l) => l.add_visible_variables(vars), - ListPattern::Slice(l, _, _) => l.add_visible_variables(vars), - } - } -} - -struct SparqlListPattern<'a> { - algebra: &'a ListPattern, - dataset: &'a DatasetSpec, -} - -impl<'a> fmt::Display for SparqlListPattern<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.algebra { - ListPattern::Data(bs) => if bs.is_empty() { + GraphPattern::Data(bs) => if bs.is_empty() { Ok(()) } else { write!(f, "VALUES ( ")?; @@ -1264,96 +1148,127 @@ impl<'a> fmt::Display for SparqlListPattern<'a> { } write!(f, " }}") }, - ListPattern::ToList(l) => write!(f, "{{ {} }}", SparqlMultiSetPattern(&*l)), - ListPattern::OrderBy(l, o) => write!( + GraphPattern::AggregateJoin(GroupPattern(group, p), agg) => write!( f, - "{} ORDER BY {}", - SparqlListPattern { - algebra: &*l, - dataset: self.dataset - }, - o.iter() - .map(|c| SparqlOrderComparator(c).to_string()) + "{{ SELECT {} WHERE {{ {} }} GROUP BY {} }}", + agg.iter() + .map(|(a, v)| format!("({} AS {})", SparqlAggregation(&a), v)) + .collect::>() + .join(" "), + SparqlGraphPattern(&*p), + group + .iter() + .map(|e| format!("({})", e.to_string())) .collect::>() .join(" ") ), - ListPattern::Project(l, pv) => write!( + p => write!( f, - "SELECT {} {} WHERE {}", - build_sparql_select_arguments(pv), - self.dataset, - SparqlListPattern { - algebra: &*l, + "{{ {} }}", + SparqlGraphRootPattern { + algebra: p, dataset: &EMPTY_DATASET } ), - ListPattern::Distinct(l) => match l.as_ref() { - ListPattern::Project(l, pv) => write!( - f, - "SELECT DISTINCT {} {} WHERE {}", - build_sparql_select_arguments(pv), - self.dataset, - SparqlListPattern { - algebra: &*l, - dataset: &EMPTY_DATASET - } - ), - l => write!( - f, - "DISTINCT {}", - SparqlListPattern { - algebra: &l, - dataset: self.dataset - } - ), - }, - ListPattern::Reduced(l) => match l.as_ref() { - ListPattern::Project(l, pv) => write!( - f, - "SELECT REDUCED {} {} WHERE {}", - build_sparql_select_arguments(pv), - self.dataset, - SparqlListPattern { - algebra: &*l, - dataset: &EMPTY_DATASET + } + } +} + +struct SparqlGraphRootPattern<'a> { + algebra: &'a GraphPattern, + dataset: &'a DatasetSpec, +} + +impl<'a> fmt::Display for SparqlGraphRootPattern<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut distinct = false; + let mut reduced = false; + let mut order = None; + let mut start = 0; + let mut length = None; + let mut project: &[Variable] = &[]; + + let mut child = self.algebra; + loop { + match child { + GraphPattern::OrderBy(l, o) => { + order = Some(o); + child = &*l; + } + GraphPattern::Project(l, pv) if project.is_empty() => { + project = pv; + child = &*l; + } + GraphPattern::Distinct(l) => { + distinct = true; + child = &*l; + } + GraphPattern::Reduced(l) => { + reduced = true; + child = &*l; + } + GraphPattern::Slice(l, s, len) => { + start = *s; + length = *len; + child = l; + } + p => { + write!(f, "SELECT ")?; + if distinct { + write!(f, "DISTINCT ")?; } - ), - l => write!( - f, - "REDUCED {}", - SparqlListPattern { - algebra: &l, - dataset: self.dataset + if reduced { + write!(f, "REDUCED ")?; } - ), - }, - ListPattern::Slice(l, start, length) => length - .map(|length| { - write!( - f, - "{} LIMIT {} OFFSET {}", - SparqlListPattern { - algebra: &*l, - dataset: self.dataset - }, - start, - length - ) - }).unwrap_or_else(|| { write!( f, - "{} LIMIT {}", - SparqlListPattern { - algebra: &*l, - dataset: self.dataset - }, - start - ) - }), + "{} {} WHERE {{ {} }}", + build_sparql_select_arguments(project), + self.dataset, + SparqlGraphPattern(p) + )?; + if let Some(order) = order { + write!( + f, + " ORDER BY {}", + order + .iter() + .map(|c| SparqlOrderComparator(c).to_string()) + .collect::>() + .join(" ") + )?; + } + if start > 0 { + write!(f, " OFFSET {}", start)?; + } + if let Some(length) = length { + write!(f, " LIMIT {}", length)?; + } + return Ok(()); + } + } } } } +#[derive(Eq, PartialEq, Ord, PartialOrd, 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() @@ -1589,20 +1504,20 @@ lazy_static! { pub enum Query { SelectQuery { dataset: DatasetSpec, - algebra: ListPattern, + algebra: GraphPattern, }, ConstructQuery { construct: Vec, dataset: DatasetSpec, - algebra: ListPattern, + algebra: GraphPattern, }, DescribeQuery { dataset: DatasetSpec, - algebra: ListPattern, + algebra: GraphPattern, }, AskQuery { dataset: DatasetSpec, - algebra: ListPattern, + algebra: GraphPattern, }, } @@ -1612,7 +1527,7 @@ impl fmt::Display for Query { Query::SelectQuery { dataset, algebra } => write!( f, "{}", - SparqlListPattern { + SparqlGraphRootPattern { algebra: &algebra, dataset: &dataset } @@ -1630,7 +1545,7 @@ impl fmt::Display for Query { .collect::>() .join(" . "), dataset, - SparqlListPattern { + SparqlGraphRootPattern { algebra: &algebra, dataset: &EMPTY_DATASET } @@ -1639,7 +1554,7 @@ impl fmt::Display for Query { f, "DESCRIBE * {} WHERE {{ {} }}", dataset, - SparqlListPattern { + SparqlGraphRootPattern { algebra: &algebra, dataset: &EMPTY_DATASET } @@ -1648,7 +1563,7 @@ impl fmt::Display for Query { f, "ASK {} WHERE {{ {} }}", dataset, - SparqlListPattern { + SparqlGraphRootPattern { algebra: &algebra, dataset: &EMPTY_DATASET } diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index d14e4d35..bd2c45e1 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -163,47 +163,20 @@ impl SparqlEvaluator { match query { Query::SelectQuery { algebra, dataset } => { Ok(QueryResult::Bindings(self.decode_bindings( - self.eval_list_pattern(algebra, EncodedBindingsIterator::default())?, + self.eval_graph_pattern(algebra, EncodedBindingsIterator::default())?, ))) } _ => unimplemented!(), } } - fn eval_list_pattern( + fn eval_graph_pattern( &self, - pattern: &ListPattern, + pattern: &GraphPattern, from: EncodedBindingsIterator, ) -> Result { match pattern { - ListPattern::Data(bs) => Ok(self.encode_bindings(bs)), - ListPattern::ToList(l) => self.eval_multi_set_pattern(l, from), - ListPattern::OrderBy(l, o) => self.eval_list_pattern(l, from), //TODO - ListPattern::Project(l, new_variables) => Ok(self - .eval_list_pattern(l, from)? - .project(new_variables.to_vec())), - ListPattern::Distinct(l) => Ok(self.eval_list_pattern(l, from)?.unique()), - ListPattern::Reduced(l) => self.eval_list_pattern(l, from), - ListPattern::Slice(l, start, length) => { - let mut iter = self.eval_list_pattern(l, from)?; - if *start > 0 { - iter = iter.skip(*start); - } - if let Some(length) = length { - iter = iter.take(*length); - } - Ok(iter) - } - } - } - - fn eval_multi_set_pattern( - &self, - pattern: &MultiSetPattern, - from: EncodedBindingsIterator, - ) -> Result { - match pattern { - MultiSetPattern::BGP(p) => { + GraphPattern::BGP(p) => { let mut iter = from; for pattern in p { iter = match pattern { @@ -215,13 +188,13 @@ impl SparqlEvaluator { } Ok(iter) } - MultiSetPattern::Join(a, b) => { - self.eval_multi_set_pattern(b, self.eval_multi_set_pattern(a, from)?) + GraphPattern::Join(a, b) => { + self.eval_graph_pattern(b, self.eval_graph_pattern(a, from)?) } - MultiSetPattern::LeftJoin(a, b, e) => unimplemented!(), - MultiSetPattern::Filter(e, p) => { + GraphPattern::LeftJoin(a, b, e) => unimplemented!(), + GraphPattern::Filter(e, p) => { let EncodedBindingsIterator { variables, iter } = - self.eval_multi_set_pattern(p, from)?; + self.eval_graph_pattern(p, from)?; let expression = e.clone(); let evaluator = Self { store: self.store.clone(), @@ -239,18 +212,34 @@ impl SparqlEvaluator { })), }) } - MultiSetPattern::Union(a, b) => { + GraphPattern::Union(a, b) => { let (from1, from2) = from.duplicate(); Ok(self - .eval_multi_set_pattern(a, from1)? - .chain(self.eval_multi_set_pattern(b, from2)?)) + .eval_graph_pattern(a, from1)? + .chain(self.eval_graph_pattern(b, from2)?)) + } + GraphPattern::Graph(g, p) => unimplemented!(), + GraphPattern::Extend(p, v, e) => unimplemented!(), + GraphPattern::Minus(a, b) => unimplemented!(), + GraphPattern::Service(n, p, s) => unimplemented!(), + GraphPattern::AggregateJoin(g, a) => unimplemented!(), + GraphPattern::Data(bs) => Ok(self.encode_bindings(bs)), + GraphPattern::OrderBy(l, o) => self.eval_graph_pattern(l, from), //TODO + GraphPattern::Project(l, new_variables) => Ok(self + .eval_graph_pattern(l, from)? + .project(new_variables.to_vec())), + GraphPattern::Distinct(l) => Ok(self.eval_graph_pattern(l, from)?.unique()), + GraphPattern::Reduced(l) => self.eval_graph_pattern(l, from), + GraphPattern::Slice(l, start, length) => { + let mut iter = self.eval_graph_pattern(l, from)?; + if *start > 0 { + iter = iter.skip(*start); + } + if let Some(length) = length { + iter = iter.take(*length); + } + Ok(iter) } - MultiSetPattern::Graph(g, p) => unimplemented!(), - MultiSetPattern::Extend(p, v, e) => unimplemented!(), - MultiSetPattern::Minus(a, b) => unimplemented!(), - MultiSetPattern::ToMultiSet(l) => self.eval_list_pattern(l, from), - MultiSetPattern::Service(n, p, s) => unimplemented!(), - MultiSetPattern::AggregateJoin(g, a) => unimplemented!(), } } diff --git a/lib/src/sparql/parser.rs b/lib/src/sparql/parser.rs index cb5ea015..d2c7b74f 100644 --- a/lib/src/sparql/parser.rs +++ b/lib/src/sparql/parser.rs @@ -140,21 +140,21 @@ mod grammar { #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] enum PartialGraphPattern { - Optional(MultiSetPattern), - Minus(MultiSetPattern), + Optional(GraphPattern), + Minus(GraphPattern), Bind(Expression, Variable), Filter(Expression), - Other(MultiSetPattern), + Other(GraphPattern), } - fn new_join(l: MultiSetPattern, r: MultiSetPattern) -> MultiSetPattern { + fn new_join(l: GraphPattern, r: GraphPattern) -> GraphPattern { //Avoid to output empty BGPs - if let MultiSetPattern::BGP(pl) = &l { + if let GraphPattern::BGP(pl) = &l { if pl.is_empty() { return r; } } - if let MultiSetPattern::BGP(pr) = &r { + if let GraphPattern::BGP(pr) = &r { if pr.is_empty() { return l; } @@ -162,11 +162,11 @@ mod grammar { //Merge BGPs match (l, r) { - (MultiSetPattern::BGP(mut pl), MultiSetPattern::BGP(pr)) => { + (GraphPattern::BGP(mut pl), GraphPattern::BGP(pr)) => { pl.extend_from_slice(&pr); - MultiSetPattern::BGP(pl) + GraphPattern::BGP(pl) } - (l, r) => MultiSetPattern::Join(Box::new(l), Box::new(r)), + (l, r) => GraphPattern::Join(Box::new(l), Box::new(r)), } } @@ -207,28 +207,28 @@ mod grammar { fn build_select( select: Selection, - wher: MultiSetPattern, + wher: GraphPattern, group: Option<(Vec, Vec<(Expression, Variable)>)>, having: Option, order_by: Option>, offset_limit: Option<(usize, Option)>, - values: Option, + values: Option, state: &mut ParserState, - ) -> ListPattern { + ) -> GraphPattern { let mut p = wher; //GROUP BY if let Some((clauses, binds)) = group { for (e, v) in binds { - p = MultiSetPattern::Extend(Box::new(p), v, e); + p = GraphPattern::Extend(Box::new(p), v, e); } let g = GroupPattern(clauses, Box::new(p)); - p = MultiSetPattern::AggregateJoin(g, state.aggregations.clone()); + p = GraphPattern::AggregateJoin(g, state.aggregations.clone()); state.aggregations = BTreeMap::default(); } if !state.aggregations.is_empty() { let g = GroupPattern(vec![Literal::from(1).into()], Box::new(p)); - p = MultiSetPattern::AggregateJoin(g, state.aggregations.clone()); + p = GraphPattern::AggregateJoin(g, state.aggregations.clone()); state.aggregations = BTreeMap::default(); } @@ -236,12 +236,12 @@ mod grammar { //HAVING if let Some(ex) = having { - p = MultiSetPattern::Filter(ex, Box::new(p)); + p = GraphPattern::Filter(ex, Box::new(p)); } //VALUES if let Some(data) = values { - p = MultiSetPattern::Join(Box::new(p), Box::new(data)); + p = new_join(p, data); } //SELECT @@ -254,7 +254,7 @@ mod grammar { SelectionMember::Expression(e, v) => if pv.contains(&v) { //TODO: fail } else { - p = MultiSetPattern::Extend(Box::new(p), v.clone(), e); + p = GraphPattern::Extend(Box::new(p), v.clone(), e); pv.push(v); }, } @@ -264,24 +264,24 @@ mod grammar { pv.extend(p.visible_variables().into_iter().cloned()) //TODO: is it really useful to do a projection? } } - let mut m = ListPattern::from(p); + let mut m = GraphPattern::from(p); //ORDER BY if let Some(order) = order_by { - m = ListPattern::OrderBy(Box::new(m), order); + m = GraphPattern::OrderBy(Box::new(m), order); } //PROJECT - m = ListPattern::Project(Box::new(m), pv); + m = GraphPattern::Project(Box::new(m), pv); match select.option { - SelectionOption::Distinct => m = ListPattern::Distinct(Box::new(m)), - SelectionOption::Reduced => m = ListPattern::Reduced(Box::new(m)), + SelectionOption::Distinct => m = GraphPattern::Distinct(Box::new(m)), + SelectionOption::Reduced => m = GraphPattern::Reduced(Box::new(m)), SelectionOption::Default => (), } //OFFSET LIMIT if let Some((offset, limit)) = offset_limit { - m = ListPattern::Slice(Box::new(m), offset, limit) + m = GraphPattern::Slice(Box::new(m), offset, limit) } m } diff --git a/lib/src/sparql/sparql_grammar.rustpeg b/lib/src/sparql/sparql_grammar.rustpeg index 2dadb2cc..ac68711d 100644 --- a/lib/src/sparql/sparql_grammar.rustpeg +++ b/lib/src/sparql/sparql_grammar.rustpeg @@ -45,7 +45,7 @@ SelectQuery -> Query = s:SelectClause _ d:DatasetClauses _ w:WhereClause _ g:Gro } //[8] -SubSelect -> MultiSetPattern = s:SelectClause _ w:WhereClause _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { //TODO: Modifiers +SubSelect -> GraphPattern = s:SelectClause _ w:WhereClause _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { //TODO: Modifiers build_select(s, w, g, h, o, l, v, state).into() } @@ -82,7 +82,7 @@ ConstructQuery -> Query = dataset: d, algebra: build_select( Selection::default(), - MultiSetPattern::BGP(c.into_iter().map(TripleOrPathPattern::from).collect()), + GraphPattern::BGP(c.into_iter().map(TripleOrPathPattern::from).collect()), g, h, o, l, v, state ) } @@ -95,7 +95,7 @@ DescribeQuery -> Query = "DESCRIBE"i _ '*' _ d:DatasetClauses w:WhereClause? _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { Query::DescribeQuery { dataset: d, - algebra: build_select(Selection::default(), w.unwrap_or_else(MultiSetPattern::default), g, h, o, l, v, state) + algebra: build_select(Selection::default(), w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state) } } / "DESCRIBE"i _ p:DescribeQuery_item+ _ d:DatasetClauses w:WhereClause? _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { @@ -107,7 +107,7 @@ DescribeQuery -> Query = NamedNodeOrVariable::NamedNode(n) => SelectionMember::Expression(n.into(), Variable::default()), NamedNodeOrVariable::Variable(v) => SelectionMember::Variable(v) }).collect()) - }, w.unwrap_or_else(MultiSetPattern::default), g, h, o, l, v, state) + }, w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state) } } DescribeQuery_item -> NamedNodeOrVariable = i:VarOrIri _ { i } @@ -140,7 +140,7 @@ NamedGraphClause -> DatasetSpec = "NAMED"i _ s:SourceSelector { SourceSelector -> NamedNode = iri //[17] -WhereClause -> MultiSetPattern = "WHERE"i? _ p:GroupGraphPattern { +WhereClause -> GraphPattern = "WHERE"i? _ p:GroupGraphPattern { p } @@ -203,7 +203,7 @@ OffsetClause -> usize = "OFFSET"i _ o:$(INTEGER) {? } //[28] -ValuesClause -> Option = +ValuesClause -> Option = "VALUES"i _ p:DataBlock { Some(p) } / { None } @@ -220,33 +220,33 @@ TriplesTemplate_tail -> Vec = '.' _ t:TriplesTemplate? _ { } //[53] -GroupGraphPattern -> MultiSetPattern = +GroupGraphPattern -> GraphPattern = '{' _ p:GroupGraphPatternSub _ '}' { p } / '{' _ p:SubSelect _ '}' { p } //[54] -GroupGraphPatternSub -> MultiSetPattern = a:TriplesBlock? _ b:GroupGraphPatternSub_item* { - let mut p = a.map(|v| vec![PartialGraphPattern::Other(MultiSetPattern::BGP(v))]).unwrap_or_else(|| vec![]); +GroupGraphPatternSub -> GraphPattern = a:TriplesBlock? _ b:GroupGraphPatternSub_item* { + let mut p = a.map(|v| vec![PartialGraphPattern::Other(GraphPattern::BGP(v))]).unwrap_or_else(|| vec![]); for v in b { p.extend_from_slice(&v) } let mut filter: Option = None; - let mut g = MultiSetPattern::default(); + let mut g = GraphPattern::default(); for e in p { match e { PartialGraphPattern::Optional(p) => match p { - MultiSetPattern::Filter(f, a2) => { - g = MultiSetPattern::LeftJoin(Box::new(g), a2, f) + GraphPattern::Filter(f, a2) => { + g = GraphPattern::LeftJoin(Box::new(g), a2, f) } a => { - g = MultiSetPattern::LeftJoin(Box::new(g), Box::new(a), Literal::from(true).into()) + g = GraphPattern::LeftJoin(Box::new(g), Box::new(a), Literal::from(true).into()) } } PartialGraphPattern::Minus(p) => { - g = MultiSetPattern::Minus(Box::new(g), Box::new(p)) + g = GraphPattern::Minus(Box::new(g), Box::new(p)) } PartialGraphPattern::Bind(expr, var) => { - g = MultiSetPattern::Extend(Box::new(g), var, expr) + g = GraphPattern::Extend(Box::new(g), var, expr) } PartialGraphPattern::Filter(expr) => match filter { Some(f) => { filter = Some(Expression::AndExpression(Box::new(f), Box::new(expr))) }, @@ -256,14 +256,14 @@ GroupGraphPatternSub -> MultiSetPattern = a:TriplesBlock? _ b:GroupGraphPatternS } } match filter { - Some(filter) => MultiSetPattern::Filter(filter, Box::new(g)), + Some(filter) => GraphPattern::Filter(filter, Box::new(g)), None => g } } GroupGraphPatternSub_item -> Vec = a:GraphPatternNotTriples _ ('.' _)? b:TriplesBlock? _ { let mut result = vec![a]; if let Some(v) = b { - result.push(PartialGraphPattern::Other(MultiSetPattern::BGP(v))); + result.push(PartialGraphPattern::Other(GraphPattern::BGP(v))); } result } @@ -290,13 +290,13 @@ OptionalGraphPattern -> PartialGraphPattern = "OPTIONAL"i _ p:GroupGraphPattern //[58] GraphGraphPattern -> PartialGraphPattern = "GRAPH"i _ g:VarOrIri _ p:GroupGraphPattern { - PartialGraphPattern::Other(MultiSetPattern::Graph(g, Box::new(p))) + PartialGraphPattern::Other(GraphPattern::Graph(g, Box::new(p))) } //[59] ServiceGraphPattern -> PartialGraphPattern = - "SERVICE"i _ "SILENT"i _ s:VarOrIri _ p:GroupGraphPattern { PartialGraphPattern::Other(MultiSetPattern::Service(s, Box::new(p), true)) } / - "SERVICE"i _ s:VarOrIri _ p:GroupGraphPattern { PartialGraphPattern::Other(MultiSetPattern::Service(s, Box::new(p), false)) } + "SERVICE"i _ "SILENT"i _ s:VarOrIri _ p:GroupGraphPattern { PartialGraphPattern::Other(GraphPattern::Service(s, Box::new(p), true)) } / + "SERVICE"i _ s:VarOrIri _ p:GroupGraphPattern { PartialGraphPattern::Other(GraphPattern::Service(s, Box::new(p), false)) } //[60] Bind -> PartialGraphPattern = "BIND"i _ '(' _ e:Expression _ "AS"i _ v:Var _ ')' { @@ -307,8 +307,8 @@ Bind -> PartialGraphPattern = "BIND"i _ '(' _ e:Expression _ "AS"i _ v:Var _ ')' InlineData -> PartialGraphPattern = "VALUES"i _ p:DataBlock { PartialGraphPattern::Other(p) } //[62] -DataBlock -> MultiSetPattern = l:(InlineDataOneVar / InlineDataFull) { - ListPattern::Data(l).into() +DataBlock -> GraphPattern = l:(InlineDataOneVar / InlineDataFull) { + GraphPattern::Data(l).into() } //[63] @@ -341,10 +341,10 @@ MinusGraphPattern -> PartialGraphPattern = "MINUS"i _ p: GroupGraphPattern { //[67] GroupOrUnionGraphPattern -> PartialGraphPattern = p:GroupOrUnionGraphPattern_item **<1,> ("UNION"i _) {? not_empty_fold(p.into_iter(), |a, b| { - MultiSetPattern::Union(Box::new(a), Box::new(b)) + GraphPattern::Union(Box::new(a), Box::new(b)) }).map(PartialGraphPattern::Other) } -GroupOrUnionGraphPattern_item -> MultiSetPattern = p:GroupGraphPattern _ { p } +GroupOrUnionGraphPattern_item -> GraphPattern = p:GroupGraphPattern _ { p } //[68] Filter -> PartialGraphPattern = "FILTER"i _ c:Constraint {