#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
use super::io::RdfParseError;
use super::io::{RdfFormat, RdfParser, RdfSerializer};
use super::model::*;
use super::sparql::{
evaluate_query, evaluate_update, EvaluationError, Query, QueryExplanation, QueryOptions,
QueryResults, Update, UpdateOptions,
};
use super::storage::numeric_encoder::{Decoder, EncodedQuad, EncodedTerm, StrHash};
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
use super::storage::StorageBulkLoader;
pub use super::storage::{CorruptionError, LoaderError, SerializerError, StorageError};
use super::storage::{DecodingGraphIterator, Storage, StorageReader, StorageWriter};
use std::collections::HashSet;
use std::error::Error;
use std::io::{Read, Write};
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
use std::path::Path;
use std::{fmt, str};
#[derive(Clone)]
pub struct Store {
storage: Storage,
}
impl Store {
pub fn new() -> Result<Self, StorageError> {
Ok(Self {
storage: Storage::new()?,
})
}
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
pub fn open(path: impl AsRef<Path>) -> Result<Self, StorageError> {
Ok(Self {
storage: Storage::open(path.as_ref(), None)?,
})
}
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
pub fn open_with_key(path: impl AsRef<Path>, key: [u8; 32]) -> Result<Self, StorageError> {
Ok(Self {
storage: Storage::open(path.as_ref(), Some(key))?,
})
}
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
pub fn open_read_only(
path: impl AsRef<Path>,
key: Option<[u8; 32]>,
) -> Result<Self, StorageError> {
Ok(Self {
storage: Storage::open_read_only(path.as_ref(), key)?,
})
}
pub fn query(
&self,
query: impl TryInto<Query, Error = impl Into<EvaluationError>>,
default_graph: Option<String>,
) -> Result<QueryResults, EvaluationError> {
let mut opts = QueryOptions::default();
opts.set_default_graph(default_graph);
self.query_opt(query, opts)
}
pub fn query_opt(
&self,
query: impl TryInto<Query, Error = impl Into<EvaluationError>>,
options: QueryOptions,
) -> Result<QueryResults, EvaluationError> {
let (results, _) = self.explain_query_opt(query, options, false)?;
results
}
pub fn explain_query_opt(
&self,
query: impl TryInto<Query, Error = impl Into<EvaluationError>>,
options: QueryOptions,
with_stats: bool,
) -> Result<(Result<QueryResults, EvaluationError>, QueryExplanation), EvaluationError> {
evaluate_query(self.storage.snapshot(), query, options, with_stats)
}
pub fn quads_for_pattern(
&self,
subject: Option<SubjectRef<'_>>,
predicate: Option<NamedNodeRef<'_>>,
object: Option<TermRef<'_>>,
graph_name: Option<GraphNameRef<'_>>,
) -> QuadIter {
let reader = self.storage.snapshot();
let match_by = if graph_name.is_some() {
if let GraphName::NamedNode(nn) = graph_name.unwrap().into_owned() {
match reader.parse_graph_name(nn.as_string(), None) {
Err(e) => {
return QuadIter {
iter: OneErrorQuadIter::new_boxed(e),
reader,
}
}
Ok(o) => Some(o),
}
} else {
panic!("invalid graph name");
}
} else {
None
};
QuadIter {
iter: reader.quads_for_pattern(
subject.map(EncodedTerm::from).as_ref(),
predicate.map(EncodedTerm::from).as_ref(),
object.map(EncodedTerm::from).as_ref(),
match_by,
),
reader,
}
}
pub fn iter(&self) -> QuadIter {
self.quads_for_pattern(None, None, None, None)
}
pub fn contains<'a>(&self, quad: impl Into<QuadRef<'a>>) -> Result<bool, StorageError> {
let quad = EncodedQuad::from(quad.into());
self.storage.snapshot().contains(&quad)
}
pub fn len(&self) -> Result<usize, StorageError> {
self.storage.snapshot().len()
}
pub fn is_empty(&self) -> Result<bool, StorageError> {
self.storage.snapshot().is_empty()
}
fn transaction<'a, 'b: 'a, T, E: Error + 'static + From<StorageError>>(
&'b self,
mut f: impl FnMut(Transaction<'a>) -> Result<T, E>,
) -> Result<T, E> {
self.storage
.ng_transaction(|writer| f(Transaction { writer }))
}
pub fn ng_update(
&self,
update: impl TryInto<Update, Error = impl Into<EvaluationError>>,
default_graph: Option<String>,
) -> Result<(HashSet<Quad>, HashSet<Quad>), EvaluationError> {
let mut opts = UpdateOptions::default();
opts.set_default_graph(default_graph);
self.ng_update_opt(update, opts)
}
pub fn ng_update_opt(
&self,
update: impl TryInto<Update, Error = impl Into<EvaluationError>>,
options: impl Into<UpdateOptions>,
) -> Result<(HashSet<Quad>, HashSet<Quad>), EvaluationError> {
let update = update.try_into().map_err(Into::into)?;
let options = options.into();
self.storage.transaction(|mut t| {
evaluate_update(&mut t, &update, &options)?;
Ok(t.get_update())
})
}
#[doc(hidden)]
pub fn ng_transaction<'a, 'b: 'a, T, E: Error + 'static + From<StorageError>>(
&'b self,
mut f: impl FnMut(Transaction<'a>) -> Result<T, E>,
) -> Result<T, E> {
self.storage
.ng_transaction(|writer| f(Transaction { writer }))
}
pub fn load_from_read(
&self,
parser: impl Into<RdfParser>,
read: impl Read,
) -> Result<(), LoaderError> {
unimplemented!();
let quads = parser
.into()
.rename_blank_nodes()
.parse_read(read)
.collect::<Result<Vec<_>, _>>()?;
self.storage.transaction(move |mut t| {
for quad in &quads {
t.insert(quad.as_ref())?;
}
Ok(())
})
}
#[deprecated(note = "use Store.load_from_read instead", since = "0.4.0")]
pub fn load_graph(
&self,
read: impl Read,
format: impl Into<RdfFormat>,
to_graph_name: impl Into<GraphName>,
base_iri: Option<&str>,
) -> Result<(), LoaderError> {
let mut parser = RdfParser::from_format(format.into())
.without_named_graphs()
.with_default_graph(to_graph_name);
if let Some(base_iri) = base_iri {
parser = parser
.with_base_iri(base_iri)
.map_err(|e| LoaderError::InvalidBaseIri {
iri: base_iri.into(),
error: e,
})?;
}
self.load_from_read(parser, read)
}
#[deprecated(note = "use Store.load_from_read instead", since = "0.4.0")]
pub fn load_dataset(
&self,
read: impl Read,
format: impl Into<RdfFormat>,
base_iri: Option<&str>,
) -> Result<(), LoaderError> {
let mut parser = RdfParser::from_format(format.into());
if let Some(base_iri) = base_iri {
parser = parser
.with_base_iri(base_iri)
.map_err(|e| LoaderError::InvalidBaseIri {
iri: base_iri.into(),
error: e,
})?;
}
self.load_from_read(parser, read)
}
pub fn remove<'a>(&self, quad: impl Into<QuadRef<'a>>) -> Result<bool, StorageError> {
unimplemented!();
let quad = quad.into();
self.transaction(move |mut t| t.remove(quad))
}
pub fn dump_to_write<W: Write>(
&self,
serializer: impl Into<RdfSerializer>,
write: W,
) -> Result<W, SerializerError> {
let serializer = serializer.into();
if !serializer.format().supports_datasets() {
return Err(SerializerError::DatasetFormatExpected(serializer.format()));
}
let mut writer = serializer.serialize_to_write(write);
for quad in self {
writer.write_quad(&quad?)?;
}
Ok(writer.finish()?)
}
pub fn dump_graph_to_write<'a, W: Write>(
&self,
from_graph_name: impl Into<GraphNameRef<'a>>,
serializer: impl Into<RdfSerializer>,
write: W,
) -> Result<W, SerializerError> {
let mut writer = serializer.into().serialize_to_write(write);
for quad in self.quads_for_pattern(None, None, None, Some(from_graph_name.into())) {
writer.write_triple(quad?.as_ref())?;
}
Ok(writer.finish()?)
}
#[deprecated(note = "use Store.dump_graph_to_write instead", since = "0.4.0")]
pub fn dump_graph<'a, W: Write>(
&self,
write: W,
format: impl Into<RdfFormat>,
from_graph_name: impl Into<GraphNameRef<'a>>,
) -> Result<W, SerializerError> {
self.dump_graph_to_write(from_graph_name, format.into(), write)
}
#[deprecated(note = "use Store.dump_to_write instead", since = "0.4.0")]
pub fn dump_dataset<W: Write>(
&self,
write: W,
format: impl Into<RdfFormat>,
) -> Result<W, SerializerError> {
self.dump_to_write(format.into(), write)
}
pub fn clear_graph<'a>(
&self,
graph_name: impl Into<GraphNameRef<'a>>,
) -> Result<(), StorageError> {
let graph_name = graph_name.into();
self.transaction(|mut t| t.clear_graph(graph_name))
}
pub fn remove_named_graph<'a>(
&self,
graph_name: impl Into<NamedOrBlankNodeRef<'a>>,
) -> Result<bool, StorageError> {
let graph_name = graph_name.into();
self.transaction(|mut t| t.remove_named_graph(graph_name))
}
pub fn clear(&self) -> Result<(), StorageError> {
self.transaction(|mut t| t.clear())
}
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
pub fn flush(&self) -> Result<(), StorageError> {
self.storage.flush()
}
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
pub fn optimize(&self) -> Result<(), StorageError> {
self.storage.compact()
}
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
pub fn backup(&self, target_directory: impl AsRef<Path>) -> Result<(), StorageError> {
self.storage.backup(target_directory.as_ref())
}
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
pub fn bulk_loader(&self) -> BulkLoader {
BulkLoader {
storage: StorageBulkLoader::new(self.storage.clone()),
on_parse_error: None,
}
}
#[doc(hidden)]
pub fn validate(&self) -> Result<(), StorageError> {
self.storage.snapshot().validate()
}
}
impl fmt::Display for Store {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for t in self {
writeln!(f, "{} .", t.map_err(|_| fmt::Error)?)?;
}
Ok(())
}
}
impl IntoIterator for &Store {
type IntoIter = QuadIter;
type Item = Result<Quad, StorageError>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct Transaction<'a> {
writer: StorageWriter<'a>,
}
impl<'a> Transaction<'a> {
pub fn query(
&self,
query: impl TryInto<Query, Error = impl Into<EvaluationError>>,
) -> Result<QueryResults, EvaluationError> {
self.query_opt(query, QueryOptions::default())
}
pub fn query_opt(
&self,
query: impl TryInto<Query, Error = impl Into<EvaluationError>>,
options: QueryOptions,
) -> Result<QueryResults, EvaluationError> {
let (results, _) = evaluate_query(self.writer.reader(), query, options, false)?;
results
}
pub fn quads_for_pattern(
&self,
subject: Option<SubjectRef<'_>>,
predicate: Option<NamedNodeRef<'_>>,
object: Option<TermRef<'_>>,
graph_name: Option<GraphNameRef<'_>>,
) -> QuadIter {
let reader = self.writer.reader();
let match_by = if graph_name.is_some() {
if let GraphName::NamedNode(nn) = graph_name.unwrap().into_owned() {
match reader.parse_graph_name(nn.as_string(), None) {
Err(e) => {
return QuadIter {
iter: OneErrorQuadIter::new_boxed(e),
reader,
}
}
Ok(o) => Some(o),
}
} else {
panic!("invalid graph name");
}
} else {
None
};
QuadIter {
iter: reader.quads_for_pattern(
subject.map(EncodedTerm::from).as_ref(),
predicate.map(EncodedTerm::from).as_ref(),
object.map(EncodedTerm::from).as_ref(),
match_by,
),
reader,
}
}
pub fn iter(&self) -> QuadIter {
self.quads_for_pattern(None, None, None, None)
}
pub fn contains<'b>(&self, quad: impl Into<QuadRef<'b>>) -> Result<bool, StorageError> {
let quad = EncodedQuad::from(quad.into());
self.writer.reader().contains(&quad)
}
pub fn len(&self) -> Result<usize, StorageError> {
self.writer.reader().len()
}
pub fn is_empty(&self) -> Result<bool, StorageError> {
self.writer.reader().is_empty()
}
pub fn ng_get_heads(
&self,
topic: &StrHash,
overlay: &StrHash,
) -> Result<HashSet<StrHash>, StorageError> {
self.writer.reader().ng_get_heads(topic, overlay)
}
pub fn ng_get_reader(&self) -> StorageReader {
self.writer.reader()
}
pub fn update_heads(
&mut self,
topic: &StrHash,
overlay: &StrHash,
commit: &StrHash,
direct_causal_past: &HashSet<StrHash>,
) -> Result<(), StorageError> {
self.writer
.ng_update_heads(topic, overlay, commit, direct_causal_past)
}
pub fn update_past(
&mut self,
commit: &StrHash,
direct_causal_past: &HashSet<StrHash>,
skip_has_no_graph: bool,
) -> Result<(), StorageError> {
self.writer
.ng_update_past(commit, direct_causal_past, skip_has_no_graph)
}
pub fn update_branch_and_token(
&mut self,
overlay_encoded: &StrHash,
branch_encoded: &StrHash,
topic_encoded: &StrHash,
token_encoded: &StrHash,
) -> Result<(), StorageError> {
self.writer.update_branch_and_token(
overlay_encoded,
branch_encoded,
topic_encoded,
token_encoded,
)
}
pub fn doc_in_store(
&mut self,
graph_name: NamedNodeRef<'_>,
overlay: &StrHash,
remove: bool,
) -> Result<(), StorageError> {
self.writer.doc_in_store(graph_name, overlay, remove)
}
pub fn named_commit_or_branch(
&mut self,
ov_graph_name: NamedNodeRef<'_>,
name: &String,
value: &Option<Vec<u8>>,
) -> Result<(), StorageError> {
self.writer
.named_commit_or_branch(ov_graph_name, name, value)
}
pub fn insert<'b>(
&mut self,
quad: impl Into<QuadRef<'b>>,
value: u8,
cv: bool,
) -> Result<(), StorageError> {
self.writer.ng_insert(quad.into(), value, cv)
}
pub fn insert_encoded(
&mut self,
encoded: &EncodedQuad,
value: u8,
cv: bool,
) -> Result<bool, StorageError> {
self.writer.ng_insert_encoded(encoded, value, cv)
}
pub fn ng_remove(&mut self, quad: &EncodedQuad, commit: &StrHash) -> Result<(), StorageError> {
self.writer.ng_remove(quad, commit)
}
pub fn remove<'b>(&mut self, quad: impl Into<QuadRef<'b>>) -> Result<bool, StorageError> {
self.writer.remove(quad.into())
}
pub fn clear_graph<'b>(
&mut self,
graph_name: impl Into<GraphNameRef<'b>>,
) -> Result<(), StorageError> {
self.writer.clear_graph(graph_name.into())
}
pub fn remove_named_graph<'b>(
&mut self,
graph_name: impl Into<NamedOrBlankNodeRef<'b>>,
) -> Result<bool, StorageError> {
self.writer.remove_named_graph(graph_name.into())
}
pub fn clear(&mut self) -> Result<(), StorageError> {
self.writer.clear()
}
}
impl IntoIterator for &Transaction<'_> {
type IntoIter = QuadIter;
type Item = Result<Quad, StorageError>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct QuadIter {
iter: Box<dyn Iterator<Item = Result<EncodedQuad, StorageError>>>,
reader: StorageReader,
}
impl Iterator for QuadIter {
type Item = Result<Quad, StorageError>;
fn next(&mut self) -> Option<Self::Item> {
Some(match self.iter.next()? {
Ok(quad) => self.reader.decode_quad(&quad),
Err(error) => Err(error),
})
}
}
pub struct OneErrorQuadIter {
err: Option<StorageError>,
}
impl OneErrorQuadIter {
pub fn new_boxed(err: StorageError) -> Box<OneErrorQuadIter> {
Box::new(Self { err: Some(err) })
}
}
impl Iterator for OneErrorQuadIter {
type Item = Result<EncodedQuad, StorageError>;
fn next(&mut self) -> Option<Self::Item> {
match self.err.take() {
Some(e) => Some(Err(e)),
None => None,
}
}
}
pub struct GraphNameIter {
iter: DecodingGraphIterator,
reader: StorageReader,
}
impl Iterator for GraphNameIter {
type Item = Result<NamedOrBlankNode, StorageError>;
fn next(&mut self) -> Option<Self::Item> {
Some(
self.iter
.next()?
.and_then(|graph_name| self.reader.decode_named_or_blank_node(&graph_name)),
)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
#[must_use]
pub struct BulkLoader {
storage: StorageBulkLoader,
on_parse_error: Option<Box<dyn Fn(RdfParseError) -> Result<(), RdfParseError>>>,
}
#[cfg(all(not(target_family = "wasm"), not(docsrs)))]
impl BulkLoader {
pub fn with_num_threads(mut self, num_threads: usize) -> Self {
self.storage = self.storage.with_num_threads(num_threads);
self
}
#[doc(hidden)]
#[deprecated(note = "Use with_num_threads", since = "0.4.0")]
pub fn set_num_threads(self, num_threads: usize) -> Self {
self.with_num_threads(num_threads)
}
pub fn with_max_memory_size_in_megabytes(mut self, max_memory_size: usize) -> Self {
self.storage = self
.storage
.with_max_memory_size_in_megabytes(max_memory_size);
self
}
#[doc(hidden)]
#[deprecated(note = "Use with_max_memory_size_in_megabytes", since = "0.4.0")]
pub fn set_max_memory_size_in_megabytes(self, max_memory_size: usize) -> Self {
self.with_max_memory_size_in_megabytes(max_memory_size)
}
pub fn on_progress(mut self, callback: impl Fn(u64) + 'static) -> Self {
self.storage = self.storage.on_progress(callback);
self
}
pub fn on_parse_error(
mut self,
callback: impl Fn(RdfParseError) -> Result<(), RdfParseError> + 'static,
) -> Self {
self.on_parse_error = Some(Box::new(callback));
self
}
pub fn load_from_read(
&self,
parser: impl Into<RdfParser>,
read: impl Read,
) -> Result<(), LoaderError> {
self.load_ok_quads(
parser
.into()
.rename_blank_nodes()
.parse_read(read)
.filter_map(|r| match r {
Ok(q) => Some(Ok(q)),
Err(e) => {
if let Some(callback) = &self.on_parse_error {
if let Err(e) = callback(e) {
Some(Err(e))
} else {
None
}
} else {
Some(Err(e))
}
}
}),
)
}
#[deprecated(note = "use BulkLoader.load_from_read instead", since = "0.4.0")]
pub fn load_dataset(
&self,
read: impl Read,
format: impl Into<RdfFormat>,
base_iri: Option<&str>,
) -> Result<(), LoaderError> {
let mut parser = RdfParser::from_format(format.into()).rename_blank_nodes();
if let Some(base_iri) = base_iri {
parser = parser
.with_base_iri(base_iri)
.map_err(|e| LoaderError::InvalidBaseIri {
iri: base_iri.into(),
error: e,
})?;
}
self.load_ok_quads(parser.parse_read(read).filter_map(|r| match r {
Ok(q) => Some(Ok(q)),
Err(e) => {
if let Some(callback) = &self.on_parse_error {
if let Err(e) = callback(e) {
Some(Err(e))
} else {
None
}
} else {
Some(Err(e))
}
}
}))
}
#[deprecated(note = "use BulkLoader.load_from_read instead", since = "0.4.0")]
pub fn load_graph(
&self,
read: impl Read,
format: impl Into<RdfFormat>,
to_graph_name: impl Into<GraphName>,
base_iri: Option<&str>,
) -> Result<(), LoaderError> {
let mut parser = RdfParser::from_format(format.into())
.without_named_graphs()
.with_default_graph(to_graph_name)
.rename_blank_nodes();
if let Some(base_iri) = base_iri {
parser = parser
.with_base_iri(base_iri)
.map_err(|e| LoaderError::InvalidBaseIri {
iri: base_iri.into(),
error: e,
})?;
}
self.load_ok_quads(parser.parse_read(read).filter_map(|r| match r {
Ok(q) => Some(Ok(q)),
Err(e) => {
if let Some(callback) = &self.on_parse_error {
if let Err(e) = callback(e) {
Some(Err(e))
} else {
None
}
} else {
Some(Err(e))
}
}
}))
}
pub fn load_quads(
&self,
quads: impl IntoIterator<Item = impl Into<Quad>>,
) -> Result<(), StorageError> {
self.load_ok_quads(quads.into_iter().map(Ok::<_, StorageError>))
}
pub fn load_ok_quads<EI, EO: From<StorageError> + From<EI>>(
&self,
quads: impl IntoIterator<Item = Result<impl Into<Quad>, EI>>,
) -> Result<(), EO> {
self.storage
.load(quads.into_iter().map(|q| q.map(Into::into)))
}
}
#[cfg(test)]
#[allow(clippy::panic_in_result_fn)]
mod tests {
use super::*;
#[test]
fn store() -> Result<(), StorageError> {
use super::super::model::*;
let main_s = Subject::from(BlankNode::default());
let main_p = NamedNode::new("http://example.com").unwrap();
let main_o = Term::from(Literal::from(1));
let main_g = GraphName::from(BlankNode::default());
let default_quad = Quad::new(
main_s.clone(),
main_p.clone(),
main_o.clone(),
GraphName::DefaultGraph,
);
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),
GraphName::DefaultGraph,
),
default_quad.clone(),
Quad::new(
main_s.clone(),
main_p.clone(),
Literal::from(200_000_000),
GraphName::DefaultGraph,
),
];
let all_quads = vec![
Quad::new(
main_s.clone(),
main_p.clone(),
Literal::from(0),
GraphName::DefaultGraph,
),
default_quad.clone(),
Quad::new(
main_s.clone(),
main_p.clone(),
Literal::from(200_000_000),
GraphName::DefaultGraph,
),
named_quad.clone(),
];
let store = Store::new()?;
assert_eq!(store.len()?, 4);
assert_eq!(store.iter().collect::<Result<Vec<_>, _>>()?, all_quads);
assert_eq!(
store
.quads_for_pattern(Some(main_s.as_ref()), None, None, None)
.collect::<Result<Vec<_>, _>>()?,
all_quads
);
assert_eq!(
store
.quads_for_pattern(Some(main_s.as_ref()), Some(main_p.as_ref()), None, None)
.collect::<Result<Vec<_>, _>>()?,
all_quads
);
assert_eq!(
store
.quads_for_pattern(
Some(main_s.as_ref()),
Some(main_p.as_ref()),
Some(main_o.as_ref()),
None
)
.collect::<Result<Vec<_>, _>>()?,
vec![default_quad.clone(), named_quad.clone()]
);
assert_eq!(
store
.quads_for_pattern(
Some(main_s.as_ref()),
Some(main_p.as_ref()),
Some(main_o.as_ref()),
Some(GraphNameRef::DefaultGraph)
)
.collect::<Result<Vec<_>, _>>()?,
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::<Result<Vec<_>, _>>()?,
vec![named_quad.clone()]
);
assert_eq!(
store
.quads_for_pattern(
Some(main_s.as_ref()),
Some(main_p.as_ref()),
None,
Some(GraphNameRef::DefaultGraph)
)
.collect::<Result<Vec<_>, _>>()?,
default_quads
);
assert_eq!(
store
.quads_for_pattern(Some(main_s.as_ref()), None, Some(main_o.as_ref()), None)
.collect::<Result<Vec<_>, _>>()?,
vec![default_quad.clone(), named_quad.clone()]
);
assert_eq!(
store
.quads_for_pattern(
Some(main_s.as_ref()),
None,
Some(main_o.as_ref()),
Some(GraphNameRef::DefaultGraph)
)
.collect::<Result<Vec<_>, _>>()?,
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::<Result<Vec<_>, _>>()?,
vec![named_quad.clone()]
);
assert_eq!(
store
.quads_for_pattern(
Some(main_s.as_ref()),
None,
None,
Some(GraphNameRef::DefaultGraph)
)
.collect::<Result<Vec<_>, _>>()?,
default_quads
);
assert_eq!(
store
.quads_for_pattern(None, Some(main_p.as_ref()), None, None)
.collect::<Result<Vec<_>, _>>()?,
all_quads
);
assert_eq!(
store
.quads_for_pattern(None, Some(main_p.as_ref()), Some(main_o.as_ref()), None)
.collect::<Result<Vec<_>, _>>()?,
vec![default_quad.clone(), named_quad.clone()]
);
assert_eq!(
store
.quads_for_pattern(None, None, Some(main_o.as_ref()), None)
.collect::<Result<Vec<_>, _>>()?,
vec![default_quad.clone(), named_quad.clone()]
);
assert_eq!(
store
.quads_for_pattern(None, None, None, Some(GraphNameRef::DefaultGraph))
.collect::<Result<Vec<_>, _>>()?,
default_quads
);
assert_eq!(
store
.quads_for_pattern(
None,
Some(main_p.as_ref()),
Some(main_o.as_ref()),
Some(GraphNameRef::DefaultGraph)
)
.collect::<Result<Vec<_>, _>>()?,
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::<Result<Vec<_>, _>>()?,
vec![named_quad]
);
Ok(())
}
}