GraphPattern: Renames visible_variables into on_in_scope_variable

pull/171/head
Tpt 3 years ago
parent 0ed7319fd7
commit 83d54b39c4
  1. 73
      spargebra/src/algebra.rs
  2. 21
      spargebra/src/parser.rs

@ -780,95 +780,106 @@ impl Default for GraphPattern {
} }
impl GraphPattern { impl GraphPattern {
/// Returns the list of [in-scope variables](https://www.w3.org/TR/sparql11-query/#variableScope) /// Calls `callback` on each [in-scope variable](https://www.w3.org/TR/sparql11-query/#variableScope) occurrence
pub fn visible_variables(&self) -> BTreeSet<&Variable> { pub fn on_in_scope_variable<'a>(&'a self, mut callback: impl FnMut(&'a Variable)) {
let mut vars = BTreeSet::default(); self.lookup_in_scope_variables(&mut callback)
self.add_visible_variables(&mut vars);
vars
} }
fn add_visible_variables<'a>(&'a self, vars: &mut BTreeSet<&'a Variable>) { fn lookup_in_scope_variables<'a>(&'a self, callback: &mut impl FnMut(&'a Variable)) {
match self { match self {
Self::Bgp(p) => { Self::Bgp(p) => {
for pattern in p { for pattern in p {
add_triple_pattern_variables(pattern, vars) lookup_triple_pattern_variables(pattern, callback)
} }
} }
Self::Path { Self::Path {
subject, object, .. subject, object, ..
} => { } => {
if let TermPattern::Variable(s) = subject { if let TermPattern::Variable(s) = subject {
vars.insert(s); callback(s);
} }
#[cfg(feature = "rdf-star")] #[cfg(feature = "rdf-star")]
if let TermPattern::Triple(s) = subject { if let TermPattern::Triple(s) = subject {
add_triple_pattern_variables(s, vars) lookup_triple_pattern_variables(s, callback)
} }
if let TermPattern::Variable(o) = object { if let TermPattern::Variable(o) = object {
vars.insert(o); callback(o);
} }
#[cfg(feature = "rdf-star")] #[cfg(feature = "rdf-star")]
if let TermPattern::Triple(o) = object { if let TermPattern::Triple(o) = object {
add_triple_pattern_variables(o, vars) lookup_triple_pattern_variables(o, callback)
} }
} }
Self::Sequence(elements) => { Self::Sequence(elements) => {
for e in elements { for e in elements {
e.add_visible_variables(vars); e.lookup_in_scope_variables(callback);
} }
} }
Self::Join { left, right } Self::Join { left, right }
| Self::LeftJoin { left, right, .. } | Self::LeftJoin { left, right, .. }
| Self::Union { left, right } => { | Self::Union { left, right } => {
left.add_visible_variables(vars); left.lookup_in_scope_variables(callback);
right.add_visible_variables(vars); right.lookup_in_scope_variables(callback);
} }
Self::Graph { graph_name, inner } => { Self::Graph { graph_name, inner } => {
if let NamedNodePattern::Variable(ref g) = graph_name { if let NamedNodePattern::Variable(ref g) = graph_name {
vars.insert(g); callback(g);
} }
inner.add_visible_variables(vars); inner.lookup_in_scope_variables(callback);
} }
Self::Extend { inner, var, .. } => { Self::Extend { inner, var, .. } => {
vars.insert(var); callback(var);
inner.add_visible_variables(vars); inner.lookup_in_scope_variables(callback);
} }
Self::Minus { left, .. } => left.add_visible_variables(vars), Self::Minus { left, .. } => left.lookup_in_scope_variables(callback),
Self::Service { pattern, .. } => pattern.add_visible_variables(vars), Self::Service { pattern, .. } => pattern.lookup_in_scope_variables(callback),
Self::Group { by, aggregates, .. } => { Self::Group { by, aggregates, .. } => {
vars.extend(by); for v in by {
callback(v);
}
for (v, _) in aggregates { for (v, _) in aggregates {
vars.insert(v); callback(v);
}
}
Self::Table { variables, .. } => {
for v in variables {
callback(v);
}
}
Self::Project { projection, .. } => {
for v in projection {
callback(v);
} }
} }
Self::Table { variables, .. } => vars.extend(variables),
Self::Project { projection, .. } => vars.extend(projection.iter()),
Self::Filter { inner, .. } Self::Filter { inner, .. }
| Self::OrderBy { inner, .. } | Self::OrderBy { inner, .. }
| Self::Distinct { inner } | Self::Distinct { inner }
| Self::Reduced { inner } | Self::Reduced { inner }
| Self::Slice { inner, .. } => inner.add_visible_variables(vars), | Self::Slice { inner, .. } => inner.lookup_in_scope_variables(callback),
} }
} }
} }
fn add_triple_pattern_variables<'a>(pattern: &'a TriplePattern, vars: &mut BTreeSet<&'a Variable>) { fn lookup_triple_pattern_variables<'a>(
pattern: &'a TriplePattern,
callback: &mut impl FnMut(&'a Variable),
) {
if let TermPattern::Variable(s) = &pattern.subject { if let TermPattern::Variable(s) = &pattern.subject {
vars.insert(s); callback(s);
} }
#[cfg(feature = "rdf-star")] #[cfg(feature = "rdf-star")]
if let TermPattern::Triple(s) = &pattern.subject { if let TermPattern::Triple(s) = &pattern.subject {
add_triple_pattern_variables(s, vars) lookup_triple_pattern_variables(s, callback)
} }
if let NamedNodePattern::Variable(p) = &pattern.predicate { if let NamedNodePattern::Variable(p) = &pattern.predicate {
vars.insert(p); callback(p);
} }
if let TermPattern::Variable(o) = &pattern.object { if let TermPattern::Variable(o) = &pattern.object {
vars.insert(o); callback(o);
} }
#[cfg(feature = "rdf-star")] #[cfg(feature = "rdf-star")]
if let TermPattern::Triple(o) = &pattern.object { if let TermPattern::Triple(o) = &pattern.object {
add_triple_pattern_variables(o, vars) lookup_triple_pattern_variables(o, callback)
} }
} }

