Adds basic native support of xsd:integer, xsd:float and xsd:double

pull/10/head
Tpt 6 years ago
parent ea7f61dc1b
commit 53ffd231a0
  1. 4
      lib/Cargo.toml
  2. 2
      lib/src/lib.rs
  3. 182
      lib/src/model/literal.rs
  4. 6
      lib/src/rio/turtle/turtle_grammar.rustpeg
  5. 29
      lib/src/sparql/eval.rs
  6. 15
      lib/src/sparql/sparql_grammar.rustpeg
  7. 117
      lib/src/store/numeric_encoder.rs
  8. 7
      lib/tests/sparql_test_cases.rs

@ -21,8 +21,10 @@ rocksdb = "0.10"
url = "1" url = "1"
uuid = { version = "0.7", features = ["v4"] } uuid = { version = "0.7", features = ["v4"] }
bzip2 = "0.3" bzip2 = "0.3"
byteorder = "1" byteorder = {version="1", features = ["i128"] }
quick-xml = "0.13" quick-xml = "0.13"
ordered-float = "1"
num-traits = "0.2"
[build-dependencies] [build-dependencies]
peg = "0.5" peg = "0.5"

@ -3,6 +3,8 @@ extern crate byteorder;
extern crate error_chain; extern crate error_chain;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
extern crate num_traits;
extern crate ordered_float;
extern crate quick_xml; extern crate quick_xml;
extern crate rocksdb; extern crate rocksdb;
extern crate url; extern crate url;

