diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index dd0e060b..c28e9ced 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -135,6 +135,27 @@ impl SimpleEvaluator { iter })) } + PlanNode::Extend { + child, + position, + expression, + } => { + let eval = self.clone(); + Box::new( + self.eval_plan(*child, from) + .filter_map(move |tuple| match tuple { + Ok(mut tuple) => { + put_value( + position, + eval.eval_expression(&expression, &tuple)?, + &mut tuple, + ); + Some(Ok(tuple)) + } + Err(error) => Some(Err(error)), + }), + ) + } PlanNode::HashDeduplicate { child } => { let iter = self.eval_plan(*child, from); let mut values = HashSet::with_capacity(iter.size_hint().0); @@ -335,16 +356,17 @@ fn get_pattern_value( fn put_pattern_value(selector: &PatternValue, value: EncodedTerm, tuple: &mut EncodedTuple) { match selector { PatternValue::Constant(_) => (), - PatternValue::Variable(v) => { - let v = *v; - if tuple.len() > v { - tuple[v] = Some(value) - } else { - if tuple.len() < v { - tuple.resize(v, None); - } - tuple.push(Some(value)) - } + PatternValue::Variable(v) => put_value(*v, value, tuple), + } +} + +fn put_value(position: usize, value: EncodedTerm, tuple: &mut EncodedTuple) { + if tuple.len() > position { + tuple[position] = Some(value) + } else { + if tuple.len() < position { + tuple.resize(position, None); } + tuple.push(Some(value)) } } diff --git a/lib/src/sparql/plan.rs b/lib/src/sparql/plan.rs index fc06cd08..77cd1b71 100644 --- a/lib/src/sparql/plan.rs +++ b/lib/src/sparql/plan.rs @@ -26,6 +26,11 @@ pub enum PlanNode { entry: Box, children: Vec, }, + Extend { + child: Box, + position: usize, + expression: PlanExpression, + }, HashDeduplicate { child: Box, }, @@ -222,7 +227,11 @@ impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> { } } GraphPattern::Graph(g, p) => unimplemented!(), - GraphPattern::Extend(p, v, e) => unimplemented!(), + GraphPattern::Extend(p, v, e) => PlanNode::Extend { + child: Box::new(self.build_for_graph_pattern(p, input, variables)?), + position: variable_key(variables, &v), + expression: self.build_for_expression(e, variables)?, + }, GraphPattern::Minus(a, b) => unimplemented!(), GraphPattern::Service(n, p, s) => unimplemented!(), GraphPattern::AggregateJoin(g, a) => unimplemented!(), diff --git a/lib/tests/rdf_test_cases.rs b/lib/tests/rdf_test_cases.rs index 95450926..62498d61 100644 --- a/lib/tests/rdf_test_cases.rs +++ b/lib/tests/rdf_test_cases.rs @@ -365,7 +365,7 @@ impl<'a> Iterator for TestManifest<'a> { Some(Term::BlankNode(list)) => { self.manifests_to_do.extend( RdfListIterator::iter(&self.graph, list.clone().into()) - .flat_map(|m| match m { + .filter_map(|m| match m { Term::NamedNode(nm) => Some(nm.as_url().clone()), _ => None, }), diff --git a/lib/tests/sparql_test_cases.rs b/lib/tests/sparql_test_cases.rs index ed267df8..be653dcc 100644 --- a/lib/tests/sparql_test_cases.rs +++ b/lib/tests/sparql_test_cases.rs @@ -481,7 +481,7 @@ impl<'a> Iterator for TestManifest<'a> { Some(Term::BlankNode(list)) => { self.manifests_to_do.extend( RdfListIterator::iter(&self.graph, list.clone().into()) - .flat_map(|m| match m { + .filter_map(|m| match m { Term::NamedNode(nm) => Some(nm.as_url().clone()), _ => None, }),