Adds basic GROUP BY support

pull/10/head
Tpt 6 years ago
parent 9e0bd6470a
commit 28cb7b276c
  1. 299
      src/sparql/algebra.rs
  2. 2
      src/sparql/model.rs
  3. 44
      src/sparql/parser.rs
  4. 90
      src/sparql/sparql_grammar.rustpeg

@ -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<Expression>, Box<Expression>, Option<Box<Expression>>),
CustomFunctionCall(NamedNode, Vec<Expression>),
ExistsFunctionCall(Box<MultiSetPattern>),
CountAggregate(Option<Box<Expression>>, bool),
SumAggregate(Box<Expression>, bool),
MinAggregate(Box<Expression>, bool),
MaxAggregate(Box<Expression>, bool),
AvgAggregate(Box<Expression>, bool),
SampleAggregate(Box<Expression>, bool),
GroupConcatAggregate(Box<Expression>, bool, Option<String>),
}
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<MultiSetPattern>, Box<MultiSetPattern>),
ToMultiSet(Box<ListPattern>),
Service(NamedNodeOrVariable, Box<MultiSetPattern>, bool),
AggregateJoin(GroupPattern, BTreeMap<Aggregation, Variable>),
}
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::<Vec<String>>()
.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::<Vec<String>>()
.join(" "),
SparqlMultiSetPattern(p),
group
.iter()
.map(|e| format!("({})", e.to_string()))
.collect::<Vec<String>>()
.join(" ")
),
}
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
pub struct GroupPattern(pub Vec<Expression>, pub Box<MultiSetPattern>);
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::<Vec<String>>()
.join(", "),
self.1
)
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
pub enum ListPattern {
Data(Vec<Binding>),
@ -1191,6 +1121,147 @@ fn build_sparql_select_arguments(args: &Vec<Variable>) -> String {
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
pub enum Aggregation {
Count(Option<Box<Expression>>, bool),
Sum(Box<Expression>, bool),
Min(Box<Expression>, bool),
Max(Box<Expression>, bool),
Avg(Box<Expression>, bool),
Sample(Box<Expression>, bool),
GroupConcat(Box<Expression>, bool, Option<String>),
}
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),

@ -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(),
}
}
}

@ -177,18 +177,43 @@ mod grammar {
fn build_select(
select: Selection,
wher: MultiSetPattern,
group: Option<(Vec<Expression>, Vec<(Expression, Variable)>)>,
having: Option<Expression>,
order_by: Option<Vec<OrderComparator>>,
offset_limit: Option<(usize, Option<usize>)>,
values: Option<MultiSetPattern>,
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<Variable> = 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<Url>,
namespaces: HashMap<String, String>,
bnodes_map: BTreeMap<String, BlankNode>,
aggregations: BTreeMap<Aggregation, Variable>,
}
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();

@ -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<TriplePattern> = 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<Expression>, 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<Variable>) = c:GroupCondition _ { c }
//[20]
GroupCondition -> () = BuiltInCall / FunctionCall / '(' _ Expression _ ("AS"i _ Var _)? ')' / Var
GroupCondition -> (Expression, Option<Variable>) =
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 =

Loading…
Cancel
Save