use crate::{QueryEvaluationError, QuerySolutionIter};
use oxiri::Iri;
use oxrdf::NamedNode;
use spargebra::algebra::GraphPattern;
use std::collections::HashMap;
use std::error::Error;
use std::sync::Arc;
pub trait ServiceHandler: Send + Sync {
type Error: Error + Send + Sync + 'static;
fn handle(
&self,
pattern: &GraphPattern,
base_iri: Option<&Iri<String>>,
) -> Result<QuerySolutionIter<'static>, Self::Error>;
}
pub trait DefaultServiceHandler: Send + Sync {
type Error: Error + Send + Sync + 'static;
fn handle(
&self,
service_name: &NamedNode,
pattern: &GraphPattern,
base_iri: Option<&Iri<String>>,
) -> Result<QuerySolutionIter<'static>, Self::Error>;
}
#[derive(Clone, Default)]
pub struct ServiceHandlerRegistry {
default: Option<Arc<dyn DefaultServiceHandler<Error = QueryEvaluationError>>>,
handlers: HashMap<NamedNode, Arc<dyn ServiceHandler<Error = QueryEvaluationError>>>,
}
impl ServiceHandlerRegistry {
pub fn with_handler(
mut self,
service_name: NamedNode,
handler: impl ServiceHandler + 'static,
) -> Self {
self.handlers.insert(
service_name,
Arc::new(ErrorConversionServiceHandler(handler)),
);
self
}
pub fn with_default_handler(mut self, default: impl DefaultServiceHandler + 'static) -> Self {
self.default = Some(Arc::new(ErrorConversionServiceHandler(default)));
self
}
pub fn has_default_handler(&self) -> bool {
self.default.is_some()
}
pub fn handle(
&self,
service_name: &NamedNode,
pattern: &GraphPattern,
base_iri: Option<&Iri<String>>,
) -> Result<QuerySolutionIter<'static>, QueryEvaluationError> {
if let Some(handler) = self.handlers.get(service_name) {
return handler.handle(pattern, base_iri);
}
if let Some(default) = &self.default {
return default.handle(service_name, pattern, base_iri);
}
Err(QueryEvaluationError::UnsupportedService(
service_name.clone(),
))
}
}
struct ErrorConversionServiceHandler<S>(S);
impl<S: ServiceHandler> ServiceHandler for ErrorConversionServiceHandler<S> {
type Error = QueryEvaluationError;
fn handle(
&self,
pattern: &GraphPattern,
base_iri: Option<&Iri<String>>,
) -> Result<QuerySolutionIter<'static>, QueryEvaluationError> {
self.0.handle(pattern, base_iri).map_err(wrap_service_error)
}
}
impl<S: DefaultServiceHandler> DefaultServiceHandler for ErrorConversionServiceHandler<S> {
type Error = QueryEvaluationError;
fn handle(
&self,
service_name: &NamedNode,
pattern: &GraphPattern,
base_iri: Option<&Iri<String>>,
) -> Result<QuerySolutionIter<'static>, QueryEvaluationError> {
self.0
.handle(service_name, pattern, base_iri)
.map_err(wrap_service_error)
}
}
fn wrap_service_error(error: impl Error + Send + Sync + 'static) -> QueryEvaluationError {
let error: Box<dyn Error + Send + Sync> = Box::new(error);
match error.downcast() {
Ok(error) => *error,
Err(error) => QueryEvaluationError::Service(error),
}
}