Uses io::Error for all basic disk store operations

pull/46/head
Tpt 4 years ago
parent 562cda7d97
commit 0d4743f452
  1. 40
      lib/src/error.rs
  2. 7
      lib/src/lib.rs
  3. 7
      lib/src/sparql/eval.rs
  4. 2
      lib/src/sparql/mod.rs
  5. 18
      lib/src/sparql/model.rs
  6. 3
      lib/src/sparql/parser.rs
  7. 56
      lib/src/sparql/plan.rs
  8. 4
      lib/src/sparql/plan_builder.rs
  9. 72
      lib/src/store/memory.rs
  10. 66
      lib/src/store/mod.rs
  11. 104
      lib/src/store/numeric_encoder.rs
  12. 158
      lib/src/store/rocksdb.rs
  13. 137
      lib/src/store/sled.rs
  14. 22
      python/src/sled_store.rs
  15. 2
      wikibase/src/loader.rs

@ -2,7 +2,6 @@ use crate::model::{BlankNodeIdParseError, IriParseError, LanguageTagParseError};
use crate::sparql::SparqlParseError; use crate::sparql::SparqlParseError;
use rio_turtle::TurtleError; use rio_turtle::TurtleError;
use rio_xml::RdfXmlError; use rio_xml::RdfXmlError;
use std::convert::Infallible;
use std::error; use std::error;
use std::fmt; use std::fmt;
use std::io; use std::io;
@ -78,6 +77,12 @@ impl From<Infallible> for Error {
} }
} }
impl From<std::convert::Infallible> for Error {
fn from(error: std::convert::Infallible) -> Self {
match error {}
}
}
impl From<io::Error> for Error { impl From<io::Error> for Error {
fn from(error: io::Error) -> Self { fn from(error: io::Error) -> Self {
Self { Self {
@ -142,17 +147,34 @@ impl From<SparqlParseError> for Error {
} }
} }
#[cfg(feature = "rocksdb")] //TODO: convert to "!" when "never_type" is going to be stabilized
impl From<rocksdb::Error> for Error { #[allow(clippy::empty_enum)]
fn from(error: rocksdb::Error) -> Self { #[derive(Eq, PartialEq, Debug, Clone, Hash)]
Self::wrap(error) pub(crate) enum Infallible {}
impl fmt::Display for Infallible {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {}
} }
} }
#[cfg(feature = "sled")] impl std::error::Error for Infallible {}
impl From<sled::Error> for Error {
fn from(error: sled::Error) -> Self { impl From<Infallible> for std::convert::Infallible {
Self::wrap(error) fn from(error: Infallible) -> Self {
match error {}
}
}
impl From<std::convert::Infallible> for Infallible {
fn from(error: std::convert::Infallible) -> Self {
match error {}
}
}
impl From<Infallible> for std::io::Error {
fn from(error: Infallible) -> Self {
match error {}
} }
} }

@ -15,10 +15,9 @@
//! Usage example with the `MemoryStore`: //! Usage example with the `MemoryStore`:
//! //!
//! ``` //! ```
//! use oxigraph::MemoryStore;
//! use oxigraph::model::*; //! use oxigraph::model::*;
//! use oxigraph::{MemoryStore, Result}; //! use oxigraph::sparql::{QueryOptions, QueryResult};
//! use crate::oxigraph::sparql::QueryOptions;
//! use oxigraph::sparql::QueryResult;
//! //!
//! let store = MemoryStore::new(); //! let store = MemoryStore::new();
//! //!
@ -35,7 +34,7 @@
//! if let QueryResult::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())? { //! 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())); //! assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
//! } //! }
//! # Result::Ok(()) //! # oxigraph::Result::Ok(())
//! ``` //! ```
#![deny( #![deny(
future_incompatible, future_incompatible,

@ -2396,7 +2396,12 @@ impl<S: ReadableEncodedStore + 'static> Iterator for DescribeIterator<S> {
loop { loop {
if let Some(quad) = self.quads.next() { if let Some(quad) = self.quads.next() {
return Some(match quad { 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), Err(error) => Err(error),
}); });
} }

@ -146,8 +146,8 @@ impl<S: ReadableEncodedStore + 'static> SimplePreparedQuery<S> {
/// Might be used to implement [SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) /// 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::{MemoryStore, Result};
/// use oxigraph::model::*;
/// use oxigraph::sparql::{QueryOptions, QueryResult, ServiceHandler, Query}; /// use oxigraph::sparql::{QueryOptions, QueryResult, ServiceHandler, Query};
/// ///
/// #[derive(Default)] /// #[derive(Default)]

@ -37,8 +37,8 @@ impl QueryResult {
/// This method fails if it is called on the `Graph` results /// This method fails if it is called on the `Graph` results
/// ///
/// ``` /// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result};
/// use oxigraph::sparql::{QueryOptions, QueryResultSyntax}; /// use oxigraph::sparql::{QueryOptions, QueryResultSyntax};
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
@ -48,7 +48,7 @@ impl QueryResult {
/// let mut results = Vec::new(); /// let mut results = Vec::new();
/// store.query("SELECT ?s WHERE { ?s ?p ?o }", QueryOptions::default())?.write(&mut results, QueryResultSyntax::Json)?; /// 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()); /// 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<()> { pub fn write(self, writer: &mut impl Write, syntax: QueryResultSyntax) -> Result<()> {
match syntax { match syntax {
@ -62,9 +62,9 @@ impl QueryResult {
/// This method fails if it is called on the `Solution` or `Boolean` results /// This method fails if it is called on the `Solution` or `Boolean` results
/// ///
/// ``` /// ```
/// use oxigraph::model::*; /// use oxigraph::{MemoryStore, GraphSyntax};
/// use oxigraph::{MemoryStore, Result, GraphSyntax};
/// use oxigraph::sparql::QueryOptions; /// use oxigraph::sparql::QueryOptions;
/// use oxigraph::model::*;
/// use std::io::Cursor; /// use std::io::Cursor;
/// ///
/// let graph = "<http://example.com> <http://example.com> <http://example.com> .\n".as_bytes(); /// let graph = "<http://example.com> <http://example.com> <http://example.com> .\n".as_bytes();
@ -75,7 +75,7 @@ impl QueryResult {
/// let mut results = Vec::new(); /// let mut results = Vec::new();
/// store.query("CONSTRUCT WHERE { ?s ?p ?o }", QueryOptions::default())?.write_graph(&mut results, GraphSyntax::NTriples)?; /// store.query("CONSTRUCT WHERE { ?s ?p ?o }", QueryOptions::default())?.write_graph(&mut results, GraphSyntax::NTriples)?;
/// assert_eq!(results, graph); /// assert_eq!(results, graph);
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn write_graph(self, write: &mut impl Write, syntax: GraphSyntax) -> Result<()> { pub fn write_graph(self, write: &mut impl Write, syntax: GraphSyntax) -> Result<()> {
if let QueryResult::Graph(triples) = self { if let QueryResult::Graph(triples) = self {
@ -162,7 +162,7 @@ impl FileSyntax for QueryResultSyntax {
/// An iterator over query result solutions /// An iterator over query result solutions
/// ///
/// ``` /// ```
/// use oxigraph::{MemoryStore, Result}; /// use oxigraph::MemoryStore;
/// use oxigraph::sparql::{QueryResult, QueryOptions}; /// use oxigraph::sparql::{QueryResult, QueryOptions};
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
@ -171,7 +171,7 @@ impl FileSyntax for QueryResultSyntax {
/// println!("{:?}", solution?.get("s")); /// println!("{:?}", solution?.get("s"));
/// } /// }
/// } /// }
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub struct QuerySolutionsIterator { pub struct QuerySolutionsIterator {
variables: Rc<Vec<Variable>>, variables: Rc<Vec<Variable>>,
@ -189,14 +189,14 @@ impl QuerySolutionsIterator {
/// The variables used in the solutions /// The variables used in the solutions
/// ///
/// ``` /// ```
/// use oxigraph::{MemoryStore, Result}; /// use oxigraph::MemoryStore;
/// use oxigraph::sparql::{QueryResult, QueryOptions, Variable}; /// use oxigraph::sparql::{QueryResult, QueryOptions, Variable};
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
/// if let QueryResult::Solutions(solutions) = store.query("SELECT ?s ?o WHERE { ?s ?p ?o }", QueryOptions::default())? { /// 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")]); /// assert_eq!(solutions.variables(), &[Variable::new("s"), Variable::new("o")]);
/// } /// }
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn variables(&self) -> &[Variable] { pub fn variables(&self) -> &[Variable] {
&*self.variables &*self.variables

@ -19,14 +19,13 @@ use std::{char, fmt};
/// A parsed [SPARQL query](https://www.w3.org/TR/sparql11-query/) /// A parsed [SPARQL query](https://www.w3.org/TR/sparql11-query/)
/// ///
/// ``` /// ```
/// # use oxigraph::Result;
/// use oxigraph::sparql::Query; /// use oxigraph::sparql::Query;
/// ///
/// let query_str = "SELECT ?s ?p ?o WHERE { ?s ?p ?o . }"; /// let query_str = "SELECT ?s ?p ?o WHERE { ?s ?p ?o . }";
/// let query = Query::parse(query_str, None)?; /// let query = Query::parse(query_str, None)?;
/// ///
/// assert_eq!(query.to_string(), query_str); /// assert_eq!(query.to_string(), query_str);
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
#[derive(Eq, PartialEq, Debug, Clone, Hash)] #[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct Query(pub(crate) QueryVariants); pub struct Query(pub(crate) QueryVariants);

@ -9,6 +9,7 @@ use crate::store::ReadableEncodedStore;
use crate::Result; use crate::Result;
use std::cell::{RefCell, RefMut}; use std::cell::{RefCell, RefMut};
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::io;
use std::rc::Rc; use std::rc::Rc;
#[derive(Eq, PartialEq, Debug, Clone, Hash)] #[derive(Eq, PartialEq, Debug, Clone, Hash)]
@ -583,32 +584,35 @@ impl<S: ReadableEncodedStore> DatasetView<S> {
) -> Box<dyn Iterator<Item = Result<EncodedQuad>>> { ) -> Box<dyn Iterator<Item = Result<EncodedQuad>>> {
if graph_name == None { if graph_name == None {
Box::new( Box::new(
self.store map_io_err(
.encoded_quads_for_pattern(subject, predicate, object, None) self.store
.filter(|quad| match quad { .encoded_quads_for_pattern(subject, predicate, object, None),
Err(_) => true, )
Ok(quad) => quad.graph_name != ENCODED_DEFAULT_GRAPH, .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 { } else if graph_name == Some(ENCODED_DEFAULT_GRAPH) && self.default_graph_as_union {
Box::new( Box::new(
self.store map_io_err(
.encoded_quads_for_pattern(subject, predicate, object, None) self.store
.map(|quad| { .encoded_quads_for_pattern(subject, predicate, object, None),
let quad = quad?; )
Ok(EncodedQuad::new( .map(|quad| {
quad.subject, let quad = quad?;
quad.predicate, Ok(EncodedQuad::new(
quad.object, quad.subject,
ENCODED_DEFAULT_GRAPH, quad.predicate,
)) quad.object,
}), ENCODED_DEFAULT_GRAPH,
))
}),
) )
} else { } else {
Box::new( Box::new(map_io_err(self.store.encoded_quads_for_pattern(
self.store subject, predicate, object, graph_name,
.encoded_quads_for_pattern(subject, predicate, object, graph_name), )))
)
} }
} }
@ -620,8 +624,14 @@ impl<S: ReadableEncodedStore> DatasetView<S> {
} }
} }
fn map_io_err<'a, T>(
iter: impl Iterator<Item = std::result::Result<T, impl Into<io::Error>>> + 'a,
) -> impl Iterator<Item = Result<T>> + 'a {
iter.map(|e| e.map_err(|e| e.into().into()))
}
impl<S: ReadableEncodedStore> StrLookup for DatasetView<S> { impl<S: ReadableEncodedStore> StrLookup for DatasetView<S> {
type Error = S::Error; type Error = <S as StrLookup>::Error;
fn get_str(&self, id: StrHash) -> std::result::Result<Option<String>, Self::Error> { fn get_str(&self, id: StrHash) -> std::result::Result<Option<String>, Self::Error> {
if let Some(value) = self.extra.borrow().get_str(id).unwrap_infallible() { 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> { impl<'a, S: ReadableEncodedStore> StrContainer for DatasetViewStrContainer<'a, S> {
type Error = S::Error; type Error = <S as StrLookup>::Error;
fn insert_str(&mut self, key: StrHash, value: &str) -> std::result::Result<(), Self::Error> { fn insert_str(&mut self, key: StrHash, value: &str) -> std::result::Result<(), Self::Error> {
if self.store.get_str(key)?.is_none() { if self.store.get_str(key)?.is_none() {

@ -8,7 +8,7 @@ use crate::Result;
use std::collections::{BTreeSet, HashSet}; use std::collections::{BTreeSet, HashSet};
use std::rc::Rc; use std::rc::Rc;
pub struct PlanBuilder<E: Encoder> { pub(crate) struct PlanBuilder<E: Encoder> {
encoder: E, encoder: E,
} }
@ -270,7 +270,7 @@ impl<E: Encoder> PlanBuilder<E> {
PropertyPath::NegatedPropertySet(p) => PlanPropertyPath::NegatedPropertySet(Rc::new( PropertyPath::NegatedPropertySet(p) => PlanPropertyPath::NegatedPropertySet(Rc::new(
p.iter() p.iter()
.map(|p| self.encoder.encode_named_node(p).map_err(|e| e.into())) .map(|p| self.encoder.encode_named_node(p).map_err(|e| e.into()))
.collect::<Result<Vec<_>>>()?, .collect::<std::result::Result<Vec<_>, _>>()?,
)), )),
}) })
} }

@ -1,6 +1,6 @@
//! In-memory store. //! In-memory store.
use crate::error::UnwrapInfallible; use crate::error::{Infallible, UnwrapInfallible};
use crate::model::*; use crate::model::*;
use crate::sparql::{Query, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::sparql::{Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
@ -10,14 +10,14 @@ use crate::store::{
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, TryInto}; use std::convert::TryInto;
use std::fmt;
use std::hash::{BuildHasherDefault, Hash, Hasher}; use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::io::{BufRead, Write}; use std::io::{BufRead, Write};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::mem::size_of; use std::mem::size_of;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::vec::IntoIter; use std::vec::IntoIter;
use std::{fmt, io};
/// In-memory store. /// 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. /// 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: /// Usage example:
/// ``` /// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result};
/// use oxigraph::sparql::{QueryResult, QueryOptions}; /// use oxigraph::sparql::{QueryResult, QueryOptions};
/// ///
/// let store = MemoryStore::new(); /// 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())? { /// 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())); /// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
/// } /// }
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
#[derive(Clone)] #[derive(Clone)]
pub struct MemoryStore { pub struct MemoryStore {
@ -87,9 +87,9 @@ impl MemoryStore {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result}; /// use oxigraph::sparql::{QueryResult, QueryOptions};
/// use oxigraph::sparql::{QueryOptions, QueryResult};
/// ///
/// let store = MemoryStore::new(); /// 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())? { /// 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())); /// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
/// } /// }
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn query( pub fn query(
&self, &self,
@ -116,9 +116,9 @@ impl MemoryStore {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result}; /// use oxigraph::sparql::{QueryResult, QueryOptions};
/// use oxigraph::sparql::{QueryOptions, QueryResult};
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
/// ///
@ -131,7 +131,7 @@ impl MemoryStore {
/// if let QueryResult::Solutions(mut solutions) = prepared_query.exec()? { /// if let QueryResult::Solutions(mut solutions) = prepared_query.exec()? {
/// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into())); /// assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
/// } /// }
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn prepare_query( pub fn prepare_query(
&self, &self,
@ -149,8 +149,8 @@ impl MemoryStore {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result};
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
/// ///
@ -162,7 +162,7 @@ impl MemoryStore {
/// // quad filter /// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect(); /// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// assert_eq!(vec![quad], results); /// assert_eq!(vec![quad], results);
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn quads_for_pattern( pub fn quads_for_pattern(
&self, &self,
@ -214,8 +214,9 @@ impl MemoryStore {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::MemoryStore;
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result}; /// use std::convert::Infallible;
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
/// ///
@ -225,17 +226,17 @@ impl MemoryStore {
/// // transaction /// // transaction
/// store.transaction(|transaction| { /// store.transaction(|transaction| {
/// transaction.insert(quad.clone()); /// transaction.insert(quad.clone());
/// Ok(()) /// Ok(()) as Result<(),Infallible>
/// })?; /// })?;
/// ///
/// // quad filter /// // quad filter
/// assert!(store.contains(&quad)); /// assert!(store.contains(&quad));
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn transaction<'a>( pub fn transaction<'a, E>(
&'a self, &'a self,
f: impl FnOnce(&mut MemoryTransaction<'a>) -> crate::Result<()>, f: impl FnOnce(&mut MemoryTransaction<'a>) -> Result<(), E>,
) -> crate::Result<()> { ) -> Result<(), E> {
let mut transaction = MemoryTransaction { let mut transaction = MemoryTransaction {
store: self, store: self,
ops: Vec::new(), ops: Vec::new(),
@ -250,8 +251,8 @@ impl MemoryStore {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::{MemoryStore, GraphSyntax};
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result, GraphSyntax};
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
/// ///
@ -263,7 +264,7 @@ impl MemoryStore {
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect(); /// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::new("http://example.com")?; /// let ex = NamedNode::new("http://example.com")?;
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results); /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results);
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn load_graph( pub fn load_graph(
&self, &self,
@ -280,8 +281,8 @@ impl MemoryStore {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::{MemoryStore, DatasetSyntax};
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result, DatasetSyntax};
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
/// ///
@ -293,7 +294,7 @@ impl MemoryStore {
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect(); /// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::new("http://example.com")?; /// let ex = NamedNode::new("http://example.com")?;
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), Some(ex.into()))], results); /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), Some(ex.into()))], results);
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn load_dataset( pub fn load_dataset(
&self, &self,
@ -334,8 +335,8 @@ impl MemoryStore {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::{MemoryStore, GraphSyntax};
/// use oxigraph::model::GraphName; /// use oxigraph::model::GraphName;
/// use oxigraph::{MemoryStore, Result, GraphSyntax};
/// ///
/// let file = "<http://example.com> <http://example.com> <http://example.com> .\n".as_bytes(); /// let file = "<http://example.com> <http://example.com> <http://example.com> .\n".as_bytes();
/// ///
@ -345,14 +346,14 @@ impl MemoryStore {
/// let mut buffer = Vec::new(); /// let mut buffer = Vec::new();
/// store.dump_graph(&mut buffer, GraphSyntax::NTriples, &GraphName::DefaultGraph)?; /// store.dump_graph(&mut buffer, GraphSyntax::NTriples, &GraphName::DefaultGraph)?;
/// assert_eq!(file, buffer.as_slice()); /// assert_eq!(file, buffer.as_slice());
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn dump_graph( pub fn dump_graph(
&self, &self,
writer: &mut impl Write, writer: &mut impl Write,
syntax: GraphSyntax, syntax: GraphSyntax,
from_graph_name: &GraphName, from_graph_name: &GraphName,
) -> crate::Result<()> { ) -> Result<(), io::Error> {
dump_graph( dump_graph(
self.quads_for_pattern(None, None, None, Some(from_graph_name)) self.quads_for_pattern(None, None, None, Some(from_graph_name))
.map(|q| Ok(q.into())), .map(|q| Ok(q.into())),
@ -365,7 +366,7 @@ impl MemoryStore {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::{MemoryStore, Result, DatasetSyntax}; /// use oxigraph::{MemoryStore, DatasetSyntax};
/// ///
/// let file = "<http://example.com> <http://example.com> <http://example.com> <http://example.com> .\n".as_bytes(); /// let file = "<http://example.com> <http://example.com> <http://example.com> <http://example.com> .\n".as_bytes();
/// ///
@ -375,13 +376,13 @@ impl MemoryStore {
/// let mut buffer = Vec::new(); /// let mut buffer = Vec::new();
/// store.dump_dataset(&mut buffer, DatasetSyntax::NQuads)?; /// store.dump_dataset(&mut buffer, DatasetSyntax::NQuads)?;
/// assert_eq!(file, buffer.as_slice()); /// assert_eq!(file, buffer.as_slice());
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn dump_dataset( pub fn dump_dataset(
&self, &self,
writer: &mut impl Write, writer: &mut impl Write,
syntax: DatasetSyntax, syntax: DatasetSyntax,
) -> crate::Result<()> { ) -> Result<(), io::Error> {
dump_dataset( dump_dataset(
self.quads_for_pattern(None, None, None, None).map(Ok), self.quads_for_pattern(None, None, None, None).map(Ok),
writer, writer,
@ -718,6 +719,7 @@ impl StrContainer for MemoryStoreIndexes {
} }
impl<'a> ReadableEncodedStore for MemoryStore { impl<'a> ReadableEncodedStore for MemoryStore {
type Error = Infallible;
type QuadsIter = EncodedQuadsIter; type QuadsIter = EncodedQuadsIter;
fn encoded_quads_for_pattern( fn encoded_quads_for_pattern(
@ -961,8 +963,8 @@ impl<'a> MemoryTransaction<'a> {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::{MemoryStore, GraphSyntax};
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result, GraphSyntax};
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
/// ///
@ -976,7 +978,7 @@ impl<'a> MemoryTransaction<'a> {
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect(); /// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::new("http://example.com")?; /// let ex = NamedNode::new("http://example.com")?;
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results); /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results);
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn load_graph( pub fn load_graph(
&mut self, &mut self,
@ -992,8 +994,8 @@ impl<'a> MemoryTransaction<'a> {
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::{MemoryStore, DatasetSyntax};
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{MemoryStore, Result, DatasetSyntax};
/// ///
/// let store = MemoryStore::new(); /// let store = MemoryStore::new();
/// ///
@ -1005,7 +1007,7 @@ impl<'a> MemoryTransaction<'a> {
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect(); /// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::new("http://example.com")?; /// let ex = NamedNode::new("http://example.com")?;
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), Some(ex.into()))], results); /// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), Some(ex.into()))], results);
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
pub fn load_dataset( pub fn load_dataset(
&mut self, &mut self,
@ -1102,9 +1104,9 @@ pub(crate) struct EncodedQuadsIter {
} }
impl Iterator for EncodedQuadsIter { impl Iterator for EncodedQuadsIter {
type Item = Result<EncodedQuad, Error>; type Item = Result<EncodedQuad, Infallible>;
fn next(&mut self) -> Option<Result<EncodedQuad, Error>> { fn next(&mut self) -> Option<Result<EncodedQuad, Infallible>> {
self.iter.next().map(Ok) self.iter.next().map(Ok)
} }

@ -18,20 +18,24 @@ pub use crate::store::sled::SledStore;
use crate::model::*; use crate::model::*;
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
use crate::{DatasetSyntax, Error, GraphSyntax, Result}; use crate::{DatasetSyntax, GraphSyntax};
use rio_api::formatter::{QuadsFormatter, TriplesFormatter}; use rio_api::formatter::{QuadsFormatter, TriplesFormatter};
use rio_api::parser::{QuadsParser, TriplesParser}; use rio_api::parser::{QuadsParser, TriplesParser};
use rio_turtle::{ use rio_turtle::{
NQuadsFormatter, NQuadsParser, NTriplesFormatter, NTriplesParser, TriGFormatter, TriGParser, NQuadsFormatter, NQuadsParser, NTriplesFormatter, NTriplesParser, TriGFormatter, TriGParser,
TurtleFormatter, TurtleParser, TurtleFormatter, TurtleParser,
}; };
use rio_xml::{RdfXmlFormatter, RdfXmlParser}; use rio_xml::{RdfXmlError, RdfXmlFormatter, RdfXmlParser};
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error;
use std::io;
use std::io::{BufRead, Write}; use std::io::{BufRead, Write};
use std::iter::Iterator; use std::iter::Iterator;
pub(crate) trait ReadableEncodedStore: StrLookup { pub(crate) trait ReadableEncodedStore: StrLookup {
type QuadsIter: Iterator<Item = Result<EncodedQuad>> + 'static; type Error: From<<Self as StrLookup>::Error> + Error + Into<io::Error> + 'static;
type QuadsIter: Iterator<Item = Result<EncodedQuad, <Self as ReadableEncodedStore>::Error>>
+ 'static;
fn encoded_quads_for_pattern( fn encoded_quads_for_pattern(
&self, &self,
@ -43,17 +47,17 @@ pub(crate) trait ReadableEncodedStore: StrLookup {
} }
pub(crate) trait WritableEncodedStore: StrContainer { pub(crate) trait WritableEncodedStore: StrContainer {
type Error: From<<Self as StrContainer>::Error> + std::error::Error + Into<Error>; type Error: From<<Self as StrContainer>::Error> + Error + Into<io::Error>;
fn insert_encoded( fn insert_encoded(
&mut self, &mut self,
quad: &EncodedQuad, quad: &EncodedQuad,
) -> std::result::Result<(), <Self as WritableEncodedStore>::Error>; ) -> Result<(), <Self as WritableEncodedStore>::Error>;
fn remove_encoded( fn remove_encoded(
&mut self, &mut self,
quad: &EncodedQuad, quad: &EncodedQuad,
) -> std::result::Result<(), <Self as WritableEncodedStore>::Error>; ) -> Result<(), <Self as WritableEncodedStore>::Error>;
} }
fn load_graph<S: WritableEncodedStore>( fn load_graph<S: WritableEncodedStore>(
@ -62,7 +66,10 @@ fn load_graph<S: WritableEncodedStore>(
syntax: GraphSyntax, syntax: GraphSyntax,
to_graph_name: &GraphName, to_graph_name: &GraphName,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error>
where
crate::Error: From<<S as WritableEncodedStore>::Error> + From<<S as StrContainer>::Error>,
{
let base_iri = base_iri.unwrap_or(""); let base_iri = base_iri.unwrap_or("");
match syntax { match syntax {
GraphSyntax::NTriples => { GraphSyntax::NTriples => {
@ -81,9 +88,11 @@ fn load_from_triple_parser<S: WritableEncodedStore, P: TriplesParser>(
store: &mut S, store: &mut S,
mut parser: P, mut parser: P,
to_graph_name: &GraphName, to_graph_name: &GraphName,
) -> Result<()> ) -> Result<(), crate::Error>
where where
Error: From<P::Error>, crate::Error: From<P::Error>
+ From<<S as WritableEncodedStore>::Error>
+ From<<S as StrContainer>::Error>,
{ {
let mut bnode_map = HashMap::default(); let mut bnode_map = HashMap::default();
let to_graph_name = store let to_graph_name = store
@ -92,16 +101,17 @@ where
parser.parse_all(&mut move |t| { parser.parse_all(&mut move |t| {
let quad = store let quad = store
.encode_rio_triple_in_graph(t, to_graph_name, &mut bnode_map) .encode_rio_triple_in_graph(t, to_graph_name, &mut bnode_map)
.map_err(|e| e.into())?; .map_err(crate::Error::from)?;
store.insert_encoded(&quad).map_err(|e| e.into()) store.insert_encoded(&quad).map_err(crate::Error::from)?;
Ok(())
}) })
} }
fn dump_graph( fn dump_graph(
triples: impl Iterator<Item = Result<Triple>>, triples: impl Iterator<Item = Result<Triple, io::Error>>,
writer: &mut impl Write, writer: &mut impl Write,
syntax: GraphSyntax, syntax: GraphSyntax,
) -> Result<()> { ) -> Result<(), io::Error> {
match syntax { match syntax {
GraphSyntax::NTriples => { GraphSyntax::NTriples => {
let mut formatter = NTriplesFormatter::new(writer); let mut formatter = NTriplesFormatter::new(writer);
@ -118,22 +128,29 @@ fn dump_graph(
formatter.finish()?; formatter.finish()?;
} }
GraphSyntax::RdfXml => { GraphSyntax::RdfXml => {
let mut formatter = RdfXmlFormatter::new(writer)?; let mut formatter = RdfXmlFormatter::new(writer).map_err(map_xml_err)?;
for triple in triples { 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(()) Ok(())
} }
fn map_xml_err(e: RdfXmlError) -> io::Error {
io::Error::new(io::ErrorKind::Other, e)
}
fn load_dataset<S: WritableEncodedStore>( fn load_dataset<S: WritableEncodedStore>(
store: &mut S, store: &mut S,
reader: impl BufRead, reader: impl BufRead,
syntax: DatasetSyntax, syntax: DatasetSyntax,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error>
where
crate::Error: From<<S as WritableEncodedStore>::Error> + From<<S as StrContainer>::Error>,
{
let base_iri = base_iri.unwrap_or(""); let base_iri = base_iri.unwrap_or("");
match syntax { match syntax {
DatasetSyntax::NQuads => load_from_quad_parser(store, NQuadsParser::new(reader)?), DatasetSyntax::NQuads => load_from_quad_parser(store, NQuadsParser::new(reader)?),
@ -144,24 +161,27 @@ fn load_dataset<S: WritableEncodedStore>(
fn load_from_quad_parser<S: WritableEncodedStore, P: QuadsParser>( fn load_from_quad_parser<S: WritableEncodedStore, P: QuadsParser>(
store: &mut S, store: &mut S,
mut parser: P, mut parser: P,
) -> Result<()> ) -> Result<(), crate::Error>
where where
Error: From<P::Error>, crate::Error: From<P::Error>
+ From<<S as WritableEncodedStore>::Error>
+ From<<S as StrContainer>::Error>,
{ {
let mut bnode_map = HashMap::default(); let mut bnode_map = HashMap::default();
parser.parse_all(&mut move |q| { parser.parse_all(&mut move |q| {
let quad = store let quad = store
.encode_rio_quad(q, &mut bnode_map) .encode_rio_quad(q, &mut bnode_map)
.map_err(|e| e.into())?; .map_err(crate::Error::from)?;
store.insert_encoded(&quad).map_err(|e| e.into()) store.insert_encoded(&quad).map_err(crate::Error::from)?;
Ok(())
}) })
} }
fn dump_dataset( fn dump_dataset(
quads: impl Iterator<Item = Result<Quad>>, quads: impl Iterator<Item = Result<Quad, io::Error>>,
writer: &mut impl Write, writer: &mut impl Write,
syntax: DatasetSyntax, syntax: DatasetSyntax,
) -> Result<()> { ) -> Result<(), io::Error> {
match syntax { match syntax {
DatasetSyntax::NQuads => { DatasetSyntax::NQuads => {
let mut formatter = NQuadsFormatter::new(writer); let mut formatter = NQuadsFormatter::new(writer);

@ -1,22 +1,21 @@
#![allow(clippy::unreadable_literal)] #![allow(clippy::unreadable_literal)]
use crate::error::UnwrapInfallible; use crate::error::{Infallible, UnwrapInfallible};
use crate::model::vocab::rdf; use crate::model::vocab::rdf;
use crate::model::vocab::xsd; use crate::model::vocab::xsd;
use crate::model::xsd::*; use crate::model::xsd::*;
use crate::model::*; use crate::model::*;
use crate::{Error as OxError, Result as OxResult};
use rand::random; use rand::random;
use rio_api::model as rio; use rio_api::model as rio;
use siphasher::sip128::{Hasher128, SipHasher24}; use siphasher::sip128::{Hasher128, SipHasher24};
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::Infallible;
use std::error::Error; use std::error::Error;
use std::hash::Hash; use std::hash::Hash;
use std::hash::Hasher; 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::mem::size_of;
use std::str; use std::{fmt, str};
#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone, Hash)] #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone, Hash)]
#[repr(transparent)] #[repr(transparent)]
@ -609,17 +608,17 @@ impl From<&Quad> for EncodedQuad {
} }
pub trait TermReader { pub trait TermReader {
fn read_term(&mut self) -> IoResult<EncodedTerm>; fn read_term(&mut self) -> Result<EncodedTerm, io::Error>;
fn read_spog_quad(&mut self) -> IoResult<EncodedQuad>; fn read_spog_quad(&mut self) -> Result<EncodedQuad, io::Error>;
fn read_posg_quad(&mut self) -> IoResult<EncodedQuad>; fn read_posg_quad(&mut self) -> Result<EncodedQuad, io::Error>;
fn read_ospg_quad(&mut self) -> IoResult<EncodedQuad>; fn read_ospg_quad(&mut self) -> Result<EncodedQuad, io::Error>;
fn read_gspo_quad(&mut self) -> IoResult<EncodedQuad>; fn read_gspo_quad(&mut self) -> Result<EncodedQuad, io::Error>;
fn read_gpos_quad(&mut self) -> IoResult<EncodedQuad>; fn read_gpos_quad(&mut self) -> Result<EncodedQuad, io::Error>;
fn read_gosp_quad(&mut self) -> IoResult<EncodedQuad>; fn read_gosp_quad(&mut self) -> Result<EncodedQuad, io::Error>;
} }
impl<R: Read> TermReader for R { impl<R: Read> TermReader for R {
fn read_term(&mut self) -> IoResult<EncodedTerm> { fn read_term(&mut self) -> Result<EncodedTerm, io::Error> {
let mut type_buffer = [0]; let mut type_buffer = [0];
self.read_exact(&mut type_buffer)?; self.read_exact(&mut type_buffer)?;
match type_buffer[0] { match type_buffer[0] {
@ -732,14 +731,13 @@ impl<R: Read> TermReader for R {
DayTimeDuration::from_be_bytes(buffer), DayTimeDuration::from_be_bytes(buffer),
)) ))
} }
_ => Err(IoError::new( _ => Err(DecoderError::build(
ErrorKind::InvalidData,
"the term buffer has an invalid type id", "the term buffer has an invalid type id",
)), )),
} }
} }
fn read_spog_quad(&mut self) -> IoResult<EncodedQuad> { fn read_spog_quad(&mut self) -> Result<EncodedQuad, io::Error> {
let subject = self.read_term()?; let subject = self.read_term()?;
let predicate = self.read_term()?; let predicate = self.read_term()?;
let object = self.read_term()?; let object = self.read_term()?;
@ -752,7 +750,7 @@ impl<R: Read> TermReader for R {
}) })
} }
fn read_posg_quad(&mut self) -> IoResult<EncodedQuad> { fn read_posg_quad(&mut self) -> Result<EncodedQuad, io::Error> {
let predicate = self.read_term()?; let predicate = self.read_term()?;
let object = self.read_term()?; let object = self.read_term()?;
let subject = self.read_term()?; let subject = self.read_term()?;
@ -765,7 +763,7 @@ impl<R: Read> TermReader for R {
}) })
} }
fn read_ospg_quad(&mut self) -> IoResult<EncodedQuad> { fn read_ospg_quad(&mut self) -> Result<EncodedQuad, io::Error> {
let object = self.read_term()?; let object = self.read_term()?;
let subject = self.read_term()?; let subject = self.read_term()?;
let predicate = self.read_term()?; let predicate = self.read_term()?;
@ -778,7 +776,7 @@ impl<R: Read> TermReader for R {
}) })
} }
fn read_gspo_quad(&mut self) -> IoResult<EncodedQuad> { fn read_gspo_quad(&mut self) -> Result<EncodedQuad, io::Error> {
let graph_name = self.read_term()?; let graph_name = self.read_term()?;
let subject = self.read_term()?; let subject = self.read_term()?;
let predicate = self.read_term()?; let predicate = self.read_term()?;
@ -791,7 +789,7 @@ impl<R: Read> TermReader for R {
}) })
} }
fn read_gpos_quad(&mut self) -> IoResult<EncodedQuad> { fn read_gpos_quad(&mut self) -> Result<EncodedQuad, io::Error> {
let graph_name = self.read_term()?; let graph_name = self.read_term()?;
let predicate = self.read_term()?; let predicate = self.read_term()?;
let object = self.read_term()?; let object = self.read_term()?;
@ -804,7 +802,7 @@ impl<R: Read> TermReader for R {
}) })
} }
fn read_gosp_quad(&mut self) -> IoResult<EncodedQuad> { fn read_gosp_quad(&mut self) -> Result<EncodedQuad, io::Error> {
let graph_name = self.read_term()?; let graph_name = self.read_term()?;
let object = self.read_term()?; let object = self.read_term()?;
let subject = self.read_term()?; let subject = self.read_term()?;
@ -858,14 +856,14 @@ pub fn write_term(sink: &mut Vec<u8>, term: EncodedTerm) {
} }
} }
pub trait StrLookup { pub(crate) trait StrLookup {
type Error: Error + Into<OxError>; type Error: Error + Into<io::Error>;
fn get_str(&self, id: StrHash) -> Result<Option<String>, Self::Error>; fn get_str(&self, id: StrHash) -> Result<Option<String>, Self::Error>;
} }
pub trait StrContainer { pub(crate) trait StrContainer {
type Error: Error + Into<OxError>; type Error: Error + Into<io::Error>;
fn insert_str(&mut self, key: StrHash, value: &str) -> Result<(), Self::Error>; fn insert_str(&mut self, key: StrHash, value: &str) -> Result<(), Self::Error>;
@ -924,8 +922,8 @@ impl StrContainer for MemoryStrStore {
} }
} }
pub trait Encoder { pub(crate) trait Encoder {
type Error: Error + Into<OxError>; type Error: Error + Into<io::Error>;
fn encode_named_node(&mut self, named_node: &NamedNode) -> Result<EncodedTerm, Self::Error> { fn encode_named_node(&mut self, named_node: &NamedNode) -> Result<EncodedTerm, Self::Error> {
self.encode_rio_named_node(named_node.into()) self.encode_rio_named_node(named_node.into())
@ -1221,32 +1219,35 @@ pub fn parse_day_time_duration_str(value: &str) -> Option<EncodedTerm> {
value.parse().map(EncodedTerm::DayTimeDurationLiteral).ok() value.parse().map(EncodedTerm::DayTimeDurationLiteral).ok()
} }
pub trait Decoder { pub(crate) trait Decoder {
fn decode_term(&self, encoded: EncodedTerm) -> OxResult<Term>; fn decode_term(&self, encoded: EncodedTerm) -> Result<Term, io::Error>;
fn decode_named_or_blank_node(&self, encoded: EncodedTerm) -> OxResult<NamedOrBlankNode> { fn decode_named_or_blank_node(
&self,
encoded: EncodedTerm,
) -> Result<NamedOrBlankNode, io::Error> {
match self.decode_term(encoded)? { match self.decode_term(encoded)? {
Term::NamedNode(named_node) => Ok(named_node.into()), Term::NamedNode(named_node) => Ok(named_node.into()),
Term::BlankNode(blank_node) => Ok(blank_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", "A literal has ben found instead of a named node",
)), )),
} }
} }
fn decode_named_node(&self, encoded: EncodedTerm) -> OxResult<NamedNode> { fn decode_named_node(&self, encoded: EncodedTerm) -> Result<NamedNode, io::Error> {
match self.decode_term(encoded)? { match self.decode_term(encoded)? {
Term::NamedNode(named_node) => Ok(named_node), 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", "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", "A literal has ben found instead of a named node",
)), )),
} }
} }
fn decode_triple(&self, encoded: &EncodedQuad) -> OxResult<Triple> { fn decode_triple(&self, encoded: &EncodedQuad) -> Result<Triple, io::Error> {
Ok(Triple::new( Ok(Triple::new(
self.decode_named_or_blank_node(encoded.subject)?, self.decode_named_or_blank_node(encoded.subject)?,
self.decode_named_node(encoded.predicate)?, self.decode_named_node(encoded.predicate)?,
@ -1254,7 +1255,7 @@ pub trait Decoder {
)) ))
} }
fn decode_quad(&self, encoded: &EncodedQuad) -> OxResult<Quad> { fn decode_quad(&self, encoded: &EncodedQuad) -> Result<Quad, io::Error> {
Ok(Quad::new( Ok(Quad::new(
self.decode_named_or_blank_node(encoded.subject)?, self.decode_named_or_blank_node(encoded.subject)?,
self.decode_named_node(encoded.predicate)?, self.decode_named_node(encoded.predicate)?,
@ -1268,11 +1269,11 @@ pub trait Decoder {
} }
impl<S: StrLookup> Decoder for S { impl<S: StrLookup> Decoder for S {
fn decode_term(&self, encoded: EncodedTerm) -> OxResult<Term> { fn decode_term(&self, encoded: EncodedTerm) -> Result<Term, io::Error> {
match encoded { match encoded {
EncodedTerm::DefaultGraph => { EncodedTerm::DefaultGraph => Err(DecoderError::build(
Err(OxError::msg("The default graph tag is not a valid term")) "The default graph tag is not a valid term",
} )),
EncodedTerm::NamedNode { iri_id } => { EncodedTerm::NamedNode { iri_id } => {
Ok(NamedNode::new_unchecked(get_required_str(self, iri_id)?).into()) Ok(NamedNode::new_unchecked(get_required_str(self, iri_id)?).into())
} }
@ -1314,15 +1315,34 @@ impl<S: StrLookup> Decoder for S {
} }
} }
fn get_required_str(lookup: &impl StrLookup, id: StrHash) -> OxResult<String> { fn get_required_str(lookup: &impl StrLookup, id: StrHash) -> Result<String, io::Error> {
lookup.get_str(id).map_err(|e| e.into())?.ok_or_else(|| { 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", "Not able to find the string with id {:?} in the string store",
id id
)) ))
}) })
} }
#[derive(Debug)]
pub struct DecoderError {
msg: String,
}
impl DecoderError {
pub fn build(msg: impl Into<String>) -> 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] #[test]
fn test_encoding() { fn test_encoding() {
let mut store = MemoryStrStore::default(); let mut store = MemoryStrStore::default();

@ -1,15 +1,16 @@
//! Store based on the [RocksDB](https://rocksdb.org/) key-value database. //! 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::model::*;
use crate::sparql::{Query, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::sparql::{Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
use crate::store::{ use crate::store::{
dump_dataset, dump_graph, load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore, dump_dataset, dump_graph, load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore,
}; };
use crate::{DatasetSyntax, GraphSyntax, Result}; use crate::{DatasetSyntax, GraphSyntax};
use rocksdb::*; use rocksdb::*;
use std::convert::{Infallible, TryInto}; use std::convert::TryInto;
use std::io;
use std::io::{BufRead, Cursor, Write}; use std::io::{BufRead, Cursor, Write};
use std::mem::{take, transmute}; use std::mem::{take, transmute};
use std::path::Path; use std::path::Path;
@ -23,8 +24,8 @@ use std::{fmt, str};
/// ///
/// Usage example: /// Usage example:
/// ``` /// ```
/// use oxigraph::RocksDbStore;
/// use oxigraph::model::*; /// use oxigraph::model::*;
/// use oxigraph::{Result, RocksDbStore};
/// use oxigraph::sparql::{QueryOptions, QueryResult}; /// use oxigraph::sparql::{QueryOptions, QueryResult};
/// # use std::fs::remove_dir_all; /// # use std::fs::remove_dir_all;
/// ///
@ -37,7 +38,7 @@ use std::{fmt, str};
/// store.insert(&quad)?; /// store.insert(&quad)?;
/// ///
/// // quad filter /// // quad filter
/// let results: Result<Vec<Quad>> = store.quads_for_pattern(None, None, None, None).collect(); /// let results: Result<Vec<Quad>,_> = store.quads_for_pattern(None, None, None, None).collect();
/// assert_eq!(vec![quad], results?); /// assert_eq!(vec![quad], results?);
/// ///
/// // SPARQL query /// // SPARQL query
@ -47,7 +48,7 @@ use std::{fmt, str};
/// # /// #
/// # }; /// # };
/// # remove_dir_all("example.db")?; /// # remove_dir_all("example.db")?;
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
#[derive(Clone)] #[derive(Clone)]
pub struct RocksDbStore { pub struct RocksDbStore {
@ -72,14 +73,14 @@ const MAX_TRANSACTION_SIZE: usize = 1024;
impl RocksDbStore { impl RocksDbStore {
/// Opens a `RocksDbStore` /// Opens a `RocksDbStore`
pub fn open(path: impl AsRef<Path>) -> Result<Self> { pub fn open(path: impl AsRef<Path>) -> Result<Self, io::Error> {
let mut options = Options::default(); let mut options = Options::default();
options.create_if_missing(true); options.create_if_missing(true);
options.create_missing_column_families(true); options.create_missing_column_families(true);
options.set_compaction_style(DBCompactionStyle::Universal); options.set_compaction_style(DBCompactionStyle::Universal);
let new = Self { 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(); let mut transaction = new.auto_batch_writer();
@ -96,7 +97,7 @@ impl RocksDbStore {
&self, &self,
query: impl TryInto<Query, Error = impl Into<crate::Error>>, query: impl TryInto<Query, Error = impl Into<crate::Error>>,
options: QueryOptions, options: QueryOptions,
) -> Result<QueryResult> { ) -> Result<QueryResult, crate::Error> {
self.prepare_query(query, options)?.exec() self.prepare_query(query, options)?.exec()
} }
@ -108,7 +109,7 @@ impl RocksDbStore {
&self, &self,
query: impl TryInto<Query, Error = impl Into<crate::Error>>, query: impl TryInto<Query, Error = impl Into<crate::Error>>,
options: QueryOptions, options: QueryOptions,
) -> Result<RocksDbPreparedQuery> { ) -> Result<RocksDbPreparedQuery, crate::Error> {
Ok(RocksDbPreparedQuery(SimplePreparedQuery::new( Ok(RocksDbPreparedQuery(SimplePreparedQuery::new(
(*self).clone(), (*self).clone(),
query, query,
@ -125,7 +126,7 @@ impl RocksDbStore {
predicate: Option<&NamedNode>, predicate: Option<&NamedNode>,
object: Option<&Term>, object: Option<&Term>,
graph_name: Option<&GraphName>, graph_name: Option<&GraphName>,
) -> impl Iterator<Item = Result<Quad>> { ) -> impl Iterator<Item = Result<Quad, io::Error>> {
let subject = subject.map(|s| s.into()); let subject = subject.map(|s| s.into());
let predicate = predicate.map(|p| p.into()); let predicate = predicate.map(|p| p.into());
let object = object.map(|o| o.into()); let object = object.map(|o| o.into());
@ -136,7 +137,7 @@ impl RocksDbStore {
} }
/// Checks if this store contains a given quad /// Checks if this store contains a given quad
pub fn contains(&self, quad: &Quad) -> Result<bool> { pub fn contains(&self, quad: &Quad) -> Result<bool, io::Error> {
let quad = quad.into(); let quad = quad.into();
self.contains_encoded(&quad) self.contains_encoded(&quad)
} }
@ -162,10 +163,10 @@ impl RocksDbStore {
/// Nothing is done if the closure returns `Err`. /// Nothing is done if the closure returns `Err`.
/// ///
/// See `MemoryStore` for a usage example. /// See `MemoryStore` for a usage example.
pub fn transaction<'a>( pub fn transaction<'a, E: From<io::Error>>(
&'a self, &'a self,
f: impl FnOnce(&mut RocksDbTransaction<'a>) -> Result<()>, f: impl FnOnce(&mut RocksDbTransaction<'a>) -> Result<(), E>,
) -> Result<()> { ) -> Result<(), E> {
let mut transaction = RocksDbTransaction { let mut transaction = RocksDbTransaction {
inner: BatchWriter { inner: BatchWriter {
store: self, store: self,
@ -174,7 +175,7 @@ impl RocksDbStore {
}, },
}; };
f(&mut transaction)?; f(&mut transaction)?;
transaction.inner.apply() Ok(transaction.inner.apply()?)
} }
/// Loads a graph file (i.e. triples) into the store /// Loads a graph file (i.e. triples) into the store
@ -189,10 +190,10 @@ impl RocksDbStore {
syntax: GraphSyntax, syntax: GraphSyntax,
to_graph_name: &GraphName, to_graph_name: &GraphName,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error> {
let mut transaction = self.auto_batch_writer(); let mut transaction = self.auto_batch_writer();
load_graph(&mut transaction, reader, syntax, to_graph_name, base_iri)?; 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. /// Loads a dataset file (i.e. quads) into the store.
@ -206,14 +207,14 @@ impl RocksDbStore {
reader: impl BufRead, reader: impl BufRead,
syntax: DatasetSyntax, syntax: DatasetSyntax,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error> {
let mut transaction = self.auto_batch_writer(); let mut transaction = self.auto_batch_writer();
load_dataset(&mut transaction, reader, syntax, base_iri)?; load_dataset(&mut transaction, reader, syntax, base_iri)?;
transaction.apply() Ok(transaction.apply()?)
} }
/// Adds a quad to this store. /// 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 mut transaction = self.auto_batch_writer();
let quad = transaction.encode_quad(quad)?; let quad = transaction.encode_quad(quad)?;
transaction.insert_encoded(&quad)?; transaction.insert_encoded(&quad)?;
@ -221,7 +222,7 @@ impl RocksDbStore {
} }
/// Removes a quad from this store. /// 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 mut transaction = self.auto_batch_writer();
let quad = quad.into(); let quad = quad.into();
transaction.remove_encoded(&quad)?; transaction.remove_encoded(&quad)?;
@ -236,7 +237,7 @@ impl RocksDbStore {
writer: &mut impl Write, writer: &mut impl Write,
syntax: GraphSyntax, syntax: GraphSyntax,
from_graph_name: &GraphName, from_graph_name: &GraphName,
) -> Result<()> { ) -> Result<(), io::Error> {
dump_graph( dump_graph(
self.quads_for_pattern(None, None, None, Some(from_graph_name)) self.quads_for_pattern(None, None, None, Some(from_graph_name))
.map(|q| Ok(q?.into())), .map(|q| Ok(q?.into())),
@ -248,7 +249,11 @@ impl RocksDbStore {
/// Dumps the store dataset into a file. /// Dumps the store dataset into a file.
/// ///
/// See `MemoryStore` for a usage example. /// 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( dump_dataset(
self.quads_for_pattern(None, None, None, None), self.quads_for_pattern(None, None, None, None),
writer, writer,
@ -294,10 +299,14 @@ impl RocksDbStore {
} }
} }
fn contains_encoded(&self, quad: &EncodedQuad) -> Result<bool> { fn contains_encoded(&self, quad: &EncodedQuad) -> Result<bool, io::Error> {
let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE); let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE);
write_spog_quad(&mut buffer, quad); 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 { fn quads(&self) -> DecodingIndexIterator {
@ -455,18 +464,20 @@ impl fmt::Display for RocksDbStore {
} }
impl StrLookup for RocksDbStore { impl StrLookup for RocksDbStore {
type Error = crate::Error; type Error = io::Error;
fn get_str(&self, id: StrHash) -> Result<Option<String>> { fn get_str(&self, id: StrHash) -> Result<Option<String>, io::Error> {
Ok(self self.db
.db .get_cf(self.id2str_cf(), &id.to_be_bytes())
.get_cf(self.id2str_cf(), &id.to_be_bytes())? .map_err(map_err)?
.map(String::from_utf8) .map(String::from_utf8)
.transpose()?) .transpose()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
} }
} }
impl ReadableEncodedStore for RocksDbStore { impl ReadableEncodedStore for RocksDbStore {
type Error = io::Error;
type QuadsIter = DecodingIndexIterator; type QuadsIter = DecodingIndexIterator;
fn encoded_quads_for_pattern( fn encoded_quads_for_pattern(
@ -538,7 +549,7 @@ pub struct RocksDbPreparedQuery(SimplePreparedQuery<RocksDbStore>);
impl RocksDbPreparedQuery { impl RocksDbPreparedQuery {
/// Evaluates the query and returns its results /// Evaluates the query and returns its results
pub fn exec(&self) -> Result<QueryResult> { pub fn exec(&self) -> Result<QueryResult, crate::Error> {
self.0.exec() self.0.exec()
} }
} }
@ -562,7 +573,7 @@ impl RocksDbTransaction<'_> {
syntax: GraphSyntax, syntax: GraphSyntax,
to_graph_name: &GraphName, to_graph_name: &GraphName,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error> {
load_graph(&mut self.inner, reader, syntax, to_graph_name, base_iri) load_graph(&mut self.inner, reader, syntax, to_graph_name, base_iri)
} }
@ -578,7 +589,7 @@ impl RocksDbTransaction<'_> {
reader: impl BufRead, reader: impl BufRead,
syntax: DatasetSyntax, syntax: DatasetSyntax,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error> {
load_dataset(&mut self.inner, reader, syntax, base_iri) load_dataset(&mut self.inner, reader, syntax, base_iri)
} }
@ -604,7 +615,7 @@ struct BatchWriter<'a> {
impl StrContainer for BatchWriter<'_> { impl StrContainer for BatchWriter<'_> {
type Error = Infallible; 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 self.batch
.put_cf(self.store.id2str_cf(), &key.to_be_bytes(), value); .put_cf(self.store.id2str_cf(), &key.to_be_bytes(), value);
Ok(()) Ok(())
@ -614,7 +625,7 @@ impl StrContainer for BatchWriter<'_> {
impl WritableEncodedStore for BatchWriter<'_> { impl WritableEncodedStore for BatchWriter<'_> {
type Error = Infallible; 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); write_spog_quad(&mut self.buffer, quad);
self.batch.put_cf(self.store.spog_cf(), &self.buffer, &[]); self.batch.put_cf(self.store.spog_cf(), &self.buffer, &[]);
self.buffer.clear(); self.buffer.clear();
@ -642,7 +653,7 @@ impl WritableEncodedStore for BatchWriter<'_> {
Ok(()) 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); write_spog_quad(&mut self.buffer, quad);
self.batch.delete_cf(self.store.spog_cf(), &self.buffer); self.batch.delete_cf(self.store.spog_cf(), &self.buffer);
self.buffer.clear(); self.buffer.clear();
@ -672,8 +683,8 @@ impl WritableEncodedStore for BatchWriter<'_> {
} }
impl BatchWriter<'_> { impl BatchWriter<'_> {
fn apply(self) -> Result<()> { fn apply(self) -> Result<(), io::Error> {
Ok(self.store.db.write(self.batch)?) self.store.db.write(self.batch).map_err(map_err)
} }
} }
@ -682,35 +693,39 @@ struct AutoBatchWriter<'a> {
} }
impl StrContainer for AutoBatchWriter<'_> { 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)?) Ok(self.inner.insert_str(key, value)?)
} }
} }
impl WritableEncodedStore for AutoBatchWriter<'_> { 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.inner.insert_encoded(quad)?;
self.apply_if_big() 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.inner.remove_encoded(quad)?;
self.apply_if_big() self.apply_if_big()
} }
} }
impl AutoBatchWriter<'_> { impl AutoBatchWriter<'_> {
fn apply(self) -> Result<()> { fn apply(self) -> Result<(), io::Error> {
self.inner.apply() 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 { 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(()) Ok(())
} }
@ -779,12 +794,12 @@ pub(crate) struct DecodingIndexIterator {
} }
impl Iterator for DecodingIndexIterator { impl Iterator for DecodingIndexIterator {
type Item = Result<EncodedQuad>; type Item = Result<EncodedQuad, io::Error>;
fn next(&mut self) -> Option<Result<EncodedQuad>> { fn next(&mut self) -> Option<Result<EncodedQuad, io::Error>> {
if let Some(key) = self.iter.iter.key() { if let Some(key) = self.iter.iter.key() {
if key.starts_with(&self.prefix) { 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(); self.iter.iter.next();
Some(result) Some(result)
} else { } else {
@ -849,23 +864,26 @@ enum QuadEncoding {
} }
impl QuadEncoding { impl QuadEncoding {
fn decode(self, buffer: &[u8]) -> Result<EncodedQuad> { fn decode(self, buffer: &[u8]) -> Result<EncodedQuad, io::Error> {
let mut cursor = Cursor::new(&buffer); let mut cursor = Cursor::new(&buffer);
Ok(match self { match self {
QuadEncoding::SPOG => cursor.read_spog_quad(), QuadEncoding::SPOG => cursor.read_spog_quad(),
QuadEncoding::POSG => cursor.read_posg_quad(), QuadEncoding::POSG => cursor.read_posg_quad(),
QuadEncoding::OSPG => cursor.read_ospg_quad(), QuadEncoding::OSPG => cursor.read_ospg_quad(),
QuadEncoding::GSPO => cursor.read_gspo_quad(), QuadEncoding::GSPO => cursor.read_gspo_quad(),
QuadEncoding::GPOS => cursor.read_gpos_quad(), QuadEncoding::GPOS => cursor.read_gpos_quad(),
QuadEncoding::GOSP => cursor.read_gosp_quad(), QuadEncoding::GOSP => cursor.read_gosp_quad(),
}?) }
} }
} }
fn map_err(e: Error) -> io::Error {
io::Error::new(io::ErrorKind::Other, e)
}
#[test] #[test]
fn store() -> Result<()> { fn store() -> Result<(), crate::Error> {
use crate::model::*; use crate::model::*;
use crate::*;
use rand::random; use rand::random;
use std::env::temp_dir; use std::env::temp_dir;
use std::fs::remove_dir_all; use std::fs::remove_dir_all;
@ -895,25 +913,25 @@ fn store() -> Result<()> {
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, None, None, None) .quads_for_pattern(None, None, None, None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), None, None, None) .quads_for_pattern(Some(&main_s), None, None, None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), Some(&main_p), None, None) .quads_for_pattern(Some(&main_s), Some(&main_p), None, None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), Some(&main_p), Some(&main_o), None) .quads_for_pattern(Some(&main_s), Some(&main_p), Some(&main_o), None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
@ -924,7 +942,7 @@ fn store() -> Result<()> {
Some(&main_o), Some(&main_o),
Some(&GraphName::DefaultGraph) Some(&GraphName::DefaultGraph)
) )
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
@ -935,13 +953,13 @@ fn store() -> Result<()> {
None, None,
Some(&GraphName::DefaultGraph) Some(&GraphName::DefaultGraph)
) )
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), None, Some(&main_o), None) .quads_for_pattern(Some(&main_s), None, Some(&main_o), None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
@ -952,37 +970,37 @@ fn store() -> Result<()> {
Some(&main_o), Some(&main_o),
Some(&GraphName::DefaultGraph) Some(&GraphName::DefaultGraph)
) )
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), None, None, Some(&GraphName::DefaultGraph)) .quads_for_pattern(Some(&main_s), None, None, Some(&GraphName::DefaultGraph))
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, Some(&main_p), None, None) .quads_for_pattern(None, Some(&main_p), None, None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, Some(&main_p), Some(&main_o), None) .quads_for_pattern(None, Some(&main_p), Some(&main_o), None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, None, Some(&main_o), None) .quads_for_pattern(None, None, Some(&main_o), None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, None, None, Some(&GraphName::DefaultGraph)) .quads_for_pattern(None, None, None, Some(&GraphName::DefaultGraph))
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
@ -993,7 +1011,7 @@ fn store() -> Result<()> {
Some(&main_o), Some(&main_o),
Some(&GraphName::DefaultGraph) Some(&GraphName::DefaultGraph)
) )
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
} }

@ -1,18 +1,18 @@
//! Store based on the [Sled](https://sled.rs/) key-value database. //! 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::model::*;
use crate::sparql::{Query, QueryOptions, QueryResult, SimplePreparedQuery}; use crate::sparql::{Query, QueryOptions, QueryResult, SimplePreparedQuery};
use crate::store::numeric_encoder::*; use crate::store::numeric_encoder::*;
use crate::store::{ use crate::store::{
dump_dataset, dump_graph, load_dataset, load_graph, ReadableEncodedStore, WritableEncodedStore, 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 sled::{Batch, Config, Iter, Tree};
use std::convert::{Infallible, TryInto}; use std::convert::TryInto;
use std::io::{BufRead, Cursor, Write}; use std::io::{BufRead, Cursor, Write};
use std::path::Path; use std::path::Path;
use std::{fmt, str}; use std::{fmt, io, str};
/// Store based on the [Sled](https://sled.rs/) key-value database. /// 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. /// 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: /// Usage example:
/// ``` /// ```
/// use oxigraph::model::*; /// use oxigraph::SledStore;
/// use oxigraph::{Result, SledStore};
/// use oxigraph::sparql::{QueryOptions, QueryResult}; /// use oxigraph::sparql::{QueryOptions, QueryResult};
/// use oxigraph::model::*;
/// # use std::fs::remove_dir_all; /// # use std::fs::remove_dir_all;
/// ///
/// # { /// # {
@ -37,7 +37,7 @@ use std::{fmt, str};
/// store.insert(&quad)?; /// store.insert(&quad)?;
/// ///
/// // quad filter /// // quad filter
/// let results: Result<Vec<Quad>> = store.quads_for_pattern(None, None, None, None).collect(); /// let results: Result<Vec<Quad>,_> = store.quads_for_pattern(None, None, None, None).collect();
/// assert_eq!(vec![quad], results?); /// assert_eq!(vec![quad], results?);
/// ///
/// // SPARQL query /// // SPARQL query
@ -47,7 +47,7 @@ use std::{fmt, str};
/// # /// #
/// # }; /// # };
/// # remove_dir_all("example.db")?; /// # remove_dir_all("example.db")?;
/// # Result::Ok(()) /// # oxigraph::Result::Ok(())
/// ``` /// ```
#[derive(Clone)] #[derive(Clone)]
pub struct SledStore { pub struct SledStore {
@ -66,16 +66,16 @@ const GOSP_PREFIX: u8 = 6;
impl SledStore { impl SledStore {
/// Opens a temporary `SledStore` that will be deleted after drop. /// Opens a temporary `SledStore` that will be deleted after drop.
pub fn new() -> Result<Self> { pub fn new() -> Result<Self, io::Error> {
Self::do_open(&Config::new().temporary(true)) Self::do_open(&Config::new().temporary(true))
} }
/// Opens a `SledStore` /// Opens a `SledStore`
pub fn open(path: impl AsRef<Path>) -> Result<Self> { pub fn open(path: impl AsRef<Path>) -> Result<Self, io::Error> {
Self::do_open(&Config::new().path(path)) Self::do_open(&Config::new().path(path))
} }
fn do_open(config: &Config) -> Result<Self> { fn do_open(config: &Config) -> Result<Self, io::Error> {
let db = config.open()?; let db = config.open()?;
let new = Self { let new = Self {
id2str: db.open_tree("id2str")?, id2str: db.open_tree("id2str")?,
@ -90,9 +90,9 @@ impl SledStore {
/// See `MemoryStore` for a usage example. /// See `MemoryStore` for a usage example.
pub fn query( pub fn query(
&self, &self,
query: impl TryInto<Query, Error = impl Into<Error>>, query: impl TryInto<Query, Error = impl Into<crate::Error>>,
options: QueryOptions, options: QueryOptions,
) -> Result<QueryResult> { ) -> Result<QueryResult, crate::Error> {
self.prepare_query(query, options)?.exec() self.prepare_query(query, options)?.exec()
} }
@ -101,9 +101,9 @@ impl SledStore {
/// See `MemoryStore` for a usage example. /// See `MemoryStore` for a usage example.
pub fn prepare_query( pub fn prepare_query(
&self, &self,
query: impl TryInto<Query, Error = impl Into<Error>>, query: impl TryInto<Query, Error = impl Into<crate::Error>>,
options: QueryOptions, options: QueryOptions,
) -> Result<SledPreparedQuery> { ) -> Result<SledPreparedQuery, crate::Error> {
Ok(SledPreparedQuery(SimplePreparedQuery::new( Ok(SledPreparedQuery(SimplePreparedQuery::new(
(*self).clone(), (*self).clone(),
query, query,
@ -120,7 +120,7 @@ impl SledStore {
predicate: Option<&NamedNode>, predicate: Option<&NamedNode>,
object: Option<&Term>, object: Option<&Term>,
graph_name: Option<&GraphName>, graph_name: Option<&GraphName>,
) -> impl Iterator<Item = Result<Quad>> { ) -> impl Iterator<Item = Result<Quad, io::Error>> {
let subject = subject.map(|s| s.into()); let subject = subject.map(|s| s.into());
let predicate = predicate.map(|p| p.into()); let predicate = predicate.map(|p| p.into());
let object = object.map(|o| o.into()); let object = object.map(|o| o.into());
@ -131,7 +131,7 @@ impl SledStore {
} }
/// Checks if this store contains a given quad /// Checks if this store contains a given quad
pub fn contains(&self, quad: &Quad) -> Result<bool> { pub fn contains(&self, quad: &Quad) -> Result<bool, io::Error> {
let quad = quad.into(); let quad = quad.into();
self.contains_encoded(&quad) self.contains_encoded(&quad)
} }
@ -152,15 +152,15 @@ impl SledStore {
/// Nothing is done if the closure returns `Err`. /// Nothing is done if the closure returns `Err`.
/// ///
/// See `MemoryStore` for a usage example. /// See `MemoryStore` for a usage example.
pub fn transaction<'a>( pub fn transaction<'a, E: From<io::Error>>(
&'a self, &'a self,
f: impl FnOnce(&mut SledTransaction<'a>) -> Result<()>, f: impl FnOnce(&mut SledTransaction<'a>) -> Result<(), E>,
) -> Result<()> { ) -> Result<(), E> {
let mut transaction = SledTransaction { let mut transaction = SledTransaction {
inner: BatchWriter::new(self), inner: BatchWriter::new(self),
}; };
f(&mut transaction)?; f(&mut transaction)?;
transaction.inner.apply() Ok(transaction.inner.apply()?)
} }
/// Loads a graph file (i.e. triples) into the store /// Loads a graph file (i.e. triples) into the store
@ -175,7 +175,7 @@ impl SledStore {
syntax: GraphSyntax, syntax: GraphSyntax,
to_graph_name: &GraphName, to_graph_name: &GraphName,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error> {
load_graph( load_graph(
&mut DirectWriter::new(self), &mut DirectWriter::new(self),
reader, reader,
@ -196,19 +196,19 @@ impl SledStore {
reader: impl BufRead, reader: impl BufRead,
syntax: DatasetSyntax, syntax: DatasetSyntax,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error> {
load_dataset(&mut DirectWriter::new(self), reader, syntax, base_iri) load_dataset(&mut DirectWriter::new(self), reader, syntax, base_iri)
} }
/// Adds a quad to this store. /// 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 mut writer = DirectWriter::new(self);
let quad = writer.encode_quad(quad)?; let quad = writer.encode_quad(quad)?;
writer.insert_encoded(&quad) writer.insert_encoded(&quad)
} }
/// Removes a quad from this store. /// 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(); let quad = quad.into();
DirectWriter::new(self).remove_encoded(&quad) DirectWriter::new(self).remove_encoded(&quad)
} }
@ -221,7 +221,7 @@ impl SledStore {
writer: &mut impl Write, writer: &mut impl Write,
syntax: GraphSyntax, syntax: GraphSyntax,
from_graph_name: &GraphName, from_graph_name: &GraphName,
) -> Result<()> { ) -> Result<(), io::Error> {
dump_graph( dump_graph(
self.quads_for_pattern(None, None, None, Some(from_graph_name)) self.quads_for_pattern(None, None, None, Some(from_graph_name))
.map(|q| Ok(q?.into())), .map(|q| Ok(q?.into())),
@ -233,7 +233,11 @@ impl SledStore {
/// Dumps the store dataset into a file. /// Dumps the store dataset into a file.
/// ///
/// See `MemoryStore` for a usage example. /// 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( dump_dataset(
self.quads_for_pattern(None, None, None, None), self.quads_for_pattern(None, None, None, None),
writer, writer,
@ -241,7 +245,7 @@ impl SledStore {
) )
} }
fn contains_encoded(&self, quad: &EncodedQuad) -> Result<bool> { fn contains_encoded(&self, quad: &EncodedQuad) -> Result<bool, io::Error> {
let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE); let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE);
write_spog_quad(&mut buffer, quad); write_spog_quad(&mut buffer, quad);
Ok(self.quads.contains_key(buffer)?) Ok(self.quads.contains_key(buffer)?)
@ -378,18 +382,19 @@ impl fmt::Display for SledStore {
} }
impl StrLookup for SledStore { impl StrLookup for SledStore {
type Error = Error; type Error = io::Error;
fn get_str(&self, id: StrHash) -> Result<Option<String>> { fn get_str(&self, id: StrHash) -> Result<Option<String>, io::Error> {
Ok(self self.id2str
.id2str
.get(id.to_be_bytes())? .get(id.to_be_bytes())?
.map(|v| String::from_utf8(v.to_vec())) .map(|v| String::from_utf8(v.to_vec()))
.transpose()?) .transpose()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
} }
} }
impl ReadableEncodedStore for SledStore { impl ReadableEncodedStore for SledStore {
type Error = io::Error;
type QuadsIter = DecodingQuadIterator; type QuadsIter = DecodingQuadIterator;
fn encoded_quads_for_pattern( fn encoded_quads_for_pattern(
@ -475,9 +480,9 @@ impl<'a> DirectWriter<'a> {
} }
impl<'a> StrContainer for 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 self.store
.id2str .id2str
.insert(key.to_be_bytes().as_ref(), value)?; .insert(key.to_be_bytes().as_ref(), value)?;
@ -486,9 +491,9 @@ impl<'a> StrContainer for DirectWriter<'a> {
} }
impl<'a> WritableEncodedStore 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); write_spog_quad(&mut self.buffer, quad);
self.store.quads.insert(self.buffer.as_slice(), &[])?; self.store.quads.insert(self.buffer.as_slice(), &[])?;
self.buffer.clear(); self.buffer.clear();
@ -516,7 +521,7 @@ impl<'a> WritableEncodedStore for DirectWriter<'a> {
Ok(()) 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); write_spog_quad(&mut self.buffer, quad);
self.store.quads.remove(self.buffer.as_slice())?; self.store.quads.remove(self.buffer.as_slice())?;
self.buffer.clear(); self.buffer.clear();
@ -564,7 +569,7 @@ impl<'a> BatchWriter<'a> {
} }
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.id2str.apply_batch(self.id2str)?;
self.store.quads.apply_batch(self.quads)?; self.store.quads.apply_batch(self.quads)?;
Ok(()) Ok(())
@ -574,7 +579,7 @@ impl<'a> BatchWriter<'a> {
impl<'a> StrContainer for BatchWriter<'a> { impl<'a> StrContainer for BatchWriter<'a> {
type Error = Infallible; 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); self.id2str.insert(key.to_be_bytes().as_ref(), value);
Ok(()) Ok(())
} }
@ -583,7 +588,7 @@ impl<'a> StrContainer for BatchWriter<'a> {
impl<'a> WritableEncodedStore for BatchWriter<'a> { impl<'a> WritableEncodedStore for BatchWriter<'a> {
type Error = Infallible; 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); write_spog_quad(&mut self.buffer, quad);
self.quads.insert(self.buffer.as_slice(), &[]); self.quads.insert(self.buffer.as_slice(), &[]);
self.buffer.clear(); self.buffer.clear();
@ -611,7 +616,7 @@ impl<'a> WritableEncodedStore for BatchWriter<'a> {
Ok(()) 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); write_spog_quad(&mut self.buffer, quad);
self.quads.remove(self.buffer.as_slice()); self.quads.remove(self.buffer.as_slice());
self.buffer.clear(); self.buffer.clear();
@ -659,7 +664,7 @@ impl SledTransaction<'_> {
syntax: GraphSyntax, syntax: GraphSyntax,
to_graph_name: &GraphName, to_graph_name: &GraphName,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error> {
load_graph(&mut self.inner, reader, syntax, to_graph_name, base_iri) load_graph(&mut self.inner, reader, syntax, to_graph_name, base_iri)
} }
@ -675,7 +680,7 @@ impl SledTransaction<'_> {
reader: impl BufRead, reader: impl BufRead,
syntax: DatasetSyntax, syntax: DatasetSyntax,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> Result<()> { ) -> Result<(), crate::Error> {
load_dataset(&mut self.inner, reader, syntax, base_iri) load_dataset(&mut self.inner, reader, syntax, base_iri)
} }
@ -697,7 +702,7 @@ pub struct SledPreparedQuery(SimplePreparedQuery<SledStore>);
impl SledPreparedQuery { impl SledPreparedQuery {
/// Evaluates the query and returns its results /// Evaluates the query and returns its results
pub fn exec(&self) -> Result<QueryResult> { pub fn exec(&self) -> Result<QueryResult, crate::Error> {
self.0.exec() self.0.exec()
} }
} }
@ -747,9 +752,9 @@ pub(crate) struct DecodingQuadIterator {
} }
impl Iterator for DecodingQuadIterator { impl Iterator for DecodingQuadIterator {
type Item = Result<EncodedQuad>; type Item = Result<EncodedQuad, io::Error>;
fn next(&mut self) -> Option<Result<EncodedQuad>> { fn next(&mut self) -> Option<Result<EncodedQuad, io::Error>> {
Some(match self.iter.next()? { Some(match self.iter.next()? {
Ok((encoded, _)) => decode_quad(&encoded), Ok((encoded, _)) => decode_quad(&encoded),
Err(error) => Err(error.into()), Err(error) => Err(error.into()),
@ -805,7 +810,7 @@ fn write_gosp_quad(sink: &mut Vec<u8>, quad: &EncodedQuad) {
write_term(sink, quad.predicate); write_term(sink, quad.predicate);
} }
fn decode_quad(encoded: &[u8]) -> Result<EncodedQuad> { fn decode_quad(encoded: &[u8]) -> Result<EncodedQuad, io::Error> {
let mut cursor = Cursor::new(&encoded[1..]); let mut cursor = Cursor::new(&encoded[1..]);
match encoded[0] { match encoded[0] {
SPOG_PREFIX => Ok(cursor.read_spog_quad()?), SPOG_PREFIX => Ok(cursor.read_spog_quad()?),
@ -814,14 +819,16 @@ fn decode_quad(encoded: &[u8]) -> Result<EncodedQuad> {
GSPO_PREFIX => Ok(cursor.read_gspo_quad()?), GSPO_PREFIX => Ok(cursor.read_gspo_quad()?),
GPOS_PREFIX => Ok(cursor.read_gpos_quad()?), GPOS_PREFIX => Ok(cursor.read_gpos_quad()?),
GOSP_PREFIX => Ok(cursor.read_gosp_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] #[test]
fn store() -> Result<()> { fn store() -> Result<(), crate::Error> {
use crate::model::*; use crate::model::*;
use crate::*;
let main_s = NamedOrBlankNode::from(BlankNode::default()); let main_s = NamedOrBlankNode::from(BlankNode::default());
let main_p = NamedNode::new("http://example.com")?; let main_p = NamedNode::new("http://example.com")?;
@ -844,25 +851,25 @@ fn store() -> Result<()> {
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, None, None, None) .quads_for_pattern(None, None, None, None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), None, None, None) .quads_for_pattern(Some(&main_s), None, None, None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), Some(&main_p), None, None) .quads_for_pattern(Some(&main_s), Some(&main_p), None, None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), Some(&main_p), Some(&main_o), None) .quads_for_pattern(Some(&main_s), Some(&main_p), Some(&main_o), None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
@ -873,7 +880,7 @@ fn store() -> Result<()> {
Some(&main_o), Some(&main_o),
Some(&GraphName::DefaultGraph) Some(&GraphName::DefaultGraph)
) )
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
@ -884,13 +891,13 @@ fn store() -> Result<()> {
None, None,
Some(&GraphName::DefaultGraph) Some(&GraphName::DefaultGraph)
) )
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), None, Some(&main_o), None) .quads_for_pattern(Some(&main_s), None, Some(&main_o), None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
@ -901,37 +908,37 @@ fn store() -> Result<()> {
Some(&main_o), Some(&main_o),
Some(&GraphName::DefaultGraph) Some(&GraphName::DefaultGraph)
) )
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(Some(&main_s), None, None, Some(&GraphName::DefaultGraph)) .quads_for_pattern(Some(&main_s), None, None, Some(&GraphName::DefaultGraph))
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, Some(&main_p), None, None) .quads_for_pattern(None, Some(&main_p), None, None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, Some(&main_p), Some(&main_o), None) .quads_for_pattern(None, Some(&main_p), Some(&main_o), None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, None, Some(&main_o), None) .quads_for_pattern(None, None, Some(&main_o), None)
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );
assert_eq!( assert_eq!(
store store
.quads_for_pattern(None, None, None, Some(&GraphName::DefaultGraph)) .quads_for_pattern(None, None, None, Some(&GraphName::DefaultGraph))
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
all_o all_o
); );
assert_eq!( assert_eq!(
@ -942,7 +949,7 @@ fn store() -> Result<()> {
Some(&main_o), Some(&main_o),
Some(&GraphName::DefaultGraph) Some(&GraphName::DefaultGraph)
) )
.collect::<Result<Vec<_>>>()?, .collect::<Result<Vec<_>, _>>()?,
target target
); );

@ -2,16 +2,14 @@ use crate::model::*;
use crate::store_utils::*; use crate::store_utils::*;
use oxigraph::model::*; use oxigraph::model::*;
use oxigraph::sparql::QueryOptions; use oxigraph::sparql::QueryOptions;
use oxigraph::{DatasetSyntax, FileSyntax, GraphSyntax, Result, SledStore}; use oxigraph::{DatasetSyntax, FileSyntax, GraphSyntax, SledStore};
use pyo3::create_exception; use pyo3::exceptions::{IOError, ValueError};
use pyo3::exceptions::ValueError;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyTuple; use pyo3::types::PyTuple;
use pyo3::{PyIterProtocol, PyObjectProtocol, PySequenceProtocol}; use pyo3::{PyIterProtocol, PyObjectProtocol, PySequenceProtocol};
use std::io;
use std::io::Cursor; use std::io::Cursor;
create_exception!(oxigraph, SledError, pyo3::exceptions::RuntimeError);
#[pyclass(name = SledStore)] #[pyclass(name = SledStore)]
#[derive(Clone)] #[derive(Clone)]
pub struct PySledStore { pub struct PySledStore {
@ -24,9 +22,9 @@ impl PySledStore {
fn new(path: Option<&str>) -> PyResult<Self> { fn new(path: Option<&str>) -> PyResult<Self> {
Ok(Self { Ok(Self {
inner: if let Some(path) = path { 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 { } 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<()> { fn add(&self, quad: &PyTuple) -> PyResult<()> {
self.inner self.inner
.insert(&extract_quad(quad)?) .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<()> { fn remove(&self, quad: &PyTuple) -> PyResult<()> {
self.inner self.inner
.remove(&extract_quad(quad)?) .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( fn r#match(
@ -136,7 +134,7 @@ impl PySequenceProtocol for PySledStore {
fn __contains__(&self, quad: &PyTuple) -> PyResult<bool> { fn __contains__(&self, quad: &PyTuple) -> PyResult<bool> {
self.inner self.inner
.contains(&extract_quad(quad)?) .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)] #[pyclass(unsendable)]
pub struct QuadIter { pub struct QuadIter {
inner: Box<dyn Iterator<Item = Result<Quad>>>, inner: Box<dyn Iterator<Item = Result<Quad, io::Error>>>,
} }
#[pyproto] #[pyproto]
@ -168,7 +166,7 @@ impl PyIterProtocol for QuadIter {
.map(move |q| { .map(move |q| {
Ok(quad_to_python( Ok(quad_to_python(
slf.py(), slf.py(),
q.map_err(|e| SledError::py_err(e.to_string()))?, q.map_err(|e| IOError::py_err(e.to_string()))?,
)) ))
}) })
.transpose() .transpose()

@ -264,7 +264,7 @@ impl WikibaseLoader {
let to_remove = self let to_remove = self
.store .store
.quads_for_pattern(None, None, None, Some(&graph_name)) .quads_for_pattern(None, None, None, Some(&graph_name))
.collect::<oxigraph::Result<Vec<_>>>()?; .collect::<std::result::Result<Vec<_>, _>>()?;
for q in to_remove { for q in to_remove {
transaction.remove(&q); transaction.remove(&q);
} }

Loading…
Cancel
Save