custom functions are working

pull/13/head
Dustin Whitney 6 years ago
parent cfc00cd80d
commit 6532888da5
  1. 13
      lib/src/sparql/eval.rs
  2. 37
      lib/src/sparql/mod.rs
  3. 25
      lib/tests/custom_functions_test_cases.rs

@ -3,7 +3,7 @@ use crate::model::Triple;
use crate::sparql::algebra::GraphPattern; use crate::sparql::algebra::GraphPattern;
use crate::sparql::model::*; use crate::sparql::model::*;
use crate::sparql::plan::*; use crate::sparql::plan::*;
use crate::sparql::ServiceHandler; use crate::sparql::{CustomFunctionsHandler, ServiceHandler};
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
use crate::store::StoreConnection; use crate::store::StoreConnection;
use crate::Result; use crate::Result;
@ -45,6 +45,7 @@ pub struct SimpleEvaluator<S: StoreConnection> {
bnodes_map: Mutex<BTreeMap<u128, u128>>, bnodes_map: Mutex<BTreeMap<u128, u128>>,
now: DateTime<FixedOffset>, now: DateTime<FixedOffset>,
service_handler: Box<dyn ServiceHandler>, service_handler: Box<dyn ServiceHandler>,
custom_functions_handler: Box<dyn CustomFunctionsHandler>,
} }
impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> { impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
@ -52,6 +53,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
dataset: DatasetView<S>, dataset: DatasetView<S>,
base_iri: Option<Iri<String>>, base_iri: Option<Iri<String>>,
service_handler: Box<dyn ServiceHandler>, service_handler: Box<dyn ServiceHandler>,
custom_functions_handler: Box<dyn CustomFunctionsHandler>,
) -> Self { ) -> Self {
Self { Self {
dataset, dataset,
@ -59,6 +61,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
base_iri, base_iri,
now: Utc::now().with_timezone(&FixedOffset::east(0)), now: Utc::now().with_timezone(&FixedOffset::east(0)),
service_handler, service_handler,
custom_functions_handler,
} }
} }
@ -1412,9 +1415,6 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
value_id: self.to_string_id(self.eval_expression(e, tuple)?)?, value_id: self.to_string_id(self.eval_expression(e, tuple)?)?,
}), }),
PlanExpression::CustomFunction { name, parameters } => { PlanExpression::CustomFunction { name, parameters } => {
println!("name: {:?}", name);
println!("parameters: {:?}", parameters);
println!("tuple: {:?}", tuple);
let parameters = parameters let parameters = parameters
.iter() .iter()
.map(|p| { .map(|p| {
@ -1422,9 +1422,8 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
.and_then(|encoded| self.dataset.decode_term(encoded).ok()) .and_then(|encoded| self.dataset.decode_term(encoded).ok())
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.custom_functions_handler.handle(name, &parameters)
println!("parameters: {:?}", parameters); .and_then(|term| self.dataset.encoder().encode_term(&term).ok())
None
} }
} }
} }

