From 0d4743f4526ba8efdda26b10da7ccadfb50468d2 Mon Sep 17 00:00:00 2001 From: Tpt Date: Wed, 29 Jul 2020 16:34:35 +0200 Subject: [PATCH] Uses io::Error for all basic disk store operations --- lib/src/error.rs | 40 ++++++-- lib/src/lib.rs | 7 +- lib/src/sparql/eval.rs | 7 +- lib/src/sparql/mod.rs | 2 +- lib/src/sparql/model.rs | 18 ++-- lib/src/sparql/parser.rs | 3 +- lib/src/sparql/plan.rs | 56 ++++++----- lib/src/sparql/plan_builder.rs | 4 +- lib/src/store/memory.rs | 72 +++++++------- lib/src/store/mod.rs | 66 ++++++++----- lib/src/store/numeric_encoder.rs | 104 ++++++++++++-------- lib/src/store/rocksdb.rs | 158 +++++++++++++++++-------------- lib/src/store/sled.rs | 137 ++++++++++++++------------- python/src/sled_store.rs | 22 ++--- wikibase/src/loader.rs | 2 +- 15 files changed, 399 insertions(+), 299 deletions(-) diff --git a/lib/src/error.rs b/lib/src/error.rs index 2b442dd6..102dfa8f 100644 --- a/lib/src/error.rs +++ b/lib/src/error.rs @@ -2,7 +2,6 @@ use crate::model::{BlankNodeIdParseError, IriParseError, LanguageTagParseError}; use crate::sparql::SparqlParseError; use rio_turtle::TurtleError; use rio_xml::RdfXmlError; -use std::convert::Infallible; use std::error; use std::fmt; use std::io; @@ -78,6 +77,12 @@ impl From for Error { } } +impl From for Error { + fn from(error: std::convert::Infallible) -> Self { + match error {} + } +} + impl From for Error { fn from(error: io::Error) -> Self { Self { @@ -142,17 +147,34 @@ impl From for Error { } } -#[cfg(feature = "rocksdb")] -impl From for Error { - fn from(error: rocksdb::Error) -> Self { - Self::wrap(error) +//TODO: convert to "!" when "never_type" is going to be stabilized +#[allow(clippy::empty_enum)] +#[derive(Eq, PartialEq, Debug, Clone, Hash)] +pub(crate) enum Infallible {} + +impl fmt::Display for Infallible { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self {} } } -#[cfg(feature = "sled")] -impl From for Error { - fn from(error: sled::Error) -> Self { - Self::wrap(error) +impl std::error::Error for Infallible {} + +impl From for std::convert::Infallible { + fn from(error: Infallible) -> Self { + match error {} + } +} + +impl From for Infallible { + fn from(error: std::convert::Infallible) -> Self { + match error {} + } +} + +impl From for std::io::Error { + fn from(error: Infallible) -> Self { + match error {} } } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 542448bd..7c04213e 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -15,10 +15,9 @@ //! Usage example with the `MemoryStore`: //! //! ``` +//! use oxigraph::MemoryStore; //! use oxigraph::model::*; -//! use oxigraph::{MemoryStore, Result}; -//! use crate::oxigraph::sparql::QueryOptions; -//! use oxigraph::sparql::QueryResult; +//! use oxigraph::sparql::{QueryOptions, QueryResult}; //! //! let store = MemoryStore::new(); //! @@ -35,7 +34,7 @@ //! if let QueryResult::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? { //! assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into())); //! } -//! # Result::Ok(()) +//! # oxigraph::Result::Ok(()) //! ``` #![deny( future_incompatible, diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index 2a71e4dc..32951c58 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -2396,7 +2396,12 @@ impl Iterator for DescribeIterator { loop { if let Some(quad) = self.quads.next() { return Some(match quad { - Ok(quad) => self.eval.dataset.decode_quad(&quad).map(|q| q.into()), + Ok(quad) => self + .eval + .dataset + .decode_quad(&quad) + .map(|q| q.into()) + .map_err(|e| e.into()), Err(error) => Err(error), }); } diff --git a/lib/src/sparql/mod.rs b/lib/src/sparql/mod.rs index ecd2254d..2ded469b 100644 --- a/lib/src/sparql/mod.rs +++ b/lib/src/sparql/mod.rs @@ -146,8 +146,8 @@ impl SimplePreparedQuery { /// Might be used to implement [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) /// /// ``` -/// use oxigraph::model::*; /// use oxigraph::{MemoryStore, Result}; +/// use oxigraph::model::*; /// use oxigraph::sparql::{QueryOptions, QueryResult, ServiceHandler, Query}; /// /// #[derive(Default)] diff --git a/lib/src/sparql/model.rs b/lib/src/sparql/model.rs index a2d391ba..2738538f 100644 --- a/lib/src/sparql/model.rs +++ b/lib/src/sparql/model.rs @@ -37,8 +37,8 @@ impl QueryResult { /// This method fails if it is called on the `Graph` results /// /// ``` + /// use oxigraph::MemoryStore; /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result}; /// use oxigraph::sparql::{QueryOptions, QueryResultSyntax}; /// /// let store = MemoryStore::new(); @@ -48,7 +48,7 @@ impl QueryResult { /// let mut results = Vec::new(); /// store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())?.write(&mut results, QueryResultSyntax::Json)?; /// assert_eq!(results, "{\"head\":{\"vars\":[\"s\"]},\"results\":{\"bindings\":[{\"s\":{\"type\":\"uri\",\"value\":\"http://example.com\"}}]}}".as_bytes()); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn write(self, writer: &mut impl Write, syntax: QueryResultSyntax) -> Result<()> { match syntax { @@ -62,9 +62,9 @@ impl QueryResult { /// This method fails if it is called on the `Solution` or `Boolean` results /// /// ``` - /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result, GraphSyntax}; + /// use oxigraph::{MemoryStore, GraphSyntax}; /// use oxigraph::sparql::QueryOptions; + /// use oxigraph::model::*; /// use std::io::Cursor; /// /// let graph = " .\n".as_bytes(); @@ -75,7 +75,7 @@ impl QueryResult { /// let mut results = Vec::new(); /// store.query("CONSTRUCT WHERE { ?s ?p ?o }", QueryOptions::default())?.write_graph(&mut results, GraphSyntax::NTriples)?; /// assert_eq!(results, graph); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn write_graph(self, write: &mut impl Write, syntax: GraphSyntax) -> Result<()> { if let QueryResult::Graph(triples) = self { @@ -162,7 +162,7 @@ impl FileSyntax for QueryResultSyntax { /// An iterator over query result solutions /// /// ``` -/// use oxigraph::{MemoryStore, Result}; +/// use oxigraph::MemoryStore; /// use oxigraph::sparql::{QueryResult, QueryOptions}; /// /// let store = MemoryStore::new(); @@ -171,7 +171,7 @@ impl FileSyntax for QueryResultSyntax { /// println!("{:?}", solution?.get("s")); /// } /// } -/// # Result::Ok(()) +/// # oxigraph::Result::Ok(()) /// ``` pub struct QuerySolutionsIterator { variables: Rc>, @@ -189,14 +189,14 @@ impl QuerySolutionsIterator { /// The variables used in the solutions /// /// ``` - /// use oxigraph::{MemoryStore, Result}; + /// use oxigraph::MemoryStore; /// use oxigraph::sparql::{QueryResult, QueryOptions, Variable}; /// /// let store = MemoryStore::new(); /// if let QueryResult::Solutions(solutions) = store.query("SELECT ?s ?o WHERE { ?s ?p ?o }", QueryOptions::default())? { /// assert_eq!(solutions.variables(), &[Variable::new("s"), Variable::new("o")]); /// } - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn variables(&self) -> &[Variable] { &*self.variables diff --git a/lib/src/sparql/parser.rs b/lib/src/sparql/parser.rs index 2d7ea626..cd85c42c 100644 --- a/lib/src/sparql/parser.rs +++ b/lib/src/sparql/parser.rs @@ -19,14 +19,13 @@ use std::{char, fmt}; /// A parsed [SPARQL query](https://www.w3.org/TR/sparql11-query/) /// /// ``` -/// # use oxigraph::Result; /// use oxigraph::sparql::Query; /// /// let query_str = "SELECT ?s ?p ?o WHERE { ?s ?p ?o . }"; /// let query = Query::parse(query_str, None)?; /// /// assert_eq!(query.to_string(), query_str); -/// # Result::Ok(()) +/// # oxigraph::Result::Ok(()) /// ``` #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct Query(pub(crate) QueryVariants); diff --git a/lib/src/sparql/plan.rs b/lib/src/sparql/plan.rs index 530b34dd..261f1b8f 100644 --- a/lib/src/sparql/plan.rs +++ b/lib/src/sparql/plan.rs @@ -9,6 +9,7 @@ use crate::store::ReadableEncodedStore; use crate::Result; use std::cell::{RefCell, RefMut}; use std::collections::BTreeSet; +use std::io; use std::rc::Rc; #[derive(Eq, PartialEq, Debug, Clone, Hash)] @@ -583,32 +584,35 @@ impl DatasetView { ) -> Box>> { if graph_name == None { Box::new( - self.store - .encoded_quads_for_pattern(subject, predicate, object, None) - .filter(|quad| match quad { - Err(_) => true, - Ok(quad) => quad.graph_name != ENCODED_DEFAULT_GRAPH, - }), + map_io_err( + self.store + .encoded_quads_for_pattern(subject, predicate, object, None), + ) + .filter(|quad| match quad { + Err(_) => true, + Ok(quad) => quad.graph_name != ENCODED_DEFAULT_GRAPH, + }), ) } else if graph_name == Some(ENCODED_DEFAULT_GRAPH) && self.default_graph_as_union { Box::new( - self.store - .encoded_quads_for_pattern(subject, predicate, object, None) - .map(|quad| { - let quad = quad?; - Ok(EncodedQuad::new( - quad.subject, - quad.predicate, - quad.object, - ENCODED_DEFAULT_GRAPH, - )) - }), + map_io_err( + self.store + .encoded_quads_for_pattern(subject, predicate, object, None), + ) + .map(|quad| { + let quad = quad?; + Ok(EncodedQuad::new( + quad.subject, + quad.predicate, + quad.object, + ENCODED_DEFAULT_GRAPH, + )) + }), ) } else { - Box::new( - self.store - .encoded_quads_for_pattern(subject, predicate, object, graph_name), - ) + Box::new(map_io_err(self.store.encoded_quads_for_pattern( + subject, predicate, object, graph_name, + ))) } } @@ -620,8 +624,14 @@ impl DatasetView { } } +fn map_io_err<'a, T>( + iter: impl Iterator>> + 'a, +) -> impl Iterator> + 'a { + iter.map(|e| e.map_err(|e| e.into().into())) +} + impl StrLookup for DatasetView { - type Error = S::Error; + type Error = ::Error; fn get_str(&self, id: StrHash) -> std::result::Result, Self::Error> { if let Some(value) = self.extra.borrow().get_str(id).unwrap_infallible() { @@ -638,7 +648,7 @@ struct DatasetViewStrContainer<'a, S: ReadableEncodedStore> { } impl<'a, S: ReadableEncodedStore> StrContainer for DatasetViewStrContainer<'a, S> { - type Error = S::Error; + type Error = ::Error; fn insert_str(&mut self, key: StrHash, value: &str) -> std::result::Result<(), Self::Error> { if self.store.get_str(key)?.is_none() { diff --git a/lib/src/sparql/plan_builder.rs b/lib/src/sparql/plan_builder.rs index c44f7d0d..65f9691b 100644 --- a/lib/src/sparql/plan_builder.rs +++ b/lib/src/sparql/plan_builder.rs @@ -8,7 +8,7 @@ use crate::Result; use std::collections::{BTreeSet, HashSet}; use std::rc::Rc; -pub struct PlanBuilder { +pub(crate) struct PlanBuilder { encoder: E, } @@ -270,7 +270,7 @@ impl PlanBuilder { PropertyPath::NegatedPropertySet(p) => PlanPropertyPath::NegatedPropertySet(Rc::new( p.iter() .map(|p| self.encoder.encode_named_node(p).map_err(|e| e.into())) - .collect::>>()?, + .collect::, _>>()?, )), }) } diff --git a/lib/src/store/memory.rs b/lib/src/store/memory.rs index bab80b9c..0665950f 100644 --- a/lib/src/store/memory.rs +++ b/lib/src/store/memory.rs @@ -1,6 +1,6 @@ //! In-memory store. -use crate::error::UnwrapInfallible; +use crate::error::{Infallible, UnwrapInfallible}; use crate::model::*; use crate::sparql::{Query, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::store::numeric_encoder::*; @@ -10,14 +10,14 @@ use crate::store::{ use crate::{DatasetSyntax, Error, GraphSyntax}; use std::collections::hash_map::DefaultHasher; use std::collections::{HashMap, HashSet}; -use std::convert::{Infallible, TryInto}; -use std::fmt; +use std::convert::TryInto; use std::hash::{BuildHasherDefault, Hash, Hasher}; use std::io::{BufRead, Write}; use std::iter::FromIterator; use std::mem::size_of; use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::vec::IntoIter; +use std::{fmt, io}; /// In-memory store. /// It encodes a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) and allows to query and update it using SPARQL. @@ -25,8 +25,8 @@ use std::vec::IntoIter; /// /// Usage example: /// ``` +/// use oxigraph::MemoryStore; /// use oxigraph::model::*; -/// use oxigraph::{MemoryStore, Result}; /// use oxigraph::sparql::{QueryResult, QueryOptions}; /// /// let store = MemoryStore::new(); @@ -44,7 +44,7 @@ use std::vec::IntoIter; /// if let QueryResult::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? { /// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into())); /// } -/// # Result::Ok(()) +/// # oxigraph::Result::Ok(()) /// ``` #[derive(Clone)] pub struct MemoryStore { @@ -87,9 +87,9 @@ impl MemoryStore { /// /// Usage example: /// ``` + /// use oxigraph::MemoryStore; /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result}; - /// use oxigraph::sparql::{QueryOptions, QueryResult}; + /// use oxigraph::sparql::{QueryResult, QueryOptions}; /// /// let store = MemoryStore::new(); /// @@ -101,7 +101,7 @@ impl MemoryStore { /// if let QueryResult::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? { /// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into())); /// } - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn query( &self, @@ -116,9 +116,9 @@ impl MemoryStore { /// /// Usage example: /// ``` + /// use oxigraph::MemoryStore; /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result}; - /// use oxigraph::sparql::{QueryOptions, QueryResult}; + /// use oxigraph::sparql::{QueryResult, QueryOptions}; /// /// let store = MemoryStore::new(); /// @@ -131,7 +131,7 @@ impl MemoryStore { /// if let QueryResult::Solutions(mut solutions) = prepared_query.exec()? { /// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into())); /// } - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn prepare_query( &self, @@ -149,8 +149,8 @@ impl MemoryStore { /// /// Usage example: /// ``` + /// use oxigraph::MemoryStore; /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result}; /// /// let store = MemoryStore::new(); /// @@ -162,7 +162,7 @@ impl MemoryStore { /// // quad filter /// let results: Vec = store.quads_for_pattern(None, None, None, None).collect(); /// assert_eq!(vec![quad], results); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn quads_for_pattern( &self, @@ -214,8 +214,9 @@ impl MemoryStore { /// /// Usage example: /// ``` + /// use oxigraph::MemoryStore; /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result}; + /// use std::convert::Infallible; /// /// let store = MemoryStore::new(); /// @@ -225,17 +226,17 @@ impl MemoryStore { /// // transaction /// store.transaction(|transaction| { /// transaction.insert(quad.clone()); - /// Ok(()) + /// Ok(()) as Result<(),Infallible> /// })?; /// /// // quad filter /// assert!(store.contains(&quad)); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` - pub fn transaction<'a>( + pub fn transaction<'a, E>( &'a self, - f: impl FnOnce(&mut MemoryTransaction<'a>) -> crate::Result<()>, - ) -> crate::Result<()> { + f: impl FnOnce(&mut MemoryTransaction<'a>) -> Result<(), E>, + ) -> Result<(), E> { let mut transaction = MemoryTransaction { store: self, ops: Vec::new(), @@ -250,8 +251,8 @@ impl MemoryStore { /// /// Usage example: /// ``` + /// use oxigraph::{MemoryStore, GraphSyntax}; /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result, GraphSyntax}; /// /// let store = MemoryStore::new(); /// @@ -263,7 +264,7 @@ impl MemoryStore { /// let results: Vec = store.quads_for_pattern(None, None, None, None).collect(); /// let ex = NamedNode::new("http://example.com")?; /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn load_graph( &self, @@ -280,8 +281,8 @@ impl MemoryStore { /// /// Usage example: /// ``` + /// use oxigraph::{MemoryStore, DatasetSyntax}; /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result, DatasetSyntax}; /// /// let store = MemoryStore::new(); /// @@ -293,7 +294,7 @@ impl MemoryStore { /// let results: Vec = store.quads_for_pattern(None, None, None, None).collect(); /// let ex = NamedNode::new("http://example.com")?; /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), Some(ex.into()))], results); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn load_dataset( &self, @@ -334,8 +335,8 @@ impl MemoryStore { /// /// Usage example: /// ``` + /// use oxigraph::{MemoryStore, GraphSyntax}; /// use oxigraph::model::GraphName; - /// use oxigraph::{MemoryStore, Result, GraphSyntax}; /// /// let file = " .\n".as_bytes(); /// @@ -345,14 +346,14 @@ impl MemoryStore { /// let mut buffer = Vec::new(); /// store.dump_graph(&mut buffer, GraphSyntax::NTriples, &GraphName::DefaultGraph)?; /// assert_eq!(file, buffer.as_slice()); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn dump_graph( &self, writer: &mut impl Write, syntax: GraphSyntax, from_graph_name: &GraphName, - ) -> crate::Result<()> { + ) -> Result<(), io::Error> { dump_graph( self.quads_for_pattern(None, None, None, Some(from_graph_name)) .map(|q| Ok(q.into())), @@ -365,7 +366,7 @@ impl MemoryStore { /// /// Usage example: /// ``` - /// use oxigraph::{MemoryStore, Result, DatasetSyntax}; + /// use oxigraph::{MemoryStore, DatasetSyntax}; /// /// let file = " .\n".as_bytes(); /// @@ -375,13 +376,13 @@ impl MemoryStore { /// let mut buffer = Vec::new(); /// store.dump_dataset(&mut buffer, DatasetSyntax::NQuads)?; /// assert_eq!(file, buffer.as_slice()); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn dump_dataset( &self, writer: &mut impl Write, syntax: DatasetSyntax, - ) -> crate::Result<()> { + ) -> Result<(), io::Error> { dump_dataset( self.quads_for_pattern(None, None, None, None).map(Ok), writer, @@ -718,6 +719,7 @@ impl StrContainer for MemoryStoreIndexes { } impl<'a> ReadableEncodedStore for MemoryStore { + type Error = Infallible; type QuadsIter = EncodedQuadsIter; fn encoded_quads_for_pattern( @@ -961,8 +963,8 @@ impl<'a> MemoryTransaction<'a> { /// /// Usage example: /// ``` + /// use oxigraph::{MemoryStore, GraphSyntax}; /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result, GraphSyntax}; /// /// let store = MemoryStore::new(); /// @@ -976,7 +978,7 @@ impl<'a> MemoryTransaction<'a> { /// let results: Vec = store.quads_for_pattern(None, None, None, None).collect(); /// let ex = NamedNode::new("http://example.com")?; /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn load_graph( &mut self, @@ -992,8 +994,8 @@ impl<'a> MemoryTransaction<'a> { /// /// Usage example: /// ``` + /// use oxigraph::{MemoryStore, DatasetSyntax}; /// use oxigraph::model::*; - /// use oxigraph::{MemoryStore, Result, DatasetSyntax}; /// /// let store = MemoryStore::new(); /// @@ -1005,7 +1007,7 @@ impl<'a> MemoryTransaction<'a> { /// let results: Vec = store.quads_for_pattern(None, None, None, None).collect(); /// let ex = NamedNode::new("http://example.com")?; /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), Some(ex.into()))], results); - /// # Result::Ok(()) + /// # oxigraph::Result::Ok(()) /// ``` pub fn load_dataset( &mut self, @@ -1102,9 +1104,9 @@ pub(crate) struct EncodedQuadsIter { } impl Iterator for EncodedQuadsIter { - type Item = Result; + type Item = Result; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { self.iter.next().map(Ok) } diff --git a/lib/src/store/mod.rs b/lib/src/store/mod.rs index 078c7246..8eef6096 100644 --- a/lib/src/store/mod.rs +++ b/lib/src/store/mod.rs @@ -18,20 +18,24 @@ pub use crate::store::sled::SledStore; use crate::model::*; use crate::store::numeric_encoder::*; -use crate::{DatasetSyntax, Error, GraphSyntax, Result}; +use crate::{DatasetSyntax, GraphSyntax}; use rio_api::formatter::{QuadsFormatter, TriplesFormatter}; use rio_api::parser::{QuadsParser, TriplesParser}; use rio_turtle::{ NQuadsFormatter, NQuadsParser, NTriplesFormatter, NTriplesParser, TriGFormatter, TriGParser, TurtleFormatter, TurtleParser, }; -use rio_xml::{RdfXmlFormatter, RdfXmlParser}; +use rio_xml::{RdfXmlError, RdfXmlFormatter, RdfXmlParser}; use std::collections::HashMap; +use std::error::Error; +use std::io; use std::io::{BufRead, Write}; use std::iter::Iterator; pub(crate) trait ReadableEncodedStore: StrLookup { - type QuadsIter: Iterator> + 'static; + type Error: From<::Error> + Error + Into + 'static; + type QuadsIter: Iterator::Error>> + + 'static; fn encoded_quads_for_pattern( &self, @@ -43,17 +47,17 @@ pub(crate) trait ReadableEncodedStore: StrLookup { } pub(crate) trait WritableEncodedStore: StrContainer { - type Error: From<::Error> + std::error::Error + Into; + type Error: From<::Error> + Error + Into; fn insert_encoded( &mut self, quad: &EncodedQuad, - ) -> std::result::Result<(), ::Error>; + ) -> Result<(), ::Error>; fn remove_encoded( &mut self, quad: &EncodedQuad, - ) -> std::result::Result<(), ::Error>; + ) -> Result<(), ::Error>; } fn load_graph( @@ -62,7 +66,10 @@ fn load_graph( syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, -) -> Result<()> { +) -> Result<(), crate::Error> +where + crate::Error: From<::Error> + From<::Error>, +{ let base_iri = base_iri.unwrap_or(""); match syntax { GraphSyntax::NTriples => { @@ -81,9 +88,11 @@ fn load_from_triple_parser( store: &mut S, mut parser: P, to_graph_name: &GraphName, -) -> Result<()> +) -> Result<(), crate::Error> where - Error: From, + crate::Error: From + + From<::Error> + + From<::Error>, { let mut bnode_map = HashMap::default(); let to_graph_name = store @@ -92,16 +101,17 @@ where parser.parse_all(&mut move |t| { let quad = store .encode_rio_triple_in_graph(t, to_graph_name, &mut bnode_map) - .map_err(|e| e.into())?; - store.insert_encoded(&quad).map_err(|e| e.into()) + .map_err(crate::Error::from)?; + store.insert_encoded(&quad).map_err(crate::Error::from)?; + Ok(()) }) } fn dump_graph( - triples: impl Iterator>, + triples: impl Iterator>, writer: &mut impl Write, syntax: GraphSyntax, -) -> Result<()> { +) -> Result<(), io::Error> { match syntax { GraphSyntax::NTriples => { let mut formatter = NTriplesFormatter::new(writer); @@ -118,22 +128,29 @@ fn dump_graph( formatter.finish()?; } GraphSyntax::RdfXml => { - let mut formatter = RdfXmlFormatter::new(writer)?; + let mut formatter = RdfXmlFormatter::new(writer).map_err(map_xml_err)?; for triple in triples { - formatter.format(&(&triple?).into())?; + formatter.format(&(&triple?).into()).map_err(map_xml_err)?; } - formatter.finish()?; + formatter.finish().map_err(map_xml_err)?; } } Ok(()) } +fn map_xml_err(e: RdfXmlError) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) +} + fn load_dataset( store: &mut S, reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, -) -> Result<()> { +) -> Result<(), crate::Error> +where + crate::Error: From<::Error> + From<::Error>, +{ let base_iri = base_iri.unwrap_or(""); match syntax { DatasetSyntax::NQuads => load_from_quad_parser(store, NQuadsParser::new(reader)?), @@ -144,24 +161,27 @@ fn load_dataset( fn load_from_quad_parser( store: &mut S, mut parser: P, -) -> Result<()> +) -> Result<(), crate::Error> where - Error: From, + crate::Error: From + + From<::Error> + + From<::Error>, { let mut bnode_map = HashMap::default(); parser.parse_all(&mut move |q| { let quad = store .encode_rio_quad(q, &mut bnode_map) - .map_err(|e| e.into())?; - store.insert_encoded(&quad).map_err(|e| e.into()) + .map_err(crate::Error::from)?; + store.insert_encoded(&quad).map_err(crate::Error::from)?; + Ok(()) }) } fn dump_dataset( - quads: impl Iterator>, + quads: impl Iterator>, writer: &mut impl Write, syntax: DatasetSyntax, -) -> Result<()> { +) -> Result<(), io::Error> { match syntax { DatasetSyntax::NQuads => { let mut formatter = NQuadsFormatter::new(writer); diff --git a/lib/src/store/numeric_encoder.rs b/lib/src/store/numeric_encoder.rs index 5323dd9e..baa7534d 100644 --- a/lib/src/store/numeric_encoder.rs +++ b/lib/src/store/numeric_encoder.rs @@ -1,22 +1,21 @@ #![allow(clippy::unreadable_literal)] -use crate::error::UnwrapInfallible; +use crate::error::{Infallible, UnwrapInfallible}; use crate::model::vocab::rdf; use crate::model::vocab::xsd; use crate::model::xsd::*; use crate::model::*; -use crate::{Error as OxError, Result as OxResult}; use rand::random; use rio_api::model as rio; use siphasher::sip128::{Hasher128, SipHasher24}; use std::collections::HashMap; -use std::convert::Infallible; use std::error::Error; use std::hash::Hash; use std::hash::Hasher; -use std::io::{Error as IoError, ErrorKind, Read, Result as IoResult}; +use std::io; +use std::io::Read; use std::mem::size_of; -use std::str; +use std::{fmt, str}; #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone, Hash)] #[repr(transparent)] @@ -609,17 +608,17 @@ impl From<&Quad> for EncodedQuad { } pub trait TermReader { - fn read_term(&mut self) -> IoResult; - fn read_spog_quad(&mut self) -> IoResult; - fn read_posg_quad(&mut self) -> IoResult; - fn read_ospg_quad(&mut self) -> IoResult; - fn read_gspo_quad(&mut self) -> IoResult; - fn read_gpos_quad(&mut self) -> IoResult; - fn read_gosp_quad(&mut self) -> IoResult; + fn read_term(&mut self) -> Result; + fn read_spog_quad(&mut self) -> Result; + fn read_posg_quad(&mut self) -> Result; + fn read_ospg_quad(&mut self) -> Result; + fn read_gspo_quad(&mut self) -> Result; + fn read_gpos_quad(&mut self) -> Result; + fn read_gosp_quad(&mut self) -> Result; } impl TermReader for R { - fn read_term(&mut self) -> IoResult { + fn read_term(&mut self) -> Result { let mut type_buffer = [0]; self.read_exact(&mut type_buffer)?; match type_buffer[0] { @@ -732,14 +731,13 @@ impl TermReader for R { DayTimeDuration::from_be_bytes(buffer), )) } - _ => Err(IoError::new( - ErrorKind::InvalidData, + _ => Err(DecoderError::build( "the term buffer has an invalid type id", )), } } - fn read_spog_quad(&mut self) -> IoResult { + fn read_spog_quad(&mut self) -> Result { let subject = self.read_term()?; let predicate = self.read_term()?; let object = self.read_term()?; @@ -752,7 +750,7 @@ impl TermReader for R { }) } - fn read_posg_quad(&mut self) -> IoResult { + fn read_posg_quad(&mut self) -> Result { let predicate = self.read_term()?; let object = self.read_term()?; let subject = self.read_term()?; @@ -765,7 +763,7 @@ impl TermReader for R { }) } - fn read_ospg_quad(&mut self) -> IoResult { + fn read_ospg_quad(&mut self) -> Result { let object = self.read_term()?; let subject = self.read_term()?; let predicate = self.read_term()?; @@ -778,7 +776,7 @@ impl TermReader for R { }) } - fn read_gspo_quad(&mut self) -> IoResult { + fn read_gspo_quad(&mut self) -> Result { let graph_name = self.read_term()?; let subject = self.read_term()?; let predicate = self.read_term()?; @@ -791,7 +789,7 @@ impl TermReader for R { }) } - fn read_gpos_quad(&mut self) -> IoResult { + fn read_gpos_quad(&mut self) -> Result { let graph_name = self.read_term()?; let predicate = self.read_term()?; let object = self.read_term()?; @@ -804,7 +802,7 @@ impl TermReader for R { }) } - fn read_gosp_quad(&mut self) -> IoResult { + fn read_gosp_quad(&mut self) -> Result { let graph_name = self.read_term()?; let object = self.read_term()?; let subject = self.read_term()?; @@ -858,14 +856,14 @@ pub fn write_term(sink: &mut Vec, term: EncodedTerm) { } } -pub trait StrLookup { - type Error: Error + Into; +pub(crate) trait StrLookup { + type Error: Error + Into; fn get_str(&self, id: StrHash) -> Result, Self::Error>; } -pub trait StrContainer { - type Error: Error + Into; +pub(crate) trait StrContainer { + type Error: Error + Into; fn insert_str(&mut self, key: StrHash, value: &str) -> Result<(), Self::Error>; @@ -924,8 +922,8 @@ impl StrContainer for MemoryStrStore { } } -pub trait Encoder { - type Error: Error + Into; +pub(crate) trait Encoder { + type Error: Error + Into; fn encode_named_node(&mut self, named_node: &NamedNode) -> Result { self.encode_rio_named_node(named_node.into()) @@ -1221,32 +1219,35 @@ pub fn parse_day_time_duration_str(value: &str) -> Option { value.parse().map(EncodedTerm::DayTimeDurationLiteral).ok() } -pub trait Decoder { - fn decode_term(&self, encoded: EncodedTerm) -> OxResult; +pub(crate) trait Decoder { + fn decode_term(&self, encoded: EncodedTerm) -> Result; - fn decode_named_or_blank_node(&self, encoded: EncodedTerm) -> OxResult { + fn decode_named_or_blank_node( + &self, + encoded: EncodedTerm, + ) -> Result { match self.decode_term(encoded)? { Term::NamedNode(named_node) => Ok(named_node.into()), Term::BlankNode(blank_node) => Ok(blank_node.into()), - Term::Literal(_) => Err(OxError::msg( + Term::Literal(_) => Err(DecoderError::build( "A literal has ben found instead of a named node", )), } } - fn decode_named_node(&self, encoded: EncodedTerm) -> OxResult { + fn decode_named_node(&self, encoded: EncodedTerm) -> Result { match self.decode_term(encoded)? { Term::NamedNode(named_node) => Ok(named_node), - Term::BlankNode(_) => Err(OxError::msg( + Term::BlankNode(_) => Err(DecoderError::build( "A blank node has been found instead of a named node", )), - Term::Literal(_) => Err(OxError::msg( + Term::Literal(_) => Err(DecoderError::build( "A literal has ben found instead of a named node", )), } } - fn decode_triple(&self, encoded: &EncodedQuad) -> OxResult { + fn decode_triple(&self, encoded: &EncodedQuad) -> Result { Ok(Triple::new( self.decode_named_or_blank_node(encoded.subject)?, self.decode_named_node(encoded.predicate)?, @@ -1254,7 +1255,7 @@ pub trait Decoder { )) } - fn decode_quad(&self, encoded: &EncodedQuad) -> OxResult { + fn decode_quad(&self, encoded: &EncodedQuad) -> Result { Ok(Quad::new( self.decode_named_or_blank_node(encoded.subject)?, self.decode_named_node(encoded.predicate)?, @@ -1268,11 +1269,11 @@ pub trait Decoder { } impl Decoder for S { - fn decode_term(&self, encoded: EncodedTerm) -> OxResult { + fn decode_term(&self, encoded: EncodedTerm) -> Result { match encoded { - EncodedTerm::DefaultGraph => { - Err(OxError::msg("The default graph tag is not a valid term")) - } + EncodedTerm::DefaultGraph => Err(DecoderError::build( + "The default graph tag is not a valid term", + )), EncodedTerm::NamedNode { iri_id } => { Ok(NamedNode::new_unchecked(get_required_str(self, iri_id)?).into()) } @@ -1314,15 +1315,34 @@ impl Decoder for S { } } -fn get_required_str(lookup: &impl StrLookup, id: StrHash) -> OxResult { +fn get_required_str(lookup: &impl StrLookup, id: StrHash) -> Result { lookup.get_str(id).map_err(|e| e.into())?.ok_or_else(|| { - OxError::msg(format!( + DecoderError::build(format!( "Not able to find the string with id {:?} in the string store", id )) }) } +#[derive(Debug)] +pub struct DecoderError { + msg: String, +} + +impl DecoderError { + pub fn build(msg: impl Into) -> io::Error { + io::Error::new(io::ErrorKind::InvalidData, Self { msg: msg.into() }) + } +} + +impl fmt::Display for DecoderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.msg) + } +} + +impl Error for DecoderError {} + #[test] fn test_encoding() { let mut store = MemoryStrStore::default(); diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index cd4e6de9..7952f86e 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -1,15 +1,16 @@ //! Store based on the [RocksDB](https://rocksdb.org/) key-value database. -use crate::error::UnwrapInfallible; +use crate::error::{Infallible, UnwrapInfallible}; use crate::model::*; use crate::sparql::{Query, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::store::numeric_encoder::*; use crate::store::{ dump_dataset, dump_graph, load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore, }; -use crate::{DatasetSyntax, GraphSyntax, Result}; +use crate::{DatasetSyntax, GraphSyntax}; use rocksdb::*; -use std::convert::{Infallible, TryInto}; +use std::convert::TryInto; +use std::io; use std::io::{BufRead, Cursor, Write}; use std::mem::{take, transmute}; use std::path::Path; @@ -23,8 +24,8 @@ use std::{fmt, str}; /// /// Usage example: /// ``` +/// use oxigraph::RocksDbStore; /// use oxigraph::model::*; -/// use oxigraph::{Result, RocksDbStore}; /// use oxigraph::sparql::{QueryOptions, QueryResult}; /// # use std::fs::remove_dir_all; /// @@ -37,7 +38,7 @@ use std::{fmt, str}; /// store.insert(&quad)?; /// /// // quad filter -/// let results: Result> = store.quads_for_pattern(None, None, None, None).collect(); +/// let results: Result,_> = store.quads_for_pattern(None, None, None, None).collect(); /// assert_eq!(vec![quad], results?); /// /// // SPARQL query @@ -47,7 +48,7 @@ use std::{fmt, str}; /// # /// # }; /// # remove_dir_all("example.db")?; -/// # Result::Ok(()) +/// # oxigraph::Result::Ok(()) /// ``` #[derive(Clone)] pub struct RocksDbStore { @@ -72,14 +73,14 @@ const MAX_TRANSACTION_SIZE: usize = 1024; impl RocksDbStore { /// Opens a `RocksDbStore` - pub fn open(path: impl AsRef) -> Result { + pub fn open(path: impl AsRef) -> Result { let mut options = Options::default(); options.create_if_missing(true); options.create_missing_column_families(true); options.set_compaction_style(DBCompactionStyle::Universal); let new = Self { - db: Arc::new(DB::open_cf(&options, path, &COLUMN_FAMILIES)?), + db: Arc::new(DB::open_cf(&options, path, &COLUMN_FAMILIES).map_err(map_err)?), }; let mut transaction = new.auto_batch_writer(); @@ -96,7 +97,7 @@ impl RocksDbStore { &self, query: impl TryInto>, options: QueryOptions, - ) -> Result { + ) -> Result { self.prepare_query(query, options)?.exec() } @@ -108,7 +109,7 @@ impl RocksDbStore { &self, query: impl TryInto>, options: QueryOptions, - ) -> Result { + ) -> Result { Ok(RocksDbPreparedQuery(SimplePreparedQuery::new( (*self).clone(), query, @@ -125,7 +126,7 @@ impl RocksDbStore { predicate: Option<&NamedNode>, object: Option<&Term>, graph_name: Option<&GraphName>, - ) -> impl Iterator> { + ) -> impl Iterator> { let subject = subject.map(|s| s.into()); let predicate = predicate.map(|p| p.into()); let object = object.map(|o| o.into()); @@ -136,7 +137,7 @@ impl RocksDbStore { } /// Checks if this store contains a given quad - pub fn contains(&self, quad: &Quad) -> Result { + pub fn contains(&self, quad: &Quad) -> Result { let quad = quad.into(); self.contains_encoded(&quad) } @@ -162,10 +163,10 @@ impl RocksDbStore { /// Nothing is done if the closure returns `Err`. /// /// See `MemoryStore` for a usage example. - pub fn transaction<'a>( + pub fn transaction<'a, E: From>( &'a self, - f: impl FnOnce(&mut RocksDbTransaction<'a>) -> Result<()>, - ) -> Result<()> { + f: impl FnOnce(&mut RocksDbTransaction<'a>) -> Result<(), E>, + ) -> Result<(), E> { let mut transaction = RocksDbTransaction { inner: BatchWriter { store: self, @@ -174,7 +175,7 @@ impl RocksDbStore { }, }; f(&mut transaction)?; - transaction.inner.apply() + Ok(transaction.inner.apply()?) } /// Loads a graph file (i.e. triples) into the store @@ -189,10 +190,10 @@ impl RocksDbStore { syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, - ) -> Result<()> { + ) -> Result<(), crate::Error> { let mut transaction = self.auto_batch_writer(); load_graph(&mut transaction, reader, syntax, to_graph_name, base_iri)?; - transaction.apply() + Ok(transaction.apply()?) } /// Loads a dataset file (i.e. quads) into the store. @@ -206,14 +207,14 @@ impl RocksDbStore { reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, - ) -> Result<()> { + ) -> Result<(), crate::Error> { let mut transaction = self.auto_batch_writer(); load_dataset(&mut transaction, reader, syntax, base_iri)?; - transaction.apply() + Ok(transaction.apply()?) } /// Adds a quad to this store. - pub fn insert(&self, quad: &Quad) -> Result<()> { + pub fn insert(&self, quad: &Quad) -> Result<(), io::Error> { let mut transaction = self.auto_batch_writer(); let quad = transaction.encode_quad(quad)?; transaction.insert_encoded(&quad)?; @@ -221,7 +222,7 @@ impl RocksDbStore { } /// Removes a quad from this store. - pub fn remove(&self, quad: &Quad) -> Result<()> { + pub fn remove(&self, quad: &Quad) -> Result<(), io::Error> { let mut transaction = self.auto_batch_writer(); let quad = quad.into(); transaction.remove_encoded(&quad)?; @@ -236,7 +237,7 @@ impl RocksDbStore { writer: &mut impl Write, syntax: GraphSyntax, from_graph_name: &GraphName, - ) -> Result<()> { + ) -> Result<(), io::Error> { dump_graph( self.quads_for_pattern(None, None, None, Some(from_graph_name)) .map(|q| Ok(q?.into())), @@ -248,7 +249,11 @@ impl RocksDbStore { /// Dumps the store dataset into a file. /// /// See `MemoryStore` for a usage example. - pub fn dump_dataset(&self, writer: &mut impl Write, syntax: DatasetSyntax) -> Result<()> { + pub fn dump_dataset( + &self, + writer: &mut impl Write, + syntax: DatasetSyntax, + ) -> Result<(), io::Error> { dump_dataset( self.quads_for_pattern(None, None, None, None), writer, @@ -294,10 +299,14 @@ impl RocksDbStore { } } - fn contains_encoded(&self, quad: &EncodedQuad) -> Result { + fn contains_encoded(&self, quad: &EncodedQuad) -> Result { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE); write_spog_quad(&mut buffer, quad); - Ok(self.db.get_pinned_cf(self.spog_cf(), &buffer)?.is_some()) + Ok(self + .db + .get_pinned_cf(self.spog_cf(), &buffer) + .map_err(map_err)? + .is_some()) } fn quads(&self) -> DecodingIndexIterator { @@ -455,18 +464,20 @@ impl fmt::Display for RocksDbStore { } impl StrLookup for RocksDbStore { - type Error = crate::Error; + type Error = io::Error; - fn get_str(&self, id: StrHash) -> Result> { - Ok(self - .db - .get_cf(self.id2str_cf(), &id.to_be_bytes())? + fn get_str(&self, id: StrHash) -> Result, io::Error> { + self.db + .get_cf(self.id2str_cf(), &id.to_be_bytes()) + .map_err(map_err)? .map(String::from_utf8) - .transpose()?) + .transpose() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) } } impl ReadableEncodedStore for RocksDbStore { + type Error = io::Error; type QuadsIter = DecodingIndexIterator; fn encoded_quads_for_pattern( @@ -538,7 +549,7 @@ pub struct RocksDbPreparedQuery(SimplePreparedQuery); impl RocksDbPreparedQuery { /// Evaluates the query and returns its results - pub fn exec(&self) -> Result { + pub fn exec(&self) -> Result { self.0.exec() } } @@ -562,7 +573,7 @@ impl RocksDbTransaction<'_> { syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, - ) -> Result<()> { + ) -> Result<(), crate::Error> { load_graph(&mut self.inner, reader, syntax, to_graph_name, base_iri) } @@ -578,7 +589,7 @@ impl RocksDbTransaction<'_> { reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, - ) -> Result<()> { + ) -> Result<(), crate::Error> { load_dataset(&mut self.inner, reader, syntax, base_iri) } @@ -604,7 +615,7 @@ struct BatchWriter<'a> { impl StrContainer for BatchWriter<'_> { type Error = Infallible; - fn insert_str(&mut self, key: StrHash, value: &str) -> std::result::Result<(), Infallible> { + fn insert_str(&mut self, key: StrHash, value: &str) -> Result<(), Infallible> { self.batch .put_cf(self.store.id2str_cf(), &key.to_be_bytes(), value); Ok(()) @@ -614,7 +625,7 @@ impl StrContainer for BatchWriter<'_> { impl WritableEncodedStore for BatchWriter<'_> { type Error = Infallible; - fn insert_encoded(&mut self, quad: &EncodedQuad) -> std::result::Result<(), Infallible> { + fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<(), Infallible> { write_spog_quad(&mut self.buffer, quad); self.batch.put_cf(self.store.spog_cf(), &self.buffer, &[]); self.buffer.clear(); @@ -642,7 +653,7 @@ impl WritableEncodedStore for BatchWriter<'_> { Ok(()) } - fn remove_encoded(&mut self, quad: &EncodedQuad) -> std::result::Result<(), Infallible> { + fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<(), Infallible> { write_spog_quad(&mut self.buffer, quad); self.batch.delete_cf(self.store.spog_cf(), &self.buffer); self.buffer.clear(); @@ -672,8 +683,8 @@ impl WritableEncodedStore for BatchWriter<'_> { } impl BatchWriter<'_> { - fn apply(self) -> Result<()> { - Ok(self.store.db.write(self.batch)?) + fn apply(self) -> Result<(), io::Error> { + self.store.db.write(self.batch).map_err(map_err) } } @@ -682,35 +693,39 @@ struct AutoBatchWriter<'a> { } impl StrContainer for AutoBatchWriter<'_> { - type Error = crate::Error; + type Error = io::Error; - fn insert_str(&mut self, key: StrHash, value: &str) -> Result<()> { + fn insert_str(&mut self, key: StrHash, value: &str) -> Result<(), io::Error> { Ok(self.inner.insert_str(key, value)?) } } impl WritableEncodedStore for AutoBatchWriter<'_> { - type Error = crate::Error; + type Error = io::Error; - fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<()> { + fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<(), io::Error> { self.inner.insert_encoded(quad)?; self.apply_if_big() } - fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<()> { + fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<(), io::Error> { self.inner.remove_encoded(quad)?; self.apply_if_big() } } impl AutoBatchWriter<'_> { - fn apply(self) -> Result<()> { + fn apply(self) -> Result<(), io::Error> { self.inner.apply() } - fn apply_if_big(&mut self) -> Result<()> { + fn apply_if_big(&mut self) -> Result<(), io::Error> { if self.inner.batch.len() > MAX_TRANSACTION_SIZE { - self.inner.store.db.write(take(&mut self.inner.batch))?; + self.inner + .store + .db + .write(take(&mut self.inner.batch)) + .map_err(map_err)?; } Ok(()) } @@ -779,12 +794,12 @@ pub(crate) struct DecodingIndexIterator { } impl Iterator for DecodingIndexIterator { - type Item = Result; + type Item = Result; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { if let Some(key) = self.iter.iter.key() { if key.starts_with(&self.prefix) { - let result = self.encoding.decode(key).map_err(crate::Error::from); + let result = self.encoding.decode(key); self.iter.iter.next(); Some(result) } else { @@ -849,23 +864,26 @@ enum QuadEncoding { } impl QuadEncoding { - fn decode(self, buffer: &[u8]) -> Result { + fn decode(self, buffer: &[u8]) -> Result { let mut cursor = Cursor::new(&buffer); - Ok(match self { + match self { QuadEncoding::SPOG => cursor.read_spog_quad(), QuadEncoding::POSG => cursor.read_posg_quad(), QuadEncoding::OSPG => cursor.read_ospg_quad(), QuadEncoding::GSPO => cursor.read_gspo_quad(), QuadEncoding::GPOS => cursor.read_gpos_quad(), QuadEncoding::GOSP => cursor.read_gosp_quad(), - }?) + } } } +fn map_err(e: Error) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) +} + #[test] -fn store() -> Result<()> { +fn store() -> Result<(), crate::Error> { use crate::model::*; - use crate::*; use rand::random; use std::env::temp_dir; use std::fs::remove_dir_all; @@ -895,25 +913,25 @@ fn store() -> Result<()> { assert_eq!( store .quads_for_pattern(None, None, None, None) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(Some(&main_s), None, None, None) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(Some(&main_s), Some(&main_p), None, None) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(Some(&main_s), Some(&main_p), Some(&main_o), None) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( @@ -924,7 +942,7 @@ fn store() -> Result<()> { Some(&main_o), Some(&GraphName::DefaultGraph) ) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( @@ -935,13 +953,13 @@ fn store() -> Result<()> { None, Some(&GraphName::DefaultGraph) ) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(Some(&main_s), None, Some(&main_o), None) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( @@ -952,37 +970,37 @@ fn store() -> Result<()> { Some(&main_o), Some(&GraphName::DefaultGraph) ) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( store .quads_for_pattern(Some(&main_s), None, None, Some(&GraphName::DefaultGraph)) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(None, Some(&main_p), None, None) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(None, Some(&main_p), Some(&main_o), None) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( store .quads_for_pattern(None, None, Some(&main_o), None) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( store .quads_for_pattern(None, None, None, Some(&GraphName::DefaultGraph)) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( @@ -993,7 +1011,7 @@ fn store() -> Result<()> { Some(&main_o), Some(&GraphName::DefaultGraph) ) - .collect::>>()?, + .collect::, _>>()?, target ); } diff --git a/lib/src/store/sled.rs b/lib/src/store/sled.rs index a369c233..dd45a3df 100644 --- a/lib/src/store/sled.rs +++ b/lib/src/store/sled.rs @@ -1,18 +1,18 @@ //! Store based on the [Sled](https://sled.rs/) key-value database. -use crate::error::UnwrapInfallible; +use crate::error::{Infallible, UnwrapInfallible}; use crate::model::*; use crate::sparql::{Query, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::store::numeric_encoder::*; use crate::store::{ dump_dataset, dump_graph, load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore, }; -use crate::{DatasetSyntax, Error, GraphSyntax, Result}; +use crate::{DatasetSyntax, GraphSyntax}; use sled::{Batch, Config, Iter, Tree}; -use std::convert::{Infallible, TryInto}; +use std::convert::TryInto; use std::io::{BufRead, Cursor, Write}; use std::path::Path; -use std::{fmt, str}; +use std::{fmt, io, str}; /// Store based on the [Sled](https://sled.rs/) key-value database. /// It encodes a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) and allows to query and update it using SPARQL. @@ -23,9 +23,9 @@ use std::{fmt, str}; /// /// Usage example: /// ``` -/// use oxigraph::model::*; -/// use oxigraph::{Result, SledStore}; +/// use oxigraph::SledStore; /// use oxigraph::sparql::{QueryOptions, QueryResult}; +/// use oxigraph::model::*; /// # use std::fs::remove_dir_all; /// /// # { @@ -37,7 +37,7 @@ use std::{fmt, str}; /// store.insert(&quad)?; /// /// // quad filter -/// let results: Result> = store.quads_for_pattern(None, None, None, None).collect(); +/// let results: Result,_> = store.quads_for_pattern(None, None, None, None).collect(); /// assert_eq!(vec![quad], results?); /// /// // SPARQL query @@ -47,7 +47,7 @@ use std::{fmt, str}; /// # /// # }; /// # remove_dir_all("example.db")?; -/// # Result::Ok(()) +/// # oxigraph::Result::Ok(()) /// ``` #[derive(Clone)] pub struct SledStore { @@ -66,16 +66,16 @@ const GOSP_PREFIX: u8 = 6; impl SledStore { /// Opens a temporary `SledStore` that will be deleted after drop. - pub fn new() -> Result { + pub fn new() -> Result { Self::do_open(&Config::new().temporary(true)) } /// Opens a `SledStore` - pub fn open(path: impl AsRef) -> Result { + pub fn open(path: impl AsRef) -> Result { Self::do_open(&Config::new().path(path)) } - fn do_open(config: &Config) -> Result { + fn do_open(config: &Config) -> Result { let db = config.open()?; let new = Self { id2str: db.open_tree("id2str")?, @@ -90,9 +90,9 @@ impl SledStore { /// See `MemoryStore` for a usage example. pub fn query( &self, - query: impl TryInto>, + query: impl TryInto>, options: QueryOptions, - ) -> Result { + ) -> Result { self.prepare_query(query, options)?.exec() } @@ -101,9 +101,9 @@ impl SledStore { /// See `MemoryStore` for a usage example. pub fn prepare_query( &self, - query: impl TryInto>, + query: impl TryInto>, options: QueryOptions, - ) -> Result { + ) -> Result { Ok(SledPreparedQuery(SimplePreparedQuery::new( (*self).clone(), query, @@ -120,7 +120,7 @@ impl SledStore { predicate: Option<&NamedNode>, object: Option<&Term>, graph_name: Option<&GraphName>, - ) -> impl Iterator> { + ) -> impl Iterator> { let subject = subject.map(|s| s.into()); let predicate = predicate.map(|p| p.into()); let object = object.map(|o| o.into()); @@ -131,7 +131,7 @@ impl SledStore { } /// Checks if this store contains a given quad - pub fn contains(&self, quad: &Quad) -> Result { + pub fn contains(&self, quad: &Quad) -> Result { let quad = quad.into(); self.contains_encoded(&quad) } @@ -152,15 +152,15 @@ impl SledStore { /// Nothing is done if the closure returns `Err`. /// /// See `MemoryStore` for a usage example. - pub fn transaction<'a>( + pub fn transaction<'a, E: From>( &'a self, - f: impl FnOnce(&mut SledTransaction<'a>) -> Result<()>, - ) -> Result<()> { + f: impl FnOnce(&mut SledTransaction<'a>) -> Result<(), E>, + ) -> Result<(), E> { let mut transaction = SledTransaction { inner: BatchWriter::new(self), }; f(&mut transaction)?; - transaction.inner.apply() + Ok(transaction.inner.apply()?) } /// Loads a graph file (i.e. triples) into the store @@ -175,7 +175,7 @@ impl SledStore { syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, - ) -> Result<()> { + ) -> Result<(), crate::Error> { load_graph( &mut DirectWriter::new(self), reader, @@ -196,19 +196,19 @@ impl SledStore { reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, - ) -> Result<()> { + ) -> Result<(), crate::Error> { load_dataset(&mut DirectWriter::new(self), reader, syntax, base_iri) } /// Adds a quad to this store. - pub fn insert(&self, quad: &Quad) -> Result<()> { + pub fn insert(&self, quad: &Quad) -> Result<(), io::Error> { let mut writer = DirectWriter::new(self); let quad = writer.encode_quad(quad)?; writer.insert_encoded(&quad) } /// Removes a quad from this store. - pub fn remove(&self, quad: &Quad) -> Result<()> { + pub fn remove(&self, quad: &Quad) -> Result<(), io::Error> { let quad = quad.into(); DirectWriter::new(self).remove_encoded(&quad) } @@ -221,7 +221,7 @@ impl SledStore { writer: &mut impl Write, syntax: GraphSyntax, from_graph_name: &GraphName, - ) -> Result<()> { + ) -> Result<(), io::Error> { dump_graph( self.quads_for_pattern(None, None, None, Some(from_graph_name)) .map(|q| Ok(q?.into())), @@ -233,7 +233,11 @@ impl SledStore { /// Dumps the store dataset into a file. /// /// See `MemoryStore` for a usage example. - pub fn dump_dataset(&self, writer: &mut impl Write, syntax: DatasetSyntax) -> Result<()> { + pub fn dump_dataset( + &self, + writer: &mut impl Write, + syntax: DatasetSyntax, + ) -> Result<(), io::Error> { dump_dataset( self.quads_for_pattern(None, None, None, None), writer, @@ -241,7 +245,7 @@ impl SledStore { ) } - fn contains_encoded(&self, quad: &EncodedQuad) -> Result { + fn contains_encoded(&self, quad: &EncodedQuad) -> Result { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE); write_spog_quad(&mut buffer, quad); Ok(self.quads.contains_key(buffer)?) @@ -378,18 +382,19 @@ impl fmt::Display for SledStore { } impl StrLookup for SledStore { - type Error = Error; + type Error = io::Error; - fn get_str(&self, id: StrHash) -> Result> { - Ok(self - .id2str + fn get_str(&self, id: StrHash) -> Result, io::Error> { + self.id2str .get(id.to_be_bytes())? .map(|v| String::from_utf8(v.to_vec())) - .transpose()?) + .transpose() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) } } impl ReadableEncodedStore for SledStore { + type Error = io::Error; type QuadsIter = DecodingQuadIterator; fn encoded_quads_for_pattern( @@ -475,9 +480,9 @@ impl<'a> DirectWriter<'a> { } impl<'a> StrContainer for DirectWriter<'a> { - type Error = Error; + type Error = io::Error; - fn insert_str(&mut self, key: StrHash, value: &str) -> Result<()> { + fn insert_str(&mut self, key: StrHash, value: &str) -> Result<(), io::Error> { self.store .id2str .insert(key.to_be_bytes().as_ref(), value)?; @@ -486,9 +491,9 @@ impl<'a> StrContainer for DirectWriter<'a> { } impl<'a> WritableEncodedStore for DirectWriter<'a> { - type Error = Error; + type Error = io::Error; - fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<()> { + fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<(), io::Error> { write_spog_quad(&mut self.buffer, quad); self.store.quads.insert(self.buffer.as_slice(), &[])?; self.buffer.clear(); @@ -516,7 +521,7 @@ impl<'a> WritableEncodedStore for DirectWriter<'a> { Ok(()) } - fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<()> { + fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<(), io::Error> { write_spog_quad(&mut self.buffer, quad); self.store.quads.remove(self.buffer.as_slice())?; self.buffer.clear(); @@ -564,7 +569,7 @@ impl<'a> BatchWriter<'a> { } impl<'a> BatchWriter<'a> { - fn apply(self) -> Result<()> { + fn apply(self) -> Result<(), io::Error> { self.store.id2str.apply_batch(self.id2str)?; self.store.quads.apply_batch(self.quads)?; Ok(()) @@ -574,7 +579,7 @@ impl<'a> BatchWriter<'a> { impl<'a> StrContainer for BatchWriter<'a> { type Error = Infallible; - fn insert_str(&mut self, key: StrHash, value: &str) -> std::result::Result<(), Infallible> { + fn insert_str(&mut self, key: StrHash, value: &str) -> Result<(), Infallible> { self.id2str.insert(key.to_be_bytes().as_ref(), value); Ok(()) } @@ -583,7 +588,7 @@ impl<'a> StrContainer for BatchWriter<'a> { impl<'a> WritableEncodedStore for BatchWriter<'a> { type Error = Infallible; - fn insert_encoded(&mut self, quad: &EncodedQuad) -> std::result::Result<(), Infallible> { + fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<(), Infallible> { write_spog_quad(&mut self.buffer, quad); self.quads.insert(self.buffer.as_slice(), &[]); self.buffer.clear(); @@ -611,7 +616,7 @@ impl<'a> WritableEncodedStore for BatchWriter<'a> { Ok(()) } - fn remove_encoded(&mut self, quad: &EncodedQuad) -> std::result::Result<(), Infallible> { + fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<(), Infallible> { write_spog_quad(&mut self.buffer, quad); self.quads.remove(self.buffer.as_slice()); self.buffer.clear(); @@ -659,7 +664,7 @@ impl SledTransaction<'_> { syntax: GraphSyntax, to_graph_name: &GraphName, base_iri: Option<&str>, - ) -> Result<()> { + ) -> Result<(), crate::Error> { load_graph(&mut self.inner, reader, syntax, to_graph_name, base_iri) } @@ -675,7 +680,7 @@ impl SledTransaction<'_> { reader: impl BufRead, syntax: DatasetSyntax, base_iri: Option<&str>, - ) -> Result<()> { + ) -> Result<(), crate::Error> { load_dataset(&mut self.inner, reader, syntax, base_iri) } @@ -697,7 +702,7 @@ pub struct SledPreparedQuery(SimplePreparedQuery); impl SledPreparedQuery { /// Evaluates the query and returns its results - pub fn exec(&self) -> Result { + pub fn exec(&self) -> Result { self.0.exec() } } @@ -747,9 +752,9 @@ pub(crate) struct DecodingQuadIterator { } impl Iterator for DecodingQuadIterator { - type Item = Result; + type Item = Result; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { Some(match self.iter.next()? { Ok((encoded, _)) => decode_quad(&encoded), Err(error) => Err(error.into()), @@ -805,7 +810,7 @@ fn write_gosp_quad(sink: &mut Vec, quad: &EncodedQuad) { write_term(sink, quad.predicate); } -fn decode_quad(encoded: &[u8]) -> Result { +fn decode_quad(encoded: &[u8]) -> Result { let mut cursor = Cursor::new(&encoded[1..]); match encoded[0] { SPOG_PREFIX => Ok(cursor.read_spog_quad()?), @@ -814,14 +819,16 @@ fn decode_quad(encoded: &[u8]) -> Result { GSPO_PREFIX => Ok(cursor.read_gspo_quad()?), GPOS_PREFIX => Ok(cursor.read_gpos_quad()?), GOSP_PREFIX => Ok(cursor.read_gosp_quad()?), - _ => Err(Error::msg("Invalid quad type identifier")), + _ => Err(DecoderError::build(format!( + "Invalid quad type identifier: {}", + encoded[0] + ))), } } #[test] -fn store() -> Result<()> { +fn store() -> Result<(), crate::Error> { use crate::model::*; - use crate::*; let main_s = NamedOrBlankNode::from(BlankNode::default()); let main_p = NamedNode::new("http://example.com")?; @@ -844,25 +851,25 @@ fn store() -> Result<()> { assert_eq!( store .quads_for_pattern(None, None, None, None) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(Some(&main_s), None, None, None) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(Some(&main_s), Some(&main_p), None, None) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(Some(&main_s), Some(&main_p), Some(&main_o), None) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( @@ -873,7 +880,7 @@ fn store() -> Result<()> { Some(&main_o), Some(&GraphName::DefaultGraph) ) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( @@ -884,13 +891,13 @@ fn store() -> Result<()> { None, Some(&GraphName::DefaultGraph) ) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(Some(&main_s), None, Some(&main_o), None) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( @@ -901,37 +908,37 @@ fn store() -> Result<()> { Some(&main_o), Some(&GraphName::DefaultGraph) ) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( store .quads_for_pattern(Some(&main_s), None, None, Some(&GraphName::DefaultGraph)) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(None, Some(&main_p), None, None) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( store .quads_for_pattern(None, Some(&main_p), Some(&main_o), None) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( store .quads_for_pattern(None, None, Some(&main_o), None) - .collect::>>()?, + .collect::, _>>()?, target ); assert_eq!( store .quads_for_pattern(None, None, None, Some(&GraphName::DefaultGraph)) - .collect::>>()?, + .collect::, _>>()?, all_o ); assert_eq!( @@ -942,7 +949,7 @@ fn store() -> Result<()> { Some(&main_o), Some(&GraphName::DefaultGraph) ) - .collect::>>()?, + .collect::, _>>()?, target ); diff --git a/python/src/sled_store.rs b/python/src/sled_store.rs index 454349f6..90795f97 100644 --- a/python/src/sled_store.rs +++ b/python/src/sled_store.rs @@ -2,16 +2,14 @@ use crate::model::*; use crate::store_utils::*; use oxigraph::model::*; use oxigraph::sparql::QueryOptions; -use oxigraph::{DatasetSyntax, FileSyntax, GraphSyntax, Result, SledStore}; -use pyo3::create_exception; -use pyo3::exceptions::ValueError; +use oxigraph::{DatasetSyntax, FileSyntax, GraphSyntax, SledStore}; +use pyo3::exceptions::{IOError, ValueError}; use pyo3::prelude::*; use pyo3::types::PyTuple; use pyo3::{PyIterProtocol, PyObjectProtocol, PySequenceProtocol}; +use std::io; use std::io::Cursor; -create_exception!(oxigraph, SledError, pyo3::exceptions::RuntimeError); - #[pyclass(name = SledStore)] #[derive(Clone)] pub struct PySledStore { @@ -24,9 +22,9 @@ impl PySledStore { fn new(path: Option<&str>) -> PyResult { Ok(Self { inner: if let Some(path) = path { - SledStore::open(path).map_err(|e| SledError::py_err(e.to_string()))? + SledStore::open(path).map_err(|e| IOError::py_err(e.to_string()))? } else { - SledStore::new().map_err(|e| SledError::py_err(e.to_string()))? + SledStore::new().map_err(|e| IOError::py_err(e.to_string()))? }, }) } @@ -34,13 +32,13 @@ impl PySledStore { fn add(&self, quad: &PyTuple) -> PyResult<()> { self.inner .insert(&extract_quad(quad)?) - .map_err(|e| SledError::py_err(e.to_string())) + .map_err(|e| IOError::py_err(e.to_string())) } fn remove(&self, quad: &PyTuple) -> PyResult<()> { self.inner .remove(&extract_quad(quad)?) - .map_err(|e| SledError::py_err(e.to_string())) + .map_err(|e| IOError::py_err(e.to_string())) } fn r#match( @@ -136,7 +134,7 @@ impl PySequenceProtocol for PySledStore { fn __contains__(&self, quad: &PyTuple) -> PyResult { self.inner .contains(&extract_quad(quad)?) - .map_err(|e| SledError::py_err(e.to_string())) + .map_err(|e| IOError::py_err(e.to_string())) } } @@ -151,7 +149,7 @@ impl PyIterProtocol for PySledStore { #[pyclass(unsendable)] pub struct QuadIter { - inner: Box>>, + inner: Box>>, } #[pyproto] @@ -168,7 +166,7 @@ impl PyIterProtocol for QuadIter { .map(move |q| { Ok(quad_to_python( slf.py(), - q.map_err(|e| SledError::py_err(e.to_string()))?, + q.map_err(|e| IOError::py_err(e.to_string()))?, )) }) .transpose() diff --git a/wikibase/src/loader.rs b/wikibase/src/loader.rs index a1f211a1..942d5d38 100644 --- a/wikibase/src/loader.rs +++ b/wikibase/src/loader.rs @@ -264,7 +264,7 @@ impl WikibaseLoader { let to_remove = self .store .quads_for_pattern(None, None, None, Some(&graph_name)) - .collect::>>()?; + .collect::, _>>()?; for q in to_remove { transaction.remove(&q); }