Drops base_iri from QueryOptions and allows to Give a Query object to execute

The base IRI should now be given to the Query::parse method
pull/46/head
Tpt 4 years ago
parent 90d4baae2a
commit 36bc870ca8
  1. 35
      lib/src/sparql/mod.rs
  2. 17
      lib/src/sparql/parser.rs
  3. 10
      lib/src/store/memory.rs
  4. 18
      lib/src/store/rocksdb.rs
  5. 18
      lib/src/store/sled.rs
  6. 30
      lib/tests/service_test_cases.rs
  7. 6
      testsuite/src/sparql_evaluator.rs

@ -18,7 +18,6 @@ use crate::sparql::plan_builder::PlanBuilder;
use crate::store::ReadableEncodedStore; use crate::store::ReadableEncodedStore;
use crate::Error; use crate::Error;
use crate::Result; use crate::Result;
use oxiri::Iri;
pub use crate::sparql::algebra::GraphPattern; pub use crate::sparql::algebra::GraphPattern;
pub use crate::sparql::model::QuerySolution; pub use crate::sparql::model::QuerySolution;
@ -30,6 +29,7 @@ pub use crate::sparql::model::QueryResultSyntax;
pub use crate::sparql::model::Variable; pub use crate::sparql::model::Variable;
pub use crate::sparql::parser::Query; pub use crate::sparql::parser::Query;
pub use crate::sparql::parser::SparqlParseError; pub use crate::sparql::parser::SparqlParseError;
use std::convert::TryInto;
/// A prepared [SPARQL query](https://www.w3.org/TR/sparql11-query/) /// A prepared [SPARQL query](https://www.w3.org/TR/sparql11-query/)
#[deprecated( #[deprecated(
@ -62,9 +62,13 @@ enum SimplePreparedQueryAction<S: ReadableEncodedStore> {
} }
impl<S: ReadableEncodedStore> SimplePreparedQuery<S> { impl<S: ReadableEncodedStore> SimplePreparedQuery<S> {
pub(crate) fn new(store: S, query: &str, options: QueryOptions<'_>) -> Result<Self> { pub(crate) fn new(
store: S,
query: impl TryInto<Query, Error = impl Into<Error>>,
options: QueryOptions,
) -> Result<Self> {
let dataset = DatasetView::new(store, options.default_graph_as_union); let dataset = DatasetView::new(store, options.default_graph_as_union);
Ok(Self(match Query::parse(query, options.base_iri)?.0 { Ok(Self(match query.try_into().map_err(|e| e.into())?.0 {
QueryVariants::Select { QueryVariants::Select {
algebra, base_iri, .. algebra, base_iri, ..
} => { } => {
@ -117,19 +121,14 @@ impl<S: ReadableEncodedStore> SimplePreparedQuery<S> {
pub(crate) fn new_from_pattern( pub(crate) fn new_from_pattern(
store: S, store: S,
pattern: &GraphPattern, pattern: &GraphPattern,
options: QueryOptions<'_>, options: QueryOptions,
) -> Result<Self> { ) -> Result<Self> {
let dataset = DatasetView::new(store, options.default_graph_as_union); let dataset = DatasetView::new(store, options.default_graph_as_union);
let (plan, variables) = PlanBuilder::build(dataset.encoder(), pattern)?; let (plan, variables) = PlanBuilder::build(dataset.encoder(), pattern)?;
let base_iri = if let Some(base_iri) = options.base_iri {
Some(Iri::parse(base_iri.to_string())?)
} else {
None
};
Ok(Self(SimplePreparedQueryAction::Select { Ok(Self(SimplePreparedQueryAction::Select {
plan, plan,
variables, variables,
evaluator: SimpleEvaluator::new(dataset, base_iri, options.service_handler), evaluator: SimpleEvaluator::new(dataset, None, options.service_handler),
})) }))
} }
@ -190,30 +189,22 @@ impl ServiceHandler for EmptyServiceHandler {
} }
} }
/// Options for SPARQL query parsing and evaluation like the query base IRI /// Options for SPARQL query evaluation
pub struct QueryOptions<'a> { pub struct QueryOptions {
pub(crate) base_iri: Option<&'a str>,
pub(crate) default_graph_as_union: bool, pub(crate) default_graph_as_union: bool,
pub(crate) service_handler: Box<dyn ServiceHandler>, pub(crate) service_handler: Box<dyn ServiceHandler>,
} }
impl<'a> Default for QueryOptions<'a> { impl Default for QueryOptions {
fn default() -> Self { fn default() -> Self {
Self { Self {
base_iri: None,
default_graph_as_union: false, default_graph_as_union: false,
service_handler: Box::new(EmptyServiceHandler), service_handler: Box::new(EmptyServiceHandler),
} }
} }
} }
impl<'a> QueryOptions<'a> { impl QueryOptions {
/// Allows setting 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 store as the default graph /// Consider the union of all graphs in the store as the default graph
pub const fn with_default_graph_as_union(mut self) -> Self { pub const fn with_default_graph_as_union(mut self) -> Self {
self.default_graph_as_union = true; self.default_graph_as_union = true;

@ -9,6 +9,7 @@ use peg::parser;
use peg::str::LineCol; use peg::str::LineCol;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::convert::TryFrom;
use std::error::Error; use std::error::Error;
use std::str::Chars; use std::str::Chars;
use std::str::FromStr; use std::str::FromStr;
@ -61,6 +62,22 @@ impl FromStr for Query {
} }
} }
impl<'a> TryFrom<&'a str> for Query {
type Error = SparqlParseError;
fn try_from(query: &str) -> Result<Self, SparqlParseError> {
Self::from_str(query)
}
}
impl<'a> TryFrom<&'a String> for Query {
type Error = SparqlParseError;
fn try_from(query: &String) -> Result<Self, SparqlParseError> {
Self::from_str(query)
}
}
/// Error returned during SPARQL parsing. /// Error returned during SPARQL parsing.
#[derive(Debug)] #[derive(Debug)]
pub struct SparqlParseError { pub struct SparqlParseError {

@ -2,13 +2,13 @@
use crate::error::UnwrapInfallible; use crate::error::UnwrapInfallible;
use crate::model::*; use crate::model::*;
use crate::sparql::{GraphPattern, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::sparql::{GraphPattern, Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
use crate::store::{load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore}; use crate::store::{load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore};
use crate::{DatasetSyntax, Error, GraphSyntax}; use crate::{DatasetSyntax, Error, GraphSyntax};
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::convert::Infallible; use std::convert::{Infallible, TryInto};
use std::fmt; use std::fmt;
use std::hash::{BuildHasherDefault, Hash, Hasher}; use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::io::BufRead; use std::io::BufRead;
@ -105,8 +105,8 @@ impl MemoryStore {
/// ``` /// ```
pub fn prepare_query( pub fn prepare_query(
&self, &self,
query: &str, query: impl TryInto<Query, Error = impl Into<Error>>,
options: QueryOptions<'_>, options: QueryOptions,
) -> crate::Result<MemoryPreparedQuery> { ) -> crate::Result<MemoryPreparedQuery> {
Ok(MemoryPreparedQuery(SimplePreparedQuery::new( Ok(MemoryPreparedQuery(SimplePreparedQuery::new(
self.clone(), self.clone(),
@ -119,7 +119,7 @@ impl MemoryStore {
pub fn prepare_query_from_pattern( pub fn prepare_query_from_pattern(
&self, &self,
graph_pattern: &GraphPattern, graph_pattern: &GraphPattern,
options: QueryOptions<'_>, options: QueryOptions,
) -> crate::Result<MemoryPreparedQuery> { ) -> crate::Result<MemoryPreparedQuery> {
Ok(MemoryPreparedQuery(SimplePreparedQuery::new_from_pattern( Ok(MemoryPreparedQuery(SimplePreparedQuery::new_from_pattern(
self.clone(), self.clone(),

@ -2,12 +2,12 @@
use crate::error::UnwrapInfallible; use crate::error::UnwrapInfallible;
use crate::model::*; use crate::model::*;
use crate::sparql::{GraphPattern, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::sparql::{GraphPattern, Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
use crate::store::{load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore}; use crate::store::{load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore};
use crate::{DatasetSyntax, GraphSyntax, Result}; use crate::{DatasetSyntax, GraphSyntax, Result};
use rocksdb::*; use rocksdb::*;
use std::convert::Infallible; use std::convert::{Infallible, TryInto};
use std::io::{BufRead, Cursor}; use std::io::{BufRead, Cursor};
use std::mem::{take, transmute}; use std::mem::{take, transmute};
use std::path::Path; use std::path::Path;
@ -92,10 +92,10 @@ impl RocksDbStore {
/// Prepares a [SPARQL 1.1 query](https://www.w3.org/TR/sparql11-query/) and returns an object that could be used to execute it. /// Prepares a [SPARQL 1.1 query](https://www.w3.org/TR/sparql11-query/) and returns an object that could be used to execute it.
/// ///
/// See `MemoryStore` for a usage example. /// See `MemoryStore` for a usage example.
pub fn prepare_query<'a>( pub fn prepare_query(
&'a self, &self,
query: &str, query: impl TryInto<Query, Error = impl Into<crate::Error>>,
options: QueryOptions<'_>, options: QueryOptions,
) -> Result<RocksDbPreparedQuery> { ) -> Result<RocksDbPreparedQuery> {
Ok(RocksDbPreparedQuery(SimplePreparedQuery::new( Ok(RocksDbPreparedQuery(SimplePreparedQuery::new(
(*self).clone(), (*self).clone(),
@ -105,10 +105,10 @@ impl RocksDbStore {
} }
/// This is similar to `prepare_query`, but useful if a SPARQL query has already been parsed, which is the case when building `ServiceHandler`s for federated queries with `SERVICE` clauses. For examples, look in the tests. /// This is similar to `prepare_query`, but useful if a SPARQL query has already been parsed, which is the case when building `ServiceHandler`s for federated queries with `SERVICE` clauses. For examples, look in the tests.
pub fn prepare_query_from_pattern<'a>( pub fn prepare_query_from_pattern(
&'a self, &self,
graph_pattern: &GraphPattern, graph_pattern: &GraphPattern,
options: QueryOptions<'_>, options: QueryOptions,
) -> Result<RocksDbPreparedQuery> { ) -> Result<RocksDbPreparedQuery> {
Ok(RocksDbPreparedQuery(SimplePreparedQuery::new_from_pattern( Ok(RocksDbPreparedQuery(SimplePreparedQuery::new_from_pattern(
(*self).clone(), (*self).clone(),

@ -2,12 +2,12 @@
use crate::error::UnwrapInfallible; use crate::error::UnwrapInfallible;
use crate::model::*; use crate::model::*;
use crate::sparql::{GraphPattern, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::sparql::{GraphPattern, Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
use crate::store::{load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore}; use crate::store::{load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore};
use crate::{DatasetSyntax, Error, GraphSyntax, Result}; use crate::{DatasetSyntax, Error, GraphSyntax, Result};
use sled::{Batch, Config, Iter, Tree}; use sled::{Batch, Config, Iter, Tree};
use std::convert::Infallible; use std::convert::{Infallible, TryInto};
use std::io::{BufRead, Cursor}; use std::io::{BufRead, Cursor};
use std::path::Path; use std::path::Path;
use std::{fmt, str}; use std::{fmt, str};
@ -87,10 +87,10 @@ impl SledStore {
/// Prepares a [SPARQL 1.1 query](https://www.w3.org/TR/sparql11-query/) and returns an object that could be used to execute it. /// Prepares a [SPARQL 1.1 query](https://www.w3.org/TR/sparql11-query/) and returns an object that could be used to execute it.
/// ///
/// See `MemoryStore` for a usage example. /// See `MemoryStore` for a usage example.
pub fn prepare_query<'a>( pub fn prepare_query(
&'a self, &self,
query: &str, query: impl TryInto<Query, Error = impl Into<Error>>,
options: QueryOptions<'_>, options: QueryOptions,
) -> Result<SledPreparedQuery> { ) -> Result<SledPreparedQuery> {
Ok(SledPreparedQuery(SimplePreparedQuery::new( Ok(SledPreparedQuery(SimplePreparedQuery::new(
(*self).clone(), (*self).clone(),
@ -100,10 +100,10 @@ impl SledStore {
} }
/// This is similar to `prepare_query`, but useful if a SPARQL query has already been parsed, which is the case when building `ServiceHandler`s for federated queries with `SERVICE` clauses. For examples, look in the tests. /// This is similar to `prepare_query`, but useful if a SPARQL query has already been parsed, which is the case when building `ServiceHandler`s for federated queries with `SERVICE` clauses. For examples, look in the tests.
pub fn prepare_query_from_pattern<'a>( pub fn prepare_query_from_pattern(
&'a self, &self,
graph_pattern: &GraphPattern, graph_pattern: &GraphPattern,
options: QueryOptions<'_>, options: QueryOptions,
) -> Result<SledPreparedQuery> { ) -> Result<SledPreparedQuery> {
Ok(SledPreparedQuery(SimplePreparedQuery::new_from_pattern( Ok(SledPreparedQuery(SimplePreparedQuery::new_from_pattern(
(*self).clone(), (*self).clone(),

@ -30,7 +30,7 @@ fn simple_service_test() {
.to_string(); .to_string();
let options = QueryOptions::default().with_service_handler(TestServiceHandler); let options = QueryOptions::default().with_service_handler(TestServiceHandler);
let collected = do_query(b"".as_ref(), query, options) let collected = do_query(b"".as_ref(), &query, options)
.unwrap() .unwrap()
.map(|b| { .map(|b| {
b.unwrap() b.unwrap()
@ -93,7 +93,7 @@ fn two_service_test() {
.to_string(); .to_string();
let options = QueryOptions::default().with_service_handler(TwoServiceTest); let options = QueryOptions::default().with_service_handler(TwoServiceTest);
let collected = do_query(b"".as_ref(), query, options) let collected = do_query(b"".as_ref(), &query, options)
.unwrap() .unwrap()
.map(|b| { .map(|b| {
b.unwrap() b.unwrap()
@ -139,7 +139,7 @@ fn silent_service_empty_set_test() {
let triples = b"".as_ref(); let triples = b"".as_ref();
let options = QueryOptions::default().with_service_handler(ServiceTest); let options = QueryOptions::default().with_service_handler(ServiceTest);
assert_eq!(do_query(triples, query, options).unwrap().count(), 1); assert_eq!(do_query(triples, &query, options).unwrap().count(), 1);
} }
#[test] #[test]
@ -172,7 +172,7 @@ fn non_silent_service_test() {
let triples = b"".as_ref(); let triples = b"".as_ref();
let options = QueryOptions::default().with_service_handler(ServiceTest); let options = QueryOptions::default().with_service_handler(ServiceTest);
let mut solutions = do_query(triples, query, options).unwrap(); let mut solutions = do_query(triples, &query, options).unwrap();
if let Some(Err(_)) = solutions.next() { if let Some(Err(_)) = solutions.next() {
} else { } else {
panic!("This should have been an error since the service fails") panic!("This should have been an error since the service fails")
@ -204,12 +204,12 @@ fn make_store(reader: impl BufRead) -> Result<MemoryStore> {
Ok(store) Ok(store)
} }
fn query_store<'a>( fn query_store(
store: MemoryStore, store: MemoryStore,
query: String, query: &str,
options: QueryOptions<'a>, options: QueryOptions,
) -> Result<QuerySolutionsIterator<'a>> { ) -> Result<QuerySolutionsIterator<'_>> {
match store.prepare_query(&query, options)?.exec()? { match store.prepare_query(query, options)?.exec()? {
QueryResult::Solutions(iterator) => { QueryResult::Solutions(iterator) => {
let (variables, iter) = iterator.destruct(); let (variables, iter) = iterator.destruct();
let collected = iter.collect::<Vec<_>>(); let collected = iter.collect::<Vec<_>>();
@ -225,7 +225,7 @@ fn query_store<'a>(
fn pattern_store<'a>( fn pattern_store<'a>(
store: MemoryStore, store: MemoryStore,
pattern: &'a GraphPattern, pattern: &'a GraphPattern,
options: QueryOptions<'a>, options: QueryOptions,
) -> Result<QuerySolutionsIterator<'a>> { ) -> Result<QuerySolutionsIterator<'a>> {
match store match store
.prepare_query_from_pattern(&pattern, options)? .prepare_query_from_pattern(&pattern, options)?
@ -243,11 +243,11 @@ fn pattern_store<'a>(
} }
} }
fn do_query<'a>( fn do_query(
reader: impl BufRead, reader: impl BufRead,
query: String, query: &str,
options: QueryOptions<'a>, options: QueryOptions,
) -> Result<QuerySolutionsIterator<'a>> { ) -> Result<QuerySolutionsIterator<'_>> {
let store = make_store(reader)?; let store = make_store(reader)?;
query_store(store, query, options) query_store(store, query, options)
} }
@ -255,7 +255,7 @@ fn do_query<'a>(
fn do_pattern<'a>( fn do_pattern<'a>(
reader: impl BufRead, reader: impl BufRead,
pattern: &'a GraphPattern, pattern: &'a GraphPattern,
options: QueryOptions<'a>, options: QueryOptions,
) -> Result<QuerySolutionsIterator<'a>> { ) -> Result<QuerySolutionsIterator<'a>> {
let store = make_store(reader)?; let store = make_store(reader)?;
pattern_store(store, pattern, options) pattern_store(store, pattern, options)

@ -83,9 +83,11 @@ fn evaluate_sparql_test(test: &Test) -> Result<()> {
.as_deref() .as_deref()
.ok_or_else(|| Error::msg(format!("No action found for test {}", test)))?; .ok_or_else(|| Error::msg(format!("No action found for test {}", test)))?;
let options = QueryOptions::default() let options = QueryOptions::default()
.with_base_iri(query_file)
.with_service_handler(StaticServiceHandler::new(&test.service_data)?); .with_service_handler(StaticServiceHandler::new(&test.service_data)?);
match store.prepare_query(&read_file_to_string(query_file)?, options) { match store.prepare_query(
Query::parse(&read_file_to_string(query_file)?, Some(query_file))?,
options,
) {
Err(error) => Err(Error::msg(format!( Err(error) => Err(Error::msg(format!(
"Failure to parse query of {} with error: {}", "Failure to parse query of {} with error: {}",
test, error test, error

Loading…
Cancel
Save