Simplifies the definition of the ServiceHandler trait

pull/21/head
Tpt 5 years ago
parent 33ecea643c
commit a1fcb6a9b7
  1. 32
      lib/src/sparql/eval.rs
  2. 39
      lib/src/sparql/mod.rs
  3. 82
      lib/tests/service_test_cases.rs

@ -482,28 +482,24 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator<S> {
fn evaluate_service<'b>(
&'b self,
service_name: &PatternValue,
graph_pattern: &GraphPattern,
graph_pattern: &'b GraphPattern,
variables: &'b [Variable],
from: EncodedTuple,
) -> Result<EncodedTuplesIterator<'b>> {
let service_name =
self.dataset
.decode_named_node(get_pattern_value(service_name, &[]).ok_or_else(|| {
format_err!("The SERVICE handler name variable is not bound")
})?)?;
let service = self.service_handler.handle(&service_name).ok_or_else(|| {
format_err!(
"The handler supplied was unable to produce any result set for service {}",
service_name
)
})?;
let service_name = self.dataset.decode_named_node(
get_pattern_value(service_name, &[])
.ok_or_else(|| format_err!("The SERVICE name is not bound"))?,
)?;
Ok(Box::new(
self.encode_bindings(variables, service(graph_pattern.clone())?)
.flat_map(move |binding| {
binding
.map(|binding| combine_tuples(&binding, &from))
.transpose()
}),
self.encode_bindings(
variables,
self.service_handler.handle(&service_name, &graph_pattern)?,
)
.flat_map(move |binding| {
binding
.map(|binding| combine_tuples(&binding, &from))
.transpose()
}),
))
}

@ -18,6 +18,7 @@ use crate::sparql::plan::{DatasetView, PlanNode};
use crate::sparql::plan_builder::PlanBuilder;
use crate::store::StoreConnection;
use crate::Result;
use failure::format_err;
use rio_api::iri::Iri;
use std::fmt;
@ -163,25 +164,31 @@ impl<S: StoreConnection> PreparedQuery for SimplePreparedQuery<S> {
///
/// Might be used to implement [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/)
pub trait ServiceHandler {
/// Get the handler for a given service identified by a RDF IRI.
///
/// A service is a function that returns an iterator of bindings from a `GraphPattern`.
/// Returns `None` if there is no handler for the service.
/// Evaluates a `GraphPattern` against a given service identified by a `NamedNode`.
fn handle<'a>(
&'a self,
node: &NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)>;
service_name: &NamedNode,
graph_pattern: &'a GraphPattern,
) -> Result<BindingsIterator<'a>>;
}
#[derive(Default)]
struct EmptyServiceHandler {}
impl<F: for<'a> Fn(&NamedNode, &'a GraphPattern) -> Result<BindingsIterator<'a>>> ServiceHandler
for F
{
fn handle<'a>(
&'a self,
service_name: &NamedNode,
graph_pattern: &'a GraphPattern,
) -> Result<BindingsIterator<'a>> {
self(service_name, graph_pattern)
}
}
struct EmptyServiceHandler;
impl ServiceHandler for EmptyServiceHandler {
fn handle(
&self,
_node: &NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'static>>)> {
None
fn handle<'a>(&'a self, _: &NamedNode, _: &'a GraphPattern) -> Result<BindingsIterator<'a>> {
Err(format_err!("The SERVICE feature is not implemented"))
}
}
@ -197,7 +204,7 @@ impl<'a> Default for QueryOptions<'a> {
Self {
base_iri: None,
default_graph_as_union: false,
service_handler: Box::new(EmptyServiceHandler::default()),
service_handler: Box::new(EmptyServiceHandler),
}
}
}
@ -216,8 +223,8 @@ impl<'a> QueryOptions<'a> {
}
/// Consider the union of all graphs in the repository as the default graph
pub fn with_service_handler(mut self, service_handler: Box<dyn ServiceHandler>) -> Self {
self.service_handler = service_handler;
pub fn with_service_handler(mut self, service_handler: impl ServiceHandler + 'static) -> Self {
self.service_handler = Box::new(service_handler);
self
}
}