@ -1,6 +1,8 @@
use model::named_node::NamedNode; use model::named_node::NamedNode;
use model::vocab::rdf; use model::vocab::rdf;
use model::vocab::xsd; use model::vocab::xsd;
use num_traits::identities::Zero;
use ordered_float::OrderedFloat;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use std::option::Option; use std::option::Option;
@ -31,12 +33,15 @@ use utils::Escaper;
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
pub struct Literal(LiteralContent); pub struct Literal(LiteralContent);
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] #[derive(PartialEq, Eq, Ord, PartialOrd, Debug, Clone, Hash)]
enum LiteralContent { enum LiteralContent {
SimpleLiteral(String), SimpleLiteral(String),
String(String), String(String),
LanguageTaggedString { value: String, language: String }, LanguageTaggedString { value: String, language: String },
Boolean(bool), Boolean(bool),
Float(OrderedFloat<f32>),
Double(OrderedFloat<f64>),
Integer(i128),
TypedLiteral { value: String, datatype: NamedNode }, TypedLiteral { value: String, datatype: NamedNode },
} }
@ -50,17 +55,32 @@ impl Literal {
pub fn new_typed_literal(value: impl Into<String>, datatype: impl Into<NamedNode>) -> Self { pub fn new_typed_literal(value: impl Into<String>, datatype: impl Into<NamedNode>) -> Self {
let value = value.into(); let value = value.into();
let datatype = datatype.into(); let datatype = datatype.into();
if datatype == *xsd::BOOLEAN { Literal(if datatype == *xsd::BOOLEAN {
match value.as_str() { match value.as_str() {
"true" | "1" => Literal(LiteralContent::Boolean(true)), "true" | "1" => LiteralContent::Boolean(true),
"false" | "0" => Literal(LiteralContent::Boolean(false)), "false" | "0" => LiteralContent::Boolean(false),
_ => Literal(LiteralContent::TypedLiteral { value, datatype }), _ => LiteralContent::TypedLiteral { value, datatype },
} }
} else if datatype == *xsd::STRING { } else if datatype == *xsd::STRING {
Literal(LiteralContent::String(value)) LiteralContent::String(value)
} else { } else if datatype == *xsd::FLOAT {
Literal(LiteralContent::TypedLiteral { value, datatype }) match value.parse() {
Ok(value) => LiteralContent::Float(OrderedFloat(value)),
Err(_) => LiteralContent::TypedLiteral { value, datatype },
}
} else if datatype == *xsd::DOUBLE {
match value.parse() {
Ok(value) => LiteralContent::Double(OrderedFloat(value)),
Err(_) => LiteralContent::TypedLiteral { value, datatype },
}
} else if datatype == *xsd::INTEGER {
match value.parse() {
Ok(value) => LiteralContent::Integer(value),
Err(_) => LiteralContent::TypedLiteral { value, datatype },
} }
} else {
LiteralContent::TypedLiteral { value, datatype }
})
} }
/// Builds a RDF [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string) /// Builds a RDF [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string)
@ -77,10 +97,14 @@ impl Literal {
/// The literal [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form) /// The literal [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form)
pub fn value(&self) -> Cow<String> { pub fn value(&self) -> Cow<String> {
match self.0 { match self.0 {
LiteralContent::SimpleLiteral(ref value) => Cow::Borrowed(value), LiteralContent::SimpleLiteral(ref value) | LiteralContent::String(ref value) => {
LiteralContent::String(ref value) => Cow::Borrowed(value), Cow::Borrowed(value)
}
LiteralContent::LanguageTaggedString { ref value, .. } => Cow::Borrowed(value), LiteralContent::LanguageTaggedString { ref value, .. } => Cow::Borrowed(value),
LiteralContent::Boolean(value) => Cow::Owned(value.to_string()), LiteralContent::Boolean(value) => Cow::Owned(value.to_string()),
LiteralContent::Float(value) => Cow::Owned(value.to_string()),
LiteralContent::Double(value) => Cow::Owned(value.to_string()),
LiteralContent::Integer(value) => Cow::Owned(value.to_string()),
LiteralContent::TypedLiteral { ref value, .. } => Cow::Borrowed(value), LiteralContent::TypedLiteral { ref value, .. } => Cow::Borrowed(value),
} }
} }
@ -100,10 +124,12 @@ impl Literal {
/// The datatype of [simple literals](https://www.w3.org/TR/rdf11-concepts/#dfn-simple-literal) is [xsd:string](http://www.w3.org/2001/XMLSchema#string). /// The datatype of [simple literals](https://www.w3.org/TR/rdf11-concepts/#dfn-simple-literal) is [xsd:string](http://www.w3.org/2001/XMLSchema#string).
pub fn datatype(&self) -> &NamedNode { pub fn datatype(&self) -> &NamedNode {
match self.0 { match self.0 {
LiteralContent::SimpleLiteral(_) => &xsd::STRING, LiteralContent::SimpleLiteral(_) | LiteralContent::String(_) => &xsd::STRING,
LiteralContent::String(_) => &xsd::STRING,
LiteralContent::LanguageTaggedString { .. } => &rdf::LANG_STRING, LiteralContent::LanguageTaggedString { .. } => &rdf::LANG_STRING,
LiteralContent::Boolean(_) => &xsd::BOOLEAN, LiteralContent::Boolean(_) => &xsd::BOOLEAN,
LiteralContent::Float(_) => &xsd::FLOAT,
LiteralContent::Double(_) => &xsd::DOUBLE,
LiteralContent::Integer(_) => &xsd::INTEGER,
LiteralContent::TypedLiteral { ref datatype, .. } => datatype, LiteralContent::TypedLiteral { ref datatype, .. } => datatype,
} }
} }
@ -128,7 +154,7 @@ impl Literal {
} }
} }
/// Checks if the literal has the datatype [xsd:boolean](http://www.w3.org/2001/XMLSchema#string) and is valid /// Checks if the literal has the datatype [xsd:boolean](http://www.w3.org/2001/XMLSchema#boolean) and is valid
pub fn is_boolean(&self) -> bool { pub fn is_boolean(&self) -> bool {
match self.0 { match self.0 {
LiteralContent::Boolean(_) => true, LiteralContent::Boolean(_) => true,
@ -136,17 +162,86 @@ impl Literal {
} }
} }
/// Checks if the literal has the datatype [xsd:float](http://www.w3.org/2001/XMLSchema#float) and is valid
pub fn is_float(&self) -> bool {
match self.0 {
LiteralContent::Float(_) => true,
_ => false,
}
}
/// Checks if the literal has the datatype [xsd:double](http://www.w3.org/2001/XMLSchema#double) and is valid
pub fn is_double(&self) -> bool {
match self.0 {
LiteralContent::Double(_) => true,
_ => false,
}
}
/// Checks if the literal has the datatype [xsd:integer](http://www.w3.org/2001/XMLSchema#integer) and is valid
pub fn is_integer(&self) -> bool {
match self.0 {
LiteralContent::Integer(_) => true,
_ => false,
}
}
/// Returns the [effective boolean value](https://www.w3.org/TR/sparql11-query/#ebv) of the literal if it exists /// Returns the [effective boolean value](https://www.w3.org/TR/sparql11-query/#ebv) of the literal if it exists
pub fn to_bool(&self) -> Option<bool> { pub fn to_bool(&self) -> Option<bool> {
//TODO: numeric literals
match self.0 { match self.0 {
LiteralContent::SimpleLiteral(ref value) => Some(!value.is_empty()), LiteralContent::SimpleLiteral(ref value) | LiteralContent::String(ref value) => {
LiteralContent::String(ref value) => Some(!value.is_empty()), Some(!value.is_empty())
}
LiteralContent::LanguageTaggedString { .. } => None, LiteralContent::LanguageTaggedString { .. } => None,
LiteralContent::Boolean(value) => Some(value), LiteralContent::Boolean(value) => Some(value),
LiteralContent::Float(value) => Some(!value.is_zero()),
LiteralContent::Double(value) => Some(!value.is_zero()),
LiteralContent::Integer(value) => Some(!value.is_zero()),
LiteralContent::TypedLiteral { .. } => None, LiteralContent::TypedLiteral { .. } => None,
} }
} }
/// Returns the value of this literal as an f32 if it exists following the rules of [XPath xsd:float casting](https://www.w3.org/TR/xpath-functions/#casting-to-float)
pub fn to_float(&self) -> Option<f32> {
match self.0 {
LiteralContent::Float(value) => Some(*value),
LiteralContent::Boolean(value) => Some(if value { 1. } else { 0. }),
LiteralContent::Double(value) => Some(*value as f32),
LiteralContent::Integer(value) => Some(value as f32),
LiteralContent::SimpleLiteral(ref value) | LiteralContent::String(ref value) => {
value.parse().ok()
}
_ => None,
}
}
/// Returns the value of this literal as an f64 if it exists following the rules of [XPath xsd:double casting](https://www.w3.org/TR/xpath-functions/#casting-to-double)
pub fn to_double(&self) -> Option<f64> {
match self.0 {
LiteralContent::Double(value) => Some(*value),
LiteralContent::Float(value) => Some(*value as f64),
LiteralContent::Integer(value) => Some(value as f64),
LiteralContent::Boolean(value) => Some(if value { 1. } else { 0. }),
LiteralContent::SimpleLiteral(ref value) | LiteralContent::String(ref value) => {
value.parse().ok()
}
_ => None,
}
}
/// Returns the value of this literal as an i128 if it exists following the rules of [XPath xsd:integer casting](https://www.w3.org/TR/xpath-functions/#casting-to-integer)
pub fn to_integer(&self) -> Option<i128> {
match self.0 {
LiteralContent::Integer(value) => Some(value),
LiteralContent::Float(value) => Some(*value as i128),
LiteralContent::Double(value) => Some(*value as i128),
LiteralContent::Boolean(value) => Some(if value { 1 } else { 0 }),
LiteralContent::SimpleLiteral(ref value) | LiteralContent::String(ref value) => {
value.parse().ok()
}
_ => None,
}
}
} }
impl fmt::Display for Literal { impl fmt::Display for Literal {
@ -179,29 +274,56 @@ impl From<bool> for Literal {
} }
} }
impl From<usize> for Literal { impl From<i128> for Literal {
fn from(value: usize) -> Self { fn from(value: i128) -> Self {
Literal(LiteralContent::TypedLiteral { Literal(LiteralContent::Integer(value))
value: value.to_string(), }
datatype: xsd::INTEGER.clone(), }
})
impl From<i64> for Literal {
fn from(value: i64) -> Self {
Literal(LiteralContent::Integer(value as i128))
}
}
impl From<i32> for Literal {
fn from(value: i32) -> Self {
Literal(LiteralContent::Integer(value as i128))
}
}
impl From<i16> for Literal {
fn from(value: i16) -> Self {
Literal(LiteralContent::Integer(value as i128))
}
}
impl From<u64> for Literal {
fn from(value: u64) -> Self {
Literal(LiteralContent::Integer(value as i128))
}
}
impl From<u32> for Literal {
fn from(value: u32) -> Self {
Literal(LiteralContent::Integer(value as i128))
}
}
impl From<u16> for Literal {
fn from(value: u16) -> Self {
Literal(LiteralContent::Integer(value as i128))
} }
} }
impl From<f32> for Literal { impl From<f32> for Literal {
fn from(value: f32) -> Self { fn from(value: f32) -> Self {
Literal(LiteralContent::TypedLiteral { Literal(LiteralContent::Float(value.into()))
value: value.to_string(),
datatype: xsd::FLOAT.clone(),
})
} }
} }
impl From<f64> for Literal { impl From<f64> for Literal {
fn from(value: f64) -> Self { fn from(value: f64) -> Self {
Literal(LiteralContent::TypedLiteral { Literal(LiteralContent::Double(value.into()))
value: value.to_string(),
datatype: xsd::DOUBLE.clone(),
})
} }
} }

