From a1fcb6a9b7ff2881da45e056d9faae6769d8694b Mon Sep 17 00:00:00 2001 From: Tpt Date: Fri, 18 Oct 2019 15:56:22 +0200 Subject: [PATCH] Simplifies the definition of the ServiceHandler trait --- lib/src/sparql/eval.rs | 32 ++++++------- lib/src/sparql/mod.rs | 39 +++++++++------- lib/tests/service_test_cases.rs | 82 ++++++++++++--------------------- 3 files changed, 67 insertions(+), 86 deletions(-) diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index f436d1c4..7ddd4ad0 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -482,28 +482,24 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { fn evaluate_service<'b>( &'b self, service_name: &PatternValue, - graph_pattern: &GraphPattern, + graph_pattern: &'b GraphPattern, variables: &'b [Variable], from: EncodedTuple, ) -> Result> { - 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() + }), )) } diff --git a/lib/src/sparql/mod.rs b/lib/src/sparql/mod.rs index f0c62666..deb5d347 100644 --- a/lib/src/sparql/mod.rs +++ b/lib/src/sparql/mod.rs @@ -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 PreparedQuery for SimplePreparedQuery { /// /// 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>)>; + service_name: &NamedNode, + graph_pattern: &'a GraphPattern, + ) -> Result>; } -#[derive(Default)] -struct EmptyServiceHandler {} +impl Fn(&NamedNode, &'a GraphPattern) -> Result>> ServiceHandler + for F +{ + fn handle<'a>( + &'a self, + service_name: &NamedNode, + graph_pattern: &'a GraphPattern, + ) -> Result> { + self(service_name, graph_pattern) + } +} + +struct EmptyServiceHandler; impl ServiceHandler for EmptyServiceHandler { - fn handle( - &self, - _node: &NamedNode, - ) -> Option<(fn(GraphPattern) -> Result>)> { - None + fn handle<'a>(&'a self, _: &NamedNode, _: &'a GraphPattern) -> Result> { + 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) -> 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 } } diff --git a/lib/tests/service_test_cases.rs b/lib/tests/service_test_cases.rs index 1e4a76a5..042c6198 100644 --- a/lib/tests/service_test_cases.rs +++ b/lib/tests/service_test_cases.rs @@ -12,15 +12,12 @@ fn simple_service_test() { impl ServiceHandler for TestServiceHandler { fn handle<'a>( &'a self, - _named_node: &NamedNode, - ) -> Option<(fn(GraphPattern) -> Result>)> { - fn pattern_handler<'a>(graph_pattern: GraphPattern) -> Result> { - let triples = - b" ." - .as_ref(); - do_pattern(triples, graph_pattern, QueryOptions::default()) - }; - Some(pattern_handler) + _: &NamedNode, + graph_pattern: &'a GraphPattern, + ) -> Result> { + let triples = + b" .".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>)> { + graph_pattern: &'a GraphPattern, + ) -> Result> { 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> { - let triples = br#" + let triples = br#" "Bob" . "Alice" . "# - .as_ref(); - do_pattern(triples, graph_pattern, QueryOptions::default()) - } - - fn handle_service2<'a>(graph_pattern: GraphPattern) -> Result> { - let triples = br#" + .as_ref(); + do_pattern(triples, graph_pattern, QueryOptions::default()) + } else if named_node == &service2 { + let triples = br#" . . "# - .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>)> { - Some(ServiceTest::handle_service) - } - } - - impl ServiceTest { - fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result> { + _: &NamedNode, + _: &'a GraphPattern, + ) -> Result> { 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>)> { - Some(ServiceTest::handle_service) - } - } - - impl ServiceTest { - fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result> { + _: &NamedNode, + _: &'a GraphPattern, + ) -> Result> { 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> { 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> { let repository = make_repository(reader)?;