//! [SPARQL](https://www.w3.org/TR/sparql11-overview/) implementation.
mod algebra ;
mod dataset ;
mod error ;
mod eval ;
mod json_results ;
mod model ;
mod parser ;
mod plan ;
mod plan_builder ;
mod xml_results ;
use crate ::model ::NamedNode ;
use crate ::sparql ::algebra ::QueryVariants ;
use crate ::sparql ::eval ::SimpleEvaluator ;
pub use crate ::sparql ::model ::QuerySolution ;
pub use crate ::sparql ::model ::QuerySolutionsIterator ;
pub use crate ::sparql ::model ::QueryTriplesIterator ;
use crate ::sparql ::plan ::{ PlanNode , TripleTemplate } ;
use crate ::sparql ::plan_builder ::PlanBuilder ;
use crate ::store ::ReadableEncodedStore ;
use std ::convert ::TryInto ;
use std ::rc ::Rc ;
#[ deprecated(note = " Please directly use QuerySolutionsIterator type instead " ) ]
pub type BindingsIterator < ' a > = QuerySolutionsIterator ;
pub use crate ::sparql ::model ::QueryResult ;
pub use crate ::sparql ::model ::QueryResultFormat ;
#[ deprecated(note = " Use QueryResultFormat instead " ) ]
pub type QueryResultSyntax = QueryResultFormat ;
use crate ::sparql ::dataset ::DatasetView ;
pub use crate ::sparql ::error ::EvaluationError ;
pub use crate ::sparql ::model ::Variable ;
pub use crate ::sparql ::parser ::ParseError ;
pub use crate ::sparql ::parser ::Query ;
use crate ::store ::numeric_encoder ::WithStoreError ;
use std ::error ::Error ;
/// A prepared [SPARQL query](https://www.w3.org/TR/sparql11-query/)
#[ deprecated(
note = "Not useful anymore. The exec method is already implemented by the different PreparedQuery structures"
) ]
pub trait PreparedQuery { }
/// A prepared [SPARQL query](https://www.w3.org/TR/sparql11-query/)
pub ( crate ) struct SimplePreparedQuery < S : ReadableEncodedStore + ' static > (
SimplePreparedQueryAction < S > ,
) ;
#[ derive(Clone) ]
enum SimplePreparedQueryAction < S : ReadableEncodedStore + ' static > {
Select {
plan : Rc < PlanNode < < DatasetView < S > as WithStoreError > ::StrId > > ,
variables : Rc < Vec < Variable > > ,
evaluator : SimpleEvaluator < DatasetView < S > > ,
} ,
Ask {
plan : Rc < PlanNode < < DatasetView < S > as WithStoreError > ::StrId > > ,
evaluator : SimpleEvaluator < DatasetView < S > > ,
} ,
Construct {
plan : Rc < PlanNode < < DatasetView < S > as WithStoreError > ::StrId > > ,
construct : Rc < Vec < TripleTemplate < < DatasetView < S > as WithStoreError > ::StrId > > > ,
evaluator : SimpleEvaluator < DatasetView < S > > ,
} ,
Describe {
plan : Rc < PlanNode < < DatasetView < S > as WithStoreError > ::StrId > > ,
evaluator : SimpleEvaluator < DatasetView < S > > ,
} ,
}
impl < S : ReadableEncodedStore + ' static > SimplePreparedQuery < S > {
pub ( crate ) fn new (
store : S ,
query : impl TryInto < Query , Error = impl Into < EvaluationError > > ,
options : QueryOptions ,
) -> Result < Self , EvaluationError > {
let dataset = Rc ::new ( DatasetView ::new ( store , options . default_graph_as_union ) ) ;
Ok ( Self ( match query . try_into ( ) . map_err ( | e | e . into ( ) ) ? . 0 {
QueryVariants ::Select {
algebra , base_iri , ..
} = > {
let ( plan , variables ) = PlanBuilder ::build ( dataset . as_ref ( ) , & algebra ) ? ;
SimplePreparedQueryAction ::Select {
plan : Rc ::new ( plan ) ,
variables : Rc ::new ( variables ) ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri , options . service_handler ) ,
}
}
QueryVariants ::Ask {
algebra , base_iri , ..
} = > {
let ( plan , _ ) = PlanBuilder ::build ( dataset . as_ref ( ) , & algebra ) ? ;
SimplePreparedQueryAction ::Ask {
plan : Rc ::new ( plan ) ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri , options . service_handler ) ,
}
}
QueryVariants ::Construct {
construct ,
algebra ,
base_iri ,
..
} = > {
let ( plan , variables ) = PlanBuilder ::build ( dataset . as_ref ( ) , & algebra ) ? ;
SimplePreparedQueryAction ::Construct {
plan : Rc ::new ( plan ) ,
construct : Rc ::new ( PlanBuilder ::build_graph_template (
dataset . as_ref ( ) ,
& construct ,
variables ,
) ? ) ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri , options . service_handler ) ,
}
}
QueryVariants ::Describe {
algebra , base_iri , ..
} = > {
let ( plan , _ ) = PlanBuilder ::build ( dataset . as_ref ( ) , & algebra ) ? ;
SimplePreparedQueryAction ::Describe {
plan : Rc ::new ( plan ) ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri , options . service_handler ) ,
}
}
} ) )
}
/// Evaluates the query and returns its results
pub fn exec ( & self ) -> Result < QueryResult , EvaluationError > {
match & self . 0 {
SimplePreparedQueryAction ::Select {
plan ,
variables ,
evaluator ,
} = > evaluator . evaluate_select_plan ( plan , variables . clone ( ) ) ,
SimplePreparedQueryAction ::Ask { plan , evaluator } = > evaluator . evaluate_ask_plan ( plan ) ,
SimplePreparedQueryAction ::Construct {
plan ,
construct ,
evaluator ,
} = > evaluator . evaluate_construct_plan ( plan , construct . clone ( ) ) ,
SimplePreparedQueryAction ::Describe { plan , evaluator } = > {
evaluator . evaluate_describe_plan ( plan )
}
}
}
}
/// Options for SPARQL query evaluation
#[ derive(Clone) ]
pub struct QueryOptions {
pub ( crate ) default_graph_as_union : bool ,
pub ( crate ) service_handler : Rc < dyn ServiceHandler < Error = EvaluationError > > ,
}
impl Default for QueryOptions {
fn default ( ) -> Self {
Self {
default_graph_as_union : false ,
service_handler : Rc ::new ( EmptyServiceHandler ) ,
}
}
}
impl QueryOptions {
/// Consider the union of all graphs in the store as the default graph
pub const fn with_default_graph_as_union ( mut self ) -> Self {
self . default_graph_as_union = true ;
self
}
/// Use a given [`ServiceHandler`](trait.ServiceHandler.html) to execute [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) SERVICE calls.
pub fn with_service_handler ( mut self , service_handler : impl ServiceHandler + ' static ) -> Self {
self . service_handler = Rc ::new ( ErrorConversionServiceHandler {
handler : service_handler ,
} ) ;
self
}
}
/// Handler for [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) SERVICE.
///
/// Should be given to [`QueryOptions`](struct.QueryOptions.html#method.with_service_handler)
/// before evaluating a SPARQL query that uses SERVICE calls.
///
/// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*;
/// use oxigraph::sparql::{QueryOptions, QueryResult, ServiceHandler, Query, EvaluationError};
///
/// #[derive(Default)]
/// struct TestServiceHandler {
/// store: MemoryStore
/// }
///
/// impl ServiceHandler for TestServiceHandler {
/// type Error = EvaluationError;
///
/// fn handle(&self,service_name: NamedNode, query: Query) -> Result<QueryResult,EvaluationError> {
/// if service_name == "http://example.com/service" {
/// self.store.query(query, QueryOptions::default())
/// } else {
/// panic!()
/// }
/// }
/// }
///
/// let store = MemoryStore::new();
/// let service = TestServiceHandler::default();
/// let ex = NamedNode::new("http://example.com")?;
/// service.store.insert(Quad::new(ex.clone(), ex.clone(), ex.clone(), None));
///
/// if let QueryResult::Solutions(mut solutions) = store.query(
/// "SELECT ?s WHERE { SERVICE <http://example.com/service> { ?s ?p ?o } }",
/// QueryOptions::default().with_service_handler(service)
/// )? {
/// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
/// }
/// # Result::<_,Box<dyn std::error::Error>>::Ok(())
/// ```
pub trait ServiceHandler {
type Error : Error + Send + Sync + ' static ;
/// Evaluates a `Query` against a given service identified by a `NamedNode`.
fn handle ( & self , service_name : NamedNode , query : Query ) -> Result < QueryResult , Self ::Error > ;
}
struct EmptyServiceHandler ;
impl ServiceHandler for EmptyServiceHandler {
type Error = EvaluationError ;
fn handle ( & self , _ : NamedNode , _ : Query ) -> Result < QueryResult , EvaluationError > {
Err ( EvaluationError ::msg (
"The SERVICE feature is not implemented" ,
) )
}
}
struct ErrorConversionServiceHandler < S : ServiceHandler > {
handler : S ,
}
impl < S : ServiceHandler > ServiceHandler for ErrorConversionServiceHandler < S > {
type Error = EvaluationError ;
fn handle (
& self ,
service_name : NamedNode ,
query : Query ,
) -> Result < QueryResult , EvaluationError > {
self . handler
. handle ( service_name , query )
. map_err ( EvaluationError ::wrap )
}
}