algebra for custom functions

pull/13/head
Dustin Whitney 6 years ago
parent 5fe7b9e0d3
commit be43d4b981
  1. 15
      lib/src/sparql/eval.rs
  2. 10
      lib/src/sparql/plan.rs
  3. 3
      lib/src/sparql/plan_builder.rs
  4. 69
      lib/tests/custom_functions.rs

@ -1462,6 +1462,21 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
PlanExpression::StringCast(e) => Some(EncodedTerm::StringLiteral { PlanExpression::StringCast(e) => Some(EncodedTerm::StringLiteral {
value_id: self.to_string_id(self.eval_expression(e, tuple, options)?)?, value_id: self.to_string_id(self.eval_expression(e, tuple, options)?)?,
}), }),
PlanExpression::CustomFunction { name, parameters } => {
println!("name: {:?}", name);
println!("parameters: {:?}", parameters);
println!("tuple: {:?}", tuple);
let parameters = parameters
.iter()
.map(|p| {
self.eval_expression(p, tuple, options)
.and_then(|encoded| self.dataset.decode_term(encoded).ok())
})
.collect::<Vec<_>>();
println!("parameters: {:?}", parameters);
None
}
} }
} }

@ -1,3 +1,4 @@
use crate::model::NamedNode;
use crate::sparql::GraphPattern; use crate::sparql::GraphPattern;
use crate::sparql::model::Variable; use crate::sparql::model::Variable;
use crate::sparql::eval::StringOrStoreString; use crate::sparql::eval::StringOrStoreString;
@ -306,6 +307,10 @@ pub enum PlanExpression {
TimeCast(Box<PlanExpression>), TimeCast(Box<PlanExpression>),
DateTimeCast(Box<PlanExpression>), DateTimeCast(Box<PlanExpression>),
StringCast(Box<PlanExpression>), StringCast(Box<PlanExpression>),
CustomFunction {
name: NamedNode,
parameters: Vec<PlanExpression>
},
} }
impl PlanExpression { impl PlanExpression {
@ -415,6 +420,11 @@ impl PlanExpression {
e.add_variables(set); e.add_variables(set);
} }
} }
PlanExpression::CustomFunction{ parameters, .. } => {
for p in parameters {
p.add_variables(set);
}
}
PlanExpression::Exists(n) => n.add_variables(set), PlanExpression::Exists(n) => n.add_variables(set),
} }
} }

@ -644,7 +644,8 @@ impl<E: Encoder> PlanBuilder<E> {
"string", "string",
)? )?
} else { } else {
return Err(format_err!("Not supported custom function {}", expression)); let parameters = self.expression_list(parameters, variables, graph_name)?;
PlanExpression::CustomFunction { name: name.clone(), parameters }
} }
} }
}, },

@ -0,0 +1,69 @@
use rudf::model::*;
use rudf::{GraphSyntax, Repository, RepositoryConnection, MemoryRepository, Result};
use rudf::sparql::{BindingsIterator, PreparedQuery, QueryOptions, QueryResult};
use failure::format_err;
use std::io::BufRead;
#[test]
fn simple_custom_function_test() {
let query = r#"
PREFIX ex: <http://example.com#>
SELECT ?name ?reverse
WHERE
{
?s <http://xmlns.com/foaf/0.1/name> ?name .
BIND(ex:REVERSE(?name) as ?reverse)
}
ORDER BY ?name
"#.to_string();
let options = QueryOptions::default();
let triples = br#"
<http://example.com/bob> <http://xmlns.com/foaf/0.1/name> "Bob" .
<http://example.com/alice> <http://xmlns.com/foaf/0.1/name> "Alice" .
<http://example.com/bob> <http://xmlns.com/foaf/0.1/mbox> <mailto:bob@example.com> .
<http://example.com/alice> <http://xmlns.com/foaf/0.1/mbox> <mailto:alice@example.com> .
"#.as_ref();
let results = do_query(triples, query, options).unwrap();
let collected = results.into_values_iter().map(move |b| b.unwrap()).collect::<Vec<_>>();
let solution = vec![
vec![ Some(literal(String::from("Alice"))), Some(literal(String::from("ecilA"))) ],
vec![ Some(literal(String::from("Bob"))), Some(literal(String::from("boB"))) ],
];
assert_eq!(collected, solution);
}
fn literal(str: String) -> Term {
Term::Literal(Literal::new_simple_literal(str))
}
fn make_repository(reader: impl BufRead) -> Result<MemoryRepository> {
let repository = MemoryRepository::default();
let mut connection = repository.connection()?;
connection.load_graph(reader, GraphSyntax::NTriples, None, None).unwrap();
Ok(repository)
}
fn query_repository<'a>(repository: MemoryRepository, query: String, options: QueryOptions<'a>) -> Result<BindingsIterator<'a>> {
let connection = repository.connection()?;
let prepared_query = connection.prepare_query(&query, None)?;
let result = prepared_query.exec(&options)?;
match result {
QueryResult::Bindings(iterator) => {
let (varaibles, iter) = iterator.destruct();
let collected = iter.collect::<Vec<_>>();
Ok(BindingsIterator::new(varaibles, Box::new(collected.into_iter())))
},
_ => Err(format_err!("Excpected bindings but got another QueryResult"))
}
}
fn do_query<'a>(reader: impl BufRead, query: String, options: QueryOptions<'a>) -> Result<BindingsIterator<'a>> {
let repository = make_repository(reader)?;
query_repository(repository, query, options)
}
Loading…
Cancel
Save