use sophia_iri::Iri;
use crate::source::TripleSource;
use crate::term::Term;
use std::borrow::Borrow;
use std::error::Error;
pub trait SparqlDataset {
type BindingsTerm: Term;
type BindingsResult: SparqlBindings<Self>;
type TriplesResult: TripleSource;
type SparqlError: Error + Send + Sync + 'static;
type Query: Query<Error = Self::SparqlError>;
fn query<Q>(&self, query: Q) -> Result<SparqlResult<Self>, Self::SparqlError>
where
Q: IntoQuery<Self::Query>;
fn prepare_query(&self, query_string: &str) -> Result<Self::Query, Self::SparqlError> {
Self::Query::parse(query_string)
}
fn prepare_query_with(
&self,
query_string: &str,
base: Iri<&str>,
) -> Result<Self::Query, Self::SparqlError> {
Self::Query::parse_with(query_string, base)
}
}
pub trait Query: Sized {
type Error: Error + Send + Sync + 'static;
fn parse(query_source: &str) -> Result<Self, Self::Error>;
fn parse_with(query_source: &str, base: Iri<&str>) -> Result<Self, Self::Error>;
}
impl Query for String {
type Error = std::convert::Infallible;
fn parse(query_source: &str) -> Result<Self, Self::Error> {
Ok(query_source.into())
}
fn parse_with(query_source: &str, base: Iri<&str>) -> Result<Self, Self::Error> {
Ok(format!("BASE <{base}>\n{query_source}"))
}
}
pub trait IntoQuery<Q: Query> {
type Out: Borrow<Q>;
fn into_query(self) -> Result<Self::Out, Q::Error>;
}
impl<'a, Q> IntoQuery<Q> for &'a Q
where
Q: Query,
{
type Out = &'a Q;
fn into_query(self) -> Result<Self::Out, Q::Error> {
Ok(self)
}
}
impl<'a, Q> IntoQuery<Q> for &'a str
where
Q: Query,
{
type Out = Q;
fn into_query(self) -> Result<Self::Out, Q::Error> {
Q::parse(self)
}
}
pub enum SparqlResult<T>
where
T: SparqlDataset + ?Sized,
{
Bindings(T::BindingsResult),
Boolean(bool),
Triples(T::TriplesResult),
}
impl<T> SparqlResult<T>
where
T: SparqlDataset + ?Sized,
{
pub fn into_bindings(self) -> T::BindingsResult {
match self {
SparqlResult::Bindings(b) => b,
_ => panic!("This SparqlResult is not a Bindings"),
}
}
pub fn into_boolean(self) -> bool {
match self {
SparqlResult::Boolean(b) => b,
_ => panic!("This SparqlResult is not a Boolean"),
}
}
pub fn into_triples(self) -> T::TriplesResult {
match self {
SparqlResult::Triples(t) => t,
_ => panic!("This SparqlResult is not a Triples"),
}
}
}
pub trait SparqlBindings<D>:
IntoIterator<Item = Result<Vec<Option<D::BindingsTerm>>, D::SparqlError>>
where
D: SparqlDataset + ?Sized,
{
fn variables(&self) -> Vec<&str>;
}