@ -9,7 +9,7 @@ mod plan;
mod plan_builder; mod plan_builder;
mod xml_results; mod xml_results;
use crate::model::NamedNode; use crate::model::{NamedNode,Term};
use crate::sparql::algebra::QueryVariants; use crate::sparql::algebra::QueryVariants;
use crate::sparql::eval::SimpleEvaluator; use crate::sparql::eval::SimpleEvaluator;
use crate::sparql::parser::read_sparql_query; use crate::sparql::parser::read_sparql_query;
@ -70,7 +70,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
SimplePreparedQueryAction::Select { SimplePreparedQueryAction::Select {
plan, plan,
variables, variables,
evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler, options.custom_functions_handler),
} }
} }
QueryVariants::Ask { QueryVariants::Ask {
@ -81,7 +81,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
let (plan, _) = PlanBuilder::build(dataset.encoder(), &algebra)?; let (plan, _) = PlanBuilder::build(dataset.encoder(), &algebra)?;
SimplePreparedQueryAction::Ask { SimplePreparedQueryAction::Ask {
plan, plan,
evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler, options.custom_functions_handler),
} }
} }
QueryVariants::Construct { QueryVariants::Construct {
@ -98,7 +98,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
&construct, &construct,
variables, variables,
)?, )?,
evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler, options.custom_functions_handler),
} }
} }
QueryVariants::Describe { QueryVariants::Describe {
@ -109,7 +109,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
let (plan, _) = PlanBuilder::build(dataset.encoder(), &algebra)?; let (plan, _) = PlanBuilder::build(dataset.encoder(), &algebra)?;
SimplePreparedQueryAction::Describe { SimplePreparedQueryAction::Describe {
plan, plan,
evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler, options.custom_functions_handler),
} }
} }
})) }))
@ -131,7 +131,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
Ok(Self(SimplePreparedQueryAction::Select { Ok(Self(SimplePreparedQueryAction::Select {
plan, plan,
variables, variables,
evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler, options.custom_functions_handler),
})) }))
} }
} }
@ -185,11 +185,25 @@ impl ServiceHandler for EmptyServiceHandler {
} }
} }
pub trait CustomFunctionsHandler {
fn handle(&self, node: &NamedNode, parameters: &Vec<Option<Term>>) -> Option<Term>;
}
#[derive(Default)]
struct EmptyCustomFunctionsHandler {}
impl CustomFunctionsHandler for EmptyCustomFunctionsHandler {
fn handle(&self, _node: &NamedNode, _parameters: &Vec<Option<Term>>) -> Option<Term> {
None
}
}
/// Options for SPARQL query parsing and evaluation like the query base IRI /// Options for SPARQL query parsing and evaluation like the query base IRI
pub struct QueryOptions<'a> { pub struct QueryOptions<'a> {
pub(crate) base_iri: Option<&'a str>, pub(crate) base_iri: Option<&'a str>,
pub(crate) default_graph_as_union: bool, pub(crate) default_graph_as_union: bool,
pub(crate) service_handler: Box<dyn ServiceHandler>, pub(crate) service_handler: Box<dyn ServiceHandler>,
pub(crate) custom_functions_handler: Box<dyn CustomFunctionsHandler>,
} }
impl<'a> Default for QueryOptions<'a> { impl<'a> Default for QueryOptions<'a> {
@ -198,6 +212,7 @@ impl<'a> Default for QueryOptions<'a> {
base_iri: None, base_iri: None,
default_graph_as_union: false, default_graph_as_union: false,
service_handler: Box::new(EmptyServiceHandler::default()), service_handler: Box::new(EmptyServiceHandler::default()),
custom_functions_handler: Box::new(EmptyCustomFunctionsHandler::default()),
} }
} }
} }
@ -215,11 +230,19 @@ impl<'a> QueryOptions<'a> {
self self
} }
/// Consider the union of all graphs in the repository as the default graph /// Set a ServiceHandler to handle SERVICE clauses
pub fn with_service_handler(mut self, service_handler: Box<dyn ServiceHandler>) -> Self { pub fn with_service_handler(mut self, service_handler: Box<dyn ServiceHandler>) -> Self {
self.service_handler = service_handler; self.service_handler = service_handler;
self self
} }
/// Set a CustomFunctionHandler to add your own functions
pub fn with_custom_functions_handler(mut self, custom_functions_handler: Box<dyn CustomFunctionsHandler>) -> Self {
self.custom_functions_handler = custom_functions_handler;
self
}
} }
/// A parsed [SPARQL query](https://www.w3.org/TR/sparql11-query/) /// A parsed [SPARQL query](https://www.w3.org/TR/sparql11-query/)

@ -1,6 +1,6 @@
use rudf::model::*; use rudf::model::*;
use rudf::{GraphSyntax, Repository, RepositoryConnection, MemoryRepository, Result}; use rudf::{GraphSyntax, Repository, RepositoryConnection, MemoryRepository, Result};
use rudf::sparql::{BindingsIterator, PreparedQuery, QueryOptions, QueryResult}; use rudf::sparql::{BindingsIterator, CustomFunctionsHandler, PreparedQuery, QueryOptions, QueryResult};
use failure::format_err; use failure::format_err;
use std::io::BufRead; use std::io::BufRead;
@ -9,6 +9,27 @@ use std::io::BufRead;
#[test] #[test]
fn simple_custom_function_test() { fn simple_custom_function_test() {
struct TestHandler;
impl CustomFunctionsHandler for TestHandler {
fn handle(&self, node: &NamedNode, parameters: &Vec<Option<Term>>) -> Option<Term> {
let reverse = NamedNode::parse("http://example.com#REVERSE").ok()?;
if *node == reverse {
let param = &parameters[0];
if let Some(Term::Literal(literal)) = param {
let value = literal.value();
let reversed = value.chars().rev().collect::<String>();
let literal = Literal::new_simple_literal(reversed);
Some(Term::Literal(literal))
} else {
None
}
} else {
None
}
}
}
let query = r#" let query = r#"
PREFIX ex: <http://example.com#> PREFIX ex: <http://example.com#>
SELECT ?name ?reverse SELECT ?name ?reverse
@ -21,7 +42,7 @@ fn simple_custom_function_test() {
"#.to_string(); "#.to_string();
let options = QueryOptions::default(); let options = QueryOptions::default().with_custom_functions_handler(Box::new(TestHandler));
let triples = br#" let triples = br#"
<http://example.com/bob> <http://xmlns.com/foaf/0.1/name> "Bob" . <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/alice> <http://xmlns.com/foaf/0.1/name> "Alice" .

Loading…
Cancel
Save