diff --git a/lib/src/sparql/mod.rs b/lib/src/sparql/mod.rs index 742c9f77..fa709621 100644 --- a/lib/src/sparql/mod.rs +++ b/lib/src/sparql/mod.rs @@ -18,7 +18,6 @@ use crate::sparql::plan_builder::PlanBuilder; use crate::store::ReadableEncodedStore; use crate::Error; use crate::Result; -use oxiri::Iri; pub use crate::sparql::algebra::GraphPattern; 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::parser::Query; pub use crate::sparql::parser::SparqlParseError; +use std::convert::TryInto; /// A prepared [SPARQL query](https://www.w3.org/TR/sparql11-query/) #[deprecated( @@ -62,9 +62,13 @@ enum SimplePreparedQueryAction { } impl SimplePreparedQuery { - pub(crate) fn new(store: S, query: &str, options: QueryOptions<'_>) -> Result { + pub(crate) fn new( + store: S, + query: impl TryInto>, + options: QueryOptions, + ) -> Result { 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 { algebra, base_iri, .. } => { @@ -117,19 +121,14 @@ impl SimplePreparedQuery { pub(crate) fn new_from_pattern( store: S, pattern: &GraphPattern, - options: QueryOptions<'_>, + options: QueryOptions, ) -> Result { let dataset = DatasetView::new(store, options.default_graph_as_union); 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 { plan, 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 -pub struct QueryOptions<'a> { - pub(crate) base_iri: Option<&'a str>, +/// Options for SPARQL query evaluation +pub struct QueryOptions { pub(crate) default_graph_as_union: bool, pub(crate) service_handler: Box, } -impl<'a> Default for QueryOptions<'a> { +impl Default for QueryOptions { fn default() -> Self { Self { - base_iri: None, default_graph_as_union: false, service_handler: Box::new(EmptyServiceHandler), } } } -impl<'a> QueryOptions<'a> { - /// 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 - } - +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; diff --git a/lib/src/sparql/parser.rs b/lib/src/sparql/parser.rs index dec57ad1..c89f8d42 100644 --- a/lib/src/sparql/parser.rs +++ b/lib/src/sparql/parser.rs @@ -9,6 +9,7 @@ use peg::parser; use peg::str::LineCol; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; +use std::convert::TryFrom; use std::error::Error; use std::str::Chars; 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::from_str(query) + } +} + +impl<'a> TryFrom<&'a String> for Query { + type Error = SparqlParseError; + + fn try_from(query: &String) -> Result { + Self::from_str(query) + } +} + /// Error returned during SPARQL parsing. #[derive(Debug)] pub struct SparqlParseError { diff --git a/lib/src/store/memory.rs b/lib/src/store/memory.rs index 8eab9117..9713c955 100644 --- a/lib/src/store/memory.rs +++ b/lib/src/store/memory.rs @@ -2,13 +2,13 @@ use crate::error::UnwrapInfallible; 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::{load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore}; use crate::{DatasetSyntax, Error, GraphSyntax}; use std::collections::hash_map::DefaultHasher; use std::collections::{HashMap, HashSet}; -use std::convert::Infallible; +use std::convert::{Infallible, TryInto}; use std::fmt; use std::hash::{BuildHasherDefault, Hash, Hasher}; use std::io::BufRead; @@ -105,8 +105,8 @@ impl MemoryStore { /// ``` pub fn prepare_query( &self, - query: &str, - options: QueryOptions<'_>, + query: impl TryInto>, + options: QueryOptions, ) -> crate::Result { Ok(MemoryPreparedQuery(SimplePreparedQuery::new( self.clone(), @@ -119,7 +119,7 @@ impl MemoryStore { pub fn prepare_query_from_pattern( &self, graph_pattern: &GraphPattern, - options: QueryOptions<'_>, + options: QueryOptions, ) -> crate::Result { Ok(MemoryPreparedQuery(SimplePreparedQuery::new_from_pattern( self.clone(), diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index df87ecee..622adcbc 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -2,12 +2,12 @@ use crate::error::UnwrapInfallible; 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::{load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore}; use crate::{DatasetSyntax, GraphSyntax, Result}; use rocksdb::*; -use std::convert::Infallible; +use std::convert::{Infallible, TryInto}; use std::io::{BufRead, Cursor}; use std::mem::{take, transmute}; 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. /// /// See `MemoryStore` for a usage example. - pub fn prepare_query<'a>( - &'a self, - query: &str, - options: QueryOptions<'_>, + pub fn prepare_query( + &self, + query: impl TryInto>, + options: QueryOptions, ) -> Result { Ok(RocksDbPreparedQuery(SimplePreparedQuery::new( (*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. - pub fn prepare_query_from_pattern<'a>( - &'a self, + pub fn prepare_query_from_pattern( + &self, graph_pattern: &GraphPattern, - options: QueryOptions<'_>, + options: QueryOptions, ) -> Result { Ok(RocksDbPreparedQuery(SimplePreparedQuery::new_from_pattern( (*self).clone(), diff --git a/lib/src/store/sled.rs b/lib/src/store/sled.rs index d75a501c..2b3aec0f 100644 --- a/lib/src/store/sled.rs +++ b/lib/src/store/sled.rs @@ -2,12 +2,12 @@ use crate::error::UnwrapInfallible; 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::{load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore}; use crate::{DatasetSyntax, Error, GraphSyntax, Result}; use sled::{Batch, Config, Iter, Tree}; -use std::convert::Infallible; +use std::convert::{Infallible, TryInto}; use std::io::{BufRead, Cursor}; use std::path::Path; 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. /// /// See `MemoryStore` for a usage example. - pub fn prepare_query<'a>( - &'a self, - query: &str, - options: QueryOptions<'_>, + pub fn prepare_query( + &self, + query: impl TryInto>, + options: QueryOptions, ) -> Result { Ok(SledPreparedQuery(SimplePreparedQuery::new( (*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. - pub fn prepare_query_from_pattern<'a>( - &'a self, + pub fn prepare_query_from_pattern( + &self, graph_pattern: &GraphPattern, - options: QueryOptions<'_>, + options: QueryOptions, ) -> Result { Ok(SledPreparedQuery(SimplePreparedQuery::new_from_pattern( (*self).clone(), diff --git a/lib/tests/service_test_cases.rs b/lib/tests/service_test_cases.rs index 2f4542dd..84d7cdfb 100644 --- a/lib/tests/service_test_cases.rs +++ b/lib/tests/service_test_cases.rs @@ -30,7 +30,7 @@ fn simple_service_test() { .to_string(); 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() .map(|b| { b.unwrap() @@ -93,7 +93,7 @@ fn two_service_test() { .to_string(); 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() .map(|b| { b.unwrap() @@ -139,7 +139,7 @@ fn silent_service_empty_set_test() { let triples = b"".as_ref(); 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] @@ -172,7 +172,7 @@ fn non_silent_service_test() { let triples = b"".as_ref(); 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() { } else { panic!("This should have been an error since the service fails") @@ -204,12 +204,12 @@ fn make_store(reader: impl BufRead) -> Result { Ok(store) } -fn query_store<'a>( +fn query_store( store: MemoryStore, - query: String, - options: QueryOptions<'a>, -) -> Result> { - match store.prepare_query(&query, options)?.exec()? { + query: &str, + options: QueryOptions, +) -> Result> { + match store.prepare_query(query, options)?.exec()? { QueryResult::Solutions(iterator) => { let (variables, iter) = iterator.destruct(); let collected = iter.collect::>(); @@ -225,7 +225,7 @@ fn query_store<'a>( fn pattern_store<'a>( store: MemoryStore, pattern: &'a GraphPattern, - options: QueryOptions<'a>, + options: QueryOptions, ) -> Result> { match store .prepare_query_from_pattern(&pattern, options)? @@ -243,11 +243,11 @@ fn pattern_store<'a>( } } -fn do_query<'a>( +fn do_query( reader: impl BufRead, - query: String, - options: QueryOptions<'a>, -) -> Result> { + query: &str, + options: QueryOptions, +) -> Result> { let store = make_store(reader)?; query_store(store, query, options) } @@ -255,7 +255,7 @@ fn do_query<'a>( fn do_pattern<'a>( reader: impl BufRead, pattern: &'a GraphPattern, - options: QueryOptions<'a>, + options: QueryOptions, ) -> Result> { let store = make_store(reader)?; pattern_store(store, pattern, options) diff --git a/testsuite/src/sparql_evaluator.rs b/testsuite/src/sparql_evaluator.rs index 0d05dee9..c7cf81dd 100644 --- a/testsuite/src/sparql_evaluator.rs +++ b/testsuite/src/sparql_evaluator.rs @@ -83,9 +83,11 @@ fn evaluate_sparql_test(test: &Test) -> Result<()> { .as_deref() .ok_or_else(|| Error::msg(format!("No action found for test {}", test)))?; let options = QueryOptions::default() - .with_base_iri(query_file) .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!( "Failure to parse query of {} with error: {}", test, error