diff --git a/lib/src/store/binary_encoder.rs b/lib/src/store/binary_encoder.rs new file mode 100644 index 00000000..517f13cf --- /dev/null +++ b/lib/src/store/binary_encoder.rs @@ -0,0 +1,530 @@ +use crate::error::invalid_data_error; +use crate::model::xsd::*; +use crate::store::numeric_encoder::StrId; +use siphasher::sip128::{Hasher128, SipHasher24}; +use std::hash::Hasher; +use std::io; +use std::io::{Cursor, Read}; +use std::mem::size_of; + +type EncodedTerm = crate::store::numeric_encoder::EncodedTerm; +type EncodedQuad = crate::store::numeric_encoder::EncodedQuad; + +pub const WRITTEN_TERM_MAX_SIZE: usize = size_of::() + 2 * size_of::(); +const TYPE_DEFAULT_GRAPH_ID: u8 = 0; +const TYPE_NAMED_NODE_ID: u8 = 1; +const TYPE_INLINE_BLANK_NODE_ID: u8 = 2; +const TYPE_NAMED_BLANK_NODE_ID: u8 = 3; +const TYPE_LANG_STRING_LITERAL_ID: u8 = 4; +const TYPE_TYPED_LITERAL_ID: u8 = 5; +const TYPE_STRING_LITERAL: u8 = 6; +const TYPE_BOOLEAN_LITERAL_TRUE: u8 = 7; +const TYPE_BOOLEAN_LITERAL_FALSE: u8 = 8; +const TYPE_FLOAT_LITERAL: u8 = 9; +const TYPE_DOUBLE_LITERAL: u8 = 10; +const TYPE_INTEGER_LITERAL: u8 = 11; +const TYPE_DECIMAL_LITERAL: u8 = 12; +const TYPE_DATE_TIME_LITERAL: u8 = 13; +const TYPE_DATE_LITERAL: u8 = 14; +const TYPE_TIME_LITERAL: u8 = 15; +const TYPE_DURATION_LITERAL: u8 = 16; +const TYPE_YEAR_MONTH_DURATION_LITERAL: u8 = 17; +const TYPE_DAY_TIME_DURATION_LITERAL: u8 = 18; + +pub trait SerializableStrId: StrId { + fn len() -> usize; + + fn from_be_bytes(bytes: &[u8]) -> Self; + + fn push_be_bytes(&self, buffer: &mut Vec); +} + +#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)] +#[repr(transparent)] +pub struct StrHash { + hash: u128, +} + +impl StrHash { + pub fn new(value: &str) -> Self { + let mut hasher = SipHasher24::new(); + hasher.write(value.as_bytes()); + Self { + hash: hasher.finish128().into(), + } + } + + #[inline] + pub fn from_be_bytes(bytes: [u8; 16]) -> Self { + Self { + hash: u128::from_be_bytes(bytes), + } + } + + #[inline] + pub fn to_be_bytes(&self) -> [u8; 16] { + self.hash.to_be_bytes() + } +} + +impl StrId for StrHash {} + +impl SerializableStrId for StrHash { + fn len() -> usize { + 16 + } + + fn from_be_bytes(bytes: &[u8]) -> Self { + let mut hash = [0; 16]; + hash.copy_from_slice(bytes); + Self { + hash: u128::from_be_bytes(hash), + } + } + + fn push_be_bytes(&self, buffer: &mut Vec) { + buffer.extend_from_slice(&self.to_be_bytes()) + } +} + +#[derive(Clone, Copy)] +pub enum QuadEncoding { + SPOG, + POSG, + OSPG, + GSPO, + GPOS, + GOSP, + DSPO, + DPOS, + DOSP, +} + +impl QuadEncoding { + pub fn decode(self, buffer: &[u8]) -> Result { + let mut cursor = Cursor::new(&buffer); + match self { + QuadEncoding::SPOG => cursor.read_spog_quad(), + QuadEncoding::POSG => cursor.read_posg_quad(), + QuadEncoding::OSPG => cursor.read_ospg_quad(), + QuadEncoding::GSPO => cursor.read_gspo_quad(), + QuadEncoding::GPOS => cursor.read_gpos_quad(), + QuadEncoding::GOSP => cursor.read_gosp_quad(), + QuadEncoding::DSPO => cursor.read_dspo_quad(), + QuadEncoding::DPOS => cursor.read_dpos_quad(), + QuadEncoding::DOSP => cursor.read_dosp_quad(), + } + } +} + +pub trait TermReader { + fn read_term(&mut self) -> Result; + + fn read_spog_quad(&mut self) -> Result { + let subject = self.read_term()?; + let predicate = self.read_term()?; + let object = self.read_term()?; + let graph_name = self.read_term()?; + Ok(EncodedQuad { + subject, + predicate, + object, + graph_name, + }) + } + + fn read_posg_quad(&mut self) -> Result { + let predicate = self.read_term()?; + let object = self.read_term()?; + let subject = self.read_term()?; + let graph_name = self.read_term()?; + Ok(EncodedQuad { + subject, + predicate, + object, + graph_name, + }) + } + + fn read_ospg_quad(&mut self) -> Result { + let object = self.read_term()?; + let subject = self.read_term()?; + let predicate = self.read_term()?; + let graph_name = self.read_term()?; + Ok(EncodedQuad { + subject, + predicate, + object, + graph_name, + }) + } + + fn read_gspo_quad(&mut self) -> Result { + let graph_name = self.read_term()?; + let subject = self.read_term()?; + let predicate = self.read_term()?; + let object = self.read_term()?; + Ok(EncodedQuad { + subject, + predicate, + object, + graph_name, + }) + } + + fn read_gpos_quad(&mut self) -> Result { + let graph_name = self.read_term()?; + let predicate = self.read_term()?; + let object = self.read_term()?; + let subject = self.read_term()?; + Ok(EncodedQuad { + subject, + predicate, + object, + graph_name, + }) + } + + fn read_gosp_quad(&mut self) -> Result { + let graph_name = self.read_term()?; + let object = self.read_term()?; + let subject = self.read_term()?; + let predicate = self.read_term()?; + Ok(EncodedQuad { + subject, + predicate, + object, + graph_name, + }) + } + + fn read_dspo_quad(&mut self) -> Result { + let subject = self.read_term()?; + let predicate = self.read_term()?; + let object = self.read_term()?; + Ok(EncodedQuad { + subject, + predicate, + object, + graph_name: EncodedTerm::DefaultGraph, + }) + } + + fn read_dpos_quad(&mut self) -> Result { + let predicate = self.read_term()?; + let object = self.read_term()?; + let subject = self.read_term()?; + Ok(EncodedQuad { + subject, + predicate, + object, + graph_name: EncodedTerm::DefaultGraph, + }) + } + + fn read_dosp_quad(&mut self) -> Result { + let object = self.read_term()?; + let subject = self.read_term()?; + let predicate = self.read_term()?; + Ok(EncodedQuad { + subject, + predicate, + object, + graph_name: EncodedTerm::DefaultGraph, + }) + } +} + +impl TermReader for R { + fn read_term(&mut self) -> Result { + let mut type_buffer = [0]; + self.read_exact(&mut type_buffer)?; + match type_buffer[0] { + TYPE_DEFAULT_GRAPH_ID => Ok(EncodedTerm::DefaultGraph), + TYPE_NAMED_NODE_ID => { + let mut buffer = [0; 16]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::NamedNode { + iri_id: StrHash::from_be_bytes(buffer), + }) + } + TYPE_INLINE_BLANK_NODE_ID => { + let mut buffer = [0; 16]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::InlineBlankNode { + id: u128::from_be_bytes(buffer), + }) + } + TYPE_NAMED_BLANK_NODE_ID => { + let mut buffer = [0; 16]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::NamedBlankNode { + id_id: StrHash::from_be_bytes(buffer), + }) + } + TYPE_LANG_STRING_LITERAL_ID => { + let mut language_buffer = [0; 16]; + self.read_exact(&mut language_buffer)?; + let mut value_buffer = [0; 16]; + self.read_exact(&mut value_buffer)?; + Ok(EncodedTerm::LangStringLiteral { + language_id: StrHash::from_be_bytes(language_buffer), + value_id: StrHash::from_be_bytes(value_buffer), + }) + } + TYPE_TYPED_LITERAL_ID => { + let mut datatype_buffer = [0; 16]; + self.read_exact(&mut datatype_buffer)?; + let mut value_buffer = [0; 16]; + self.read_exact(&mut value_buffer)?; + Ok(EncodedTerm::TypedLiteral { + datatype_id: StrHash::from_be_bytes(datatype_buffer), + value_id: StrHash::from_be_bytes(value_buffer), + }) + } + TYPE_STRING_LITERAL => { + let mut buffer = [0; 16]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::StringLiteral { + value_id: StrHash::from_be_bytes(buffer), + }) + } + TYPE_BOOLEAN_LITERAL_TRUE => Ok(EncodedTerm::BooleanLiteral(true)), + TYPE_BOOLEAN_LITERAL_FALSE => Ok(EncodedTerm::BooleanLiteral(false)), + TYPE_FLOAT_LITERAL => { + let mut buffer = [0; 4]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::FloatLiteral(f32::from_be_bytes(buffer))) + } + TYPE_DOUBLE_LITERAL => { + let mut buffer = [0; 8]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::DoubleLiteral(f64::from_be_bytes(buffer))) + } + TYPE_INTEGER_LITERAL => { + let mut buffer = [0; 8]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::IntegerLiteral(i64::from_be_bytes(buffer))) + } + TYPE_DECIMAL_LITERAL => { + let mut buffer = [0; 16]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::DecimalLiteral(Decimal::from_be_bytes(buffer))) + } + TYPE_DATE_LITERAL => { + let mut buffer = [0; 18]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::DateLiteral(Date::from_be_bytes(buffer))) + } + TYPE_TIME_LITERAL => { + let mut buffer = [0; 18]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::TimeLiteral(Time::from_be_bytes(buffer))) + } + TYPE_DATE_TIME_LITERAL => { + let mut buffer = [0; 18]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::DateTimeLiteral(DateTime::from_be_bytes( + buffer, + ))) + } + TYPE_DURATION_LITERAL => { + let mut buffer = [0; 24]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::DurationLiteral(Duration::from_be_bytes( + buffer, + ))) + } + TYPE_YEAR_MONTH_DURATION_LITERAL => { + let mut buffer = [0; 8]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::YearMonthDurationLiteral( + YearMonthDuration::from_be_bytes(buffer), + )) + } + TYPE_DAY_TIME_DURATION_LITERAL => { + let mut buffer = [0; 16]; + self.read_exact(&mut buffer)?; + Ok(EncodedTerm::DayTimeDurationLiteral( + DayTimeDuration::from_be_bytes(buffer), + )) + } + _ => Err(invalid_data_error("the term buffer has an invalid type id")), + } + } +} + +pub fn write_spog_quad(sink: &mut Vec, quad: &EncodedQuad) { + write_term(sink, quad.subject); + write_term(sink, quad.predicate); + write_term(sink, quad.object); + write_term(sink, quad.graph_name); +} + +pub fn write_posg_quad(sink: &mut Vec, quad: &EncodedQuad) { + write_term(sink, quad.predicate); + write_term(sink, quad.object); + write_term(sink, quad.subject); + write_term(sink, quad.graph_name); +} + +pub fn write_ospg_quad(sink: &mut Vec, quad: &EncodedQuad) { + write_term(sink, quad.object); + write_term(sink, quad.subject); + write_term(sink, quad.predicate); + write_term(sink, quad.graph_name); +} + +pub fn write_gspo_quad(sink: &mut Vec, quad: &EncodedQuad) { + write_term(sink, quad.graph_name); + write_term(sink, quad.subject); + write_term(sink, quad.predicate); + write_term(sink, quad.object); +} + +pub fn write_gpos_quad(sink: &mut Vec, quad: &EncodedQuad) { + write_term(sink, quad.graph_name); + write_term(sink, quad.predicate); + write_term(sink, quad.object); + write_term(sink, quad.subject); +} + +pub fn write_gosp_quad(sink: &mut Vec, quad: &EncodedQuad) { + write_term(sink, quad.graph_name); + write_term(sink, quad.object); + write_term(sink, quad.subject); + write_term(sink, quad.predicate); +} + +pub fn write_spo_quad(sink: &mut Vec, quad: &EncodedQuad) { + write_term(sink, quad.subject); + write_term(sink, quad.predicate); + write_term(sink, quad.object); +} + +pub fn write_pos_quad(sink: &mut Vec, quad: &EncodedQuad) { + write_term(sink, quad.predicate); + write_term(sink, quad.object); + write_term(sink, quad.subject); +} + +pub fn write_osp_quad(sink: &mut Vec, quad: &EncodedQuad) { + write_term(sink, quad.object); + write_term(sink, quad.subject); + write_term(sink, quad.predicate); +} + +pub fn encode_term(t: EncodedTerm) -> Vec { + let mut vec = Vec::with_capacity(WRITTEN_TERM_MAX_SIZE); + write_term(&mut vec, t); + vec +} + +pub fn encode_term_pair(t1: EncodedTerm, t2: EncodedTerm) -> Vec { + let mut vec = Vec::with_capacity(2 * WRITTEN_TERM_MAX_SIZE); + write_term(&mut vec, t1); + write_term(&mut vec, t2); + vec +} + +pub fn encode_term_triple(t1: EncodedTerm, t2: EncodedTerm, t3: EncodedTerm) -> Vec { + let mut vec = Vec::with_capacity(3 * WRITTEN_TERM_MAX_SIZE); + write_term(&mut vec, t1); + write_term(&mut vec, t2); + write_term(&mut vec, t3); + vec +} + +pub fn encode_term_quad( + t1: EncodedTerm, + t2: EncodedTerm, + t3: EncodedTerm, + t4: EncodedTerm, +) -> Vec { + let mut vec = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE); + write_term(&mut vec, t1); + write_term(&mut vec, t2); + write_term(&mut vec, t3); + write_term(&mut vec, t4); + vec +} + +pub fn write_term(sink: &mut Vec, term: EncodedTerm) { + match term { + EncodedTerm::DefaultGraph => sink.push(TYPE_DEFAULT_GRAPH_ID), + EncodedTerm::NamedNode { iri_id } => { + sink.push(TYPE_NAMED_NODE_ID); + iri_id.push_be_bytes(sink) + } + EncodedTerm::InlineBlankNode { id } => { + sink.push(TYPE_INLINE_BLANK_NODE_ID); + sink.extend_from_slice(&id.to_be_bytes()) + } + EncodedTerm::NamedBlankNode { id_id } => { + sink.push(TYPE_NAMED_BLANK_NODE_ID); + id_id.push_be_bytes(sink) + } + EncodedTerm::StringLiteral { value_id } => { + sink.push(TYPE_STRING_LITERAL); + value_id.push_be_bytes(sink) + } + EncodedTerm::LangStringLiteral { + value_id, + language_id, + } => { + sink.push(TYPE_LANG_STRING_LITERAL_ID); + value_id.push_be_bytes(sink); + language_id.push_be_bytes(sink); + } + EncodedTerm::TypedLiteral { + value_id, + datatype_id, + } => { + sink.push(TYPE_TYPED_LITERAL_ID); + value_id.push_be_bytes(sink); + datatype_id.push_be_bytes(sink); + } + EncodedTerm::BooleanLiteral(true) => sink.push(TYPE_BOOLEAN_LITERAL_TRUE), + EncodedTerm::BooleanLiteral(false) => sink.push(TYPE_BOOLEAN_LITERAL_FALSE), + EncodedTerm::FloatLiteral(value) => { + sink.push(TYPE_FLOAT_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + EncodedTerm::DoubleLiteral(value) => { + sink.push(TYPE_DOUBLE_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + EncodedTerm::IntegerLiteral(value) => { + sink.push(TYPE_INTEGER_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + EncodedTerm::DecimalLiteral(value) => { + sink.push(TYPE_DECIMAL_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + EncodedTerm::DateLiteral(value) => { + sink.push(TYPE_DATE_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + EncodedTerm::TimeLiteral(value) => { + sink.push(TYPE_TIME_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + EncodedTerm::DateTimeLiteral(value) => { + sink.push(TYPE_DATE_TIME_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + EncodedTerm::DurationLiteral(value) => { + sink.push(TYPE_DURATION_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + EncodedTerm::YearMonthDurationLiteral(value) => { + sink.push(TYPE_YEAR_MONTH_DURATION_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + EncodedTerm::DayTimeDurationLiteral(value) => { + sink.push(TYPE_DAY_TIME_DURATION_LITERAL); + sink.extend_from_slice(&value.to_be_bytes()) + } + } +} diff --git a/lib/src/store/mod.rs b/lib/src/store/mod.rs index 147c47ad..0c3ff63c 100644 --- a/lib/src/store/mod.rs +++ b/lib/src/store/mod.rs @@ -3,6 +3,8 @@ //! 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")] diff --git a/lib/src/store/numeric_encoder.rs b/lib/src/store/numeric_encoder.rs index 69d053a4..34c84d54 100644 --- a/lib/src/store/numeric_encoder.rs +++ b/lib/src/store/numeric_encoder.rs @@ -4,97 +4,19 @@ use crate::error::invalid_data_error; use crate::model::xsd::*; use crate::model::*; use crate::sparql::EvaluationError; +use lasso::{Rodeo, Spur}; use rand::random; use rio_api::model as rio; -use siphasher::sip128::{Hasher128, SipHasher24}; use std::collections::HashMap; use std::convert::Infallible; use std::error::Error; use std::fmt::Debug; use std::hash::Hash; use std::hash::Hasher; -use std::io::Read; -use std::mem::size_of; use std::{fmt, io, str}; pub trait StrId: Eq + Debug + Copy + Hash {} -pub trait SerializableStrId: StrId { - fn len() -> usize; - - fn from_be_bytes(bytes: &[u8]) -> Self; - - fn push_be_bytes(&self, buffer: &mut Vec); -} - -#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)] -#[repr(transparent)] -pub struct StrHash { - hash: u128, -} - -impl StrHash { - pub fn new(value: &str) -> Self { - let mut hasher = SipHasher24::new(); - hasher.write(value.as_bytes()); - Self { - hash: hasher.finish128().into(), - } - } - - #[inline] - pub fn from_be_bytes(bytes: [u8; 16]) -> Self { - Self { - hash: u128::from_be_bytes(bytes), - } - } - - #[inline] - pub fn to_be_bytes(&self) -> [u8; 16] { - self.hash.to_be_bytes() - } -} - -impl StrId for StrHash {} - -impl SerializableStrId for StrHash { - fn len() -> usize { - 16 - } - - fn from_be_bytes(bytes: &[u8]) -> Self { - let mut hash = [0; 16]; - hash.copy_from_slice(bytes); - Self { - hash: u128::from_be_bytes(hash), - } - } - - fn push_be_bytes(&self, buffer: &mut Vec) { - buffer.extend_from_slice(&self.to_be_bytes()) - } -} - -const TYPE_DEFAULT_GRAPH_ID: u8 = 0; -const TYPE_NAMED_NODE_ID: u8 = 1; -const TYPE_INLINE_BLANK_NODE_ID: u8 = 2; -const TYPE_NAMED_BLANK_NODE_ID: u8 = 3; -const TYPE_LANG_STRING_LITERAL_ID: u8 = 4; -const TYPE_TYPED_LITERAL_ID: u8 = 5; -const TYPE_STRING_LITERAL: u8 = 6; -const TYPE_BOOLEAN_LITERAL_TRUE: u8 = 7; -const TYPE_BOOLEAN_LITERAL_FALSE: u8 = 8; -const TYPE_FLOAT_LITERAL: u8 = 9; -const TYPE_DOUBLE_LITERAL: u8 = 10; -const TYPE_INTEGER_LITERAL: u8 = 11; -const TYPE_DECIMAL_LITERAL: u8 = 12; -const TYPE_DATE_TIME_LITERAL: u8 = 13; -const TYPE_DATE_LITERAL: u8 = 14; -const TYPE_TIME_LITERAL: u8 = 15; -const TYPE_DURATION_LITERAL: u8 = 16; -const TYPE_YEAR_MONTH_DURATION_LITERAL: u8 = 17; -const TYPE_DAY_TIME_DURATION_LITERAL: u8 = 18; - #[derive(Debug, Clone, Copy)] pub enum EncodedTerm { DefaultGraph, @@ -264,30 +186,6 @@ impl EncodedTerm { *self == EncodedTerm::DefaultGraph } - fn type_id(&self) -> u8 { - match self { - Self::DefaultGraph { .. } => TYPE_DEFAULT_GRAPH_ID, - Self::NamedNode { .. } => TYPE_NAMED_NODE_ID, - Self::InlineBlankNode { .. } => TYPE_INLINE_BLANK_NODE_ID, - Self::NamedBlankNode { .. } => TYPE_NAMED_BLANK_NODE_ID, - Self::StringLiteral { .. } => TYPE_STRING_LITERAL, - Self::LangStringLiteral { .. } => TYPE_LANG_STRING_LITERAL_ID, - Self::TypedLiteral { .. } => TYPE_TYPED_LITERAL_ID, - Self::BooleanLiteral(true) => TYPE_BOOLEAN_LITERAL_TRUE, - Self::BooleanLiteral(false) => TYPE_BOOLEAN_LITERAL_FALSE, - Self::FloatLiteral(_) => TYPE_FLOAT_LITERAL, - Self::DoubleLiteral(_) => TYPE_DOUBLE_LITERAL, - Self::IntegerLiteral(_) => TYPE_INTEGER_LITERAL, - Self::DecimalLiteral(_) => TYPE_DECIMAL_LITERAL, - Self::DateLiteral(_) => TYPE_DATE_LITERAL, - Self::TimeLiteral(_) => TYPE_TIME_LITERAL, - Self::DateTimeLiteral(_) => TYPE_DATE_TIME_LITERAL, - Self::DurationLiteral(_) => TYPE_DURATION_LITERAL, - Self::YearMonthDurationLiteral(_) => TYPE_YEAR_MONTH_DURATION_LITERAL, - Self::DayTimeDurationLiteral(_) => TYPE_DAY_TIME_DURATION_LITERAL, - } - } - pub fn map_id(self, mapping: impl Fn(I) -> J) -> EncodedTerm { match self { Self::DefaultGraph { .. } => EncodedTerm::DefaultGraph, @@ -478,283 +376,6 @@ impl EncodedQuad { } } -pub trait TermReader { - fn read_term(&mut self) -> Result, io::Error>; - - fn read_spog_quad(&mut self) -> Result, io::Error> { - let subject = self.read_term()?; - let predicate = self.read_term()?; - let object = self.read_term()?; - let graph_name = self.read_term()?; - Ok(EncodedQuad { - subject, - predicate, - object, - graph_name, - }) - } - - fn read_posg_quad(&mut self) -> Result, io::Error> { - let predicate = self.read_term()?; - let object = self.read_term()?; - let subject = self.read_term()?; - let graph_name = self.read_term()?; - Ok(EncodedQuad { - subject, - predicate, - object, - graph_name, - }) - } - - fn read_ospg_quad(&mut self) -> Result, io::Error> { - let object = self.read_term()?; - let subject = self.read_term()?; - let predicate = self.read_term()?; - let graph_name = self.read_term()?; - Ok(EncodedQuad { - subject, - predicate, - object, - graph_name, - }) - } - - fn read_gspo_quad(&mut self) -> Result, io::Error> { - let graph_name = self.read_term()?; - let subject = self.read_term()?; - let predicate = self.read_term()?; - let object = self.read_term()?; - Ok(EncodedQuad { - subject, - predicate, - object, - graph_name, - }) - } - - fn read_gpos_quad(&mut self) -> Result, io::Error> { - let graph_name = self.read_term()?; - let predicate = self.read_term()?; - let object = self.read_term()?; - let subject = self.read_term()?; - Ok(EncodedQuad { - subject, - predicate, - object, - graph_name, - }) - } - - fn read_gosp_quad(&mut self) -> Result, io::Error> { - let graph_name = self.read_term()?; - let object = self.read_term()?; - let subject = self.read_term()?; - let predicate = self.read_term()?; - Ok(EncodedQuad { - subject, - predicate, - object, - graph_name, - }) - } - - fn read_dspo_quad(&mut self) -> Result, io::Error> { - let subject = self.read_term()?; - let predicate = self.read_term()?; - let object = self.read_term()?; - Ok(EncodedQuad { - subject, - predicate, - object, - graph_name: EncodedTerm::DefaultGraph, - }) - } - - fn read_dpos_quad(&mut self) -> Result, io::Error> { - let predicate = self.read_term()?; - let object = self.read_term()?; - let subject = self.read_term()?; - Ok(EncodedQuad { - subject, - predicate, - object, - graph_name: EncodedTerm::DefaultGraph, - }) - } - - fn read_dosp_quad(&mut self) -> Result, io::Error> { - let object = self.read_term()?; - let subject = self.read_term()?; - let predicate = self.read_term()?; - Ok(EncodedQuad { - subject, - predicate, - object, - graph_name: EncodedTerm::DefaultGraph, - }) - } -} - -impl TermReader for R { - fn read_term(&mut self) -> Result, io::Error> { - let mut type_buffer = [0]; - self.read_exact(&mut type_buffer)?; - match type_buffer[0] { - TYPE_DEFAULT_GRAPH_ID => Ok(EncodedTerm::DefaultGraph), - TYPE_NAMED_NODE_ID => { - let mut buffer = [0; 16]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::NamedNode { - iri_id: StrHash::from_be_bytes(buffer), - }) - } - TYPE_INLINE_BLANK_NODE_ID => { - let mut buffer = [0; 16]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::InlineBlankNode { - id: u128::from_be_bytes(buffer), - }) - } - TYPE_NAMED_BLANK_NODE_ID => { - let mut buffer = [0; 16]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::NamedBlankNode { - id_id: StrHash::from_be_bytes(buffer), - }) - } - TYPE_LANG_STRING_LITERAL_ID => { - let mut language_buffer = [0; 16]; - self.read_exact(&mut language_buffer)?; - let mut value_buffer = [0; 16]; - self.read_exact(&mut value_buffer)?; - Ok(EncodedTerm::LangStringLiteral { - language_id: StrHash::from_be_bytes(language_buffer), - value_id: StrHash::from_be_bytes(value_buffer), - }) - } - TYPE_TYPED_LITERAL_ID => { - let mut datatype_buffer = [0; 16]; - self.read_exact(&mut datatype_buffer)?; - let mut value_buffer = [0; 16]; - self.read_exact(&mut value_buffer)?; - Ok(EncodedTerm::TypedLiteral { - datatype_id: StrHash::from_be_bytes(datatype_buffer), - value_id: StrHash::from_be_bytes(value_buffer), - }) - } - TYPE_STRING_LITERAL => { - let mut buffer = [0; 16]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::StringLiteral { - value_id: StrHash::from_be_bytes(buffer), - }) - } - TYPE_BOOLEAN_LITERAL_TRUE => Ok(EncodedTerm::BooleanLiteral(true)), - TYPE_BOOLEAN_LITERAL_FALSE => Ok(EncodedTerm::BooleanLiteral(false)), - TYPE_FLOAT_LITERAL => { - let mut buffer = [0; 4]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::FloatLiteral(f32::from_be_bytes(buffer))) - } - TYPE_DOUBLE_LITERAL => { - let mut buffer = [0; 8]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::DoubleLiteral(f64::from_be_bytes(buffer))) - } - TYPE_INTEGER_LITERAL => { - let mut buffer = [0; 8]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::IntegerLiteral(i64::from_be_bytes(buffer))) - } - TYPE_DECIMAL_LITERAL => { - let mut buffer = [0; 16]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::DecimalLiteral(Decimal::from_be_bytes(buffer))) - } - TYPE_DATE_LITERAL => { - let mut buffer = [0; 18]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::DateLiteral(Date::from_be_bytes(buffer))) - } - TYPE_TIME_LITERAL => { - let mut buffer = [0; 18]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::TimeLiteral(Time::from_be_bytes(buffer))) - } - TYPE_DATE_TIME_LITERAL => { - let mut buffer = [0; 18]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::DateTimeLiteral(DateTime::from_be_bytes( - buffer, - ))) - } - TYPE_DURATION_LITERAL => { - let mut buffer = [0; 24]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::DurationLiteral(Duration::from_be_bytes( - buffer, - ))) - } - TYPE_YEAR_MONTH_DURATION_LITERAL => { - let mut buffer = [0; 8]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::YearMonthDurationLiteral( - YearMonthDuration::from_be_bytes(buffer), - )) - } - TYPE_DAY_TIME_DURATION_LITERAL => { - let mut buffer = [0; 16]; - self.read_exact(&mut buffer)?; - Ok(EncodedTerm::DayTimeDurationLiteral( - DayTimeDuration::from_be_bytes(buffer), - )) - } - _ => Err(invalid_data_error("the term buffer has an invalid type id")), - } - } -} - -pub const WRITTEN_TERM_MAX_SIZE: usize = size_of::() + 2 * size_of::(); - -pub fn write_term(sink: &mut Vec, term: EncodedTerm) { - sink.push(term.type_id()); - match term { - EncodedTerm::DefaultGraph => {} - EncodedTerm::NamedNode { iri_id } => iri_id.push_be_bytes(sink), - EncodedTerm::InlineBlankNode { id } => sink.extend_from_slice(&id.to_be_bytes()), - EncodedTerm::NamedBlankNode { id_id } => id_id.push_be_bytes(sink), - EncodedTerm::StringLiteral { value_id } => value_id.push_be_bytes(sink), - EncodedTerm::LangStringLiteral { - value_id, - language_id, - } => { - value_id.push_be_bytes(sink); - language_id.push_be_bytes(sink); - } - EncodedTerm::TypedLiteral { - value_id, - datatype_id, - } => { - value_id.push_be_bytes(sink); - datatype_id.push_be_bytes(sink); - } - EncodedTerm::BooleanLiteral(_) => {} - EncodedTerm::FloatLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), - EncodedTerm::DoubleLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), - EncodedTerm::IntegerLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), - EncodedTerm::DecimalLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), - EncodedTerm::DateLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), - EncodedTerm::TimeLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), - EncodedTerm::DateTimeLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), - EncodedTerm::DurationLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), - EncodedTerm::YearMonthDurationLiteral(value) => { - sink.extend_from_slice(&value.to_be_bytes()) - } - EncodedTerm::DayTimeDurationLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), - } -} - pub(crate) trait WithStoreError { //TODO: rename type Error: Error + Into + 'static; @@ -776,44 +397,32 @@ pub(crate) trait StrContainer: WithStoreError { fn insert_str(&mut self, value: &str) -> Result; } +#[derive(Default)] pub struct MemoryStrStore { - id2str: HashMap, + inner: Rodeo, } -impl Default for MemoryStrStore { - fn default() -> Self { - Self { - id2str: HashMap::default(), - } - } -} +impl StrId for Spur {} impl WithStoreError for MemoryStrStore { type Error = Infallible; - type StrId = StrHash; + type StrId = Spur; } impl StrLookup for MemoryStrStore { - fn get_str(&self, id: StrHash) -> Result, Infallible> { + fn get_str(&self, id: Spur) -> Result, Infallible> { //TODO: avoid copy by adding a lifetime limit to get_str - Ok(self.id2str.get(&id).cloned()) + Ok(self.inner.try_resolve(&id).map(|e| e.to_owned())) } - fn get_str_id(&self, value: &str) -> Result, Infallible> { - let id = StrHash::new(value); - Ok(if self.id2str.contains_key(&id) { - Some(id) - } else { - None - }) + fn get_str_id(&self, value: &str) -> Result, Infallible> { + Ok(self.inner.get(value)) } } impl StrContainer for MemoryStrStore { - fn insert_str(&mut self, value: &str) -> Result { - let key = StrHash::new(value); - self.id2str.entry(key).or_insert_with(|| value.to_owned()); - Ok(key) + fn insert_str(&mut self, value: &str) -> Result { + Ok(self.inner.get_or_intern(value)) } } diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index a612d418..e9b64694 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -4,9 +4,9 @@ use crate::error::invalid_data_error; use crate::io::{DatasetFormat, GraphFormat}; use crate::model::*; use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResult, SimplePreparedQuery}; +use crate::store::binary_encoder::*; use crate::store::numeric_encoder::{ - write_term, Decoder, ReadEncoder, StrContainer, StrHash, StrLookup, TermReader, WithStoreError, - WriteEncoder, WRITTEN_TERM_MAX_SIZE, + Decoder, ReadEncoder, StrContainer, StrLookup, WithStoreError, WriteEncoder, }; use crate::store::{ dump_dataset, dump_graph, get_encoded_quad_pattern, load_dataset, load_graph, @@ -16,7 +16,7 @@ use rocksdb::*; use std::collections::HashMap; use std::convert::TryInto; use std::io; -use std::io::{BufRead, Cursor, Write}; +use std::io::{BufRead, Write}; use std::iter::{once, Once}; use std::mem::{take, transmute}; use std::path::Path; @@ -1045,36 +1045,6 @@ fn get_cf<'a>(db: &'a DB, name: &str) -> &'a ColumnFamily { .expect("A column family that should exist in RocksDB does not exist") } -fn encode_term(t: EncodedTerm) -> Vec { - let mut vec = Vec::with_capacity(WRITTEN_TERM_MAX_SIZE); - write_term(&mut vec, t); - vec -} - -fn encode_term_pair(t1: EncodedTerm, t2: EncodedTerm) -> Vec { - let mut vec = Vec::with_capacity(2 * WRITTEN_TERM_MAX_SIZE); - write_term(&mut vec, t1); - write_term(&mut vec, t2); - vec -} - -fn encode_term_triple(t1: EncodedTerm, t2: EncodedTerm, t3: EncodedTerm) -> Vec { - let mut vec = Vec::with_capacity(3 * WRITTEN_TERM_MAX_SIZE); - write_term(&mut vec, t1); - write_term(&mut vec, t2); - write_term(&mut vec, t3); - vec -} - -fn encode_term_quad(t1: EncodedTerm, t2: EncodedTerm, t3: EncodedTerm, t4: EncodedTerm) -> Vec { - let mut vec = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE); - write_term(&mut vec, t1); - write_term(&mut vec, t2); - write_term(&mut vec, t3); - write_term(&mut vec, t4); - vec -} - struct StaticDBRowIterator { iter: DBRawIterator<'static>, _db: Arc, // needed to ensure that DB still lives while iter is used @@ -1162,96 +1132,6 @@ impl Iterator for DecodingIndexIterator { } } -fn write_spog_quad(sink: &mut Vec, quad: &EncodedQuad) { - write_term(sink, quad.subject); - write_term(sink, quad.predicate); - write_term(sink, quad.object); - write_term(sink, quad.graph_name); -} - -fn write_posg_quad(sink: &mut Vec, quad: &EncodedQuad) { - write_term(sink, quad.predicate); - write_term(sink, quad.object); - write_term(sink, quad.subject); - write_term(sink, quad.graph_name); -} - -fn write_ospg_quad(sink: &mut Vec, quad: &EncodedQuad) { - write_term(sink, quad.object); - write_term(sink, quad.subject); - write_term(sink, quad.predicate); - write_term(sink, quad.graph_name); -} - -fn write_gspo_quad(sink: &mut Vec, quad: &EncodedQuad) { - write_term(sink, quad.graph_name); - write_term(sink, quad.subject); - write_term(sink, quad.predicate); - write_term(sink, quad.object); -} - -fn write_gpos_quad(sink: &mut Vec, quad: &EncodedQuad) { - write_term(sink, quad.graph_name); - write_term(sink, quad.predicate); - write_term(sink, quad.object); - write_term(sink, quad.subject); -} - -fn write_gosp_quad(sink: &mut Vec, quad: &EncodedQuad) { - write_term(sink, quad.graph_name); - write_term(sink, quad.object); - write_term(sink, quad.subject); - write_term(sink, quad.predicate); -} - -fn write_spo_quad(sink: &mut Vec, quad: &EncodedQuad) { - write_term(sink, quad.subject); - write_term(sink, quad.predicate); - write_term(sink, quad.object); -} - -fn write_pos_quad(sink: &mut Vec, quad: &EncodedQuad) { - write_term(sink, quad.predicate); - write_term(sink, quad.object); - write_term(sink, quad.subject); -} - -fn write_osp_quad(sink: &mut Vec, quad: &EncodedQuad) { - write_term(sink, quad.object); - write_term(sink, quad.subject); - write_term(sink, quad.predicate); -} - -#[derive(Clone, Copy)] -enum QuadEncoding { - SPOG, - POSG, - OSPG, - GSPO, - GPOS, - GOSP, - DSPO, - DPOS, - DOSP, -} - -impl QuadEncoding { - fn decode(self, buffer: &[u8]) -> Result { - let mut cursor = Cursor::new(&buffer); - match self { - QuadEncoding::SPOG => cursor.read_spog_quad(), - QuadEncoding::POSG => cursor.read_posg_quad(), - QuadEncoding::OSPG => cursor.read_ospg_quad(), - QuadEncoding::GSPO => cursor.read_gspo_quad(), - QuadEncoding::GPOS => cursor.read_gpos_quad(), - QuadEncoding::GOSP => cursor.read_gosp_quad(), - QuadEncoding::DSPO => cursor.read_dspo_quad(), - QuadEncoding::DPOS => cursor.read_dpos_quad(), - QuadEncoding::DOSP => cursor.read_dosp_quad(), - } - } -} - fn map_err(e: Error) -> io::Error { io::Error::new(io::ErrorKind::Other, e) } @@ -1330,6 +1210,7 @@ fn store() -> Result<(), io::Error> { store.insert(t)?; } + assert_eq!(store.len(), 4); assert_eq!( store .quads_for_pattern(None, None, None, None) @@ -1464,7 +1345,7 @@ fn store() -> Result<(), io::Error> { Some(GraphNameRef::DefaultGraph) ) .collect::, _>>()?, - vec![default_quad.clone()] + vec![default_quad] ); assert_eq!( store @@ -1475,7 +1356,7 @@ fn store() -> Result<(), io::Error> { Some(main_g.as_ref()) ) .collect::, _>>()?, - vec![named_quad.clone()] + vec![named_quad] ); } diff --git a/lib/src/store/sled.rs b/lib/src/store/sled.rs index 09003f6f..f025ebcd 100644 --- a/lib/src/store/sled.rs +++ b/lib/src/store/sled.rs @@ -4,9 +4,9 @@ use crate::error::invalid_data_error; use crate::io::{DatasetFormat, GraphFormat}; use crate::model::*; use crate::sparql::{EvaluationError, Query, QueryOptions, QueryResult, SimplePreparedQuery}; +use crate::store::binary_encoder::*; use crate::store::numeric_encoder::{ - write_term, Decoder, ReadEncoder, StrContainer, StrHash, StrLookup, TermReader, WithStoreError, - WriteEncoder, WRITTEN_TERM_MAX_SIZE, + Decoder, ReadEncoder, StrContainer, StrLookup, WithStoreError, WriteEncoder, }; use crate::store::{ dump_dataset, dump_graph, get_encoded_quad_pattern, load_dataset, load_graph, @@ -19,7 +19,7 @@ use sled::transaction::{ use sled::{Config, Iter, Tree}; use std::convert::TryInto; use std::error::Error; -use std::io::{BufRead, Cursor, Write}; +use std::io::{BufRead, Write}; use std::iter::{once, Once}; use std::path::Path; use std::{fmt, io, str}; @@ -62,15 +62,17 @@ use std::{fmt, io, str}; #[derive(Clone)] pub struct SledStore { id2str: Tree, - quads: Tree, + spog: Tree, + posg: Tree, + ospg: Tree, + gspo: Tree, + gpos: Tree, + gosp: Tree, + dspo: Tree, + dpos: Tree, + dosp: Tree, } -const SPOG_PREFIX: u8 = 1; -const POSG_PREFIX: u8 = 2; -const OSPG_PREFIX: u8 = 3; -const GSPO_PREFIX: u8 = 4; -const GPOS_PREFIX: u8 = 5; -const GOSP_PREFIX: u8 = 6; type EncodedTerm = crate::store::numeric_encoder::EncodedTerm; type EncodedQuad = crate::store::numeric_encoder::EncodedQuad; @@ -91,7 +93,15 @@ impl SledStore { let db = config.open()?; Ok(Self { id2str: db.open_tree("id2str")?, - quads: db.open_tree("quads")?, + spog: db.open_tree("spog")?, + posg: db.open_tree("posg")?, + ospg: db.open_tree("ospg")?, + gspo: db.open_tree("gspo")?, + gpos: db.open_tree("gpos")?, + gosp: db.open_tree("gosp")?, + dspo: db.open_tree("dspo")?, + dpos: db.open_tree("dpos")?, + dosp: db.open_tree("dosp")?, }) } @@ -154,12 +164,12 @@ impl SledStore { /// /// Warning: this function executes a full scan pub fn len(&self) -> usize { - self.quads.len() / 6 + self.gspo.len() + self.dspo.len() } /// Returns if the store is empty pub fn is_empty(&self) -> bool { - self.quads.is_empty() + self.gspo.is_empty() && self.dspo.is_empty() } /// Executes an ACID transaction. @@ -193,8 +203,34 @@ impl SledStore { &self, f: impl Fn(SledTransaction<'_>) -> Result>, ) -> Result> { - Ok((&self.id2str, &self.quads) - .transaction(move |(id2str, quads)| Ok(f(SledTransaction { id2str, quads })?))?) + Ok(( + &self.id2str, + &self.spog, + &self.posg, + &self.ospg, + &self.gspo, + &self.gpos, + &self.gosp, + &self.dspo, + &self.dpos, + &self.dosp, + ) + .transaction( + move |(id2str, spog, posg, ospg, gspo, gpos, gosp, dspo, dpos, dosp)| { + Ok(f(SledTransaction { + id2str, + spog, + posg, + ospg, + gspo, + gpos, + gosp, + dspo, + dpos, + dosp, + })?) + }, + )?) } /// Loads a graph file (i.e. triples) into the store @@ -301,24 +337,37 @@ impl SledStore { fn contains_encoded(&self, quad: &EncodedQuad) -> Result { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE); - write_spog_quad(&mut buffer, quad); - Ok(self.quads.contains_key(buffer)?) + if quad.graph_name.is_default_graph() { + write_spo_quad(&mut buffer, quad); + Ok(self.dspo.contains_key(buffer)?) + } else { + write_gspo_quad(&mut buffer, quad); + Ok(self.gspo.contains_key(buffer)?) + } } - - fn quads(&self) -> DecodingQuadIterator { - self.inner_quads(&[SPOG_PREFIX]) + fn quads(&self) -> DecodingQuadsIterator { + DecodingQuadsIterator::pair( + self.dspo_quads(Vec::default()), + self.gspo_quads(Vec::default()), + ) } - fn quads_for_subject(&self, subject: EncodedTerm) -> DecodingQuadIterator { - self.inner_quads(encode_term(SPOG_PREFIX, subject)) + fn quads_for_subject(&self, subject: EncodedTerm) -> DecodingQuadsIterator { + DecodingQuadsIterator::pair( + self.dspo_quads(encode_term(subject)), + self.spog_quads(encode_term(subject)), + ) } fn quads_for_subject_predicate( &self, subject: EncodedTerm, predicate: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_pair(SPOG_PREFIX, subject, predicate)) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::pair( + self.dspo_quads(encode_term_pair(subject, predicate)), + self.spog_quads(encode_term_pair(subject, predicate)), + ) } fn quads_for_subject_predicate_object( @@ -326,44 +375,67 @@ impl SledStore { subject: EncodedTerm, predicate: EncodedTerm, object: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_triple(SPOG_PREFIX, subject, predicate, object)) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::pair( + self.dspo_quads(encode_term_triple(subject, predicate, object)), + self.spog_quads(encode_term_triple(subject, predicate, object)), + ) } fn quads_for_subject_object( &self, subject: EncodedTerm, object: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_pair(OSPG_PREFIX, object, subject)) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::pair( + self.dosp_quads(encode_term_pair(object, subject)), + self.ospg_quads(encode_term_pair(object, subject)), + ) } - fn quads_for_predicate(&self, predicate: EncodedTerm) -> DecodingQuadIterator { - self.inner_quads(encode_term(POSG_PREFIX, predicate)) + fn quads_for_predicate(&self, predicate: EncodedTerm) -> DecodingQuadsIterator { + DecodingQuadsIterator::pair( + self.dpos_quads(encode_term(predicate)), + self.posg_quads(encode_term(predicate)), + ) } fn quads_for_predicate_object( &self, predicate: EncodedTerm, object: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_pair(POSG_PREFIX, predicate, object)) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::pair( + self.dpos_quads(encode_term_pair(predicate, object)), + self.posg_quads(encode_term_pair(predicate, object)), + ) } - fn quads_for_object(&self, object: EncodedTerm) -> DecodingQuadIterator { - self.inner_quads(encode_term(OSPG_PREFIX, object)) + fn quads_for_object(&self, object: EncodedTerm) -> DecodingQuadsIterator { + DecodingQuadsIterator::pair( + self.dosp_quads(encode_term(object)), + self.ospg_quads(encode_term(object)), + ) } - fn quads_for_graph(&self, graph_name: EncodedTerm) -> DecodingQuadIterator { - self.inner_quads(encode_term(GSPO_PREFIX, graph_name)) + fn quads_for_graph(&self, graph_name: EncodedTerm) -> DecodingQuadsIterator { + DecodingQuadsIterator::new(if graph_name.is_default_graph() { + self.dspo_quads(Vec::default()) + } else { + self.gspo_quads(encode_term(graph_name)) + }) } fn quads_for_subject_graph( &self, subject: EncodedTerm, graph_name: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_pair(GSPO_PREFIX, graph_name, subject)) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::new(if graph_name.is_default_graph() { + self.dspo_quads(encode_term(subject)) + } else { + self.gspo_quads(encode_term_pair(graph_name, subject)) + }) } fn quads_for_subject_predicate_graph( @@ -371,13 +443,26 @@ impl SledStore { subject: EncodedTerm, predicate: EncodedTerm, graph_name: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_triple( - GSPO_PREFIX, - graph_name, - subject, - predicate, - )) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::new(if graph_name.is_default_graph() { + self.dspo_quads(encode_term_pair(subject, predicate)) + } else { + self.gspo_quads(encode_term_triple(graph_name, subject, predicate)) + }) + } + + fn quads_for_subject_predicate_object_graph( + &self, + subject: EncodedTerm, + predicate: EncodedTerm, + object: EncodedTerm, + graph_name: EncodedTerm, + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::new(if graph_name.is_default_graph() { + self.dspo_quads(encode_term_triple(subject, predicate, object)) + } else { + self.gspo_quads(encode_term_quad(graph_name, subject, predicate, object)) + }) } fn quads_for_subject_object_graph( @@ -385,16 +470,24 @@ impl SledStore { subject: EncodedTerm, object: EncodedTerm, graph_name: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_triple(GOSP_PREFIX, graph_name, object, subject)) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::new(if graph_name.is_default_graph() { + self.dosp_quads(encode_term_pair(object, subject)) + } else { + self.gosp_quads(encode_term_triple(graph_name, object, subject)) + }) } fn quads_for_predicate_graph( &self, predicate: EncodedTerm, graph_name: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_pair(GPOS_PREFIX, graph_name, predicate)) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::new(if graph_name.is_default_graph() { + self.dpos_quads(encode_term(predicate)) + } else { + self.gpos_quads(encode_term_pair(graph_name, predicate)) + }) } fn quads_for_predicate_object_graph( @@ -402,26 +495,71 @@ impl SledStore { predicate: EncodedTerm, object: EncodedTerm, graph_name: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_triple( - GPOS_PREFIX, - graph_name, - predicate, - object, - )) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::new(if graph_name.is_default_graph() { + self.dpos_quads(encode_term_pair(predicate, object)) + } else { + self.gpos_quads(encode_term_triple(graph_name, predicate, object)) + }) } fn quads_for_object_graph( &self, object: EncodedTerm, graph_name: EncodedTerm, - ) -> DecodingQuadIterator { - self.inner_quads(encode_term_pair(GPOS_PREFIX, graph_name, object)) + ) -> DecodingQuadsIterator { + DecodingQuadsIterator::new(if graph_name.is_default_graph() { + self.dosp_quads(encode_term(object)) + } else { + self.gosp_quads(encode_term_pair(graph_name, object)) + }) + } + + fn spog_quads(&self, prefix: Vec) -> DecodingQuadIterator { + self.inner_quads(&self.spog, prefix, QuadEncoding::SPOG) + } + + fn posg_quads(&self, prefix: Vec) -> DecodingQuadIterator { + self.inner_quads(&self.posg, prefix, QuadEncoding::POSG) + } + + fn ospg_quads(&self, prefix: Vec) -> DecodingQuadIterator { + self.inner_quads(&self.ospg, prefix, QuadEncoding::OSPG) + } + + fn gspo_quads(&self, prefix: Vec) -> DecodingQuadIterator { + self.inner_quads(&self.gspo, prefix, QuadEncoding::GSPO) } - fn inner_quads(&self, prefix: impl AsRef<[u8]>) -> DecodingQuadIterator { + fn gpos_quads(&self, prefix: Vec) -> DecodingQuadIterator { + self.inner_quads(&self.gpos, prefix, QuadEncoding::GPOS) + } + + fn gosp_quads(&self, prefix: Vec) -> DecodingQuadIterator { + self.inner_quads(&self.gosp, prefix, QuadEncoding::GOSP) + } + + fn dspo_quads(&self, prefix: Vec) -> DecodingQuadIterator { + self.inner_quads(&self.dspo, prefix, QuadEncoding::DSPO) + } + + fn dpos_quads(&self, prefix: Vec) -> DecodingQuadIterator { + self.inner_quads(&self.dpos, prefix, QuadEncoding::DPOS) + } + + fn dosp_quads(&self, prefix: Vec) -> DecodingQuadIterator { + self.inner_quads(&self.dosp, prefix, QuadEncoding::DOSP) + } + + fn inner_quads( + &self, + tree: &Tree, + prefix: impl AsRef<[u8]>, + encoding: QuadEncoding, + ) -> DecodingQuadIterator { DecodingQuadIterator { - iter: self.quads.scan_prefix(prefix), + iter: tree.scan_prefix(prefix), + encoding, } } } @@ -460,7 +598,7 @@ impl StrLookup for SledStore { } impl ReadableEncodedStore for SledStore { - type QuadsIter = DecodingQuadIterator; + type QuadsIter = DecodingQuadsIterator; fn encoded_quads_for_pattern( &self, @@ -468,18 +606,14 @@ impl ReadableEncodedStore for SledStore { predicate: Option, object: Option, graph_name: Option, - ) -> DecodingQuadIterator { + ) -> DecodingQuadsIterator { match subject { Some(subject) => match predicate { Some(predicate) => match object { Some(object) => match graph_name { - Some(graph_name) => self.inner_quads(encode_term_quad( - SPOG_PREFIX, - subject, - predicate, - object, - graph_name, - )), + Some(graph_name) => self.quads_for_subject_predicate_object_graph( + subject, predicate, object, graph_name, + ), None => self.quads_for_subject_predicate_object(subject, predicate, object), }, None => match graph_name { @@ -542,29 +676,43 @@ impl<'a> WritableEncodedStore for &'a SledStore { fn insert_encoded(&mut self, quad: &EncodedQuad) -> Result<(), io::Error> { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE + 1); - write_spog_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + if quad.graph_name.is_default_graph() { + write_spo_quad(&mut buffer, quad); + self.dspo.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_posg_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_pos_quad(&mut buffer, quad); + self.dpos.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_ospg_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_osp_quad(&mut buffer, quad); + self.dosp.insert(buffer.as_slice(), &[])?; + buffer.clear(); + } else { + write_spog_quad(&mut buffer, quad); + self.spog.insert(buffer.as_slice(), &[])?; + buffer.clear(); + + write_posg_quad(&mut buffer, quad); + self.posg.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gspo_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_ospg_quad(&mut buffer, quad); + self.ospg.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gpos_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_gspo_quad(&mut buffer, quad); + self.gspo.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gosp_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_gpos_quad(&mut buffer, quad); + self.gpos.insert(buffer.as_slice(), &[])?; + buffer.clear(); + + write_gosp_quad(&mut buffer, quad); + self.gosp.insert(buffer.as_slice(), &[])?; + buffer.clear(); + } Ok(()) } @@ -572,29 +720,43 @@ impl<'a> WritableEncodedStore for &'a SledStore { fn remove_encoded(&mut self, quad: &EncodedQuad) -> Result<(), io::Error> { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE + 1); - write_spog_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + if quad.graph_name.is_default_graph() { + write_spo_quad(&mut buffer, quad); + self.dspo.remove(buffer.as_slice())?; + buffer.clear(); - write_posg_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_pos_quad(&mut buffer, quad); + self.dpos.remove(buffer.as_slice())?; + buffer.clear(); - write_ospg_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_osp_quad(&mut buffer, quad); + self.dosp.remove(buffer.as_slice())?; + buffer.clear(); + } else { + write_spog_quad(&mut buffer, quad); + self.spog.remove(buffer.as_slice())?; + buffer.clear(); + + write_posg_quad(&mut buffer, quad); + self.posg.remove(buffer.as_slice())?; + buffer.clear(); - write_gspo_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_ospg_quad(&mut buffer, quad); + self.ospg.remove(buffer.as_slice())?; + buffer.clear(); - write_gpos_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_gspo_quad(&mut buffer, quad); + self.gspo.remove(buffer.as_slice())?; + buffer.clear(); - write_gosp_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_gpos_quad(&mut buffer, quad); + self.gpos.remove(buffer.as_slice())?; + buffer.clear(); + + write_gosp_quad(&mut buffer, quad); + self.gosp.remove(buffer.as_slice())?; + buffer.clear(); + } Ok(()) } @@ -602,8 +764,16 @@ impl<'a> WritableEncodedStore for &'a SledStore { /// Allows inserting and deleting quads during an ACID transaction with the [`SledStore`](struct.SledStore.html). pub struct SledTransaction<'a> { - quads: &'a TransactionalTree, id2str: &'a TransactionalTree, + spog: &'a TransactionalTree, + posg: &'a TransactionalTree, + ospg: &'a TransactionalTree, + gspo: &'a TransactionalTree, + gpos: &'a TransactionalTree, + gosp: &'a TransactionalTree, + dspo: &'a TransactionalTree, + dpos: &'a TransactionalTree, + dosp: &'a TransactionalTree, } impl SledTransaction<'_> { @@ -721,29 +891,43 @@ impl<'a> WritableEncodedStore for &'a SledTransaction<'a> { ) -> Result<(), SledUnabortableTransactionError> { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE + 1); - write_spog_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + if quad.graph_name.is_default_graph() { + write_spo_quad(&mut buffer, quad); + self.dspo.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_posg_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_pos_quad(&mut buffer, quad); + self.dpos.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_ospg_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_osp_quad(&mut buffer, quad); + self.dosp.insert(buffer.as_slice(), &[])?; + buffer.clear(); + } else { + write_spog_quad(&mut buffer, quad); + self.spog.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gspo_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_posg_quad(&mut buffer, quad); + self.posg.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gpos_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_ospg_quad(&mut buffer, quad); + self.ospg.insert(buffer.as_slice(), &[])?; + buffer.clear(); - write_gosp_quad(&mut buffer, quad); - self.quads.insert(buffer.as_slice(), &[])?; - buffer.clear(); + write_gspo_quad(&mut buffer, quad); + self.gspo.insert(buffer.as_slice(), &[])?; + buffer.clear(); + + write_gpos_quad(&mut buffer, quad); + self.gpos.insert(buffer.as_slice(), &[])?; + buffer.clear(); + + write_gosp_quad(&mut buffer, quad); + self.gosp.insert(buffer.as_slice(), &[])?; + buffer.clear(); + } Ok(()) } @@ -754,29 +938,43 @@ impl<'a> WritableEncodedStore for &'a SledTransaction<'a> { ) -> Result<(), SledUnabortableTransactionError> { let mut buffer = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE + 1); - write_spog_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + if quad.graph_name.is_default_graph() { + write_spo_quad(&mut buffer, quad); + self.dspo.remove(buffer.as_slice())?; + buffer.clear(); + + write_pos_quad(&mut buffer, quad); + self.dpos.remove(buffer.as_slice())?; + buffer.clear(); - write_posg_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_osp_quad(&mut buffer, quad); + self.dosp.remove(buffer.as_slice())?; + buffer.clear(); + } else { + write_spog_quad(&mut buffer, quad); + self.spog.remove(buffer.as_slice())?; + buffer.clear(); + + write_posg_quad(&mut buffer, quad); + self.posg.remove(buffer.as_slice())?; + buffer.clear(); - write_ospg_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_ospg_quad(&mut buffer, quad); + self.ospg.remove(buffer.as_slice())?; + buffer.clear(); - write_gspo_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_gspo_quad(&mut buffer, quad); + self.gspo.remove(buffer.as_slice())?; + buffer.clear(); - write_gpos_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_gpos_quad(&mut buffer, quad); + self.gpos.remove(buffer.as_slice())?; + buffer.clear(); - write_gosp_quad(&mut buffer, quad); - self.quads.remove(buffer.as_slice())?; - buffer.clear(); + write_gosp_quad(&mut buffer, quad); + self.gosp.remove(buffer.as_slice())?; + buffer.clear(); + } Ok(()) } @@ -937,48 +1135,44 @@ impl SledPreparedQuery { } } -fn encode_term(prefix: u8, t: EncodedTerm) -> Vec { - let mut vec = Vec::with_capacity(WRITTEN_TERM_MAX_SIZE + 1); - vec.push(prefix); - write_term(&mut vec, t); - vec +pub(crate) struct DecodingQuadsIterator { + first: DecodingQuadIterator, + second: Option, } -fn encode_term_pair(prefix: u8, t1: EncodedTerm, t2: EncodedTerm) -> Vec { - let mut vec = Vec::with_capacity(2 * WRITTEN_TERM_MAX_SIZE + 1); - vec.push(prefix); - write_term(&mut vec, t1); - write_term(&mut vec, t2); - vec -} +impl DecodingQuadsIterator { + fn new(first: DecodingQuadIterator) -> Self { + Self { + first, + second: None, + } + } -fn encode_term_triple(prefix: u8, t1: EncodedTerm, t2: EncodedTerm, t3: EncodedTerm) -> Vec { - let mut vec = Vec::with_capacity(3 * WRITTEN_TERM_MAX_SIZE + 1); - vec.push(prefix); - write_term(&mut vec, t1); - write_term(&mut vec, t2); - write_term(&mut vec, t3); - vec + fn pair(first: DecodingQuadIterator, second: DecodingQuadIterator) -> Self { + Self { + first, + second: Some(second), + } + } } -fn encode_term_quad( - prefix: u8, - t1: EncodedTerm, - t2: EncodedTerm, - t3: EncodedTerm, - t4: EncodedTerm, -) -> Vec { - let mut vec = Vec::with_capacity(4 * WRITTEN_TERM_MAX_SIZE + 1); - vec.push(prefix); - write_term(&mut vec, t1); - write_term(&mut vec, t2); - write_term(&mut vec, t3); - write_term(&mut vec, t4); - vec +impl Iterator for DecodingQuadsIterator { + type Item = Result; + + fn next(&mut self) -> Option> { + if let Some(result) = self.first.next() { + Some(result) + } else if let Some(second) = self.second.as_mut() { + second.next() + } else { + None + } + } } pub(crate) struct DecodingQuadIterator { iter: Iter, + encoding: QuadEncoding, } impl Iterator for DecodingQuadIterator { @@ -986,79 +1180,15 @@ impl Iterator for DecodingQuadIterator { fn next(&mut self) -> Option> { Some(match self.iter.next()? { - Ok((encoded, _)) => decode_quad(&encoded), + Ok((encoded, _)) => self.encoding.decode(&encoded), Err(error) => Err(error.into()), }) } } -fn write_spog_quad(sink: &mut Vec, quad: &EncodedQuad) { - sink.push(SPOG_PREFIX); - write_term(sink, quad.subject); - write_term(sink, quad.predicate); - write_term(sink, quad.object); - write_term(sink, quad.graph_name); -} - -fn write_posg_quad(sink: &mut Vec, quad: &EncodedQuad) { - sink.push(POSG_PREFIX); - write_term(sink, quad.predicate); - write_term(sink, quad.object); - write_term(sink, quad.subject); - write_term(sink, quad.graph_name); -} - -fn write_ospg_quad(sink: &mut Vec, quad: &EncodedQuad) { - sink.push(OSPG_PREFIX); - write_term(sink, quad.object); - write_term(sink, quad.subject); - write_term(sink, quad.predicate); - write_term(sink, quad.graph_name); -} - -fn write_gspo_quad(sink: &mut Vec, quad: &EncodedQuad) { - sink.push(GSPO_PREFIX); - write_term(sink, quad.graph_name); - write_term(sink, quad.subject); - write_term(sink, quad.predicate); - write_term(sink, quad.object); -} - -fn write_gpos_quad(sink: &mut Vec, quad: &EncodedQuad) { - sink.push(GPOS_PREFIX); - write_term(sink, quad.graph_name); - write_term(sink, quad.predicate); - write_term(sink, quad.object); - write_term(sink, quad.subject); -} - -fn write_gosp_quad(sink: &mut Vec, quad: &EncodedQuad) { - sink.push(GOSP_PREFIX); - write_term(sink, quad.graph_name); - write_term(sink, quad.object); - write_term(sink, quad.subject); - write_term(sink, quad.predicate); -} - -fn decode_quad(encoded: &[u8]) -> Result { - let mut cursor = Cursor::new(&encoded[1..]); - match encoded[0] { - SPOG_PREFIX => Ok(cursor.read_spog_quad()?), - POSG_PREFIX => Ok(cursor.read_posg_quad()?), - OSPG_PREFIX => Ok(cursor.read_ospg_quad()?), - GSPO_PREFIX => Ok(cursor.read_gspo_quad()?), - GPOS_PREFIX => Ok(cursor.read_gpos_quad()?), - GOSP_PREFIX => Ok(cursor.read_gosp_quad()?), - _ => Err(invalid_data_error(format!( - "Invalid quad type identifier: {}", - encoded[0] - ))), - } -} - enum QuadsIter { Quads { - iter: DecodingQuadIterator, + iter: DecodingQuadsIterator, store: SledStore, }, Error(Once), @@ -1087,38 +1217,60 @@ fn store() -> Result<(), io::Error> { let main_s = NamedOrBlankNode::from(BlankNode::default()); let main_p = NamedNode::new("http://example.com").unwrap(); let main_o = Term::from(Literal::from(1)); - - let main_quad = Quad::new(main_s.clone(), main_p.clone(), main_o.clone(), None); - let all_o = vec![ + let main_g = GraphName::from(BlankNode::default()); + + let default_quad = Quad::new(main_s.clone(), main_p.clone(), main_o.clone(), None); + let named_quad = Quad::new( + main_s.clone(), + main_p.clone(), + main_o.clone(), + main_g.clone(), + ); + let default_quads = vec![ + Quad::new(main_s.clone(), main_p.clone(), Literal::from(0), None), + default_quad.clone(), + Quad::new( + main_s.clone(), + main_p.clone(), + Literal::from(200000000), + None, + ), + ]; + let all_quads = vec![ Quad::new(main_s.clone(), main_p.clone(), Literal::from(0), None), - Quad::new(main_s.clone(), main_p.clone(), main_o.clone(), None), - Quad::new(main_s.clone(), main_p.clone(), Literal::from(2), None), + default_quad.clone(), + Quad::new( + main_s.clone(), + main_p.clone(), + Literal::from(200000000), + None, + ), + named_quad.clone(), ]; let store = SledStore::new()?; - store.insert(&main_quad)?; - for t in &all_o { + for t in &all_quads { store.insert(t)?; } - let target = vec![main_quad]; + assert_eq!(store.len(), 4); assert_eq!( store .quads_for_pattern(None, None, None, None) .collect::, _>>()?, - all_o + all_quads ); assert_eq!( store .quads_for_pattern(Some(main_s.as_ref()), None, None, None) .collect::, _>>()?, - all_o + all_quads ); assert_eq!( store .quads_for_pattern(Some(main_s.as_ref()), Some(main_p.as_ref()), None, None) .collect::, _>>()?, - all_o + all_quads ); assert_eq!( store @@ -1129,7 +1281,7 @@ fn store() -> Result<(), io::Error> { None ) .collect::, _>>()?, - target + vec![default_quad.clone(), named_quad.clone()] ); assert_eq!( store @@ -1140,7 +1292,18 @@ fn store() -> Result<(), io::Error> { Some(GraphNameRef::DefaultGraph) ) .collect::, _>>()?, - target + vec![default_quad.clone()] + ); + assert_eq!( + store + .quads_for_pattern( + Some(main_s.as_ref()), + Some(main_p.as_ref()), + Some(main_o.as_ref()), + Some(main_g.as_ref()) + ) + .collect::, _>>()?, + vec![named_quad.clone()] ); assert_eq!( store @@ -1151,13 +1314,13 @@ fn store() -> Result<(), io::Error> { Some(GraphNameRef::DefaultGraph) ) .collect::, _>>()?, - all_o + default_quads ); assert_eq!( store .quads_for_pattern(Some(main_s.as_ref()), None, Some(main_o.as_ref()), None) .collect::, _>>()?, - target + vec![default_quad.clone(), named_quad.clone()] ); assert_eq!( store @@ -1168,7 +1331,18 @@ fn store() -> Result<(), io::Error> { Some(GraphNameRef::DefaultGraph) ) .collect::, _>>()?, - target + vec![default_quad.clone()] + ); + assert_eq!( + store + .quads_for_pattern( + Some(main_s.as_ref()), + None, + Some(main_o.as_ref()), + Some(main_g.as_ref()) + ) + .collect::, _>>()?, + vec![named_quad.clone()] ); assert_eq!( store @@ -1179,31 +1353,31 @@ fn store() -> Result<(), io::Error> { Some(GraphNameRef::DefaultGraph) ) .collect::, _>>()?, - all_o + default_quads ); assert_eq!( store .quads_for_pattern(None, Some(main_p.as_ref()), None, None) .collect::, _>>()?, - all_o + all_quads ); assert_eq!( store .quads_for_pattern(None, Some(main_p.as_ref()), Some(main_o.as_ref()), None) .collect::, _>>()?, - target + vec![default_quad.clone(), named_quad.clone()] ); assert_eq!( store .quads_for_pattern(None, None, Some(main_o.as_ref()), None) .collect::, _>>()?, - target + vec![default_quad.clone(), named_quad.clone()] ); assert_eq!( store .quads_for_pattern(None, None, None, Some(GraphNameRef::DefaultGraph)) .collect::, _>>()?, - all_o + default_quads ); assert_eq!( store @@ -1214,7 +1388,18 @@ fn store() -> Result<(), io::Error> { Some(GraphNameRef::DefaultGraph) ) .collect::, _>>()?, - target + vec![default_quad] + ); + assert_eq!( + store + .quads_for_pattern( + None, + Some(main_p.as_ref()), + Some(main_o.as_ref()), + Some(main_g.as_ref()) + ) + .collect::, _>>()?, + vec![named_quad] ); Ok(())