Adds native encoding for xsd:decimal

pull/10/head
Tpt 6 years ago
parent 1edd66b31e
commit fa270a220c
  1. 1
      lib/Cargo.toml
  2. 1
      lib/src/lib.rs
  3. 68
      lib/src/model/literal.rs
  4. 53
      lib/src/sparql/eval.rs
  5. 24
      lib/src/store/numeric_encoder.rs

@ -25,6 +25,7 @@ byteorder = {version="1", features = ["i128"] }
quick-xml = "0.13"
ordered-float = "1"
num-traits = "0.2"
rust_decimal = "0.10"
[build-dependencies]
peg = "0.5"

@ -7,6 +7,7 @@ extern crate num_traits;
extern crate ordered_float;
extern crate quick_xml;
extern crate rocksdb;
extern crate rust_decimal;
extern crate url;
extern crate uuid;

@ -2,7 +2,11 @@ use model::named_node::NamedNode;
use model::vocab::rdf;
use model::vocab::xsd;
use num_traits::identities::Zero;
use num_traits::FromPrimitive;
use num_traits::One;
use num_traits::ToPrimitive;
use ordered_float::OrderedFloat;
use rust_decimal::Decimal;
use std::borrow::Cow;
use std::fmt;
use std::option::Option;
@ -42,6 +46,7 @@ enum LiteralContent {
Float(OrderedFloat<f32>),
Double(OrderedFloat<f64>),
Integer(i128),
Decimal(Decimal),
TypedLiteral { value: String, datatype: NamedNode },
}
@ -78,6 +83,11 @@ impl Literal {
Ok(value) => LiteralContent::Integer(value),
Err(_) => LiteralContent::TypedLiteral { value, datatype },
}
} else if datatype == *xsd::DECIMAL {
match value.parse() {
Ok(value) => LiteralContent::Decimal(value),
Err(_) => LiteralContent::TypedLiteral { value, datatype },
}
} else {
LiteralContent::TypedLiteral { value, datatype }
})
@ -105,6 +115,7 @@ impl Literal {
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::Decimal(value) => Cow::Owned(value.to_string()),
LiteralContent::TypedLiteral { ref value, .. } => Cow::Borrowed(value),
}
}
@ -130,6 +141,7 @@ impl Literal {
LiteralContent::Float(_) => &xsd::FLOAT,
LiteralContent::Double(_) => &xsd::DOUBLE,
LiteralContent::Integer(_) => &xsd::INTEGER,
LiteralContent::Decimal(_) => &xsd::DECIMAL,
LiteralContent::TypedLiteral { ref datatype, .. } => datatype,
}
}
@ -186,6 +198,15 @@ impl Literal {
}
}
/// Checks if the literal has the datatype [xsd:decimal](http://www.w3.org/2001/XMLSchema#decimal) or one of its sub datatype and is valid
pub fn is_decimal(&self) -> bool {
match self.0 {
LiteralContent::Integer(_) => true,
LiteralContent::Decimal(_) => true,
_ => false,
}
}
/// 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> {
match self.0 {
@ -197,6 +218,7 @@ impl Literal {
LiteralContent::Float(value) => Some(!value.is_zero()),
LiteralContent::Double(value) => Some(!value.is_zero()),
LiteralContent::Integer(value) => Some(!value.is_zero()),
LiteralContent::Decimal(value) => Some(!value.is_zero()),
LiteralContent::TypedLiteral { .. } => None,
}
}
@ -204,10 +226,11 @@ impl Literal {
/// 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::Float(value) => value.to_f32(),
LiteralContent::Double(value) => value.to_f32(),
LiteralContent::Integer(value) => value.to_f32(),
LiteralContent::Decimal(value) => value.to_f32(),
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()
}
@ -218,9 +241,10 @@ impl Literal {
/// 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::Float(value) => value.to_f64(),
LiteralContent::Double(value) => value.to_f64(),
LiteralContent::Integer(value) => value.to_f64(),
LiteralContent::Decimal(value) => value.to_f64(),
LiteralContent::Boolean(value) => Some(if value { 1. } else { 0. }),
LiteralContent::SimpleLiteral(ref value) | LiteralContent::String(ref value) => {
value.parse().ok()
@ -232,9 +256,10 @@ impl Literal {
/// 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::Float(value) => value.to_i128(),
LiteralContent::Double(value) => value.to_i128(),
LiteralContent::Integer(value) => value.to_i128(),
LiteralContent::Decimal(value) => value.to_i128(),
LiteralContent::Boolean(value) => Some(if value { 1 } else { 0 }),
LiteralContent::SimpleLiteral(ref value) | LiteralContent::String(ref value) => {
value.parse().ok()
@ -242,6 +267,25 @@ impl Literal {
_ => None,
}
}
/// Returns the value of this literal as Decimal if it exists following the rules of [XPath xsd:decimal casting](https://www.w3.org/TR/xpath-functions/#casting-to-decimal)
pub(crate) fn to_decimal(&self) -> Option<Decimal> {
match self.0 {
LiteralContent::Float(value) => Decimal::from_f32(*value),
LiteralContent::Double(value) => Decimal::from_f64(*value),
LiteralContent::Integer(value) => Decimal::from_i128(value),
LiteralContent::Decimal(value) => Some(value),
LiteralContent::Boolean(value) => Some(if value {
Decimal::one()
} else {
Decimal::zero()
}),
LiteralContent::SimpleLiteral(ref value) | LiteralContent::String(ref value) => {
value.parse().ok()
}
_ => None,
}
}
}
impl fmt::Display for Literal {
@ -327,3 +371,9 @@ impl From<f64> for Literal {
Literal(LiteralContent::Double(value.into()))
}
}
impl From<Decimal> for Literal {
fn from(value: Decimal) -> Self {
Literal(LiteralContent::Decimal(value))
}
}

@ -1,4 +1,7 @@
use num_traits::identities::Zero;
use num_traits::FromPrimitive;
use num_traits::ToPrimitive;
use rust_decimal::Decimal;
use sparql::algebra::*;
use sparql::plan::*;
use std::collections::HashSet;
@ -245,32 +248,38 @@ impl<S: EncodedQuadsStore> SimpleEvaluator<S> {
NumericBinaryOperands::Float(v1, v2) => (v1 + v2).into(),
NumericBinaryOperands::Double(v1, v2) => (v1 + v2).into(),
NumericBinaryOperands::Integer(v1, v2) => (v1 + v2).into(),
NumericBinaryOperands::Decimal(v1, v2) => (v1 + v2).into(),
}),
PlanExpression::Sub(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? {
NumericBinaryOperands::Float(v1, v2) => (v1 - v2).into(),
NumericBinaryOperands::Double(v1, v2) => (v1 - v2).into(),
NumericBinaryOperands::Integer(v1, v2) => (v1 - v2).into(),
NumericBinaryOperands::Decimal(v1, v2) => (v1 - v2).into(),
}),
PlanExpression::Mul(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? {
NumericBinaryOperands::Float(v1, v2) => (v1 * v2).into(),
NumericBinaryOperands::Double(v1, v2) => (v1 * v2).into(),
NumericBinaryOperands::Integer(v1, v2) => (v1 * v2).into(),
NumericBinaryOperands::Decimal(v1, v2) => (v1 * v2).into(),
}),
PlanExpression::Div(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? {
NumericBinaryOperands::Float(v1, v2) => (v1 / v2).into(),
NumericBinaryOperands::Double(v1, v2) => (v1 / v2).into(),
NumericBinaryOperands::Integer(v1, v2) => (v1 / v2).into(),
NumericBinaryOperands::Decimal(v1, v2) => (v1 / v2).into(),
}),
PlanExpression::UnaryPlus(e) => match self.eval_expression(e, tuple)? {
EncodedTerm::FloatLiteral(value) => Some((*value).into()),
EncodedTerm::DoubleLiteral(value) => Some((*value).into()),
EncodedTerm::IntegerLiteral(value) => Some((value).into()),
EncodedTerm::DecimalLiteral(value) => Some((value).into()),
_ => None,
},
PlanExpression::UnaryMinus(e) => match self.eval_expression(e, tuple)? {
EncodedTerm::FloatLiteral(value) => Some((-*value).into()),
EncodedTerm::DoubleLiteral(value) => Some((-*value).into()),
EncodedTerm::IntegerLiteral(value) => Some((-value).into()),
EncodedTerm::DecimalLiteral(value) => Some((-value).into()),
_ => None,
},
PlanExpression::UnaryNot(e) => self
@ -329,6 +338,7 @@ impl<S: EncodedQuadsStore> SimpleEvaluator<S> {
EncodedTerm::FloatLiteral(value) => Some(!value.is_zero()),
EncodedTerm::DoubleLiteral(value) => Some(!value.is_zero()),
EncodedTerm::IntegerLiteral(value) => Some(!value.is_zero()),
EncodedTerm::DecimalLiteral(value) => Some(!value.is_zero()),
_ => None,
}
}
@ -354,6 +364,9 @@ impl<S: EncodedQuadsStore> SimpleEvaluator<S> {
EncodedTerm::IntegerLiteral(value) => {
self.store.insert_bytes(value.to_string().as_bytes()).ok()
}
EncodedTerm::DecimalLiteral(value) => {
self.store.insert_bytes(value.to_string().as_bytes()).ok()
}
_ => None,
}
}
@ -369,20 +382,53 @@ impl<S: EncodedQuadsStore> SimpleEvaluator<S> {
self.eval_expression(&e2, tuple)?,
) {
(EncodedTerm::FloatLiteral(v1), EncodedTerm::FloatLiteral(v2)) => {
Some(NumericBinaryOperands::Float(*v1, *v2))
Some(NumericBinaryOperands::Float(*v1, v2.to_f32()?))
}
(EncodedTerm::FloatLiteral(v1), EncodedTerm::DoubleLiteral(v2)) => {
Some(NumericBinaryOperands::Double(*v1 as f64, *v2))
Some(NumericBinaryOperands::Double(v1.to_f64()?, *v2))
}
(EncodedTerm::FloatLiteral(v1), EncodedTerm::IntegerLiteral(v2)) => {
Some(NumericBinaryOperands::Float(*v1, v2.to_f32()?))
}
(EncodedTerm::FloatLiteral(v1), EncodedTerm::DecimalLiteral(v2)) => {
Some(NumericBinaryOperands::Float(*v1, v2.to_f32()?))
}
(EncodedTerm::DoubleLiteral(v1), EncodedTerm::FloatLiteral(v2)) => {
Some(NumericBinaryOperands::Double(*v1, *v2 as f64))
Some(NumericBinaryOperands::Double(*v1, v2.to_f64()?))
}
(EncodedTerm::DoubleLiteral(v1), EncodedTerm::DoubleLiteral(v2)) => {
Some(NumericBinaryOperands::Double(*v1, *v2))
}
(EncodedTerm::DoubleLiteral(v1), EncodedTerm::IntegerLiteral(v2)) => {
Some(NumericBinaryOperands::Double(*v1, v2.to_f64()?))
}
(EncodedTerm::DoubleLiteral(v1), EncodedTerm::DecimalLiteral(v2)) => {
Some(NumericBinaryOperands::Double(*v1, v2.to_f64()?))
}
(EncodedTerm::IntegerLiteral(v1), EncodedTerm::FloatLiteral(v2)) => {
Some(NumericBinaryOperands::Float(v1.to_f32()?, *v2))
}
(EncodedTerm::IntegerLiteral(v1), EncodedTerm::DoubleLiteral(v2)) => {
Some(NumericBinaryOperands::Double(v1.to_f64()?, *v2))
}
(EncodedTerm::IntegerLiteral(v1), EncodedTerm::IntegerLiteral(v2)) => {
Some(NumericBinaryOperands::Integer(v1, v2))
}
(EncodedTerm::IntegerLiteral(v1), EncodedTerm::DecimalLiteral(v2)) => {
Some(NumericBinaryOperands::Decimal(Decimal::from_i128(v1)?, v2))
}
(EncodedTerm::DecimalLiteral(v1), EncodedTerm::FloatLiteral(v2)) => {
Some(NumericBinaryOperands::Float(v1.to_f32()?, *v2))
}
(EncodedTerm::DecimalLiteral(v1), EncodedTerm::DoubleLiteral(v2)) => {
Some(NumericBinaryOperands::Double(v1.to_f64()?, *v2))
}
(EncodedTerm::DecimalLiteral(v1), EncodedTerm::IntegerLiteral(v2)) => {
Some(NumericBinaryOperands::Decimal(v1, Decimal::from_i128(v2)?))
}
(EncodedTerm::DecimalLiteral(v1), EncodedTerm::DecimalLiteral(v2)) => {
Some(NumericBinaryOperands::Decimal(v1, v2))
}
_ => None,
}
}
@ -414,6 +460,7 @@ enum NumericBinaryOperands {
Float(f32, f32),
Double(f64, f64),
Integer(i128, i128),
Decimal(Decimal, Decimal),
}
fn get_pattern_value(

@ -3,6 +3,7 @@ use model::vocab::rdf;
use model::vocab::xsd;
use model::*;
use ordered_float::OrderedFloat;
use rust_decimal::Decimal;
use std::io::Read;
use std::io::Write;
use std::ops::Deref;
@ -60,6 +61,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;
pub static ENCODED_DEFAULT_GRAPH: EncodedTerm = EncodedTerm::DefaultGraph {};
pub static ENCODED_EMPTY_SIMPLE_LITERAL: EncodedTerm = EncodedTerm::SimpleLiteral {
@ -106,6 +108,7 @@ pub enum EncodedTerm {
FloatLiteral(OrderedFloat<f32>),
DoubleLiteral(OrderedFloat<f64>),
IntegerLiteral(i128),
DecimalLiteral(Decimal),
}
impl EncodedTerm {
@ -133,6 +136,7 @@ impl EncodedTerm {
EncodedTerm::FloatLiteral(_) => true,
EncodedTerm::DoubleLiteral(_) => true,
EncodedTerm::IntegerLiteral(_) => true,
EncodedTerm::DecimalLiteral(_) => true,
_ => false,
}
}
@ -150,6 +154,7 @@ impl EncodedTerm {
EncodedTerm::FloatLiteral(..) => Some(ENCODED_XSD_FLOAT_NAMED_NODE),
EncodedTerm::DoubleLiteral(..) => Some(ENCODED_XSD_DOUBLE_NAMED_NODE),
EncodedTerm::IntegerLiteral(..) => Some(ENCODED_XSD_INTEGER_NAMED_NODE),
EncodedTerm::DecimalLiteral(..) => Some(ENCODED_XSD_DECIMAL_NAMED_NODE),
_ => None,
}
}
@ -168,6 +173,7 @@ impl EncodedTerm {
EncodedTerm::FloatLiteral(_) => TYPE_FLOAT_LITERAL,
EncodedTerm::DoubleLiteral(_) => TYPE_DOUBLE_LITERAL,
EncodedTerm::IntegerLiteral(_) => TYPE_INTEGER_LITERAL,
EncodedTerm::DecimalLiteral(_) => TYPE_DECIMAL_LITERAL,
}
}
}
@ -196,6 +202,12 @@ impl From<f64> for EncodedTerm {
}
}
impl From<Decimal> for EncodedTerm {
fn from(value: Decimal) -> Self {
EncodedTerm::DecimalLiteral(value)
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
pub struct EncodedQuad {
pub subject: EncodedTerm,
@ -264,6 +276,11 @@ impl<R: Read> TermReader for R {
TYPE_INTEGER_LITERAL => Ok(EncodedTerm::IntegerLiteral(
self.read_i128::<NetworkEndian>()?,
)),
TYPE_DECIMAL_LITERAL => {
let mut buffer = [0 as u8; 16];
self.read_exact(&mut buffer)?;
Ok(EncodedTerm::DecimalLiteral(Decimal::deserialize(buffer)))
}
_ => Err("the term buffer has an invalid type id".into()),
}
}
@ -347,6 +364,7 @@ impl<R: Write> TermWriter for R {
EncodedTerm::FloatLiteral(value) => self.write_f32::<NetworkEndian>(*value)?,
EncodedTerm::DoubleLiteral(value) => self.write_f64::<NetworkEndian>(*value)?,
EncodedTerm::IntegerLiteral(value) => self.write_i128::<NetworkEndian>(value)?,
EncodedTerm::DecimalLiteral(value) => self.write_all(&value.serialize())?,
}
Ok(())
}
@ -431,6 +449,11 @@ impl<S: BytesStore> Encoder<S> {
.to_integer()
.ok_or_else(|| Error::from("integer literal without integer value"))?
.into()
} else if literal.is_decimal() {
literal
.to_decimal()
.ok_or_else(|| Error::from("decimal literal without decimal value"))?
.into()
} else {
EncodedTerm::TypedLiteral {
value_id: self.encode_str_value(&literal.value())?,
@ -510,6 +533,7 @@ impl<S: BytesStore> Encoder<S> {
EncodedTerm::FloatLiteral(value) => Ok(Literal::from(*value).into()),
EncodedTerm::DoubleLiteral(value) => Ok(Literal::from(*value).into()),
EncodedTerm::IntegerLiteral(value) => Ok(Literal::from(value).into()),
EncodedTerm::DecimalLiteral(value) => Ok(Literal::from(value).into()),
}
}

Loading…
Cancel
Save