Allows BlankNode struct to store any valid blank node identifier

Closes #34
pull/41/head
Tpt 5 years ago
parent 3926fdc219
commit 71aa5a6c79
  1. 25
      js/src/model.rs
  2. 14
      lib/src/error.rs
  3. 2
      lib/src/lib.rs
  4. 189
      lib/src/model/blank_node.rs
  5. 3
      lib/src/model/mod.rs
  6. 9
      lib/src/model/named_node.rs
  7. 56
      lib/src/sparql/eval.rs
  8. 22
      lib/src/sparql/parser.rs
  9. 2
      lib/src/sparql/plan_builder.rs
  10. 14
      lib/src/sparql/xml_results.rs
  11. 72
      lib/src/store/memory.rs
  12. 58
      lib/src/store/numeric_encoder.rs
  13. 4
      lib/src/store/rocksdb.rs
  14. 4
      lib/src/store/sled.rs
  15. 8
      lib/tests/service_test_cases.rs
  16. 2
      lib/tests/wasm.rs
  17. 16
      testsuite/src/manifest.rs
  18. 28
      testsuite/src/sparql_evaluator.rs
  19. 44
      testsuite/src/vocab.rs
  20. 4
      wikibase/src/loader.rs

@ -15,7 +15,7 @@ pub struct JsDataFactory {
impl JsDataFactory {
#[wasm_bindgen(js_name = namedNode)]
pub fn named_node(&self, value: String) -> Result<JsNamedNode, JsValue> {
NamedNode::parse(value)
NamedNode::new(value)
.map(|v| v.into())
.map_err(|v| UriError::new(&v.to_string()).into())
}
@ -23,9 +23,7 @@ impl JsDataFactory {
#[wasm_bindgen(js_name = blankNode)]
pub fn blank_node(&self, value: Option<String>) -> Result<JsBlankNode, JsValue> {
Ok(if let Some(value) = value {
BlankNode::new_from_unique_id(u128::from_str_radix(&value, 16).map_err(|_| {
format_err!("Oxigraph only supports BlankNode created with Oxigraph DataFactory")
})?)
BlankNode::new(value).map_err(to_err)?
} else {
BlankNode::default()
}
@ -511,26 +509,19 @@ impl FromJsConverter {
let term_type = Reflect::get(&value, &self.term_type)?;
if let Some(term_type) = term_type.as_string() {
match term_type.as_str() {
"NamedNode" => Ok(NamedNode::parse(
"NamedNode" => Ok(NamedNode::new(
Reflect::get(&value, &self.value)?
.as_string()
.ok_or_else(|| format_err!("NamedNode should have a string value"))?,
)
.map_err(|v| UriError::new(&v.to_string()))?
.into()),
"BlankNode" => Ok(BlankNode::new_from_unique_id(
u128::from_str_radix(
&Reflect::get(&value, &self.value)?
.as_string()
.ok_or_else(|| format_err!("BlankNode should have a string value"))?,
16,
)
.map_err(|_| {
format_err!(
"Oxigraph only supports BlankNode created with Oxigraph DataFactory"
)
})?,
"BlankNode" => Ok(BlankNode::new(
&Reflect::get(&value, &self.value)?
.as_string()
.ok_or_else(|| format_err!("BlankNode should have a string value"))?,
)
.map_err(to_err)?
.into()),
"Literal" => {
if let JsTerm::NamedNode(datatype) =

@ -1,6 +1,5 @@
use crate::model::{BlankNodeIdParseError, IriParseError, LanguageTagParseError};
use crate::sparql::SparqlParseError;
use oxilangtag::LanguageTagParseError;
use oxiri::IriParseError;
use rio_turtle::TurtleError;
use rio_xml::RdfXmlError;
use std::error;
@ -24,6 +23,7 @@ impl fmt::Display for Error {
ErrorKind::Io(e) => e.fmt(f),
ErrorKind::FromUtf8(e) => e.fmt(f),
ErrorKind::Iri(e) => e.fmt(f),
ErrorKind::BlankNode(e) => e.fmt(f),
ErrorKind::LanguageTag(e) => e.fmt(f),
ErrorKind::Other(e) => e.fmt(f),
}
@ -37,6 +37,7 @@ impl error::Error for Error {
ErrorKind::Io(e) => Some(e),
ErrorKind::FromUtf8(e) => Some(e),
ErrorKind::Iri(e) => Some(e),
ErrorKind::BlankNode(e) => Some(e),
ErrorKind::LanguageTag(e) => Some(e),
ErrorKind::Other(e) => Some(e.as_ref()),
}
@ -65,6 +66,7 @@ enum ErrorKind {
Io(io::Error),
FromUtf8(FromUtf8Error),
Iri(IriParseError),
BlankNode(BlankNodeIdParseError),
LanguageTag(LanguageTagParseError),
Other(Box<dyn error::Error + Send + Sync + 'static>),
}
@ -93,6 +95,14 @@ impl From<IriParseError> for Error {
}
}
impl From<BlankNodeIdParseError> for Error {
fn from(error: BlankNodeIdParseError) -> Self {
Self {
inner: ErrorKind::BlankNode(error),
}
}
}
impl From<LanguageTagParseError> for Error {
fn from(error: LanguageTagParseError) -> Self {
Self {

@ -23,7 +23,7 @@
//! let store = MemoryStore::new();
//!
//! // insertion
//! let ex = NamedNode::parse("http://example.com")?;
//! let ex = NamedNode::new("http://example.com")?;
//! let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None);
//! store.insert(quad.clone());
//!

@ -1,48 +1,100 @@
use rand::random;
use rio_api::model as rio;
use std::error::Error;
use std::fmt;
use std::io::Write;
use std::str;
/// An RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node).
///
/// This implementation enforces that the blank node id is a uniquely generated ID to easily ensure
/// that it is not possible for two blank nodes to share an id.
/// The common way to create a new blank node is to use the `BlankNode::default` trait method.
///
/// The common way to create a new blank node is to use the `Default::default` trait method.
/// It is also possible to create a blank node from a blank node identifier using the `BlankNode::new` method.
/// The blank node identifier must be valid according to N-Triples, Turtle and SPARQL grammars.
///
/// The default string formatter is returning a N-Triples, Turtle and SPARQL compatible representation.
/// `BlankNode::default().to_string()` should return something like `_:00112233445566778899aabbccddeeff`
///
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
pub struct BlankNode {
id: u128,
str: [u8; 32],
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct BlankNode(BlankNodeContent);
#[derive(PartialEq, Eq, Debug, Clone, Hash)]
enum BlankNodeContent {
Named(String),
Anonymous { id: u128, str: [u8; 32] },
}
impl BlankNode {
/// Creates a blank node from a unique id
/// Creates a blank node from a unique identifier.
///
/// The blank node identifier must be valid according to N-Triples, Turtle and SPARQL grammars.
///
/// In most cases, it is much more convenient to create a blank node using `BlankNode::default()`.
/// `BlankNode::default()` creates a random ID that could be easily inlined by Oxigraph stores.
pub fn new(id: impl Into<String>) -> Result<Self, BlankNodeIdParseError> {
let id = id.into();
validate_blank_node_identifier(&id)?;
Ok(Self::new_unchecked(id))
}
/// Creates a blank node from a unique identifier without validation.
///
/// It is the caller's responsibility to ensure that `id` is a valid blank node identifier
/// according to N-Triples, Turtle and SPARQL grammars.
///
/// In most cases, you **should not*** create a blank node this way,
/// but should use `Default::default` instead.
/// Except if you really know what you do, you should use [`new`](#method.new).
pub fn new_unchecked(id: impl Into<String>) -> Self {
let id = id.into();
if let Ok(numerical_id) = u128::from_str_radix(&id, 16) {
let result = Self::new_from_unique_id(numerical_id);
if result.as_str() == id {
result
} else {
Self(BlankNodeContent::Named(id))
}
} else {
Self(BlankNodeContent::Named(id))
}
}
/// Creates a blank node from a unique numerical id
///
/// This method is only exposed for low-level library,
/// in particular bindings to other languages or APIs.
pub fn new_from_unique_id(id: u128) -> Self {
/// In most cases, it is much more convenient to create a blank node using `BlankNode::default()`.
pub fn new_from_unique_id(id: impl Into<u128>) -> Self {
let id = id.into();
let mut str = [0; 32];
write!(&mut str[..], "{:x}", id).unwrap();
Self { id, str }
Self(BlankNodeContent::Anonymous { id, str })
}
/// Returns the underlying ID of this blank node
pub fn as_str(&self) -> &str {
let len = self.str.iter().position(|x| x == &0).unwrap_or(32);
str::from_utf8(&self.str[..len]).unwrap()
match &self.0 {
BlankNodeContent::Named(id) => id,
BlankNodeContent::Anonymous { str, .. } => {
let len = str.iter().position(|x| x == &0).unwrap_or(32);
str::from_utf8(&str[..len]).unwrap()
}
}
}
/// Returns the internal ID of this blank node
pub const fn id(&self) -> u128 {
self.id
/// Returns the underlying ID of this blank node
pub fn into_string(self) -> String {
match self.0 {
BlankNodeContent::Named(id) => id,
BlankNodeContent::Anonymous { str, .. } => {
let len = str.iter().position(|x| x == &0).unwrap_or(32);
str::from_utf8(&str[..len]).unwrap().to_owned()
}
}
}
/// Returns the internal numerical ID of this blank node, if it exists
pub(crate) fn id(&self) -> Option<u128> {
match self.0 {
BlankNodeContent::Named(_) => None,
BlankNodeContent::Anonymous { id, .. } => Some(id),
}
}
}
@ -65,19 +117,114 @@ impl<'a> From<&'a BlankNode> for rio::BlankNode<'a> {
}
}
fn validate_blank_node_identifier(id: &str) -> Result<(), BlankNodeIdParseError> {
let mut chars = id.chars();
let front = chars.next().ok_or(BlankNodeIdParseError {})?;
match front {
'0'..='9'
| '_'
| ':'
| 'A'..='Z'
| 'a'..='z'
| '\u{00C0}'..='\u{00D6}'
| '\u{00D8}'..='\u{00F6}'
| '\u{00F8}'..='\u{02FF}'
| '\u{0370}'..='\u{037D}'
| '\u{037F}'..='\u{1FFF}'
| '\u{200C}'..='\u{200D}'
| '\u{2070}'..='\u{218F}'
| '\u{2C00}'..='\u{2FEF}'
| '\u{3001}'..='\u{D7FF}'
| '\u{F900}'..='\u{FDCF}'
| '\u{FDF0}'..='\u{FFFD}'
| '\u{10000}'..='\u{EFFFF}' => (),
_ => return Err(BlankNodeIdParseError {}),
}
for c in chars {
match c {
'.' // validated later
| '-'
| '0'..='9'
| '\u{00B7}'
| '\u{0300}'..='\u{036F}'
| '\u{203F}'..='\u{2040}'
| '_'
| ':'
| 'A'..='Z'
| 'a'..='z'
| '\u{00C0}'..='\u{00D6}'
| '\u{00D8}'..='\u{00F6}'
| '\u{00F8}'..='\u{02FF}'
| '\u{0370}'..='\u{037D}'
| '\u{037F}'..='\u{1FFF}'
| '\u{200C}'..='\u{200D}'
| '\u{2070}'..='\u{218F}'
| '\u{2C00}'..='\u{2FEF}'
| '\u{3001}'..='\u{D7FF}'
| '\u{F900}'..='\u{FDCF}'
| '\u{FDF0}'..='\u{FFFD}'
| '\u{10000}'..='\u{EFFFF}' => (),
_ => return Err(BlankNodeIdParseError {}),
}
}
// Could not end with a dot
if id.ends_with('.') {
Err(BlankNodeIdParseError {})
} else {
Ok(())
}
}
/// An error raised during `BlankNode` validation.
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub struct BlankNodeIdParseError {}
impl fmt::Display for BlankNodeIdParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "The blank node identifier is invalid")
}
}
impl Error for BlankNodeIdParseError {}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn as_str_partial() {
let b = BlankNode::new_from_unique_id(0x42);
let b = BlankNode::new_from_unique_id(0x42_u128);
assert_eq!(b.as_str(), "42");
}
#[test]
fn as_str_full() {
let b = BlankNode::new_from_unique_id(0x7777_6666_5555_4444_3333_2222_1111_0000);
let b = BlankNode::new_from_unique_id(0x7777_6666_5555_4444_3333_2222_1111_0000_u128);
assert_eq!(b.as_str(), "77776666555544443333222211110000");
}
#[test]
fn new_validation() {
assert!(BlankNode::new("").is_err());
assert!(BlankNode::new("a").is_ok());
assert!(BlankNode::new("-").is_err());
assert!(BlankNode::new("a-").is_ok());
assert!(BlankNode::new(".").is_err());
assert!(BlankNode::new("a.").is_err());
assert!(BlankNode::new("a.a").is_ok());
}
#[test]
fn new_numerical() {
assert_eq!(
BlankNode::new("100a").unwrap(),
BlankNode::new_from_unique_id(0x100a_u128),
);
assert_ne!(
BlankNode::new("100A").unwrap(),
BlankNode::new_from_unique_id(0x100a_u128)
);
}
}

@ -10,9 +10,12 @@ pub mod vocab;
pub(crate) mod xsd;
pub use crate::model::blank_node::BlankNode;
pub use crate::model::blank_node::BlankNodeIdParseError;
pub use crate::model::literal::Literal;
pub use crate::model::named_node::NamedNode;
pub use crate::model::triple::NamedOrBlankNode;
pub use crate::model::triple::Quad;
pub use crate::model::triple::Term;
pub use crate::model::triple::Triple;
pub use oxilangtag::LanguageTagParseError;
pub use oxiri::IriParseError;

@ -10,7 +10,7 @@ use std::fmt;
///
/// assert_eq!(
/// "<http://example.com/foo>",
/// NamedNode::parse("http://example.com/foo").unwrap().to_string()
/// NamedNode::new("http://example.com/foo").unwrap().to_string()
/// )
/// ```
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
@ -20,10 +20,15 @@ pub struct NamedNode {
impl NamedNode {
/// Builds and validate an RDF [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri)
pub fn parse(iri: impl Into<String>) -> Result<Self, IriParseError> {
pub fn new(iri: impl Into<String>) -> Result<Self, IriParseError> {
Ok(Self::new_from_iri(Iri::parse(iri.into())?))
}
#[deprecated(note = "Use the `new` method")]
pub fn parse(iri: impl Into<String>) -> Result<Self, IriParseError> {
Self::new(iri)
}
pub(crate) fn new_from_iri(iri: Iri<String>) -> Self {
Self::new_unchecked(iri.into_inner())
}

@ -19,13 +19,12 @@ use rio_api::model as rio;
use sha1::Sha1;
use sha2::{Sha256, Sha384, Sha512};
use std::cmp::Ordering;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::{HashMap, HashSet};
use std::convert::{TryFrom, TryInto};
use std::hash::Hash;
use std::iter::Iterator;
use std::iter::{empty, once};
use std::str;
use std::sync::Mutex;
const REGEX_SIZE_LIMIT: usize = 1_000_000;
@ -34,7 +33,6 @@ type EncodedTuplesIterator<'a> = Box<dyn Iterator<Item = Result<EncodedTuple>> +
pub(crate) struct SimpleEvaluator<S: ReadableEncodedStore> {
dataset: DatasetView<S>,
base_iri: Option<Iri<String>>,
bnodes_map: Mutex<BTreeMap<StrHash, u128>>,
now: DateTime,
service_handler: Box<dyn ServiceHandler>,
}
@ -47,7 +45,6 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
) -> Self {
Self {
dataset,
bnodes_map: Mutex::new(BTreeMap::default()),
base_iri,
now: DateTime::now().unwrap(),
service_handler,
@ -946,23 +943,12 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
}
}
PlanExpression::BNode(id) => match id {
Some(id) => {
if let EncodedTerm::StringLiteral { value_id } =
self.eval_expression(id, tuple)?
{
Some(EncodedTerm::BlankNode {
id: *self
.bnodes_map
.lock()
.ok()?
.entry(value_id)
.or_insert_with(random::<u128>),
})
} else {
None
}
}
None => Some(EncodedTerm::BlankNode {
Some(id) => Some(
(&BlankNode::new(self.to_simple_string(self.eval_expression(id, tuple)?)?)
.ok()?)
.into(),
),
None => Some(EncodedTerm::InlineBlankNode {
id: random::<u128>(),
}),
},
@ -1409,7 +1395,7 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
match term {
EncodedTerm::DefaultGraph => None,
EncodedTerm::NamedNode { iri_id } => Some(iri_id),
EncodedTerm::BlankNode { .. } => None,
EncodedTerm::InlineBlankNode { .. } | EncodedTerm::NamedBlankNode { .. } => None,
EncodedTerm::StringLiteral { value_id }
| EncodedTerm::LangStringLiteral { value_id, .. }
| EncodedTerm::TypedLiteral { value_id, .. } => Some(value_id),
@ -1617,7 +1603,8 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
match a {
EncodedTerm::DefaultGraph
| EncodedTerm::NamedNode { .. }
| EncodedTerm::BlankNode { .. }
| EncodedTerm::InlineBlankNode { .. }
| EncodedTerm::NamedBlankNode { .. }
| EncodedTerm::LangStringLiteral { .. } => Some(a == b),
EncodedTerm::StringLiteral { value_id: a } => match b {
EncodedTerm::StringLiteral { value_id: b } => Some(a == b),
@ -1664,7 +1651,8 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
EncodedTerm::TypedLiteral { .. } => match b {
EncodedTerm::TypedLiteral { .. } if a == b => Some(true),
EncodedTerm::NamedNode { .. }
| EncodedTerm::BlankNode { .. }
| EncodedTerm::InlineBlankNode { .. }
| EncodedTerm::NamedBlankNode { .. }
| EncodedTerm::LangStringLiteral { .. } => Some(false),
_ => None,
},
@ -1706,24 +1694,26 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
fn cmp_terms(&self, a: Option<EncodedTerm>, b: Option<EncodedTerm>) -> Ordering {
match (a, b) {
(Some(a), Some(b)) => match a {
EncodedTerm::BlankNode { id: a } => {
if let EncodedTerm::BlankNode { id: b } = b {
a.cmp(&b)
} else {
Ordering::Less
EncodedTerm::InlineBlankNode { .. } | EncodedTerm::NamedBlankNode { .. } => {
match b {
EncodedTerm::InlineBlankNode { .. }
| EncodedTerm::NamedBlankNode { .. } => Ordering::Equal,
_ => Ordering::Less,
}
}
EncodedTerm::NamedNode { iri_id: a } => match b {
EncodedTerm::NamedNode { iri_id: b } => {
self.compare_str_ids(a, b).unwrap_or(Ordering::Equal)
}
EncodedTerm::BlankNode { .. } => Ordering::Greater,
EncodedTerm::InlineBlankNode { .. } | EncodedTerm::NamedBlankNode { .. } => {
Ordering::Greater
}
_ => Ordering::Less,
},
a => match b {
EncodedTerm::NamedNode { .. } | EncodedTerm::BlankNode { .. } => {
Ordering::Greater
}
EncodedTerm::NamedNode { .. }
| EncodedTerm::InlineBlankNode { .. }
| EncodedTerm::NamedBlankNode { .. } => Ordering::Greater,
b => self.partial_cmp_literals(a, b).unwrap_or(Ordering::Equal),
},
},

@ -38,8 +38,8 @@ impl Query {
None
},
namespaces: HashMap::default(),
bnodes_map: HashMap::default(),
used_bnodes: HashSet::default(),
currently_used_bnodes: HashSet::default(),
aggregations: Vec::default(),
};
@ -356,8 +356,8 @@ enum Either<L, R> {
pub struct ParserState {
base_iri: Option<Iri<String>>,
namespaces: HashMap<String, String>,
bnodes_map: HashMap<String, BlankNode>,
used_bnodes: HashSet<String>,
used_bnodes: HashSet<BlankNode>,
currently_used_bnodes: HashSet<BlankNode>,
aggregations: Vec<Vec<(Aggregation, Variable)>>,
}
@ -841,8 +841,8 @@ parser! {
}
// We deal with blank nodes aliases rule (TODO: partial for now)
state.used_bnodes.extend(state.bnodes_map.keys().cloned());
state.bnodes_map.clear();
state.used_bnodes.extend(state.currently_used_bnodes.iter().cloned());
state.currently_used_bnodes.clear();
if let Some(filter) = filter {
GraphPattern::Filter(filter, Box::new(g))
@ -1534,10 +1534,14 @@ parser! {
//[138]
rule BlankNode() -> BlankNode =
b:BLANK_NODE_LABEL() {?
if state.used_bnodes.contains(b) {
Err("Already used blank node id")
} else {
Ok(*state.bnodes_map.entry(b.to_string()).or_insert_with(BlankNode::default))
match BlankNode::new(b) {
Ok(node) => if state.used_bnodes.contains(&node) {
Err("Already used blank node id")
} else {
state.currently_used_bnodes.insert(node.clone());
Ok(node)
},
Err(_) => Err("Invalid blank node identifier")
}
} /
ANON() { BlankNode::default() }

@ -981,7 +981,7 @@ fn bnode_key(blank_nodes: &mut Vec<BlankNode>, blank_node: &BlankNode) -> usize
match slice_key(blank_nodes, blank_node) {
Some(key) => key,
None => {
blank_nodes.push(*blank_node);
blank_nodes.push(blank_node.clone());
blank_nodes.len() - 1
}
}

@ -177,7 +177,6 @@ pub fn read_xml_results<'a>(source: impl BufRead + 'a) -> Result<QueryResult<'a>
buffer: Vec::default(),
namespace_buffer,
mapping,
bnodes_map: BTreeMap::default(),
}),
)));
} else if event.name() != b"link" && event.name() != b"results" && event.name() != b"boolean" {
@ -250,7 +249,6 @@ struct ResultsIterator<R: BufRead> {
buffer: Vec<u8>,
namespace_buffer: Vec<u8>,
mapping: BTreeMap<Vec<u8>, usize>,
bnodes_map: BTreeMap<Vec<u8>, BlankNode>,
}
impl<R: BufRead> Iterator for ResultsIterator<R> {
@ -343,7 +341,7 @@ impl<R: BufRead> ResultsIterator<R> {
if attr.key == b"xml:lang" {
lang = Some(attr.unescape_and_decode_value(&self.reader)?);
} else if attr.key == b"datatype" {
datatype = Some(NamedNode::parse(
datatype = Some(NamedNode::new(
attr.unescape_and_decode_value(&self.reader)?,
)?);
}
@ -363,16 +361,10 @@ impl<R: BufRead> ResultsIterator<R> {
let data = event.unescaped()?;
match state {
State::Uri => {
term = Some(NamedNode::parse(self.reader.decode(&data)?)?.into())
term = Some(NamedNode::new(self.reader.decode(&data)?)?.into())
}
State::BNode => {
term = Some(
self.bnodes_map
.entry(data.to_vec())
.or_insert_with(BlankNode::default)
.clone()
.into(),
)
term = Some(BlankNode::new(self.reader.decode(&data)?)?.into())
}
State::Literal => {
term = Some(

@ -27,7 +27,7 @@ use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
/// let store = MemoryStore::new();
///
/// // insertion
/// let ex = NamedNode::parse("http://example.com")?;
/// let ex = NamedNode::new("http://example.com")?;
/// let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None);
/// store.insert(quad.clone());
///
@ -90,7 +90,7 @@ impl MemoryStore {
/// let store = MemoryStore::new();
///
/// // insertions
/// let ex = NamedNode::parse("http://example.com")?;
/// let ex = NamedNode::new("http://example.com")?;
/// store.insert(Quad::new(ex.clone(), ex.clone(), ex.clone(), None));
///
/// // SPARQL query
@ -135,7 +135,7 @@ impl MemoryStore {
/// let store = MemoryStore::new();
///
/// // insertion
/// let ex = NamedNode::parse("http://example.com")?;
/// let ex = NamedNode::new("http://example.com")?;
/// let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None);
/// store.insert(quad.clone());
///
@ -182,7 +182,7 @@ impl MemoryStore {
///
/// let store = MemoryStore::new();
///
/// let ex = NamedNode::parse("http://example.com")?;
/// let ex = NamedNode::new("http://example.com")?;
/// let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None);
///
/// // transaction
@ -223,7 +223,7 @@ impl MemoryStore {
///
/// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::parse("http://example.com")?;
/// let ex = NamedNode::new("http://example.com")?;
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results);
/// # Result::Ok(())
/// ```
@ -253,7 +253,7 @@ impl MemoryStore {
///
/// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::parse("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);
/// # Result::Ok(())
/// ```
@ -857,7 +857,7 @@ impl<'a> MemoryTransaction<'a> {
///
/// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::parse("http://example.com")?;
/// let ex = NamedNode::new("http://example.com")?;
/// assert_eq!(vec![Quad::new(ex.clone(), ex.clone(), ex.clone(), None)], results);
/// # Result::Ok(())
/// ```
@ -886,7 +886,7 @@ impl<'a> MemoryTransaction<'a> {
///
/// // quad filter
/// let results: Vec<Quad> = store.quads_for_pattern(None, None, None, None).collect();
/// let ex = NamedNode::parse("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);
/// # Result::Ok(())
/// ```
@ -987,8 +987,8 @@ fn iso_canonicalize(g: &MemoryStore) -> Vec<Vec<u8>> {
fn distinguish(
g: &MemoryStore,
hash: &TrivialHashMap<u128, u64>,
partition: &[(u64, Vec<u128>)],
hash: &TrivialHashMap<EncodedTerm, u64>,
partition: &[(u64, Vec<EncodedTerm>)],
) -> Vec<Vec<u8>> {
let b_prime = partition
.iter()
@ -1021,19 +1021,21 @@ fn distinguish(
fn hash_bnodes(
g: &MemoryStore,
mut hashes: TrivialHashMap<u128, u64>,
) -> (TrivialHashMap<u128, u64>, Vec<(u64, Vec<u128>)>) {
mut hashes: TrivialHashMap<EncodedTerm, u64>,
) -> (
TrivialHashMap<EncodedTerm, u64>,
Vec<(u64, Vec<EncodedTerm>)>,
) {
let mut to_hash = Vec::new();
let mut partition: TrivialHashMap<u64, Vec<u128>> =
let mut partition: TrivialHashMap<u64, Vec<EncodedTerm>> =
TrivialHashMap::with_hasher(BuildHasherDefault::<TrivialHasher>::default());
let mut partition_len = 0;
loop {
//TODO: improve termination
let mut new_hashes =
TrivialHashMap::with_hasher(BuildHasherDefault::<TrivialHasher>::default());
for (b, old_hash) in &hashes {
let bnode = EncodedTerm::BlankNode { id: *b };
for q in g.encoded_quads_for_subject(bnode) {
for (bnode, old_hash) in &hashes {
for q in g.encoded_quads_for_subject(*bnode) {
to_hash.push((
hash_term(q.predicate, &hashes),
hash_term(q.object, &hashes),
@ -1041,7 +1043,7 @@ fn hash_bnodes(
0,
));
}
for q in g.encoded_quads_for_object(bnode) {
for q in g.encoded_quads_for_object(*bnode) {
to_hash.push((
hash_term(q.subject, &hashes),
hash_term(q.predicate, &hashes),
@ -1049,7 +1051,7 @@ fn hash_bnodes(
1,
));
}
for q in g.encoded_quads_for_graph(bnode) {
for q in g.encoded_quads_for_graph(*bnode) {
to_hash.push((
hash_term(q.subject, &hashes),
hash_term(q.predicate, &hashes),
@ -1060,8 +1062,8 @@ fn hash_bnodes(
to_hash.sort();
let hash = hash_tuple((old_hash, &to_hash));
to_hash.clear();
new_hashes.insert(*b, hash);
partition.entry(hash).or_default().push(*b);
new_hashes.insert(*bnode, hash);
partition.entry(hash).or_default().push(*bnode);
}
if partition.len() == partition_len {
let mut partition: Vec<_> = partition.into_iter().collect();
@ -1074,23 +1076,23 @@ fn hash_bnodes(
}
}
fn bnodes(g: &MemoryStore) -> TrivialHashSet<u128> {
fn bnodes(g: &MemoryStore) -> TrivialHashSet<EncodedTerm> {
let mut bnodes = TrivialHashSet::with_hasher(BuildHasherDefault::<TrivialHasher>::default());
for q in g.encoded_quads() {
if let EncodedTerm::BlankNode { id } = q.subject {
bnodes.insert(id);
if q.subject.is_blank_node() {
bnodes.insert(q.subject);
}
if let EncodedTerm::BlankNode { id } = q.object {
bnodes.insert(id);
if q.object.is_blank_node() {
bnodes.insert(q.object);
}
if let EncodedTerm::BlankNode { id } = q.graph_name {
bnodes.insert(id);
if q.graph_name.is_blank_node() {
bnodes.insert(q.graph_name);
}
}
bnodes
}
fn label(g: &MemoryStore, hashes: &TrivialHashMap<u128, u64>) -> Vec<Vec<u8>> {
fn label(g: &MemoryStore, hashes: &TrivialHashMap<EncodedTerm, u64>) -> Vec<Vec<u8>> {
//TODO: better representation?
let mut data: Vec<_> = g
.encoded_quads()
@ -1113,19 +1115,19 @@ fn label(g: &MemoryStore, hashes: &TrivialHashMap<u128, u64>) -> Vec<Vec<u8>> {
data
}
fn map_term(term: EncodedTerm, bnodes_hash: &TrivialHashMap<u128, u64>) -> EncodedTerm {
if let EncodedTerm::BlankNode { id } = term {
EncodedTerm::BlankNode {
id: (*bnodes_hash.get(&id).unwrap()).into(),
fn map_term(term: EncodedTerm, bnodes_hash: &TrivialHashMap<EncodedTerm, u64>) -> EncodedTerm {
if term.is_blank_node() {
EncodedTerm::InlineBlankNode {
id: (*bnodes_hash.get(&term).unwrap()).into(),
}
} else {
term
}
}
fn hash_term(term: EncodedTerm, bnodes_hash: &TrivialHashMap<u128, u64>) -> u64 {
if let EncodedTerm::BlankNode { id } = term {
*bnodes_hash.get(&id).unwrap()
fn hash_term(term: EncodedTerm, bnodes_hash: &TrivialHashMap<EncodedTerm, u64>) -> u64 {
if term.is_blank_node() {
*bnodes_hash.get(&term).unwrap()
} else {
hash_tuple(term)
}

@ -63,7 +63,8 @@ const XSD_DURATION_ID: StrHash = StrHash::constant(0x226af08ea5b7e6b08ceed6030c7
const TYPE_DEFAULT_GRAPH_ID: u8 = 0;
const TYPE_NAMED_NODE_ID: u8 = 1;
const TYPE_BLANK_NODE_ID: u8 = 2;
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;
@ -122,9 +123,12 @@ pub enum EncodedTerm {
NamedNode {
iri_id: StrHash,
},
BlankNode {
InlineBlankNode {
id: u128,
},
NamedBlankNode {
id_id: StrHash,
},
StringLiteral {
value_id: StrHash,
},
@ -155,9 +159,14 @@ impl PartialEq for EncodedTerm {
EncodedTerm::NamedNode { iri_id: iri_id_a },
EncodedTerm::NamedNode { iri_id: iri_id_b },
) => iri_id_a == iri_id_b,
(EncodedTerm::BlankNode { id: id_a }, EncodedTerm::BlankNode { id: id_b }) => {
id_a == id_b
}
(
EncodedTerm::InlineBlankNode { id: id_a },
EncodedTerm::InlineBlankNode { id: id_b },
) => id_a == id_b,
(
EncodedTerm::NamedBlankNode { id_id: id_a },
EncodedTerm::NamedBlankNode { id_id: id_b },
) => id_a == id_b,
(
EncodedTerm::StringLiteral {
value_id: value_id_a,
@ -218,7 +227,8 @@ impl Hash for EncodedTerm {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
EncodedTerm::NamedNode { iri_id } => iri_id.hash(state),
EncodedTerm::BlankNode { id } => id.hash(state),
EncodedTerm::InlineBlankNode { id } => id.hash(state),
EncodedTerm::NamedBlankNode { id_id } => id_id.hash(state),
EncodedTerm::DefaultGraph => (),
EncodedTerm::StringLiteral { value_id } => value_id.hash(state),
EncodedTerm::LangStringLiteral {
@ -258,7 +268,7 @@ impl EncodedTerm {
pub fn is_blank_node(&self) -> bool {
match self {
EncodedTerm::BlankNode { .. } => true,
EncodedTerm::InlineBlankNode { .. } | EncodedTerm::NamedBlankNode { .. } => true,
_ => false,
}
}
@ -305,7 +315,8 @@ impl EncodedTerm {
match self {
EncodedTerm::DefaultGraph { .. } => TYPE_DEFAULT_GRAPH_ID,
EncodedTerm::NamedNode { .. } => TYPE_NAMED_NODE_ID,
EncodedTerm::BlankNode { .. } => TYPE_BLANK_NODE_ID,
EncodedTerm::InlineBlankNode { .. } => TYPE_INLINE_BLANK_NODE_ID,
EncodedTerm::NamedBlankNode { .. } => TYPE_NAMED_BLANK_NODE_ID,
EncodedTerm::StringLiteral { .. } => TYPE_STRING_LITERAL,
EncodedTerm::LangStringLiteral { .. } => TYPE_LANG_STRING_LITERAL_ID,
EncodedTerm::TypedLiteral { .. } => TYPE_TYPED_LITERAL_ID,
@ -410,7 +421,13 @@ impl<'a> From<rio::NamedNode<'a>> for EncodedTerm {
impl From<&BlankNode> for EncodedTerm {
fn from(node: &BlankNode) -> Self {
EncodedTerm::BlankNode { id: node.id() }
if let Some(id) = node.id() {
EncodedTerm::InlineBlankNode { id }
} else {
EncodedTerm::NamedBlankNode {
id_id: StrHash::new(node.as_str()),
}
}
}
}
@ -560,13 +577,20 @@ impl<R: Read> TermReader for R {
iri_id: StrHash::from_be_bytes(buffer),
})
}
TYPE_BLANK_NODE_ID => {
TYPE_INLINE_BLANK_NODE_ID => {
let mut buffer = [0; 16];
self.read_exact(&mut buffer)?;
Ok(EncodedTerm::BlankNode {
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)?;
@ -730,7 +754,8 @@ pub fn write_term(sink: &mut Vec<u8>, term: EncodedTerm) {
match term {
EncodedTerm::DefaultGraph => {}
EncodedTerm::NamedNode { iri_id } => sink.extend_from_slice(&iri_id.to_be_bytes()),
EncodedTerm::BlankNode { id } => sink.extend_from_slice(&id.to_be_bytes()),
EncodedTerm::InlineBlankNode { id } => sink.extend_from_slice(&id.to_be_bytes()),
EncodedTerm::NamedBlankNode { id_id } => sink.extend_from_slice(&id_id.to_be_bytes()),
EncodedTerm::StringLiteral { value_id } => sink.extend_from_slice(&value_id.to_be_bytes()),
EncodedTerm::LangStringLiteral {
value_id,
@ -1009,11 +1034,11 @@ impl<S: StrContainer> Encoder for S {
bnodes_map: &mut HashMap<String, u128>,
) -> Result<EncodedTerm> {
Ok(if let Some(id) = bnodes_map.get(blank_node.id) {
EncodedTerm::BlankNode { id: *id }
EncodedTerm::InlineBlankNode { id: *id }
} else {
let id = random::<u128>();
bnodes_map.insert(blank_node.id.to_owned(), id);
EncodedTerm::BlankNode { id }
EncodedTerm::InlineBlankNode { id }
})
}
@ -1185,7 +1210,10 @@ impl<S: StrLookup> Decoder for S {
EncodedTerm::NamedNode { iri_id } => {
Ok(NamedNode::new_unchecked(get_required_str(self, iri_id)?).into())
}
EncodedTerm::BlankNode { id } => Ok(BlankNode::new_from_unique_id(id).into()),
EncodedTerm::InlineBlankNode { id } => Ok(BlankNode::new_from_unique_id(id).into()),
EncodedTerm::NamedBlankNode { id_id } => {
Ok(BlankNode::new_unchecked(get_required_str(self, id_id)?).into())
}
EncodedTerm::StringLiteral { value_id } => {
Ok(Literal::new_simple_literal(get_required_str(self, value_id)?).into())
}

@ -28,7 +28,7 @@ use std::sync::Arc;
/// let store = RocksDbStore::open("example.db")?;
///
/// // insertion
/// let ex = NamedNode::parse("http://example.com")?;
/// let ex = NamedNode::new("http://example.com")?;
/// let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None);
/// store.insert(&quad)?;
///
@ -757,7 +757,7 @@ fn store() -> Result<()> {
use std::fs::remove_dir_all;
let main_s = NamedOrBlankNode::from(BlankNode::default());
let main_p = NamedNode::parse("http://example.com")?;
let main_p = NamedNode::new("http://example.com")?;
let main_o = Term::from(Literal::from(1));
let main_quad = Quad::new(main_s.clone(), main_p.clone(), main_o.clone(), None);

@ -28,7 +28,7 @@ use std::str;
/// let store = SledStore::open("example.db")?;
///
/// // insertion
/// let ex = NamedNode::parse("http://example.com")?;
/// let ex = NamedNode::new("http://example.com")?;
/// let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None);
/// store.insert(&quad)?;
///
@ -550,7 +550,7 @@ fn store() -> Result<()> {
use crate::*;
let main_s = NamedOrBlankNode::from(BlankNode::default());
let main_p = NamedNode::parse("http://example.com")?;
let main_p = NamedNode::new("http://example.com")?;
let main_o = Term::from(Literal::from(1));
let main_quad = Quad::new(main_s.clone(), main_p.clone(), main_o.clone(), None);

@ -53,8 +53,8 @@ fn two_service_test() {
named_node: &NamedNode,
graph_pattern: &'a GraphPattern,
) -> Result<QuerySolutionsIterator<'a>> {
let service1 = NamedNode::parse("http://service1.org").unwrap();
let service2 = NamedNode::parse("http://service2.org").unwrap();
let service1 = NamedNode::new("http://service1.org").unwrap();
let service2 = NamedNode::new("http://service2.org").unwrap();
if named_node == &service1 {
let triples = br#"
<http://example.com/bob> <http://xmlns.com/foaf/0.1/name> "Bob" .
@ -180,11 +180,11 @@ fn non_silent_service_test() {
}
fn ex(id: &str) -> Term {
Term::NamedNode(NamedNode::parse(format!("http://example.com/{}", id)).unwrap())
Term::NamedNode(NamedNode::new(format!("http://example.com/{}", id)).unwrap())
}
fn mailto(id: &str) -> Term {
Term::NamedNode(NamedNode::parse(format!("mailto:{}", id)).unwrap())
Term::NamedNode(NamedNode::new(format!("mailto:{}", id)).unwrap())
}
fn literal(str: &str) -> Term {

@ -11,7 +11,7 @@ mod test {
let store = MemoryStore::new();
// insertion
let ex = NamedNode::parse("http://example.com").unwrap();
let ex = NamedNode::new("http://example.com").unwrap();
let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), None);
store.insert(quad.clone());
// quad filter

@ -176,8 +176,7 @@ impl Iterator for TestManifest {
None => {
match self.manifests_to_do.pop() {
Some(url) => {
let manifest =
NamedOrBlankNode::from(NamedNode::parse(url.clone()).unwrap());
let manifest = NamedOrBlankNode::from(NamedNode::new(url.clone()).unwrap());
if let Err(error) = load_to_store(&url, &self.graph, None) {
return Some(Err(error));
}
@ -186,11 +185,12 @@ impl Iterator for TestManifest {
match object_for_subject_predicate(&self.graph, &manifest, &*mf::INCLUDE) {
Some(Term::BlankNode(list)) => {
self.manifests_to_do.extend(
RdfListIterator::iter(&self.graph, list.clone().into())
.filter_map(|m| match m {
RdfListIterator::iter(&self.graph, list.into()).filter_map(
|m| match m {
Term::NamedNode(nm) => Some(nm.into_string()),
_ => None,
}),
},
),
);
}
Some(_) => return Some(Err(Error::msg("invalid tests list"))),
@ -200,10 +200,8 @@ impl Iterator for TestManifest {
// New tests
match object_for_subject_predicate(&self.graph, &manifest, &*mf::ENTRIES) {
Some(Term::BlankNode(list)) => {
self.tests_to_do.extend(RdfListIterator::iter(
&self.graph,
list.clone().into(),
));
self.tests_to_do
.extend(RdfListIterator::iter(&self.graph, list.into()));
}
Some(term) => {
return Some(Err(Error::msg(format!(

@ -79,7 +79,7 @@ fn evaluate_sparql_test(test: &Test) -> Result<()> {
load_to_store(
&graph_data,
&store,
Some(&NamedNode::parse(graph_data)?.into()),
Some(&NamedNode::new(graph_data)?.into()),
)?;
}
let query_file = test
@ -163,7 +163,7 @@ impl StaticServiceHandler {
services
.iter()
.map(|(name, data)| {
let name = NamedNode::parse(name)?;
let name = NamedNode::new(name)?;
let store = MemoryStore::new();
load_to_store(&data, &store, None)?;
Ok((name, store))
@ -210,7 +210,7 @@ fn to_dataset(result: QueryResult<'_>, with_order: bool) -> Result<MemoryStore>
let store = MemoryStore::new();
let result_set = BlankNode::default();
store.insert(Quad::new(
result_set,
result_set.clone(),
rdf::TYPE.clone(),
rs::RESULT_SET.clone(),
None,
@ -227,14 +227,14 @@ fn to_dataset(result: QueryResult<'_>, with_order: bool) -> Result<MemoryStore>
let store = MemoryStore::new();
let result_set = BlankNode::default();
store.insert(Quad::new(
result_set,
result_set.clone(),
rdf::TYPE.clone(),
rs::RESULT_SET.clone(),
None,
));
for variable in solutions.variables() {
store.insert(Quad::new(
result_set,
result_set.clone(),
rs::RESULT_VARIABLE.clone(),
Literal::new_simple_literal(variable.as_str()),
None,
@ -244,15 +244,25 @@ fn to_dataset(result: QueryResult<'_>, with_order: bool) -> Result<MemoryStore>
let solution = solution?;
let solution_id = BlankNode::default();
store.insert(Quad::new(
result_set,
result_set.clone(),
rs::SOLUTION.clone(),
solution_id,
solution_id.clone(),
None,
));
for (variable, value) in solution.iter() {
let binding = BlankNode::default();
store.insert(Quad::new(solution_id, rs::BINDING.clone(), binding, None));
store.insert(Quad::new(binding, rs::VALUE.clone(), value.clone(), None));
store.insert(Quad::new(
solution_id.clone(),
rs::BINDING.clone(),
binding.clone(),
None,
));
store.insert(Quad::new(
binding.clone(),
rs::VALUE.clone(),
value.clone(),
None,
));
store.insert(Quad::new(
binding,
rs::VARIABLE.clone(),

@ -4,29 +4,26 @@ pub mod rs {
lazy_static! {
pub static ref RESULT_SET: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/result-set#ResultSet")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/result-set#ResultSet")
.unwrap();
pub static ref RESULT_VARIABLE: NamedNode =
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/result-set#resultVariable")
.unwrap();
pub static ref RESULT_VARIABLE: NamedNode = NamedNode::parse(
"http://www.w3.org/2001/sw/DataAccess/tests/result-set#resultVariable"
)
.unwrap();
pub static ref SOLUTION: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/result-set#solution")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/result-set#solution")
.unwrap();
pub static ref BINDING: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/result-set#binding")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/result-set#binding")
.unwrap();
pub static ref VALUE: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/result-set#value")
.unwrap();
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/result-set#value").unwrap();
pub static ref VARIABLE: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/result-set#variable")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/result-set#variable")
.unwrap();
pub static ref INDEX: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/result-set#index")
.unwrap();
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/result-set#index").unwrap();
pub static ref BOOLEAN: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/result-set#boolean")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/result-set#boolean")
.unwrap();
}
}
@ -37,19 +34,19 @@ pub mod mf {
lazy_static! {
pub static ref INCLUDE: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#include")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#include")
.unwrap();
pub static ref ENTRIES: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#entries")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#entries")
.unwrap();
pub static ref NAME: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#name")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#name")
.unwrap();
pub static ref ACTION: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#action")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#action")
.unwrap();
pub static ref RESULT: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#result")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#result")
.unwrap();
}
}
@ -60,18 +57,17 @@ pub mod qt {
lazy_static! {
pub static ref QUERY: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-query#query")
.unwrap();
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-query#query").unwrap();
pub static ref DATA: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-query#data").unwrap();
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-query#data").unwrap();
pub static ref GRAPH_DATA: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-query#graphData")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-query#graphData")
.unwrap();
pub static ref SERVICE_DATA: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-query#serviceData")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-query#serviceData")
.unwrap();
pub static ref ENDPOINT: NamedNode =
NamedNode::parse("http://www.w3.org/2001/sw/DataAccess/tests/test-query#endpoint")
NamedNode::new("http://www.w3.org/2001/sw/DataAccess/tests/test-query#endpoint")
.unwrap();
}
}

@ -259,7 +259,7 @@ impl WikibaseLoader {
}
fn load_entity_data(&self, uri: &str, data: impl Read) -> Result<()> {
let graph_name = NamedNode::parse(uri)?.into();
let graph_name = NamedNode::new(uri)?.into();
self.store.transaction(|transaction| {
let to_remove = self
.store
@ -272,7 +272,7 @@ impl WikibaseLoader {
transaction.load_graph(
BufReader::new(data),
GraphSyntax::NTriples,
Some(&NamedNode::parse(uri)?.into()),
Some(&NamedNode::new(uri)?.into()),
None,
)
})?;

Loading…
Cancel
Save