@ -4,6 +4,7 @@ use std::char;
use model::vocab::rdf; use model::vocab::rdf;
use model::vocab::xsd; use model::vocab::xsd;
use std::iter; use std::iter;
use std::str::FromStr;
use rio::utils::unescape_unicode_codepoints; use rio::utils::unescape_unicode_codepoints;
#![arguments(state: &mut ParserState, buffer: &mut Vec<Triple>)] #![arguments(state: &mut ParserState, buffer: &mut Vec<Triple>)]
@ -120,7 +121,10 @@ collection_value -> Term = o:object_value _ { o }
//[16] //[16]
NumericLiteral -> Literal = NumericLiteral -> Literal =
d:$(DOUBLE) { Literal::new_typed_literal(d, xsd::DOUBLE.clone()) } / d:$(DOUBLE) {? match f64::from_str(d) {
Ok(value) => Ok(value.into()),
Err(_) => Err("Invalid xsd:double")
} } /
d:$(DECIMAL) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } / d:$(DECIMAL) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } /
i:$(INTEGER) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) } i:$(INTEGER) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) }

@ -1,3 +1,4 @@
use num_traits::identities::Zero;
use sparql::algebra::*; use sparql::algebra::*;
use sparql::plan::*; use sparql::plan::*;
use std::collections::HashSet; use std::collections::HashSet;
@ -223,16 +224,7 @@ impl<S: EncodedQuadsStore> SimpleEvaluator<S> {
} }
_ => None, _ => None,
}, },
PlanExpression::Datatype(e) => match self.eval_expression(e, tuple)? { PlanExpression::Datatype(e) => self.eval_expression(e, tuple)?.datatype(),
EncodedTerm::SimpleLiteral { .. } => Some(ENCODED_XSD_STRING_NAMED_NODE),
EncodedTerm::LangStringLiteral { .. } => Some(ENCODED_RDF_LANG_STRING_NAMED_NODE),
EncodedTerm::TypedLiteral { datatype_id, .. } => Some(EncodedTerm::NamedNode {
iri_id: datatype_id,
}),
EncodedTerm::StringLiteral { .. } => Some(ENCODED_XSD_STRING_NAMED_NODE),
EncodedTerm::BooleanLiteral(..) => Some(ENCODED_XSD_BOOLEAN_NAMED_NODE),
_ => None,
},
PlanExpression::Bound(v) => Some((*v >= tuple.len() && tuple[*v].is_some()).into()), PlanExpression::Bound(v) => Some((*v >= tuple.len() && tuple[*v].is_some()).into()),
PlanExpression::IRI(e) => match self.eval_expression(e, tuple)? { PlanExpression::IRI(e) => match self.eval_expression(e, tuple)? {
EncodedTerm::NamedNode { iri_id } => Some(EncodedTerm::NamedNode { iri_id }), EncodedTerm::NamedNode { iri_id } => Some(EncodedTerm::NamedNode { iri_id }),
@ -271,6 +263,9 @@ impl<S: EncodedQuadsStore> SimpleEvaluator<S> {
EncodedTerm::BooleanLiteral(value) => Some(value), EncodedTerm::BooleanLiteral(value) => Some(value),
EncodedTerm::SimpleLiteral { .. } => Some(term != ENCODED_EMPTY_SIMPLE_LITERAL), EncodedTerm::SimpleLiteral { .. } => Some(term != ENCODED_EMPTY_SIMPLE_LITERAL),
EncodedTerm::StringLiteral { .. } => Some(term != ENCODED_EMPTY_STRING_LITERAL), EncodedTerm::StringLiteral { .. } => Some(term != ENCODED_EMPTY_STRING_LITERAL),
EncodedTerm::FloatLiteral(value) => Some(!value.is_zero()),
EncodedTerm::DoubleLiteral(value) => Some(!value.is_zero()),
EncodedTerm::IntegerLiteral(value) => Some(!value.is_zero()),
_ => None, _ => None,
} }
} }
@ -278,14 +273,24 @@ impl<S: EncodedQuadsStore> SimpleEvaluator<S> {
fn to_string_id(&self, term: EncodedTerm) -> Option<u64> { fn to_string_id(&self, term: EncodedTerm) -> Option<u64> {
match term { match term {
EncodedTerm::NamedNode { iri_id } => Some(iri_id), EncodedTerm::NamedNode { iri_id } => Some(iri_id),
EncodedTerm::SimpleLiteral { value_id } => Some(value_id), EncodedTerm::SimpleLiteral { value_id } | EncodedTerm::StringLiteral { value_id } => {
Some(value_id)
}
EncodedTerm::LangStringLiteral { value_id, .. } => Some(value_id), EncodedTerm::LangStringLiteral { value_id, .. } => Some(value_id),
EncodedTerm::TypedLiteral { value_id, .. } => Some(value_id), EncodedTerm::TypedLiteral { value_id, .. } => Some(value_id),
EncodedTerm::StringLiteral { value_id } => Some(value_id),
EncodedTerm::BooleanLiteral(value) => self EncodedTerm::BooleanLiteral(value) => self
.store .store
.insert_bytes(if value { b"true" } else { b"false" }) .insert_bytes(if value { b"true" } else { b"false" })
.ok(), .ok(),
EncodedTerm::FloatLiteral(value) => {
self.store.insert_bytes(value.to_string().as_bytes()).ok()
}
EncodedTerm::DoubleLiteral(value) => {
self.store.insert_bytes(value.to_string().as_bytes()).ok()
}
EncodedTerm::IntegerLiteral(value) => {
self.store.insert_bytes(value.to_string().as_bytes()).ok()
}
_ => None, _ => None,
} }
} }

@ -871,20 +871,29 @@ NumericLiteral -> Literal = NumericLiteralUnsigned / NumericLiteralPositive / N
//[131] //[131]
NumericLiteralUnsigned -> Literal = NumericLiteralUnsigned -> Literal =
d:$(DOUBLE) { Literal::new_typed_literal(d, xsd::DOUBLE.clone()) } / d:$(DOUBLE) {? match f64::from_str(d) {
Ok(value) => Ok(value.into()),
Err(_) => Err("Invalid xsd:double")
} } /
d:$(DECIMAL) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } / d:$(DECIMAL) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } /
i:$(INTEGER) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) } i:$(INTEGER) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) }
//[132] //[132]
NumericLiteralPositive -> Literal = NumericLiteralPositive -> Literal =
d:$(DOUBLE_POSITIVE) { Literal::new_typed_literal(d, xsd::DOUBLE.clone()) } / d:$(DOUBLE_POSITIVE) {? match f64::from_str(d) {
Ok(value) => Ok(value.into()),
Err(_) => Err("Invalid xsd:double")
} } /
d:$(DECIMAL_POSITIVE) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } / d:$(DECIMAL_POSITIVE) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } /
i:$(INTEGER_POSITIVE) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) } i:$(INTEGER_POSITIVE) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) }
//[133] //[133]
NumericLiteralNegative -> Literal = NumericLiteralNegative -> Literal =
d:$(DOUBLE_NEGATIVE) { Literal::new_typed_literal(d, xsd::DOUBLE.clone()) } / d:$(DOUBLE_NEGATIVE) {? match f64::from_str(d) {
Ok(value) => Ok(value.into()),
Err(_) => Err("Invalid xsd:double")
} } /
d:$(DECIMAL_NEGATIVE) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } / d:$(DECIMAL_NEGATIVE) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } /
i:$(INTEGER_NEGATIVE) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) } i:$(INTEGER_NEGATIVE) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) }

