//! [SPARQL](https://www.w3.org/TR/sparql11-overview/) implementation. mod algebra; 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::TripleTemplate; use crate::sparql::plan::{DatasetView, PlanNode}; 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; 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 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( SimplePreparedQueryAction, ); #[derive(Clone)] enum SimplePreparedQueryAction { Select { plan: Rc, variables: Rc>, evaluator: SimpleEvaluator, }, Ask { plan: Rc, evaluator: SimpleEvaluator, }, Construct { plan: Rc, construct: Rc>, evaluator: SimpleEvaluator, }, Describe { plan: Rc, evaluator: SimpleEvaluator, }, } impl SimplePreparedQuery { pub(crate) fn new( store: S, query: impl TryInto>, options: QueryOptions, ) -> Result { 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.encoder(), &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.encoder(), &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.encoder(), &algebra)?; SimplePreparedQueryAction::Construct { plan: Rc::new(plan), construct: Rc::new(PlanBuilder::build_graph_template( dataset.encoder(), &construct, variables, )?), evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), } } QueryVariants::Describe { algebra, base_iri, .. } => { let (plan, _) = PlanBuilder::build(dataset.encoder(), &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 { 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>, } 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` to execute SPARQL 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 SERVICEs. /// /// Might be used to implement [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) /// /// ``` /// 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 { /// 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 { ?s ?p ?o } }", /// QueryOptions::default().with_service_handler(service) /// )? { /// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into())); /// } /// # Result::<_,Box>::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; } struct EmptyServiceHandler; impl ServiceHandler for EmptyServiceHandler { type Error = EvaluationError; fn handle(&self, _: NamedNode, _: Query) -> Result { Err(EvaluationError::msg( "The SERVICE feature is not implemented", )) } } struct ErrorConversionServiceHandler { handler: S, } impl ServiceHandler for ErrorConversionServiceHandler { type Error = EvaluationError; fn handle( &self, service_name: NamedNode, query: Query, ) -> Result { self.handler .handle(service_name, query) .map_err(EvaluationError::wrap) } }