@ -18,7 +18,6 @@ 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 ;
@ -31,7 +30,7 @@ pub use crate::sparql::model::Variable;
/// A prepared [SPARQL query](https://www.w3.org/TR/sparql11-query/)
pub trait PreparedQuery {
/// Evaluates the query and returns its results
fn exec < ' a > ( & ' a self , options : & ' a QueryOptions < ' a > ) -> Result < QueryResult < ' a > > ;
fn exec ( & self ) -> Result < QueryResult > ;
}
/// An implementation of `PreparedQuery` for internal use
@ -59,10 +58,9 @@ enum SimplePreparedQueryAction<S: StoreConnection> {
}
impl < ' a , S : StoreConnection + ' a > SimplePreparedQuery < S > {
pub ( crate ) fn new ( connection : S , query : & str , base_iri : Option < & ' a str > ) -> Result < Self > {
let dataset = DatasetView ::new ( connection ) ;
//TODO avoid inserting terms in the Repository StringStore
Ok ( Self ( match read_sparql_query ( query , base_iri ) ? {
pub ( crate ) fn new ( connection : S , query : & str , options : QueryOptions ) -> Result < Self > {
let dataset = DatasetView ::new ( connection , options . default_graph_as_union ) ;
Ok ( Self ( match read_sparql_query ( query , options . base_iri ) ? {
QueryVariants ::Select {
algebra ,
dataset : _ ,
@ -72,7 +70,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
SimplePreparedQueryAction ::Select {
plan ,
variables ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri ) ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri , options . service_handler ) ,
}
}
QueryVariants ::Ask {
@ -83,7 +81,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
let ( plan , _ ) = PlanBuilder ::build ( dataset . encoder ( ) , & algebra ) ? ;
SimplePreparedQueryAction ::Ask {
plan ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri ) ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri , options . service_handler ) ,
}
}
QueryVariants ::Construct {
@ -100,7 +98,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
& construct ,
variables ,
) ? ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri ) ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri , options . service_handler ) ,
}
}
QueryVariants ::Describe {
@ -111,7 +109,7 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
let ( plan , _ ) = PlanBuilder ::build ( dataset . encoder ( ) , & algebra ) ? ;
SimplePreparedQueryAction ::Describe {
plan ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri ) ,
evaluator : SimpleEvaluator ::new ( dataset , base_iri , options . service_handler ) ,
}
}
} ) )
@ -121,62 +119,77 @@ impl<'a, S: StoreConnection + 'a> SimplePreparedQuery<S> {
pub ( crate ) fn new_from_pattern (
connection : S ,
pattern : & GraphPattern ,
base_iri : Option < & ' a str > ,
options : QueryOptions ,
) -> Result < Self > {
let dataset = DatasetView ::new ( connection ) ;
let dataset = DatasetView ::new ( connection , options . default_graph_as_union ) ;
let ( plan , variables ) = PlanBuilder ::build ( dataset . encoder ( ) , pattern ) ? ;
let base_iri = base_iri . map ( | str_iri | Iri ::parse ( str_iri . to_string ( ) ) ) ;
match base_iri {
Some ( Err ( _ ) ) = > Err ( format_err ! ( "Failed to parse base_iri" ) ) ,
Some ( Ok ( base_iri ) ) = > Ok ( Self ( SimplePreparedQueryAction ::Select {
let base_iri = if let Some ( base_iri ) = options . base_iri {
Some ( Iri ::parse ( base_iri . to_string ( ) ) ? )
} else {
None
} ;
Ok ( Self ( SimplePreparedQueryAction ::Select {
plan ,
variables ,
evaluator : SimpleEvaluator ::new ( dataset , Some ( base_iri ) ) ,
} ) ) ,
None = > Ok ( Self ( SimplePreparedQueryAction ::Select {
plan ,
variables ,
evaluator : SimpleEvaluator ::new ( dataset , None ) ,
} ) ) ,
}
evaluator : SimpleEvaluator ::new ( dataset , base_iri , options . service_handler ) ,
} ) )
}
}
impl < S : StoreConnection > PreparedQuery for SimplePreparedQuery < S > {
fn exec < ' a > ( & ' a self , options : & ' a QueryOptions < ' a > ) -> Result < QueryResult < ' a > > {
fn exec ( & self ) -> Result < QueryResult > {
match & self . 0 {
SimplePreparedQueryAction ::Select {
plan ,
variables ,
evaluator ,
} = > evaluator . evaluate_select_plan ( & plan , & variables , options ) ,
} = > evaluator . evaluate_select_plan ( & plan , & variables ) ,
SimplePreparedQueryAction ::Ask { plan , evaluator } = > {
evaluator . evaluate_ask_plan ( & plan , options )
evaluator . evaluate_ask_plan ( & plan )
}
SimplePreparedQueryAction ::Construct {
plan ,
construct ,
evaluator ,
} = > evaluator . evaluate_construct_plan ( & plan , & construct , & options ) ,
} = > evaluator . evaluate_construct_plan ( & plan , & construct ) ,
SimplePreparedQueryAction ::Describe { plan , evaluator } = > {
evaluator . evaluate_describe_plan ( & plan , & options )
evaluator . evaluate_describe_plan ( & plan )
}
}
}
}
/// Handler for SPARQL SERVICEs.
///
/// 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.
fn handle < ' a > (
& ' a self ,
node : NamedNode ,
node : & NamedNode ,
) -> Option < ( fn ( GraphPattern ) -> Result < BindingsIterator < ' a > > ) > ;
}
#[ derive(Default) ]
struct EmptyServiceHandler { }
impl ServiceHandler for EmptyServiceHandler {
fn handle (
& self ,
_node : & NamedNode ,
) -> Option < ( fn ( GraphPattern ) -> Result < BindingsIterator < ' static > > ) > {
None
}
}
/// Options for SPARQL query parsing and evaluation like the query base IRI
pub struct QueryOptions < ' a > {
pub ( crate ) base_iri : Option < & ' a str > ,
pub ( crate ) default_graph_as_union : bool ,
pub ( crate ) service_handler : Option < Box < dyn ServiceHandler > > ,
pub ( crate ) service_handler : Box < dyn ServiceHandler > ,
}
impl < ' a > Default for QueryOptions < ' a > {
@ -184,7 +197,7 @@ impl<'a> Default for QueryOptions<'a> {
Self {
base_iri : None ,
default_graph_as_union : false ,
service_handler : None as Option < Box < dyn ServiceHandler > > ,
service_handler : Box ::new ( EmptyServiceHandler ::default ( ) ) ,
}
}
}
@ -204,7 +217,7 @@ 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 < dyn ServiceHandler > ) -> Self {
self . service_handler = Some ( service_handler ) ;
self . service_handler = service_handler ;
self
}
}