@ -2,6 +2,7 @@ use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
use model::vocab::rdf; use model::vocab::rdf;
use model::vocab::xsd; use model::vocab::xsd;
use model::*; use model::*;
use ordered_float::OrderedFloat;
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
use std::ops::Deref; use std::ops::Deref;
@ -56,6 +57,9 @@ const TYPE_TYPED_LITERAL_ID: u8 = 5;
const TYPE_STRING_LITERAL: u8 = 6; const TYPE_STRING_LITERAL: u8 = 6;
const TYPE_BOOLEAN_LITERAL_TRUE: u8 = 7; const TYPE_BOOLEAN_LITERAL_TRUE: u8 = 7;
const TYPE_BOOLEAN_LITERAL_FALSE: u8 = 8; 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;
pub static ENCODED_DEFAULT_GRAPH: EncodedTerm = EncodedTerm::DefaultGraph {}; pub static ENCODED_DEFAULT_GRAPH: EncodedTerm = EncodedTerm::DefaultGraph {};
pub static ENCODED_EMPTY_SIMPLE_LITERAL: EncodedTerm = EncodedTerm::SimpleLiteral { pub static ENCODED_EMPTY_SIMPLE_LITERAL: EncodedTerm = EncodedTerm::SimpleLiteral {
@ -99,23 +103,12 @@ pub enum EncodedTerm {
TypedLiteral { value_id: u64, datatype_id: u64 }, TypedLiteral { value_id: u64, datatype_id: u64 },
StringLiteral { value_id: u64 }, StringLiteral { value_id: u64 },
BooleanLiteral(bool), BooleanLiteral(bool),
FloatLiteral(OrderedFloat<f32>),
DoubleLiteral(OrderedFloat<f64>),
IntegerLiteral(i128),
} }
impl EncodedTerm { impl EncodedTerm {
fn type_id(&self) -> u8 {
match self {
EncodedTerm::DefaultGraph { .. } => TYPE_DEFAULT_GRAPH_ID,
EncodedTerm::NamedNode { .. } => TYPE_NAMED_NODE_ID,
EncodedTerm::BlankNode(_) => TYPE_BLANK_NODE_ID,
EncodedTerm::SimpleLiteral { .. } => TYPE_SIMPLE_LITERAL_ID,
EncodedTerm::LangStringLiteral { .. } => TYPE_LANG_STRING_LITERAL_ID,
EncodedTerm::TypedLiteral { .. } => TYPE_TYPED_LITERAL_ID,
EncodedTerm::StringLiteral { .. } => TYPE_STRING_LITERAL,
EncodedTerm::BooleanLiteral(true) => TYPE_BOOLEAN_LITERAL_TRUE,
EncodedTerm::BooleanLiteral(false) => TYPE_BOOLEAN_LITERAL_FALSE,
}
}
pub fn is_named_node(&self) -> bool { pub fn is_named_node(&self) -> bool {
match self { match self {
EncodedTerm::NamedNode { .. } => true, EncodedTerm::NamedNode { .. } => true,
@ -137,14 +130,69 @@ impl EncodedTerm {
EncodedTerm::TypedLiteral { .. } => true, EncodedTerm::TypedLiteral { .. } => true,
EncodedTerm::StringLiteral { .. } => true, EncodedTerm::StringLiteral { .. } => true,
EncodedTerm::BooleanLiteral(_) => true, EncodedTerm::BooleanLiteral(_) => true,
EncodedTerm::FloatLiteral(_) => true,
EncodedTerm::DoubleLiteral(_) => true,
EncodedTerm::IntegerLiteral(_) => true,
_ => false, _ => false,
} }
} }
pub fn datatype(&self) -> Option<EncodedTerm> {
match self {
EncodedTerm::SimpleLiteral { .. } | EncodedTerm::StringLiteral { .. } => {
Some(ENCODED_XSD_STRING_NAMED_NODE)
}
EncodedTerm::LangStringLiteral { .. } => Some(ENCODED_RDF_LANG_STRING_NAMED_NODE),
EncodedTerm::TypedLiteral { datatype_id, .. } => Some(EncodedTerm::NamedNode {
iri_id: *datatype_id,
}),
EncodedTerm::BooleanLiteral(..) => Some(ENCODED_XSD_BOOLEAN_NAMED_NODE),
EncodedTerm::FloatLiteral(..) => Some(ENCODED_XSD_FLOAT_NAMED_NODE),
EncodedTerm::DoubleLiteral(..) => Some(ENCODED_XSD_DOUBLE_NAMED_NODE),
EncodedTerm::IntegerLiteral(..) => Some(ENCODED_XSD_INTEGER_NAMED_NODE),
_ => None,
}
}
fn type_id(&self) -> u8 {
match self {
EncodedTerm::DefaultGraph { .. } => TYPE_DEFAULT_GRAPH_ID,
EncodedTerm::NamedNode { .. } => TYPE_NAMED_NODE_ID,
EncodedTerm::BlankNode(_) => TYPE_BLANK_NODE_ID,
EncodedTerm::SimpleLiteral { .. } => TYPE_SIMPLE_LITERAL_ID,
EncodedTerm::LangStringLiteral { .. } => TYPE_LANG_STRING_LITERAL_ID,
EncodedTerm::TypedLiteral { .. } => TYPE_TYPED_LITERAL_ID,
EncodedTerm::StringLiteral { .. } => TYPE_STRING_LITERAL,
EncodedTerm::BooleanLiteral(true) => TYPE_BOOLEAN_LITERAL_TRUE,
EncodedTerm::BooleanLiteral(false) => TYPE_BOOLEAN_LITERAL_FALSE,
EncodedTerm::FloatLiteral(_) => TYPE_FLOAT_LITERAL,
EncodedTerm::DoubleLiteral(_) => TYPE_DOUBLE_LITERAL,
EncodedTerm::IntegerLiteral(_) => TYPE_INTEGER_LITERAL,
}
}
} }
impl From<bool> for EncodedTerm { impl From<bool> for EncodedTerm {
fn from(val: bool) -> Self { fn from(value: bool) -> Self {
EncodedTerm::BooleanLiteral(val) EncodedTerm::BooleanLiteral(value)
}
}
impl From<i128> for EncodedTerm {
fn from(value: i128) -> Self {
EncodedTerm::IntegerLiteral(value)
}
}
impl From<f32> for EncodedTerm {
fn from(value: f32) -> Self {
EncodedTerm::FloatLiteral(value.into())
}
}
impl From<f64> for EncodedTerm {
fn from(value: f64) -> Self {
EncodedTerm::DoubleLiteral(value.into())
} }
} }
@ -207,6 +255,15 @@ impl<R: Read> TermReader for R {
}), }),
TYPE_BOOLEAN_LITERAL_TRUE => Ok(EncodedTerm::BooleanLiteral(true)), TYPE_BOOLEAN_LITERAL_TRUE => Ok(EncodedTerm::BooleanLiteral(true)),
TYPE_BOOLEAN_LITERAL_FALSE => Ok(EncodedTerm::BooleanLiteral(false)), TYPE_BOOLEAN_LITERAL_FALSE => Ok(EncodedTerm::BooleanLiteral(false)),
TYPE_FLOAT_LITERAL => Ok(EncodedTerm::FloatLiteral(OrderedFloat(
self.read_f32::<NetworkEndian>()?,
))),
TYPE_DOUBLE_LITERAL => Ok(EncodedTerm::DoubleLiteral(OrderedFloat(
self.read_f64::<NetworkEndian>()?,
))),
TYPE_INTEGER_LITERAL => Ok(EncodedTerm::IntegerLiteral(
self.read_i128::<NetworkEndian>()?,
)),
_ => Err("the term buffer has an invalid type id".into()), _ => Err("the term buffer has an invalid type id".into()),
} }
} }
@ -287,6 +344,9 @@ impl<R: Write> TermWriter for R {
self.write_u64::<NetworkEndian>(value_id)?; self.write_u64::<NetworkEndian>(value_id)?;
} }
EncodedTerm::BooleanLiteral(_) => {} EncodedTerm::BooleanLiteral(_) => {}
EncodedTerm::FloatLiteral(value) => self.write_f32::<NetworkEndian>(*value)?,
EncodedTerm::DoubleLiteral(value) => self.write_f64::<NetworkEndian>(*value)?,
EncodedTerm::IntegerLiteral(value) => self.write_i128::<NetworkEndian>(value)?,
} }
Ok(()) Ok(())
} }
@ -352,11 +412,25 @@ impl<S: BytesStore> Encoder<S> {
value_id: self.encode_str_value(&literal.value())?, value_id: self.encode_str_value(&literal.value())?,
} }
} else if literal.is_boolean() { } else if literal.is_boolean() {
EncodedTerm::BooleanLiteral(
literal literal
.to_bool() .to_bool()
.ok_or_else(|| Error::from("boolean literal without boolean value"))?, .ok_or_else(|| Error::from("boolean literal without boolean value"))?
) .into()
} else if literal.is_float() {
literal
.to_float()
.ok_or_else(|| Error::from("float literal without float value"))?
.into()
} else if literal.is_double() {
literal
.to_double()
.ok_or_else(|| Error::from("double literal without double value"))?
.into()
} else if literal.is_integer() {
literal
.to_integer()
.ok_or_else(|| Error::from("integer literal without integer value"))?
.into()
} else { } else {
EncodedTerm::TypedLiteral { EncodedTerm::TypedLiteral {
value_id: self.encode_str_value(&literal.value())?, value_id: self.encode_str_value(&literal.value())?,
@ -433,6 +507,9 @@ impl<S: BytesStore> Encoder<S> {
Ok(Literal::from(self.decode_str_value(value_id)?).into()) Ok(Literal::from(self.decode_str_value(value_id)?).into())
} }
EncodedTerm::BooleanLiteral(value) => Ok(Literal::from(value).into()), EncodedTerm::BooleanLiteral(value) => Ok(Literal::from(value).into()),
EncodedTerm::FloatLiteral(value) => Ok(Literal::from(*value).into()),
EncodedTerm::DoubleLiteral(value) => Ok(Literal::from(*value).into()),
EncodedTerm::IntegerLiteral(value) => Ok(Literal::from(value).into()),
} }
} }
@ -541,8 +618,10 @@ mod test {
NamedNode::from_str("http://bar.com").unwrap().into(), NamedNode::from_str("http://bar.com").unwrap().into(),
NamedNode::from_str("http://foo.com").unwrap().into(), NamedNode::from_str("http://foo.com").unwrap().into(),
BlankNode::default().into(), BlankNode::default().into(),
Literal::new_simple_literal("foo").into(),
Literal::from(true).into(), Literal::from(true).into(),
Literal::from(1.2).into(), Literal::from(1.2).into(),
Literal::from(1).into(),
Literal::from("foo").into(), Literal::from("foo").into(),
Literal::new_language_tagged_literal("foo", "fr").into(), Literal::new_language_tagged_literal("foo", "fr").into(),
]; ];

@ -88,6 +88,13 @@ fn sparql_w3c_query_evaluation_testsuite() {
.unwrap(), .unwrap(),
]; ];
let test_blacklist = vec![ let test_blacklist = vec![
//Multiple writing of the same xsd:integer. Our system does strong normalization.
NamedNode::from_str(
"http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest#distinct-1",
).unwrap(),
NamedNode::from_str(
"http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest#distinct-9",
).unwrap(),
//With LeftJoin //With LeftJoin
NamedNode::from_str( NamedNode::from_str(
"http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest#distinct-4", "http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest#distinct-4",

Loading…
Cancel
Save