diff --git a/src/sparql/algebra.rs b/src/sparql/algebra.rs index 97003d2d..bb46e6c8 100644 --- a/src/sparql/algebra.rs +++ b/src/sparql/algebra.rs @@ -1,5 +1,6 @@ use model::*; use sparql::model::*; +use std::collections::BTreeMap; use std::collections::BTreeSet; use std::fmt; use std::ops::Add; @@ -234,13 +235,6 @@ pub enum Expression { RegexFunctionCall(Box, Box, Option>), CustomFunctionCall(NamedNode, Vec), ExistsFunctionCall(Box), - CountAggregate(Option>, bool), - SumAggregate(Box, bool), - MinAggregate(Box, bool), - MaxAggregate(Box, bool), - AvgAggregate(Box, bool), - SampleAggregate(Box, bool), - GroupConcatAggregate(Box, bool, Option), } impl fmt::Display for Expression { @@ -361,56 +355,6 @@ impl fmt::Display for Expression { .join(", ") ), Expression::ExistsFunctionCall(p) => write!(f, "EXISTS {{ {} }}", p), - Expression::CountAggregate(e, distinct) => if *distinct { - e.as_ref() - .map(|ex| write!(f, "COUNT(DISTINCT {})", ex)) - .unwrap_or_else(|| write!(f, "COUNT(DISTINCT *)")) - } else { - e.as_ref() - .map(|ex| write!(f, "COUNT({})", ex)) - .unwrap_or_else(|| write!(f, "COUNT(*)")) - }, - Expression::SumAggregate(e, distinct) => if *distinct { - write!(f, "SUM(DISTINCT {})", e) - } else { - write!(f, "SUM({})", e) - }, - Expression::MinAggregate(e, distinct) => if *distinct { - write!(f, "MIN(DISTINCT {})", e) - } else { - write!(f, "MIN({})", e) - }, - Expression::MaxAggregate(e, distinct) => if *distinct { - write!(f, "MAX(DISTINCT {})", e) - } else { - write!(f, "MAX({})", e) - }, - Expression::AvgAggregate(e, distinct) => if *distinct { - write!(f, "AVG(DISTINCT {})", e) - } else { - write!(f, "AVG({})", e) - }, - Expression::SampleAggregate(e, distinct) => if *distinct { - write!(f, "SAMPLE(DISTINCT {})", e) - } else { - write!(f, "SAMPLE({})", e) - }, - Expression::GroupConcatAggregate(e, distinct, sep) => if *distinct { - sep.as_ref() - .map(|s| { - write!( - f, - "GROUP_CONCAT(DISTINCT {}; SEPARATOR = \"{}\")", - e, - s.escape() - ) - }) - .unwrap_or_else(|| write!(f, "GROUP_CONCAT(DISTINCT {})", e)) - } else { - sep.as_ref() - .map(|s| write!(f, "GROUP_CONCAT({}; SEPARATOR = \"{}\")", e, s.escape())) - .unwrap_or_else(|| write!(f, "GROUP_CONCAT({})", e)) - }, } } } @@ -703,63 +647,6 @@ impl<'a> fmt::Display for SparqlExpression<'a> { Expression::ExistsFunctionCall(p) => { write!(f, "EXISTS {{ {} }}", SparqlMultiSetPattern(&*p)) } - Expression::CountAggregate(e, distinct) => if *distinct { - e.as_ref() - .map(|ex| write!(f, "COUNT(DISTINCT {})", SparqlExpression(ex))) - .unwrap_or_else(|| write!(f, "COUNT(DISTINCT *)")) - } else { - e.as_ref() - .map(|ex| write!(f, "COUNT({})", SparqlExpression(ex))) - .unwrap_or_else(|| write!(f, "COUNT(*)")) - }, - Expression::SumAggregate(e, distinct) => if *distinct { - write!(f, "SUM(DISTINCT {})", SparqlExpression(e)) - } else { - write!(f, "SUM({})", SparqlExpression(e)) - }, - Expression::MinAggregate(e, distinct) => if *distinct { - write!(f, "MIN(DISTINCT {})", SparqlExpression(e)) - } else { - write!(f, "MIN({})", SparqlExpression(e)) - }, - Expression::MaxAggregate(e, distinct) => if *distinct { - write!(f, "MAX(DISTINCT {})", SparqlExpression(e)) - } else { - write!(f, "MAX({})", SparqlExpression(e)) - }, - Expression::AvgAggregate(e, distinct) => if *distinct { - write!(f, "AVG(DISTINCT {})", SparqlExpression(e)) - } else { - write!(f, "AVG({})", SparqlExpression(e)) - }, - Expression::SampleAggregate(e, distinct) => if *distinct { - write!(f, "SAMPLE(DISTINCT {})", SparqlExpression(e)) - } else { - write!(f, "SAMPLE({})", SparqlExpression(e)) - }, - Expression::GroupConcatAggregate(e, distinct, sep) => if *distinct { - sep.as_ref() - .map(|s| { - write!( - f, - "GROUP_CONCAT(DISTINCT {}; SEPARATOR = \"{}\")", - SparqlExpression(e), - s.escape() - ) - }) - .unwrap_or_else(|| write!(f, "GROUP_CONCAT(DISTINCT {})", SparqlExpression(e))) - } else { - sep.as_ref() - .map(|s| { - write!( - f, - "GROUP_CONCAT({}; SEPARATOR = \"{}\")", - SparqlExpression(e), - s.escape() - ) - }) - .unwrap_or_else(|| write!(f, "GROUP_CONCAT({})", SparqlExpression(e))) - }, } } } @@ -776,6 +663,7 @@ pub enum MultiSetPattern { Minus(Box, Box), ToMultiSet(Box), Service(NamedNodeOrVariable, Box, bool), + AggregateJoin(GroupPattern, BTreeMap), } impl fmt::Display for MultiSetPattern { @@ -798,6 +686,15 @@ impl fmt::Display for MultiSetPattern { 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!( + f, + "AggregateJoin({}, {})", + g, + a.iter() + .map(|(a, v)| format!("{}: {}", v, a)) + .collect::>() + .join(", ") + ), } } } @@ -878,6 +775,7 @@ impl MultiSetPattern { 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)), } } } @@ -960,10 +858,42 @@ impl<'a> fmt::Display for SparqlMultiSetPattern<'a> { } else { write!(f, "SERVICE {} {{ {} }}", n, SparqlMultiSetPattern(&*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(Vec), @@ -1191,6 +1121,147 @@ fn build_sparql_select_arguments(args: &Vec) -> String { } } +#[derive(Eq, PartialEq, Ord, PartialOrd, 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), +} + +impl fmt::Display for Aggregation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Aggregation::Count(e, distinct) => if *distinct { + e.as_ref() + .map(|ex| write!(f, "COUNT(DISTINCT {})", ex)) + .unwrap_or_else(|| write!(f, "COUNT(DISTINCT *)")) + } else { + e.as_ref() + .map(|ex| write!(f, "COUNT({})", ex)) + .unwrap_or_else(|| write!(f, "COUNT(*)")) + }, + Aggregation::Sum(e, distinct) => if *distinct { + write!(f, "Aggregation(Distinct({}), Sum, {{}})", e) + } else { + write!(f, "Aggregation({}, Sum, {{}})", e) + }, + Aggregation::Min(e, distinct) => if *distinct { + write!(f, "Aggregation(Distinct({}), Min, {{}})", e) + } else { + write!(f, "Aggregation({}, Min, {{}})", e) + }, + Aggregation::Max(e, distinct) => if *distinct { + write!(f, "Aggregation(Distinct({}), Max, {{}})", e) + } else { + write!(f, "Aggregation({}, Max, {{}})", e) + }, + Aggregation::Avg(e, distinct) => if *distinct { + write!(f, "Aggregation(Distinct({}), Avg, {{}})", e) + } else { + write!(f, "Aggregation({}, Avg, {{}})", e) + }, + Aggregation::Sample(e, distinct) => if *distinct { + write!(f, "Aggregation(Distinct({}), Sum, {{}})", e) + } else { + write!(f, "Aggregation({}, Sample, {{}})", e) + }, + Aggregation::GroupConcat(e, distinct, sep) => if *distinct { + sep.as_ref() + .map(|s| { + write!( + f, + "Aggregation(Distinct({}), GroupConcat, {{\"separator\" → \"{}\"}})", + e, + s.escape() + ) + }) + .unwrap_or_else(|| write!(f, "Aggregation(Distinct({}), GroupConcat, {{}})", e)) + } else { + sep.as_ref() + .map(|s| { + write!( + f, + "Aggregation({}, GroupConcat, {{\"separator\" → \"{}\"}})", + e, + s.escape() + ) + }) + .unwrap_or_else(|| write!(f, "Aggregation(Distinct({}), GroupConcat, {{}})", e)) + }, + } + } +} + +struct SparqlAggregation<'a>(&'a Aggregation); + +impl<'a> fmt::Display for SparqlAggregation<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + Aggregation::Count(e, distinct) => if *distinct { + e.as_ref() + .map(|ex| write!(f, "COUNT(DISTINCT {})", SparqlExpression(ex))) + .unwrap_or_else(|| write!(f, "COUNT(DISTINCT *)")) + } else { + e.as_ref() + .map(|ex| write!(f, "COUNT({})", SparqlExpression(ex))) + .unwrap_or_else(|| write!(f, "COUNT(*)")) + }, + Aggregation::Sum(e, distinct) => if *distinct { + write!(f, "SUM(DISTINCT {})", SparqlExpression(e)) + } else { + write!(f, "SUM({})", SparqlExpression(e)) + }, + Aggregation::Min(e, distinct) => if *distinct { + write!(f, "MIN(DISTINCT {})", SparqlExpression(e)) + } else { + write!(f, "MIN({})", SparqlExpression(e)) + }, + Aggregation::Max(e, distinct) => if *distinct { + write!(f, "MAX(DISTINCT {})", SparqlExpression(e)) + } else { + write!(f, "MAX({})", SparqlExpression(e)) + }, + Aggregation::Avg(e, distinct) => if *distinct { + write!(f, "AVG(DISTINCT {})", SparqlExpression(e)) + } else { + write!(f, "AVG({})", SparqlExpression(e)) + }, + Aggregation::Sample(e, distinct) => if *distinct { + write!(f, "SAMPLE(DISTINCT {})", SparqlExpression(e)) + } else { + write!(f, "SAMPLE({})", SparqlExpression(e)) + }, + Aggregation::GroupConcat(e, distinct, sep) => if *distinct { + sep.as_ref() + .map(|s| { + write!( + f, + "GROUP_CONCAT(DISTINCT {}; SEPARATOR = \"{}\")", + SparqlExpression(e), + s.escape() + ) + }) + .unwrap_or_else(|| write!(f, "GROUP_CONCAT(DISTINCT {})", SparqlExpression(e))) + } else { + sep.as_ref() + .map(|s| { + write!( + f, + "GROUP_CONCAT({}; SEPARATOR = \"{}\")", + SparqlExpression(e), + s.escape() + ) + }) + .unwrap_or_else(|| write!(f, "GROUP_CONCAT({})", SparqlExpression(e))) + }, + } + } +} + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] pub enum OrderComparator { Asc(Expression), diff --git a/src/sparql/model.rs b/src/sparql/model.rs index 3b779b99..1afa2520 100644 --- a/src/sparql/model.rs +++ b/src/sparql/model.rs @@ -24,7 +24,7 @@ impl fmt::Display for Variable { impl Default for Variable { fn default() -> Self { Self { - name: Uuid::new_v4().to_string(), + name: Uuid::new_v4().simple().to_string(), } } } diff --git a/src/sparql/parser.rs b/src/sparql/parser.rs index 71e64f1c..831cb90f 100644 --- a/src/sparql/parser.rs +++ b/src/sparql/parser.rs @@ -177,18 +177,43 @@ mod grammar { fn build_select( select: Selection, wher: MultiSetPattern, + group: Option<(Vec, Vec<(Expression, Variable)>)>, having: Option, order_by: Option>, offset_limit: Option<(usize, Option)>, values: Option, + state: &mut ParserState, ) -> ListPattern { 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); + } + let g = GroupPattern(clauses, Box::new(p)); + p = MultiSetPattern::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()); + state.aggregations = BTreeMap::default(); + } + + //TODO: not aggregated vars + + //HAVING if let Some(ex) = having { p = MultiSetPattern::Filter(ex, Box::new(p)); } + + //VALUES if let Some(data) = values { p = MultiSetPattern::Join(Box::new(p), Box::new(data)); } + + //SELECT let mut pv: Vec = Vec::default(); match select.variables { Some(sel_items) => { @@ -209,15 +234,21 @@ mod grammar { } } let mut m = ListPattern::from(p); + + //ORDER BY if let Some(order) = order_by { m = ListPattern::OrderBy(Box::new(m), order); } + + //PROJECT m = ListPattern::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::Default => (), } + + //OFFSET LIMIT if let Some((offset, limit)) = offset_limit { m = ListPattern::Slice(Box::new(m), offset, limit) } @@ -233,12 +264,24 @@ mod grammar { base_uri: Option, namespaces: HashMap, bnodes_map: BTreeMap, + aggregations: BTreeMap, } impl ParserState { fn url_parser<'a>(&'a self) -> ParseOptions<'a> { Url::options().base_url(self.base_uri.as_ref()) } + + fn new_aggregation(&mut self, agg: Aggregation) -> Variable { + self.aggregations + .get(&agg) + .map(|v| v.clone()) + .unwrap_or_else(|| { + let new_var = Variable::default(); + self.aggregations.insert(agg, new_var.clone()); + new_var + }) + } } include!(concat!(env!("OUT_DIR"), "/sparql_grammar.rs")); @@ -251,6 +294,7 @@ mod grammar { base_uri: base_uri.into(), namespaces: HashMap::default(), bnodes_map: BTreeMap::default(), + aggregations: BTreeMap::default(), }; let mut string_buffer = String::default(); diff --git a/src/sparql/sparql_grammar.rustpeg b/src/sparql/sparql_grammar.rustpeg index ff4dd980..398819ef 100644 --- a/src/sparql/sparql_grammar.rustpeg +++ b/src/sparql/sparql_grammar.rustpeg @@ -38,16 +38,16 @@ PrefixDecl -> () = "PREFIX"i _ ns:PNAME_NS _ i:IRIREF { } //[7] -SelectQuery -> Query = s:SelectClause _ d:DatasetClauses _ w:WhereClause _ GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { //TODO: Modifier +SelectQuery -> Query = s:SelectClause _ d:DatasetClauses _ w:WhereClause _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { //TODO: Modifier Query::SelectQuery { dataset: d, - algebra: build_select(s, w, h, o, l, v) + algebra: build_select(s, w, g, h, o, l, v, state) } } //[8] -SubSelect -> MultiSetPattern = s:SelectClause _ w:WhereClause _ GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { //TODO: Modifiers - build_select(s, w, h, o, l, v).into() +SubSelect -> MultiSetPattern = 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() } //[9] @@ -70,21 +70,21 @@ SelectClause_member -> SelectionMember = //[10] ConstructQuery -> Query = - "CONSTRUCT"i _ c:ConstructTemplate _ d:DatasetClauses _ w:WhereClause _ GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { + "CONSTRUCT"i _ c:ConstructTemplate _ d:DatasetClauses _ w:WhereClause _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { Query::ConstructQuery { construct: c, dataset: d, - algebra: build_select(Selection::default(), w, h, o, l, v) + algebra: build_select(Selection::default(), w, g, h, o, l, v, state) } } / - "CONSTRUCT"i _ d:DatasetClauses _ "WHERE"i _ '{' _ c:ConstructQuery_optional_triple_template _ '}' _ GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { + "CONSTRUCT"i _ d:DatasetClauses _ "WHERE"i _ '{' _ c:ConstructQuery_optional_triple_template _ '}' _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { Query::ConstructQuery { construct: c.clone(), dataset: d, algebra: build_select( Selection::default(), MultiSetPattern::BGP(c.into_iter().map(|p| TripleOrPathPattern::from(p)).collect()).into(), - h, o, l, v + g, h, o, l, v, state ) } } @@ -93,13 +93,13 @@ ConstructQuery_optional_triple_template -> Vec = TriplesTemplate //[11] DescribeQuery -> Query = - "DESCRIBE"i _ '*' _ d:DatasetClauses w:WhereClause? _ GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { + "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), h, o, l, v) + algebra: build_select(Selection::default(), w.unwrap_or_else(MultiSetPattern::default), g, h, o, l, v, state) } } / - "DESCRIBE"i _ p:DescribeQuery_item+ _ d:DatasetClauses w:WhereClause? _ GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { + "DESCRIBE"i _ p:DescribeQuery_item+ _ d:DatasetClauses w:WhereClause? _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { Query::DescribeQuery { dataset: d, algebra: build_select(Selection { @@ -108,16 +108,16 @@ DescribeQuery -> Query = NamedNodeOrVariable::NamedNode(n) => SelectionMember::Expression(n.into(), Variable::default()), NamedNodeOrVariable::Variable(v) => SelectionMember::Variable(v) }).collect()) - }, w.unwrap_or_else(MultiSetPattern::default), h, o, l, v) + }, w.unwrap_or_else(MultiSetPattern::default), g, h, o, l, v, state) } } DescribeQuery_item -> NamedNodeOrVariable = i:VarOrIri _ { i } //[12] -AskQuery -> Query = "ASK"i _ d:DatasetClauses w:WhereClause _ GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { +AskQuery -> Query = "ASK"i _ d:DatasetClauses w:WhereClause _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { Query::AskQuery { dataset: d, - algebra: build_select(Selection::default(), w, h, o, l, v) + algebra: build_select(Selection::default(), w, g, h, o, l, v, state) } } @@ -146,10 +146,28 @@ WhereClause -> MultiSetPattern = "WHERE"i? _ p:GroupGraphPattern { } //[19] -GroupClause -> () = "GROUP"i _ "BY"i _ (GroupCondition _)+ +GroupClause -> (Vec, Vec<(Expression,Variable)>) = "GROUP"i _ "BY"i _ c:GroupCondition_item+ { + let mut projections: Vec<(Expression,Variable)> = Vec::default(); + let clauses = c.into_iter().map(|(e, vo)| { + match vo { + Some(v) => { + projections.push((e, v.clone())); + v.into() + }, + None => e + } + }).collect(); + (clauses, projections) +} +GroupCondition_item -> (Expression, Option) = c:GroupCondition _ { c } //[20] -GroupCondition -> () = BuiltInCall / FunctionCall / '(' _ Expression _ ("AS"i _ Var _)? ')' / Var +GroupCondition -> (Expression, Option) = + e:BuiltInCall { (e, None) } / + e:FunctionCall { (e, None) } / + '(' _ e:Expression _ v:GroupCondition_as? ')' { (e, v) } / + e:Var { (e.into(), None) } +GroupCondition_as -> Variable = "AS"i _ v:Var _ { v } //[21] HavingClause -> Expression = "HAVING"i _ e:HavingCondition+ {? @@ -737,7 +755,7 @@ BrackettedExpression -> Expression = '(' _ e:Expression _ ')' { e } //[121] BuiltInCall -> Expression = - Aggregate / + a:Aggregate { state.new_aggregation(a).into() } / "STR"i _ '(' _ e:Expression _ ')' { Expression::StrFunctionCall(Box::new(e)) } / "LANG"i _ '(' _ e:Expression _ ')' { Expression::LangFunctionCall(Box::new(e)) } / "LANGMATCHES"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::LangMatchesFunctionCall(Box::new(a), Box::new(b)) } / @@ -814,25 +832,25 @@ ExistsFunc -> Expression = "EXISTS"i _ p:GroupGraphPattern { Expression::ExistsF NotExistsFunc -> Expression = "NOT"i _ "EXISTS"i _ p:GroupGraphPattern { Expression::UnaryNotExpression(Box::new(Expression::ExistsFunctionCall(Box::new(p)))) } //[127] -Aggregate -> Expression = - "COUNT"i _ '(' _ "DISTINCT"i _ '*' _ ')' { Expression::CountAggregate(None, true) } / - "COUNT"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Expression::CountAggregate(Some(Box::new(e)), true) } / - "COUNT"i _ '(' _ '*' _ ')' { Expression::CountAggregate(None, false) } / - "COUNT"i _ '(' _ e:Expression _ ')' { Expression::CountAggregate(Some(Box::new(e)), false) } / - "SUM"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Expression::SumAggregate(Box::new(e), true) } / - "SUM"i _ '(' _ e:Expression _ ')' { Expression::SumAggregate(Box::new(e), false) } / - "MIN"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Expression::MinAggregate(Box::new(e), true) } / - "MIN"i _ '(' _ e:Expression _ ')' { Expression::MinAggregate(Box::new(e), false) } / - "MAX"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Expression::MaxAggregate(Box::new(e), true) } / - "MAX"i _ '(' _ e:Expression _ ')' { Expression::MaxAggregate(Box::new(e), false) } / - "AVG"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Expression::AvgAggregate(Box::new(e), true) } / - "AVG"i _ '(' _ e:Expression _ ')' { Expression::AvgAggregate(Box::new(e), false) } / - "SAMPLE"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Expression::SampleAggregate(Box::new(e), true) } / - "SAMPLE"i _ '(' _ e:Expression _ ')' { Expression::SampleAggregate(Box::new(e), false) } / - "GROUP_CONCAT"i _ '(' _ "DISTINCT"i _ e:Expression _ ';' _ 'SEPARATOR'i _ '=' _ s:String _ ')' { Expression::GroupConcatAggregate(Box::new(e), true, Some(s)) } / - "GROUP_CONCAT"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Expression::GroupConcatAggregate(Box::new(e), true, None) } / - "GROUP_CONCAT"i _ '(' _ e:Expression _ ';' _ 'SEPARATOR'i _ '=' _ s:String _ ')' { Expression::GroupConcatAggregate(Box::new(e), true, Some(s)) } / - "GROUP_CONCAT"i _ '(' _ e:Expression _ ')' { Expression::GroupConcatAggregate(Box::new(e), false, None) } +Aggregate -> Aggregation = + "COUNT"i _ '(' _ "DISTINCT"i _ '*' _ ')' { Aggregation::Count(None, true) } / + "COUNT"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Count(Some(Box::new(e)), true) } / + "COUNT"i _ '(' _ '*' _ ')' { Aggregation::Count(None, false) } / + "COUNT"i _ '(' _ e:Expression _ ')' { Aggregation::Count(Some(Box::new(e)), false) } / + "SUM"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Sum(Box::new(e), true) } / + "SUM"i _ '(' _ e:Expression _ ')' { Aggregation::Sum(Box::new(e), false) } / + "MIN"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Min(Box::new(e), true) } / + "MIN"i _ '(' _ e:Expression _ ')' { Aggregation::Min(Box::new(e), false) } / + "MAX"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Max(Box::new(e), true) } / + "MAX"i _ '(' _ e:Expression _ ')' { Aggregation::Max(Box::new(e), false) } / + "AVG"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Avg(Box::new(e), true) } / + "AVG"i _ '(' _ e:Expression _ ')' { Aggregation::Avg(Box::new(e), false) } / + "SAMPLE"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Sample(Box::new(e), true) } / + "SAMPLE"i _ '(' _ e:Expression _ ')' { Aggregation::Sample(Box::new(e), false) } / + "GROUP_CONCAT"i _ '(' _ "DISTINCT"i _ e:Expression _ ';' _ 'SEPARATOR'i _ '=' _ s:String _ ')' { Aggregation::GroupConcat(Box::new(e), true, Some(s)) } / + "GROUP_CONCAT"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::GroupConcat(Box::new(e), true, None) } / + "GROUP_CONCAT"i _ '(' _ e:Expression _ ';' _ 'SEPARATOR'i _ '=' _ s:String _ ')' { Aggregation::GroupConcat(Box::new(e), true, Some(s)) } / + "GROUP_CONCAT"i _ '(' _ e:Expression _ ')' { Aggregation::GroupConcat(Box::new(e), false, None) } //[128] iriOrFunction -> Expression =