//! [SPARQL](https://www.w3.org/TR/sparql11-overview/) implementation. mod algebra; 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; use crate::sparql::parser::read_sparql_query; use crate::sparql::plan::TripleTemplate; 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; pub use crate::sparql::algebra::GraphPattern; pub use crate::sparql::model::BindingsIterator; pub use crate::sparql::model::QueryResult; pub use crate::sparql::model::QueryResultSyntax; 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>; } /// An implementation of `PreparedQuery` for internal use pub struct SimplePreparedQuery(SimplePreparedQueryAction); enum SimplePreparedQueryAction { Select { plan: PlanNode, variables: Vec, evaluator: SimpleEvaluator, }, Ask { plan: PlanNode, evaluator: SimpleEvaluator, }, Construct { plan: PlanNode, construct: Vec, evaluator: SimpleEvaluator, }, Describe { plan: PlanNode, evaluator: SimpleEvaluator, }, } impl<'a, S: StoreConnection + 'a> SimplePreparedQuery { pub(crate) fn new(connection: S, query: &str, base_iri: Option<&'a str>) -> Result { let dataset = DatasetView::new(connection); //TODO avoid inserting terms in the Repository StringStore Ok(Self(match read_sparql_query(query, base_iri)? { QueryVariants::Select { algebra, dataset: _, base_iri, } => { let (plan, variables) = PlanBuilder::build(dataset.encoder(), &algebra)?; SimplePreparedQueryAction::Select { plan, variables, evaluator: SimpleEvaluator::new(dataset, base_iri), } } QueryVariants::Ask { algebra, dataset: _, base_iri, } => { let (plan, _) = PlanBuilder::build(dataset.encoder(), &algebra)?; SimplePreparedQueryAction::Ask { plan, evaluator: SimpleEvaluator::new(dataset, base_iri), } } QueryVariants::Construct { construct, algebra, dataset: _, base_iri, } => { let (plan, variables) = PlanBuilder::build(dataset.encoder(), &algebra)?; SimplePreparedQueryAction::Construct { plan, construct: PlanBuilder::build_graph_template( dataset.encoder(), &construct, variables, )?, evaluator: SimpleEvaluator::new(dataset, base_iri), } } QueryVariants::Describe { algebra, dataset: _, base_iri, } => { let (plan, _) = PlanBuilder::build(dataset.encoder(), &algebra)?; SimplePreparedQueryAction::Describe { plan, evaluator: SimpleEvaluator::new(dataset, base_iri), } } })) } /// Builds SimplePreparedQuery from an existing `GraphPattern`. This is used to support federated queries via `SERVICE` clauses pub(crate) fn new_from_pattern( connection: S, pattern: &GraphPattern, base_iri: Option<&'a str>, ) -> Result { let dataset = DatasetView::new(connection); 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 { plan, variables, evaluator: SimpleEvaluator::new(dataset, Some(base_iri)), })), None => Ok(Self(SimplePreparedQueryAction::Select { plan, variables, evaluator: SimpleEvaluator::new(dataset, None), })), } } } impl PreparedQuery for SimplePreparedQuery { fn exec<'a>(&'a self, options: &'a QueryOptions<'a>) -> Result> { match &self.0 { SimplePreparedQueryAction::Select { plan, variables, evaluator, } => evaluator.evaluate_select_plan(&plan, &variables, options), SimplePreparedQueryAction::Ask { plan, evaluator } => { evaluator.evaluate_ask_plan(&plan, options) } SimplePreparedQueryAction::Construct { plan, construct, evaluator, } => evaluator.evaluate_construct_plan(&plan, &construct, &options), SimplePreparedQueryAction::Describe { plan, evaluator } => { evaluator.evaluate_describe_plan(&plan, &options) } } } } pub trait ServiceHandler { fn handle<'a>( &'a self, node: NamedNode, ) -> Option<(fn(GraphPattern) -> Result>)>; } /// 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>, } impl<'a> Default for QueryOptions<'a> { fn default() -> Self { Self { base_iri: None, default_graph_as_union: false, service_handler: None as Option>, } } } impl<'a> QueryOptions<'a> { /// Allows to set the base IRI of the query pub fn with_base_iri(mut self, base_iri: &'a str) -> Self { self.base_iri = Some(base_iri); self } /// Consider the union of all graphs in the repository as the default graph pub fn with_default_graph_as_union(mut self) -> Self { self.default_graph_as_union = true; self } /// Consider the union of all graphs in the repository as the default graph pub fn with_service_handler(mut self, service_handler: Box) -> Self { self.service_handler = Some(service_handler); self } } /// A parsed [SPARQL query](https://www.w3.org/TR/sparql11-query/) #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct Query(QueryVariants); impl fmt::Display for Query { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl Query { /// Parses a SPARQL query pub fn parse(query: &str, base_iri: Option<&str>) -> Result { Ok(Query(read_sparql_query(query, base_iri)?)) } }