//! RDF quads storage implementations. //! //! They encode a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) //! and allow querying and updating them using SPARQL. #[cfg(any(feature = "rocksdb", feature = "sled"))] mod binary_encoder; pub mod memory; pub(crate) mod numeric_encoder; #[cfg(feature = "rocksdb")] pub mod rocksdb; #[cfg(feature = "sled")] pub mod sled; pub(crate) mod small_string; pub use crate::store::memory::MemoryStore; #[cfg(feature = "rocksdb")] pub use crate::store::rocksdb::RocksDbStore; #[cfg(feature = "sled")] pub use crate::store::sled::SledStore; use crate::error::{invalid_data_error, invalid_input_error}; use crate::io::{DatasetFormat, DatasetSerializer, GraphFormat, GraphSerializer}; use crate::model::*; use crate::store::numeric_encoder::*; use rio_api::parser::{QuadsParser, TriplesParser}; use rio_turtle::{NQuadsParser, NTriplesParser, TriGParser, TurtleError, TurtleParser}; use rio_xml::{RdfXmlError, RdfXmlParser}; use std::collections::HashMap; use std::convert::Infallible; use std::io; use std::io::{BufRead, Write}; use std::iter::Iterator; const LATEST_STORAGE_VERSION: u64 = 0; pub(crate) trait ReadableEncodedStore: StrLookup { type QuadsIter: Iterator, Self::Error>> + 'static; fn encoded_quads_for_pattern( &self, subject: Option>, predicate: Option>, object: Option>, graph_name: Option>, ) -> Self::QuadsIter; } pub(crate) trait WritableEncodedStore: WithStoreError { fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<(), Self::Error>; fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<(), Self::Error>; } fn load_graph( store: &mut S, reader: impl BufRead, format: GraphFormat, to_graph_name: GraphNameRef<'_>, base_iri: Option<&str>, ) -> Result<(), StoreOrParseError> { let base_iri = base_iri.unwrap_or(""); match format { GraphFormat::NTriples => { load_from_triple_parser(store, NTriplesParser::new(reader), to_graph_name) } GraphFormat::Turtle => { load_from_triple_parser(store, TurtleParser::new(reader, base_iri), to_graph_name) } GraphFormat::RdfXml => { load_from_triple_parser(store, RdfXmlParser::new(reader, base_iri), to_graph_name) } } } fn load_from_triple_parser( store: &mut S, parser: Result, to_graph_name: GraphNameRef<'_>, ) -> Result<(), StoreOrParseError> where StoreOrParseError: From, P::Error: Send + Sync + 'static, { let mut parser = parser.map_err(invalid_input_error)?; let mut bnode_map = HashMap::default(); let to_graph_name = store .encode_graph_name(to_graph_name) .map_err(StoreOrParseError::Store)?; parser .parse_all(&mut move |t| { let quad = store .encode_rio_triple_in_graph(t, to_graph_name, &mut bnode_map) .map_err(StoreOrParseError::Store)?; store .insert_encoded(&quad) .map_err(StoreOrParseError::Store)?; Ok(()) }) .map_err(|e| match e { StoreOrParseError::Store(e) => StoreOrParseError::Store(e), StoreOrParseError::Parse(e) => StoreOrParseError::Parse(invalid_data_error(e)), }) } fn dump_graph( triples: impl Iterator>, writer: impl Write, format: GraphFormat, ) -> Result<(), io::Error> { let mut writer = GraphSerializer::from_format(format).triple_writer(writer)?; for triple in triples { writer.write(&triple?)?; } writer.finish() } fn load_dataset( store: &mut S, reader: impl BufRead, format: DatasetFormat, base_iri: Option<&str>, ) -> Result<(), StoreOrParseError> { let base_iri = base_iri.unwrap_or(""); match format { DatasetFormat::NQuads => load_from_quad_parser(store, NQuadsParser::new(reader)), DatasetFormat::TriG => load_from_quad_parser(store, TriGParser::new(reader, base_iri)), } } fn load_from_quad_parser( store: &mut S, parser: Result, ) -> Result<(), StoreOrParseError> where StoreOrParseError: From, P::Error: Send + Sync + 'static, { let mut parser = parser.map_err(invalid_input_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(StoreOrParseError::Store)?; store .insert_encoded(&quad) .map_err(StoreOrParseError::Store)?; Ok(()) }) .map_err(|e| match e { StoreOrParseError::Store(e) => StoreOrParseError::Store(e), StoreOrParseError::Parse(e) => StoreOrParseError::Parse(invalid_data_error(e)), }) } fn dump_dataset( quads: impl Iterator>, writer: impl Write, format: DatasetFormat, ) -> Result<(), io::Error> { let mut writer = DatasetSerializer::from_format(format).quad_writer(writer)?; for quad in quads { writer.write(&quad?)?; } writer.finish() } enum StoreOrParseError { Store(S), Parse(P), } impl From for StoreOrParseError { fn from(error: TurtleError) -> Self { Self::Parse(error) } } impl From for StoreOrParseError { fn from(error: RdfXmlError) -> Self { Self::Parse(error) } } impl From for StoreOrParseError { fn from(error: io::Error) -> Self { Self::Parse(error) } } impl> From> for io::Error { fn from(error: StoreOrParseError) -> Self { match error { StoreOrParseError::Store(error) => error, StoreOrParseError::Parse(error) => error.into(), } } } impl> From> for io::Error { fn from(error: StoreOrParseError) -> Self { match error { StoreOrParseError::Store(error) => match error {}, StoreOrParseError::Parse(error) => error.into(), } } } type QuadPattern = ( Option>, Option>, Option>, Option>, ); fn get_encoded_quad_pattern( encoder: &E, subject: Option>, predicate: Option>, object: Option>, graph_name: Option>, ) -> Result>, E::Error> { Ok(Some(( if let Some(subject) = transpose( subject .map(|t| encoder.get_encoded_named_or_blank_node(t)) .transpose()?, ) { subject } else { return Ok(None); }, if let Some(predicate) = transpose( predicate .map(|t| encoder.get_encoded_named_node(t)) .transpose()?, ) { predicate } else { return Ok(None); }, if let Some(object) = transpose(object.map(|t| encoder.get_encoded_term(t)).transpose()?) { object } else { return Ok(None); }, if let Some(graph_name) = transpose( graph_name .map(|t| encoder.get_encoded_graph_name(t)) .transpose()?, ) { graph_name } else { return Ok(None); }, ))) } fn transpose(o: Option>) -> Option> { match o { Some(Some(v)) => Some(Some(v)), Some(None) => None, None => Some(None), } }