@ -514,7 +514,10 @@ fn build_select(
let mut pv = Vec::new(); let mut pv = Vec::new();
let with_project = match select.variables { let with_project = match select.variables {
SelectionVariables::Explicit(sel_items) => { SelectionVariables::Explicit(sel_items) => {
let visible: HashSet<_> = p.visible_variables().into_iter().cloned().collect(); let mut visible = HashSet::default();
p.on_in_scope_variable(|v| {
visible.insert(v.clone());
});
for sel_item in sel_items { for sel_item in sel_items {
let v = match sel_item { let v = match sel_item {
SelectionMember::Variable(v) => { SelectionMember::Variable(v) => {
@ -556,7 +559,13 @@ fn build_select(
if with_aggregate { if with_aggregate {
return Err("SELECT * is not authorized with GROUP BY"); return Err("SELECT * is not authorized with GROUP BY");
} }
pv.extend(p.visible_variables().into_iter().cloned()); //TODO: is it really useful to do a projection? //TODO: is it really useful to do a projection?
p.on_in_scope_variable(|v| {
if !pv.contains(v) {
pv.push(v.clone());
}
});
pv.sort();
true true
} }
SelectionVariables::Everything => false, SelectionVariables::Everything => false,
@ -1390,7 +1399,13 @@ parser! {
g = GraphPattern::Minus { left: Box::new(g), right: Box::new(p) } g = GraphPattern::Minus { left: Box::new(g), right: Box::new(p) }
} }
PartialGraphPattern::Bind(expr, var) => { PartialGraphPattern::Bind(expr, var) => {
if g.visible_variables().contains(&var) { let mut contains = false;
g.on_in_scope_variable(|v| {
if *v == var {
contains = true;
}
});
if contains {
return Err("BIND is overriding an existing variable") return Err("BIND is overriding an existing variable")
} }
g = GraphPattern::Extend { inner: Box::new(g), var, expr } g = GraphPattern::Extend { inner: Box::new(g), var, expr }

Loading…
Cancel
Save