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>( fn evaluate_service<'b>(
&'b self, &'b self,
service_name: &PatternValue, service_name: &PatternValue,
graph_pattern: &GraphPattern, graph_pattern: &'b GraphPattern,
variables: &'b [Variable], variables: &'b [Variable],
from: EncodedTuple, from: EncodedTuple,
) -> Result<EncodedTuplesIterator<'b>> { ) -> Result<EncodedTuplesIterator<'b>> {
let service_name = let service_name = self.dataset.decode_named_node(
self.dataset get_pattern_value(service_name, &[])
.decode_named_node(get_pattern_value(service_name, &[]).ok_or_else(|| { .ok_or_else(|| format_err!("The SERVICE name is not bound"))?,
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
)
})?;
Ok(Box::new( Ok(Box::new(
self.encode_bindings(variables, service(graph_pattern.clone())?) self.encode_bindings(
.flat_map(move |binding| { variables,
binding self.service_handler.handle(&service_name, &graph_pattern)?,
.map(|binding| combine_tuples(&binding, &from)) )
.transpose() .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::sparql::plan_builder::PlanBuilder;
use crate::store::StoreConnection; use crate::store::StoreConnection;
use crate::Result; use crate::Result;
use failure::format_err;
use rio_api::iri::Iri; use rio_api::iri::Iri;
use std::fmt; 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/) /// Might be used to implement [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/)
pub trait ServiceHandler { pub trait ServiceHandler {
/// Get the handler for a given service identified by a RDF IRI. /// Evaluates a `GraphPattern` against a given service identified by a `NamedNode`.
///
/// A service is a function that returns an iterator of bindings from a `GraphPattern`.
/// Returns `None` if there is no handler for the service.
fn handle<'a>( fn handle<'a>(
&'a self, &'a self,
node: &NamedNode, service_name: &NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'a>>)>; graph_pattern: &'a GraphPattern,
) -> Result<BindingsIterator<'a>>;
} }
#[derive(Default)] impl<F: for<'a> Fn(&NamedNode, &'a GraphPattern) -> Result<BindingsIterator<'a>>> ServiceHandler
struct EmptyServiceHandler {} 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 { impl ServiceHandler for EmptyServiceHandler {
fn handle( fn handle<'a>(&'a self, _: &NamedNode, _: &'a GraphPattern) -> Result<BindingsIterator<'a>> {
&self, Err(format_err!("The SERVICE feature is not implemented"))
_node: &NamedNode,
) -> Option<(fn(GraphPattern) -> Result<BindingsIterator<'static>>)> {
None
} }
} }
@ -197,7 +204,7 @@ impl<'a> Default for QueryOptions<'a> {
Self { Self {
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),
} }
} }
} }
@ -216,8 +223,8 @@ impl<'a> QueryOptions<'a> {
} }
/// Consider the union of all graphs in the repository as the default graph /// 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 { pub fn with_service_handler(mut self, service_handler: impl ServiceHandler + 'static) -> Self {
self.service_handler = service_handler; self.service_handler = Box::new(service_handler);
self self
} }
} }

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

Loading…
Cancel
Save