spareval/
service.rs

1use crate::{QueryEvaluationError, QuerySolutionIter};
2use oxrdf::NamedNode;
3use spargebra::algebra::GraphPattern;
4use std::collections::HashMap;
5use std::error::Error;
6use std::sync::Arc;
7
8/// Handler for [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) SERVICEs.
9///
10/// Should be given to [`QueryOptions`](super::QueryEvaluator::with_service_handler())
11/// before evaluating a SPARQL query that uses SERVICE calls.
12///
13/// Note that you can also use [`DefaultServiceHandler`] if you need to handle any service and not a specific one.
14///
15/// ```
16/// use oxrdf::{Dataset, Literal, NamedNode, Variable};
17/// use sparesults::QuerySolution;
18/// use spareval::{QueryEvaluator, QueryResults, QuerySolutionIter, ServiceHandler};
19/// use spargebra::algebra::GraphPattern;
20/// use spargebra::Query;
21/// use std::convert::Infallible;
22/// use std::iter::once;
23/// use std::sync::Arc;
24///
25/// struct TestServiceHandler {}
26///
27/// impl ServiceHandler for TestServiceHandler {
28///     type Error = Infallible;
29///
30///     fn handle(
31///         &self,
32///         _pattern: GraphPattern,
33///         _base_iri: Option<String>,
34///     ) -> Result<QuerySolutionIter, Self::Error> {
35///         // Always return a single binding foo -> 1
36///         let variables = [Variable::new_unchecked("foo")].into();
37///         Ok(QuerySolutionIter::new(
38///             Arc::clone(&variables),
39///             once(Ok(QuerySolution::from((
40///                 variables,
41///                 vec![Some(Literal::from(1).into())],
42///             )))),
43///         ))
44///     }
45/// }
46///
47/// let evaluator = QueryEvaluator::default().with_service_handler(
48///     NamedNode::new("http://example.com/service")?,
49///     TestServiceHandler {},
50/// );
51/// let query = Query::parse(
52///     "SELECT ?foo WHERE { SERVICE <http://example.com/service> {} }",
53///     None,
54/// )?;
55/// if let QueryResults::Solutions(mut solutions) = evaluator.execute(Dataset::new(), &query)? {
56///     assert_eq!(
57///         solutions.next().unwrap()?.get("foo"),
58///         Some(&Literal::from(1).into())
59///     );
60/// }
61/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
62/// ```
63pub trait ServiceHandler: Send + Sync {
64    /// The service evaluation error.
65    type Error: Error + Send + Sync + 'static;
66
67    /// Evaluates a [`Query`](spargebra::Query) against the service.
68    fn handle(
69        &self,
70        pattern: GraphPattern,
71        base_iri: Option<String>,
72    ) -> Result<QuerySolutionIter, Self::Error>;
73}
74
75/// Default handler for [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) SERVICEs.
76///
77/// Should be given to [`QueryOptions`](super::QueryEvaluator::with_default_service_handler())
78/// before evaluating a SPARQL query that uses SERVICE calls.
79///
80/// Note that you can also use [`ServiceHandler`] if you need to handle a single service and not any service.
81///
82/// ```
83/// use oxrdf::{Dataset, NamedNode, Variable};
84/// use sparesults::QuerySolution;
85/// use spareval::{DefaultServiceHandler, QueryEvaluator, QueryResults, QuerySolutionIter};
86/// use spargebra::algebra::GraphPattern;
87/// use spargebra::Query;
88/// use std::convert::Infallible;
89/// use std::iter::once;
90/// use std::sync::Arc;
91///
92/// struct TestServiceHandler {}
93///
94/// impl DefaultServiceHandler for TestServiceHandler {
95///     type Error = Infallible;
96///
97///     fn handle(
98///         &self,
99///         service_name: NamedNode,
100///         _pattern: GraphPattern,
101///         _base_iri: Option<String>,
102///     ) -> Result<QuerySolutionIter, Self::Error> {
103///         // Always return a single binding name -> name of service
104///         let variables = [Variable::new_unchecked("foo")].into();
105///         Ok(QuerySolutionIter::new(
106///             Arc::clone(&variables),
107///             once(Ok(QuerySolution::from((
108///                 variables,
109///                 vec![Some(service_name.into())],
110///             )))),
111///         ))
112///     }
113/// }
114///
115/// let evaluator = QueryEvaluator::default().with_default_service_handler(TestServiceHandler {});
116/// let query = Query::parse(
117///     "SELECT ?foo WHERE { SERVICE <http://example.com/service> {} }",
118///     None,
119/// )?;
120/// if let QueryResults::Solutions(mut solutions) = evaluator.execute(Dataset::new(), &query)? {
121///     assert_eq!(
122///         solutions.next().unwrap()?.get("foo"),
123///         Some(&NamedNode::new("http://example.com/service")?.into())
124///     );
125/// }
126/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
127/// ```
128pub trait DefaultServiceHandler: Send + Sync {
129    /// The service evaluation error.
130    type Error: Error + Send + Sync + 'static;
131
132    /// Evaluates a [`GraphPattern`] against a given service identified by a [`NamedNode`].
133    fn handle(
134        &self,
135        service_name: NamedNode,
136        pattern: GraphPattern,
137        base_iri: Option<String>,
138    ) -> Result<QuerySolutionIter, Self::Error>;
139}
140
141#[derive(Clone, Default)]
142pub struct ServiceHandlerRegistry {
143    default: Option<Arc<dyn DefaultServiceHandler<Error = QueryEvaluationError>>>,
144    handlers: HashMap<NamedNode, Arc<dyn ServiceHandler<Error = QueryEvaluationError>>>,
145}
146
147impl ServiceHandlerRegistry {
148    pub fn with_handler(
149        mut self,
150        service_name: NamedNode,
151        handler: impl ServiceHandler + 'static,
152    ) -> Self {
153        self.handlers.insert(
154            service_name,
155            Arc::new(ErrorConversionServiceHandler(handler)),
156        );
157        self
158    }
159
160    pub fn with_default_handler(mut self, default: impl DefaultServiceHandler + 'static) -> Self {
161        self.default = Some(Arc::new(ErrorConversionServiceHandler(default)));
162        self
163    }
164
165    pub fn has_default_handler(&self) -> bool {
166        self.default.is_some()
167    }
168
169    pub fn handle(
170        &self,
171        service_name: NamedNode,
172        pattern: GraphPattern,
173        base_iri: Option<String>,
174    ) -> Result<QuerySolutionIter, QueryEvaluationError> {
175        if let Some(handler) = self.handlers.get(&service_name) {
176            return handler.handle(pattern, base_iri);
177        }
178        if let Some(default) = &self.default {
179            return default.handle(service_name, pattern, base_iri);
180        }
181        Err(QueryEvaluationError::UnsupportedService(service_name))
182    }
183}
184
185struct ErrorConversionServiceHandler<S>(S);
186
187impl<S: ServiceHandler> ServiceHandler for ErrorConversionServiceHandler<S> {
188    type Error = QueryEvaluationError;
189
190    fn handle(
191        &self,
192        pattern: GraphPattern,
193        base_iri: Option<String>,
194    ) -> Result<QuerySolutionIter, QueryEvaluationError> {
195        self.0.handle(pattern, base_iri).map_err(wrap_service_error)
196    }
197}
198
199impl<S: DefaultServiceHandler> DefaultServiceHandler for ErrorConversionServiceHandler<S> {
200    type Error = QueryEvaluationError;
201
202    fn handle(
203        &self,
204        service_name: NamedNode,
205        pattern: GraphPattern,
206        base_iri: Option<String>,
207    ) -> Result<QuerySolutionIter, QueryEvaluationError> {
208        self.0
209            .handle(service_name, pattern, base_iri)
210            .map_err(wrap_service_error)
211    }
212}
213
214fn wrap_service_error(error: impl Error + Send + Sync + 'static) -> QueryEvaluationError {
215    let error: Box<dyn Error + Send + Sync> = Box::new(error);
216    match error.downcast() {
217        Ok(error) => *error,
218        Err(error) => QueryEvaluationError::Service(error),
219    }
220}