@ -12,15 +12,12 @@ fn simple_service_test() {
impl ServiceHandler for TestServiceHandler {
fn handle<'a>(
&'a self,
_named_node: &NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> {
fn pattern_handler<'a>(graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
let triples =
b"<http://example.com/s> <http://example.com/p> <http://example.com/o> ."
.as_ref();
do_pattern(triples, graph_pattern, QueryOptions::default())
};
Some(pattern_handler)
_: &NamedNode,
graph_pattern: &'a GraphPattern,
) -> Result<BindingsIterator<'a>> {
let triples =
b"<http://example.com/s> <http://example.com/p> <http://example.com/o> .".as_ref();
do_pattern(triples, graph_pattern, QueryOptions::default())
}
}
@ -35,7 +32,7 @@ fn simple_service_test() {
"#
.to_string();
let options = QueryOptions::default().with_service_handler(Box::new(TestServiceHandler));
let options = QueryOptions::default().with_service_handler(TestServiceHandler);
let results = do_query(b"".as_ref(), query, options).unwrap();
let collected = results
.into_values_iter()
@ -57,36 +54,27 @@ fn two_service_test() {
fn handle<'a>(
&'a self,
named_node: &NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> {
graph_pattern: &'a GraphPattern,
) -> Result<BindingsIterator<'a>> {
let service1 = NamedNode::parse("http://service1.org").unwrap();
let service2 = NamedNode::parse("http://service2.org").unwrap();
if named_node == &service1 {
Some(TwoServiceTest::handle_service1)
} else if named_node == &service2 {
Some(TwoServiceTest::handle_service2)
} else {
None
}
}
}
impl TwoServiceTest {
fn handle_service1<'a>(graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
let triples = br#"
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" .
"#
.as_ref();
do_pattern(triples, graph_pattern, QueryOptions::default())
}
fn handle_service2<'a>(graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
let triples = br#"
.as_ref();
do_pattern(triples, graph_pattern, QueryOptions::default())
} else if named_node == &service2 {
let triples = br#"
<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();
do_pattern(triples, graph_pattern, QueryOptions::default())
.as_ref();
do_pattern(triples, graph_pattern, QueryOptions::default())
} else {
Err(format_err!("not found"))
}
}
}
@ -107,7 +95,7 @@ fn two_service_test() {
"#
.to_string();
let options = QueryOptions::default().with_service_handler(Box::new(TwoServiceTest));
let options = QueryOptions::default().with_service_handler(TwoServiceTest);
let results = do_query(b"".as_ref(), query, options).unwrap();
let collected = results
.into_values_iter()
@ -133,14 +121,9 @@ fn silent_service_empty_set_test() {
impl ServiceHandler for ServiceTest {
fn handle<'a>(
&'a self,
_named_node: &NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> {
Some(ServiceTest::handle_service)
}
}
impl ServiceTest {
fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
_: &NamedNode,
_: &'a GraphPattern,
) -> Result<BindingsIterator<'a>> {
Err(format_err!("This is supposed to fail"))
}
}
@ -160,7 +143,7 @@ fn silent_service_empty_set_test() {
.to_string();
let triples = b"".as_ref();
let options = QueryOptions::default().with_service_handler(Box::new(ServiceTest));
let options = QueryOptions::default().with_service_handler(ServiceTest);
let results = do_query(triples, query, options).unwrap();
let collected = results
.into_values_iter()
@ -177,14 +160,9 @@ fn non_silent_service_test() {
impl ServiceHandler for ServiceTest {
fn handle<'a>(
&'a self,
_named_node: &NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)> {
Some(ServiceTest::handle_service)
}
}
impl ServiceTest {
fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result<BindingsIterator<'a>> {
_: &NamedNode,
_: &'a GraphPattern,
) -> Result<BindingsIterator<'a>> {
Err(format_err!("This is supposed to fail"))
}
}
@ -204,7 +182,7 @@ fn non_silent_service_test() {
.to_string();
let triples = b"".as_ref();
let options = QueryOptions::default().with_service_handler(Box::new(ServiceTest));
let options = QueryOptions::default().with_service_handler(ServiceTest);
let results = do_query(triples, query, options).unwrap();
let result = results.into_values_iter().next();
match result {
@ -263,7 +241,7 @@ fn query_repository<'a>(
fn pattern_repository<'a>(
repository: MemoryRepository,
pattern: GraphPattern,
pattern: &'a GraphPattern,
options: QueryOptions<'a>,
) -> Result<BindingsIterator<'a>> {
match repository
@ -294,7 +272,7 @@ fn do_query<'a>(
fn do_pattern<'a>(
reader: impl BufRead,
pattern: GraphPattern,
pattern: &'a GraphPattern,
options: QueryOptions<'a>,
) -> Result<BindingsIterator<'a>> {
let repository = make_repository(reader)?;

Loading…
Cancel
Save