Fork of https://github.com/oxigraph/oxigraph.git for the purpose of NextGraph project
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
9.4 KiB
262 lines
9.4 KiB
//! [SPARQL](https://www.w3.org/TR/sparql11-overview/) implementation.
|
|
//!
|
|
//! Stores execute SPARQL. See [`MemoryStore`](../store/memory/struct.MemoryStore.html#method.query) for an example.
|
|
|
|
mod algebra;
|
|
mod csv_results;
|
|
mod dataset;
|
|
mod error;
|
|
mod eval;
|
|
mod http;
|
|
mod json_results;
|
|
mod model;
|
|
mod parser;
|
|
mod plan;
|
|
mod plan_builder;
|
|
mod service;
|
|
mod update;
|
|
mod xml_results;
|
|
|
|
use crate::model::{GraphName, NamedOrBlankNode};
|
|
use crate::sparql::algebra::QueryVariants;
|
|
use crate::sparql::dataset::DatasetView;
|
|
pub use crate::sparql::error::EvaluationError;
|
|
use crate::sparql::eval::SimpleEvaluator;
|
|
pub use crate::sparql::model::QueryResults;
|
|
pub use crate::sparql::model::QueryResultsFormat;
|
|
pub use crate::sparql::model::QuerySolution;
|
|
pub use crate::sparql::model::QuerySolutionIter;
|
|
pub use crate::sparql::model::QueryTripleIter;
|
|
pub use crate::sparql::model::Variable;
|
|
pub use crate::sparql::parser::ParseError;
|
|
pub use crate::sparql::parser::{Query, Update};
|
|
use crate::sparql::plan::{PlanNode, TripleTemplate};
|
|
use crate::sparql::plan_builder::PlanBuilder;
|
|
pub use crate::sparql::service::ServiceHandler;
|
|
use crate::sparql::service::{EmptyServiceHandler, ErrorConversionServiceHandler};
|
|
use crate::sparql::update::SimpleUpdateEvaluator;
|
|
use crate::store::numeric_encoder::{StrContainer, StrEncodingAware};
|
|
use crate::store::{ReadableEncodedStore, StoreOrParseError, WritableEncodedStore};
|
|
use std::convert::TryInto;
|
|
use std::io;
|
|
use std::rc::Rc;
|
|
|
|
/// 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 StrEncodingAware>::StrId>>,
|
|
variables: Rc<Vec<Variable>>,
|
|
evaluator: SimpleEvaluator<DatasetView<S>>,
|
|
},
|
|
Ask {
|
|
plan: Rc<PlanNode<<DatasetView<S> as StrEncodingAware>::StrId>>,
|
|
evaluator: SimpleEvaluator<DatasetView<S>>,
|
|
},
|
|
Construct {
|
|
plan: Rc<PlanNode<<DatasetView<S> as StrEncodingAware>::StrId>>,
|
|
construct: Rc<Vec<TripleTemplate<<DatasetView<S> as StrEncodingAware>::StrId>>>,
|
|
evaluator: SimpleEvaluator<DatasetView<S>>,
|
|
},
|
|
Describe {
|
|
plan: Rc<PlanNode<<DatasetView<S> as StrEncodingAware>::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> {
|
|
Ok(Self(match query.try_into().map_err(|e| e.into())?.0 {
|
|
QueryVariants::Select {
|
|
algebra,
|
|
base_iri,
|
|
dataset,
|
|
} => {
|
|
let dataset = Rc::new(DatasetView::new(
|
|
store,
|
|
options.default_graph_as_union,
|
|
&options.default_graphs,
|
|
&options.named_graphs,
|
|
&dataset,
|
|
)?);
|
|
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,
|
|
dataset,
|
|
} => {
|
|
let dataset = Rc::new(DatasetView::new(
|
|
store,
|
|
options.default_graph_as_union,
|
|
&options.default_graphs,
|
|
&options.named_graphs,
|
|
&dataset,
|
|
)?);
|
|
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,
|
|
dataset,
|
|
} => {
|
|
let dataset = Rc::new(DatasetView::new(
|
|
store,
|
|
options.default_graph_as_union,
|
|
&options.default_graphs,
|
|
&options.named_graphs,
|
|
&dataset,
|
|
)?);
|
|
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,
|
|
dataset,
|
|
} => {
|
|
let dataset = Rc::new(DatasetView::new(
|
|
store,
|
|
options.default_graph_as_union,
|
|
&options.default_graphs,
|
|
&options.named_graphs,
|
|
&dataset,
|
|
)?);
|
|
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<QueryResults, 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) default_graphs: Vec<GraphName>,
|
|
pub(crate) named_graphs: Vec<NamedOrBlankNode>,
|
|
pub(crate) service_handler: Rc<dyn ServiceHandler<Error = EvaluationError>>,
|
|
}
|
|
|
|
impl Default for QueryOptions {
|
|
#[inline]
|
|
fn default() -> Self {
|
|
Self {
|
|
default_graph_as_union: false,
|
|
default_graphs: Vec::new(),
|
|
named_graphs: Vec::new(),
|
|
service_handler: Rc::new(EmptyServiceHandler),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl QueryOptions {
|
|
/// Consider the union of all graphs in the store as the default graph
|
|
#[inline]
|
|
pub fn with_default_graph_as_union(mut self) -> Self {
|
|
self.default_graph_as_union = true;
|
|
self
|
|
}
|
|
|
|
/// Adds a graph to the set of graphs considered by the SPARQL query as the queried dataset default graph.
|
|
/// It overrides the `FROM` and `FROM NAMED` elements of the evaluated query.
|
|
#[inline]
|
|
pub fn with_default_graph(mut self, default_graph_name: impl Into<GraphName>) -> Self {
|
|
self.default_graphs.push(default_graph_name.into());
|
|
self
|
|
}
|
|
|
|
/// Adds a named graph to the set of graphs considered by the SPARQL query as the queried dataset named graphs.
|
|
/// It overrides the `FROM` and `FROM NAMED` elements of the evaluated query.
|
|
#[inline]
|
|
pub fn with_named_graph(mut self, named_graph_name: impl Into<NamedOrBlankNode>) -> Self {
|
|
self.named_graphs.push(named_graph_name.into());
|
|
self
|
|
}
|
|
|
|
/// Use a simple HTTP 1.1 client built into Oxigraph to execute [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) SERVICE calls.
|
|
///
|
|
/// Requires the `"http_client"` optional feature.
|
|
#[inline]
|
|
#[cfg(feature = "http_client")]
|
|
pub fn with_simple_service_handler(mut self) -> Self {
|
|
self.service_handler = Rc::new(service::SimpleServiceHandler::new());
|
|
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.
|
|
#[inline]
|
|
pub fn with_service_handler(mut self, service_handler: impl ServiceHandler + 'static) -> Self {
|
|
self.service_handler = Rc::new(ErrorConversionServiceHandler::wrap(service_handler));
|
|
self
|
|
}
|
|
}
|
|
|
|
pub(crate) fn evaluate_update<
|
|
R: ReadableEncodedStore + Clone + 'static,
|
|
W: StrContainer<StrId = R::StrId> + WritableEncodedStore<StrId = R::StrId>,
|
|
>(
|
|
read: R,
|
|
write: &mut W,
|
|
update: &Update,
|
|
) -> Result<(), EvaluationError>
|
|
where
|
|
io::Error: From<StoreOrParseError<W::Error>>,
|
|
{
|
|
SimpleUpdateEvaluator::new(
|
|
read,
|
|
write,
|
|
update.base_iri.clone(),
|
|
Rc::new(EmptyServiceHandler),
|
|
)
|
|
.eval_all(&update.operations)
|
|
}
|
|
|