Introduces native support for xsd:dayTimeDuration and xsd:yearMonthDuration

pull/41/head
Tpt 4 years ago
parent 0aa536998e
commit 79038afe44
  1. 17
      lib/src/model/literal.rs
  2. 102
      lib/src/model/xsd/date_time.rs
  3. 467
      lib/src/model/xsd/duration.rs
  4. 2
      lib/src/model/xsd/mod.rs
  5. 29
      lib/src/model/xsd/parser.rs
  6. 160
      lib/src/sparql/eval.rs
  7. 4
      lib/src/sparql/plan.rs
  8. 16
      lib/src/sparql/plan_builder.rs
  9. 101
      lib/src/store/numeric_encoder.rs

@ -304,6 +304,23 @@ impl From<Duration> for Literal {
} }
} }
impl From<YearMonthDuration> for Literal {
fn from(value: YearMonthDuration) -> Self {
Literal(LiteralContent::TypedLiteral {
value: value.to_string(),
datatype: xsd::YEAR_MONTH_DURATION.clone(),
})
}
}
impl From<DayTimeDuration> for Literal {
fn from(value: DayTimeDuration) -> Self {
Literal(LiteralContent::TypedLiteral {
value: value.to_string(),
datatype: xsd::DAY_TIME_DURATION.clone(),
})
}
}
impl<'a> From<&'a Literal> for rio::Literal<'a> { impl<'a> From<&'a Literal> for rio::Literal<'a> {
fn from(literal: &'a Literal) -> Self { fn from(literal: &'a Literal) -> Self {
if literal.is_plain() { if literal.is_plain() {

@ -1,5 +1,5 @@
use super::parser::{date_lexical_rep, date_time_lexical_rep, parse_value, time_lexical_rep}; use super::parser::{date_lexical_rep, date_time_lexical_rep, parse_value, time_lexical_rep};
use super::{Decimal, Duration, XsdParseError}; use super::{DayTimeDuration, Decimal, Duration, XsdParseError, YearMonthDuration};
use std::cmp::{min, Ordering}; use std::cmp::{min, Ordering};
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use std::error::Error; use std::error::Error;
@ -80,7 +80,7 @@ impl DateTime {
} }
/// [fn:timezone-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-timezone-from-dateTime) /// [fn:timezone-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-timezone-from-dateTime)
pub fn timezone(&self) -> Option<Duration> { pub fn timezone(&self) -> Option<DayTimeDuration> {
Some(self.timezone_offset()?.into()) Some(self.timezone_offset()?.into())
} }
@ -109,13 +109,27 @@ impl DateTime {
self.timestamp.checked_sub(rhs.into().timestamp) self.timestamp.checked_sub(rhs.into().timestamp)
} }
/// [op:add-yearMonthDuration-to-dateTime](https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDuration-to-dateTime) and [op:add-dayTimeDuration-to-dateTime](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-dateTime) /// [op:add-yearMonthDuration-to-dateTime](https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDuration-to-dateTime)
pub fn checked_add_duration(&self, rhs: impl Into<Duration>) -> Option<Self> { pub fn checked_add_year_month_duration(
&self,
rhs: impl Into<YearMonthDuration>,
) -> Option<Self> {
self.checked_add_duration(Duration::from(rhs.into()))
}
/// [op:add-dayTimeDuration-to-dateTime](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-dateTime)
pub fn checked_add_day_time_duration(&self, rhs: impl Into<Duration>) -> Option<Self> {
let rhs = rhs.into(); let rhs = rhs.into();
if rhs.all_months() == 0 {
Some(Self { Some(Self {
timestamp: self.timestamp.checked_add_seconds(rhs.all_seconds())?, timestamp: self.timestamp.checked_add_seconds(rhs.all_seconds())?,
}) })
}
/// [op:add-yearMonthDuration-to-dateTime](https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDuration-to-dateTime) and [op:add-dayTimeDuration-to-dateTime](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-dateTime)
pub fn checked_add_duration(&self, rhs: impl Into<Duration>) -> Option<Self> {
let rhs = rhs.into();
if let Ok(rhs) = DayTimeDuration::try_from(rhs) {
self.checked_add_day_time_duration(rhs)
} else { } else {
Some(Self { Some(Self {
timestamp: Timestamp::new(&date_time_plus_duration(rhs, &self.properties())?) timestamp: Timestamp::new(&date_time_plus_duration(rhs, &self.properties())?)
@ -124,13 +138,27 @@ impl DateTime {
} }
} }
/// [op:sub-yearMonthDuration-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-sub-yearMonthDuration-from-dateTime) and [op:sub-dayTimeDuration-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-sub-dayTimeDuration-from-dateTime) /// [op:sub-yearMonthDuration-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-sub-yearMonthDuration-from-dateTime)
pub fn checked_sub_duration(&self, rhs: impl Into<Duration>) -> Option<Self> { pub fn checked_sub_year_month_duration(
&self,
rhs: impl Into<YearMonthDuration>,
) -> Option<Self> {
self.checked_sub_duration(Duration::from(rhs.into()))
}
/// [op:sub-dayTimeDuration-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-sub-dayTimeDuration-from-dateTime)
pub fn checked_sub_day_time_duration(&self, rhs: impl Into<DayTimeDuration>) -> Option<Self> {
let rhs = rhs.into(); let rhs = rhs.into();
if rhs.all_months() == 0 {
Some(Self { Some(Self {
timestamp: self.timestamp.checked_sub_seconds(rhs.all_seconds())?, timestamp: self.timestamp.checked_sub_seconds(rhs.all_seconds())?,
}) })
}
/// [op:sub-yearMonthDuration-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-sub-yearMonthDuration-from-dateTime) and [op:sub-dayTimeDuration-from-dateTime](https://www.w3.org/TR/xpath-functions/#func-sub-dayTimeDuration-from-dateTime)
pub fn checked_sub_duration(&self, rhs: impl Into<Duration>) -> Option<Self> {
let rhs = rhs.into();
if let Ok(rhs) = DayTimeDuration::try_from(rhs) {
self.checked_sub_day_time_duration(rhs)
} else { } else {
Some(Self { Some(Self {
timestamp: Timestamp::new(&date_time_plus_duration(-rhs, &self.properties())?) timestamp: Timestamp::new(&date_time_plus_duration(-rhs, &self.properties())?)
@ -239,7 +267,7 @@ impl Time {
} }
/// [fn:timezone-from-time](https://www.w3.org/TR/xpath-functions/#func-timezone-from-time) /// [fn:timezone-from-time](https://www.w3.org/TR/xpath-functions/#func-timezone-from-time)
pub fn timezone(&self) -> Option<Duration> { pub fn timezone(&self) -> Option<DayTimeDuration> {
Some(self.timezone_offset()?.into()) Some(self.timezone_offset()?.into())
} }
@ -256,6 +284,11 @@ impl Time {
self.timestamp.checked_sub(rhs.into().timestamp) self.timestamp.checked_sub(rhs.into().timestamp)
} }
/// [op:add-dayTimeDuration-to-time](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-time)
pub fn checked_add_day_time_duration(&self, rhs: impl Into<DayTimeDuration>) -> Option<Self> {
self.checked_add_duration(Duration::from(rhs.into()))
}
/// [op:add-dayTimeDuration-to-time](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-time) /// [op:add-dayTimeDuration-to-time](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-time)
pub fn checked_add_duration(&self, rhs: impl Into<Duration>) -> Option<Self> { pub fn checked_add_duration(&self, rhs: impl Into<Duration>) -> Option<Self> {
DateTime::new( DateTime::new(
@ -273,6 +306,11 @@ impl Time {
.ok() .ok()
} }
/// [op:sub-dayTimeDuration-from-time](https://www.w3.org/TR/xpath-functions/#func-sub-dayTimeDuration-from-time)
pub fn checked_sub_day_time_duration(&self, rhs: impl Into<DayTimeDuration>) -> Option<Self> {
self.checked_sub_duration(Duration::from(rhs.into()))
}
/// [op:sub-dayTimeDuration-from-time](https://www.w3.org/TR/xpath-functions/#func-sub-dayTimeDuration-from-time) /// [op:sub-dayTimeDuration-from-time](https://www.w3.org/TR/xpath-functions/#func-sub-dayTimeDuration-from-time)
pub fn checked_sub_duration(&self, rhs: impl Into<Duration>) -> Option<Self> { pub fn checked_sub_duration(&self, rhs: impl Into<Duration>) -> Option<Self> {
DateTime::new( DateTime::new(
@ -377,7 +415,7 @@ impl Date {
} }
/// [fn:timezone-from-date](https://www.w3.org/TR/xpath-functions/#func-timezone-from-date) /// [fn:timezone-from-date](https://www.w3.org/TR/xpath-functions/#func-timezone-from-date)
pub fn timezone(&self) -> Option<Duration> { pub fn timezone(&self) -> Option<DayTimeDuration> {
Some(self.timezone_offset()?.into()) Some(self.timezone_offset()?.into())
} }
@ -394,6 +432,19 @@ impl Date {
self.timestamp.checked_sub(rhs.into().timestamp) self.timestamp.checked_sub(rhs.into().timestamp)
} }
/// [op:add-yearMonthDuration-to-date](https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDuration-to-date)
pub fn checked_add_year_month_duration(
&self,
rhs: impl Into<YearMonthDuration>,
) -> Option<Self> {
self.checked_add_duration(Duration::from(rhs.into()))
}
/// [op:add-dayTimeDuration-to-dateTime](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-date)
pub fn checked_add_day_time_duration(&self, rhs: impl Into<DayTimeDuration>) -> Option<Self> {
self.checked_add_duration(Duration::from(rhs.into()))
}
/// [op:add-yearMonthDuration-to-date](https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDuration-to-date) and [op:add-dayTimeDuration-to-dateTime](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-date) /// [op:add-yearMonthDuration-to-date](https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDuration-to-date) and [op:add-dayTimeDuration-to-dateTime](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDuration-to-date)
pub fn checked_add_duration(&self, rhs: impl Into<Duration>) -> Option<Self> { pub fn checked_add_duration(&self, rhs: impl Into<Duration>) -> Option<Self> {
DateTime::try_from(*self) DateTime::try_from(*self)
@ -403,6 +454,19 @@ impl Date {
.ok() .ok()
} }
/// [op:sub-yearMonthDuration-from-date](https://www.w3.org/TR/xpath-functions/#func-sub-yearMonthDuration-from-date)
pub fn checked_sub_year_month_duration(
&self,
rhs: impl Into<YearMonthDuration>,
) -> Option<Self> {
self.checked_sub_duration(Duration::from(rhs.into()))
}
/// [op:sub-dayTimeDuration-from-date](https://www.w3.org/TR/xpath-functions/#func-sub-dayTimeDuration-from-date)
pub fn checked_sub_day_time_duration(&self, rhs: impl Into<DayTimeDuration>) -> Option<Self> {
self.checked_sub_duration(Duration::from(rhs.into()))
}
/// [op:sub-yearMonthDuration-from-date](https://www.w3.org/TR/xpath-functions/#func-sub-yearMonthDuration-from-date) and [op:sub-dayTimeDuration-from-date](https://www.w3.org/TR/xpath-functions/#func-sub-dayTimeDuration-from-date) /// [op:sub-yearMonthDuration-from-date](https://www.w3.org/TR/xpath-functions/#func-sub-yearMonthDuration-from-date) and [op:sub-dayTimeDuration-from-date](https://www.w3.org/TR/xpath-functions/#func-sub-dayTimeDuration-from-date)
pub fn checked_sub_duration(&self, rhs: impl Into<Duration>) -> Option<Self> { pub fn checked_sub_duration(&self, rhs: impl Into<Duration>) -> Option<Self> {
DateTime::try_from(*self) DateTime::try_from(*self)
@ -481,9 +545,15 @@ impl From<i16> for TimezoneOffset {
} }
} }
impl From<TimezoneOffset> for DayTimeDuration {
fn from(value: TimezoneOffset) -> Self {
DayTimeDuration::new(i32::from(value.offset) * 60)
}
}
impl From<TimezoneOffset> for Duration { impl From<TimezoneOffset> for Duration {
fn from(value: TimezoneOffset) -> Self { fn from(value: TimezoneOffset) -> Self {
Duration::new(0, i32::from(value.offset) * 60) DayTimeDuration::from(value).into()
} }
} }
@ -1373,13 +1443,13 @@ mod tests {
DateTime::from_str("1999-05-31T13:20:00-05:00") DateTime::from_str("1999-05-31T13:20:00-05:00")
.unwrap() .unwrap()
.timezone(), .timezone(),
Some(Duration::from_str("-PT5H").unwrap()) Some(DayTimeDuration::from_str("-PT5H").unwrap())
); );
assert_eq!( assert_eq!(
DateTime::from_str("2000-06-12T13:20:00Z") DateTime::from_str("2000-06-12T13:20:00Z")
.unwrap() .unwrap()
.timezone(), .timezone(),
Some(Duration::from_str("PT0S").unwrap()) Some(DayTimeDuration::from_str("PT0S").unwrap())
); );
assert_eq!( assert_eq!(
DateTime::from_str("2004-08-27T00:00:00") DateTime::from_str("2004-08-27T00:00:00")
@ -1390,16 +1460,16 @@ mod tests {
assert_eq!( assert_eq!(
Date::from_str("1999-05-31-05:00").unwrap().timezone(), Date::from_str("1999-05-31-05:00").unwrap().timezone(),
Some(Duration::from_str("-PT5H").unwrap()) Some(DayTimeDuration::from_str("-PT5H").unwrap())
); );
assert_eq!( assert_eq!(
Date::from_str("2000-06-12Z").unwrap().timezone(), Date::from_str("2000-06-12Z").unwrap().timezone(),
Some(Duration::from_str("PT0S").unwrap()) Some(DayTimeDuration::from_str("PT0S").unwrap())
); );
assert_eq!( assert_eq!(
Time::from_str("13:20:00-05:00").unwrap().timezone(), Time::from_str("13:20:00-05:00").unwrap().timezone(),
Some(Duration::from_str("-PT5H").unwrap()) Some(DayTimeDuration::from_str("-PT5H").unwrap())
); );
assert_eq!(Time::from_str("13:20:00").unwrap().timezone(), None); assert_eq!(Time::from_str("13:20:00").unwrap().timezone(), None);
} }

@ -1,7 +1,6 @@
use super::parser::duration_lexical_rep; use super::decimal::DecimalOverflowError;
use super::parser::parse_value; use super::parser::*;
use super::*; use super::*;
use crate::model::xsd::decimal::DecimalOverflowError;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
@ -11,20 +10,18 @@ use std::time::Duration as StdDuration;
/// [XML Schema `duration` datatype](https://www.w3.org/TR/xmlschema11-2/#duration) implementation. /// [XML Schema `duration` datatype](https://www.w3.org/TR/xmlschema11-2/#duration) implementation.
/// ///
/// It stores the duration using the two components model suggested by the specification: /// It stores the duration using a pair of a `YearMonthDuration` and a `DayTimeDuration`.
/// - a number of months encoded using a `i64`
/// - a number of seconds encoded using a `Decimal`
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash, Default)] #[derive(Eq, PartialEq, Debug, Clone, Copy, Hash, Default)]
pub struct Duration { pub struct Duration {
months: i64, year_month: YearMonthDuration,
seconds: Decimal, day_time: DayTimeDuration,
} }
impl Duration { impl Duration {
pub fn new(months: impl Into<i64>, seconds: impl Into<Decimal>) -> Self { pub fn new(months: impl Into<i64>, seconds: impl Into<Decimal>) -> Self {
Self { Self {
months: months.into(), year_month: YearMonthDuration::new(months),
seconds: seconds.into(), day_time: DayTimeDuration::new(seconds),
} }
} }
@ -34,56 +31,53 @@ impl Duration {
let mut seconds = [8; 16]; let mut seconds = [8; 16];
seconds.copy_from_slice(&bytes[8..24]); seconds.copy_from_slice(&bytes[8..24]);
Self { Self {
months: i64::from_be_bytes(months), year_month: YearMonthDuration::from_be_bytes(months),
seconds: Decimal::from_be_bytes(seconds), day_time: DayTimeDuration::from_be_bytes(seconds),
} }
} }
/// [fn:years-from-duration](https://www.w3.org/TR/xpath-functions/#func-years-from-duration) /// [fn:years-from-duration](https://www.w3.org/TR/xpath-functions/#func-years-from-duration)
pub fn years(&self) -> i64 { pub fn years(&self) -> i64 {
self.months / 12 self.year_month.years()
} }
/// [fn:months-from-duration](https://www.w3.org/TR/xpath-functions/#func-months-from-duration) /// [fn:months-from-duration](https://www.w3.org/TR/xpath-functions/#func-months-from-duration)
pub fn months(&self) -> i64 { pub fn months(&self) -> i64 {
self.months % 12 self.year_month.months()
} }
/// [fn:days-from-duration](https://www.w3.org/TR/xpath-functions/#func-days-from-duration) /// [fn:days-from-duration](https://www.w3.org/TR/xpath-functions/#func-days-from-duration)
#[allow(clippy::cast_possible_truncation)]
pub fn days(&self) -> i64 { pub fn days(&self) -> i64 {
(self.seconds.as_i128() / 86400) as i64 self.day_time.days()
} }
/// [fn:hours-from-duration](https://www.w3.org/TR/xpath-functions/#func-hours-from-duration) /// [fn:hours-from-duration](https://www.w3.org/TR/xpath-functions/#func-hours-from-duration)
#[allow(clippy::cast_possible_truncation)]
pub fn hours(&self) -> i64 { pub fn hours(&self) -> i64 {
((self.seconds.as_i128() % 86400) / 3600) as i64 self.day_time.hours()
} }
/// [fn:minutes-from-duration](https://www.w3.org/TR/xpath-functions/#func-minutes-from-duration) /// [fn:minutes-from-duration](https://www.w3.org/TR/xpath-functions/#func-minutes-from-duration)
#[allow(clippy::cast_possible_truncation)]
pub fn minutes(&self) -> i64 { pub fn minutes(&self) -> i64 {
((self.seconds.as_i128() % 3600) / 60) as i64 self.day_time.minutes()
} }
/// [fn:seconds-from-duration](https://www.w3.org/TR/xpath-functions/#func-seconds-from-duration) /// [fn:seconds-from-duration](https://www.w3.org/TR/xpath-functions/#func-seconds-from-duration)
pub fn seconds(&self) -> Decimal { pub fn seconds(&self) -> Decimal {
self.seconds.checked_rem(60).unwrap() self.day_time.seconds()
} }
pub(super) const fn all_months(&self) -> i64 { pub(super) const fn all_months(&self) -> i64 {
self.months self.year_month.all_months()
} }
pub(super) const fn all_seconds(&self) -> Decimal { pub(super) const fn all_seconds(&self) -> Decimal {
self.seconds self.day_time.all_seconds()
} }
pub fn to_be_bytes(&self) -> [u8; 24] { pub fn to_be_bytes(&self) -> [u8; 24] {
let mut bytes = [0; 24]; let mut bytes = [0; 24];
bytes[0..8].copy_from_slice(&self.months.to_be_bytes()); bytes[0..8].copy_from_slice(&self.year_month.to_be_bytes());
bytes[8..24].copy_from_slice(&self.seconds.to_be_bytes()); bytes[8..24].copy_from_slice(&self.day_time.to_be_bytes());
bytes bytes
} }
@ -91,8 +85,8 @@ impl Duration {
pub fn checked_add(&self, rhs: impl Into<Self>) -> Option<Self> { pub fn checked_add(&self, rhs: impl Into<Self>) -> Option<Self> {
let rhs = rhs.into(); let rhs = rhs.into();
Some(Self { Some(Self {
months: self.months.checked_add(rhs.months)?, year_month: self.year_month.checked_add(rhs.year_month)?,
seconds: self.seconds.checked_add(rhs.seconds)?, day_time: self.day_time.checked_add(rhs.day_time)?,
}) })
} }
@ -100,8 +94,8 @@ impl Duration {
pub fn checked_sub(&self, rhs: impl Into<Self>) -> Option<Self> { pub fn checked_sub(&self, rhs: impl Into<Self>) -> Option<Self> {
let rhs = rhs.into(); let rhs = rhs.into();
Some(Self { Some(Self {
months: self.months.checked_sub(rhs.months)?, year_month: self.year_month.checked_sub(rhs.year_month)?,
seconds: self.seconds.checked_sub(rhs.seconds)?, day_time: self.day_time.checked_sub(rhs.day_time)?,
}) })
} }
} }
@ -110,13 +104,7 @@ impl TryFrom<StdDuration> for Duration {
type Error = DecimalOverflowError; type Error = DecimalOverflowError;
fn try_from(value: StdDuration) -> Result<Self, DecimalOverflowError> { fn try_from(value: StdDuration) -> Result<Self, DecimalOverflowError> {
Ok(Self { Ok(DayTimeDuration::try_from(value)?.into())
months: 0,
seconds: Decimal::new(
i128::try_from(value.as_nanos()).map_err(|_| DecimalOverflowError)?,
9,
)?,
})
} }
} }
@ -131,8 +119,8 @@ impl FromStr for Duration {
impl fmt::Display for Duration { impl fmt::Display for Duration {
#[allow(clippy::many_single_char_names)] #[allow(clippy::many_single_char_names)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut ym = self.months; let mut ym = self.year_month.months;
let mut ss = self.seconds; let mut ss = self.day_time.seconds;
if ym < 0 || ss < 0.into() { if ym < 0 || ss < 0.into() {
write!(f, "-")?; write!(f, "-")?;
@ -222,9 +210,343 @@ impl PartialOrd for Duration {
impl Neg for Duration { impl Neg for Duration {
type Output = Self; type Output = Self;
fn neg(self) -> Self {
Self {
year_month: self.year_month.neg(),
day_time: self.day_time.neg(),
}
}
}
/// [XML Schema `yearMonthDuration` datatype](https://www.w3.org/TR/xmlschema11-2/#yearMonthDuration) implementation.
///
/// It stores the duration as a number of months encoded using a `i64`
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash, Default)]
pub struct YearMonthDuration {
months: i64,
}
impl YearMonthDuration {
pub fn new(months: impl Into<i64>) -> Self {
Self {
months: months.into(),
}
}
pub fn from_be_bytes(bytes: [u8; 8]) -> Self {
Self {
months: i64::from_be_bytes(bytes),
}
}
/// [fn:years-from-duration](https://www.w3.org/TR/xpath-functions/#func-years-from-duration)
pub fn years(&self) -> i64 {
self.months / 12
}
/// [fn:months-from-duration](https://www.w3.org/TR/xpath-functions/#func-months-from-duration)
pub fn months(&self) -> i64 {
self.months % 12
}
/// [fn:days-from-duration](https://www.w3.org/TR/xpath-functions/#func-days-from-duration)
pub fn days(&self) -> i64 {
0
}
/// [fn:hours-from-duration](https://www.w3.org/TR/xpath-functions/#func-hours-from-duration)
pub fn hours(&self) -> i64 {
0
}
/// [fn:minutes-from-duration](https://www.w3.org/TR/xpath-functions/#func-minutes-from-duration)
pub fn minutes(&self) -> i64 {
0
}
/// [fn:seconds-from-duration](https://www.w3.org/TR/xpath-functions/#func-seconds-from-duration)
pub fn seconds(&self) -> Decimal {
Decimal::default()
}
pub(super) const fn all_months(&self) -> i64 {
self.months
}
pub fn to_be_bytes(&self) -> [u8; 8] {
self.months.to_be_bytes()
}
/// [op:add-yearMonthDurations](https://www.w3.org/TR/xpath-functions/#func-add-yearMonthDurations)
pub fn checked_add(&self, rhs: impl Into<Self>) -> Option<Self> {
let rhs = rhs.into();
Some(Self {
months: self.months.checked_add(rhs.months)?,
})
}
/// [op:subtract-yearMonthDurations](https://www.w3.org/TR/xpath-functions/#func-subtract-yearMonthDurations)
pub fn checked_sub(&self, rhs: impl Into<Self>) -> Option<Self> {
let rhs = rhs.into();
Some(Self {
months: self.months.checked_sub(rhs.months)?,
})
}
}
impl From<YearMonthDuration> for Duration {
fn from(value: YearMonthDuration) -> Self {
Self {
year_month: value,
day_time: DayTimeDuration::default(),
}
}
}
impl TryFrom<Duration> for YearMonthDuration {
type Error = DecimalOverflowError;
fn try_from(value: Duration) -> Result<Self, DecimalOverflowError> {
if value.day_time == DayTimeDuration::default() {
Ok(value.year_month)
} else {
Err(DecimalOverflowError {})
}
}
}
impl FromStr for YearMonthDuration {
type Err = XsdParseError;
fn from_str(input: &str) -> Result<Self, XsdParseError> {
parse_value(year_month_duration_lexical_rep, input)
}
}
impl fmt::Display for YearMonthDuration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.months == 0 {
write!(f, "P0M")
} else {
Duration::from(*self).fmt(f)
}
}
}
impl PartialEq<Duration> for YearMonthDuration {
fn eq(&self, other: &Duration) -> bool {
Duration::from(*self).eq(other)
}
}
impl PartialEq<YearMonthDuration> for Duration {
fn eq(&self, other: &YearMonthDuration) -> bool {
self.eq(&Duration::from(*other))
}
}
impl PartialOrd<Duration> for YearMonthDuration {
fn partial_cmp(&self, other: &Duration) -> Option<Ordering> {
Duration::from(*self).partial_cmp(other)
}
}
impl PartialOrd<YearMonthDuration> for Duration {
fn partial_cmp(&self, other: &YearMonthDuration) -> Option<Ordering> {
self.partial_cmp(&Duration::from(*other))
}
}
impl Neg for YearMonthDuration {
type Output = Self;
fn neg(self) -> Self { fn neg(self) -> Self {
Self { Self {
months: self.months.neg(), months: self.months.neg(),
}
}
}
/// [XML Schema `dayTimeDuration` datatype](https://www.w3.org/TR/xmlschema11-2/#dayTimeDuration) implementation.
///
/// It stores the duration as a number of seconds encoded using a `Decimal`
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash, Default)]
pub struct DayTimeDuration {
seconds: Decimal,
}
impl DayTimeDuration {
pub fn new(seconds: impl Into<Decimal>) -> Self {
Self {
seconds: seconds.into(),
}
}
pub fn from_be_bytes(bytes: [u8; 16]) -> Self {
Self {
seconds: Decimal::from_be_bytes(bytes),
}
}
/// [fn:years-from-duration](https://www.w3.org/TR/xpath-functions/#func-years-from-duration)
pub fn years(&self) -> i64 {
0
}
/// [fn:months-from-duration](https://www.w3.org/TR/xpath-functions/#func-months-from-duration)
pub fn months(&self) -> i64 {
0
}
/// [fn:days-from-duration](https://www.w3.org/TR/xpath-functions/#func-days-from-duration)
#[allow(clippy::cast_possible_truncation)]
pub fn days(&self) -> i64 {
(self.seconds.as_i128() / 86400) as i64
}
/// [fn:hours-from-duration](https://www.w3.org/TR/xpath-functions/#func-hours-from-duration)
#[allow(clippy::cast_possible_truncation)]
pub fn hours(&self) -> i64 {
((self.seconds.as_i128() % 86400) / 3600) as i64
}
/// [fn:minutes-from-duration](https://www.w3.org/TR/xpath-functions/#func-minutes-from-duration)
#[allow(clippy::cast_possible_truncation)]
pub fn minutes(&self) -> i64 {
((self.seconds.as_i128() % 3600) / 60) as i64
}
/// [fn:seconds-from-duration](https://www.w3.org/TR/xpath-functions/#func-seconds-from-duration)
pub fn seconds(&self) -> Decimal {
self.seconds.checked_rem(60).unwrap()
}
pub(super) const fn all_seconds(&self) -> Decimal {
self.seconds
}
pub fn to_be_bytes(&self) -> [u8; 16] {
self.seconds.to_be_bytes()
}
/// [op:add-dayTimeDurations](https://www.w3.org/TR/xpath-functions/#func-add-dayTimeDurations)
pub fn checked_add(&self, rhs: impl Into<Self>) -> Option<Self> {
let rhs = rhs.into();
Some(Self {
seconds: self.seconds.checked_add(rhs.seconds)?,
})
}
/// [op:subtract-dayTimeDurations](https://www.w3.org/TR/xpath-functions/#func-subtract-dayTimeDurations)
pub fn checked_sub(&self, rhs: impl Into<Self>) -> Option<Self> {
let rhs = rhs.into();
Some(Self {
seconds: self.seconds.checked_sub(rhs.seconds)?,
})
}
}
impl From<DayTimeDuration> for Duration {
fn from(value: DayTimeDuration) -> Self {
Self {
year_month: YearMonthDuration::default(),
day_time: value,
}
}
}
impl TryFrom<Duration> for DayTimeDuration {
type Error = DecimalOverflowError;
fn try_from(value: Duration) -> Result<Self, DecimalOverflowError> {
if value.year_month == YearMonthDuration::default() {
Ok(value.day_time)
} else {
Err(DecimalOverflowError {})
}
}
}
impl TryFrom<StdDuration> for DayTimeDuration {
type Error = DecimalOverflowError;
fn try_from(value: StdDuration) -> Result<Self, DecimalOverflowError> {
Ok(Self {
seconds: Decimal::new(
i128::try_from(value.as_nanos()).map_err(|_| DecimalOverflowError)?,
9,
)?,
})
}
}
impl FromStr for DayTimeDuration {
type Err = XsdParseError;
fn from_str(input: &str) -> Result<Self, XsdParseError> {
parse_value(day_time_duration_lexical_rep, input)
}
}
impl fmt::Display for DayTimeDuration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Duration::from(*self).fmt(f)
}
}
impl PartialEq<Duration> for DayTimeDuration {
fn eq(&self, other: &Duration) -> bool {
Duration::from(*self).eq(other)
}
}
impl PartialEq<DayTimeDuration> for Duration {
fn eq(&self, other: &DayTimeDuration) -> bool {
self.eq(&Duration::from(*other))
}
}
impl PartialEq<YearMonthDuration> for DayTimeDuration {
fn eq(&self, other: &YearMonthDuration) -> bool {
Duration::from(*self).eq(&Duration::from(*other))
}
}
impl PartialEq<DayTimeDuration> for YearMonthDuration {
fn eq(&self, other: &DayTimeDuration) -> bool {
Duration::from(*self).eq(&Duration::from(*other))
}
}
impl PartialOrd<Duration> for DayTimeDuration {
fn partial_cmp(&self, other: &Duration) -> Option<Ordering> {
Duration::from(*self).partial_cmp(other)
}
}
impl PartialOrd<DayTimeDuration> for Duration {
fn partial_cmp(&self, other: &DayTimeDuration) -> Option<Ordering> {
self.partial_cmp(&Duration::from(*other))
}
}
impl PartialOrd<YearMonthDuration> for DayTimeDuration {
fn partial_cmp(&self, other: &YearMonthDuration) -> Option<Ordering> {
Duration::from(*self).partial_cmp(&Duration::from(*other))
}
}
impl PartialOrd<DayTimeDuration> for YearMonthDuration {
fn partial_cmp(&self, other: &DayTimeDuration) -> Option<Ordering> {
Duration::from(*self).partial_cmp(&Duration::from(*other))
}
}
impl Neg for DayTimeDuration {
type Output = Self;
fn neg(self) -> Self {
Self {
seconds: self.seconds.neg(), seconds: self.seconds.neg(),
} }
} }
@ -242,17 +564,62 @@ mod tests {
); );
let max = Duration::new(i64::max_value(), Decimal::max_value()); let max = Duration::new(i64::max_value(), Decimal::max_value());
assert_eq!(
YearMonthDuration::from_str("P1Y").unwrap().to_string(),
"P1Y"
);
assert_eq!(Duration::from_str("P1Y").unwrap().to_string(), "P1Y"); assert_eq!(Duration::from_str("P1Y").unwrap().to_string(), "P1Y");
assert_eq!(
YearMonthDuration::from_str("P1M").unwrap().to_string(),
"P1M"
);
assert_eq!(Duration::from_str("P1M").unwrap().to_string(), "P1M"); assert_eq!(Duration::from_str("P1M").unwrap().to_string(), "P1M");
assert_eq!(DayTimeDuration::from_str("P1D").unwrap().to_string(), "P1D");
assert_eq!(Duration::from_str("P1D").unwrap().to_string(), "P1D"); assert_eq!(Duration::from_str("P1D").unwrap().to_string(), "P1D");
assert_eq!(
DayTimeDuration::from_str("PT1H").unwrap().to_string(),
"PT1H"
);
assert_eq!(Duration::from_str("PT1H").unwrap().to_string(), "PT1H"); assert_eq!(Duration::from_str("PT1H").unwrap().to_string(), "PT1H");
assert_eq!(
DayTimeDuration::from_str("PT1M").unwrap().to_string(),
"PT1M"
);
assert_eq!(Duration::from_str("PT1M").unwrap().to_string(), "PT1M"); assert_eq!(Duration::from_str("PT1M").unwrap().to_string(), "PT1M");
assert_eq!(
DayTimeDuration::from_str("PT1.1S").unwrap().to_string(),
"PT1.1S"
);
assert_eq!(Duration::from_str("PT1.1S").unwrap().to_string(), "PT1.1S"); assert_eq!(Duration::from_str("PT1.1S").unwrap().to_string(), "PT1.1S");
assert_eq!(
YearMonthDuration::from_str("-P1Y").unwrap().to_string(),
"-P1Y"
);
assert_eq!(Duration::from_str("-P1Y").unwrap().to_string(), "-P1Y"); assert_eq!(Duration::from_str("-P1Y").unwrap().to_string(), "-P1Y");
assert_eq!(
YearMonthDuration::from_str("-P1M").unwrap().to_string(),
"-P1M"
);
assert_eq!(Duration::from_str("-P1M").unwrap().to_string(), "-P1M"); assert_eq!(Duration::from_str("-P1M").unwrap().to_string(), "-P1M");
assert_eq!(
DayTimeDuration::from_str("-P1D").unwrap().to_string(),
"-P1D"
);
assert_eq!(Duration::from_str("-P1D").unwrap().to_string(), "-P1D"); assert_eq!(Duration::from_str("-P1D").unwrap().to_string(), "-P1D");
assert_eq!(
DayTimeDuration::from_str("-PT1H").unwrap().to_string(),
"-PT1H"
);
assert_eq!(Duration::from_str("-PT1H").unwrap().to_string(), "-PT1H"); assert_eq!(Duration::from_str("-PT1H").unwrap().to_string(), "-PT1H");
assert_eq!(
DayTimeDuration::from_str("-PT1M").unwrap().to_string(),
"-PT1M"
);
assert_eq!(Duration::from_str("-PT1M").unwrap().to_string(), "-PT1M"); assert_eq!(Duration::from_str("-PT1M").unwrap().to_string(), "-PT1M");
assert_eq!(
DayTimeDuration::from_str("-PT1.1S").unwrap().to_string(),
"-PT1.1S"
);
assert_eq!( assert_eq!(
Duration::from_str("-PT1.1S").unwrap().to_string(), Duration::from_str("-PT1.1S").unwrap().to_string(),
"-PT1.1S" "-PT1.1S"
@ -263,10 +630,34 @@ mod tests {
#[test] #[test]
fn equals() { fn equals() {
assert_eq!(
YearMonthDuration::from_str("P1Y").unwrap(),
YearMonthDuration::from_str("P12M").unwrap()
);
assert_eq!(
YearMonthDuration::from_str("P1Y").unwrap(),
Duration::from_str("P12M").unwrap()
);
assert_eq!(
Duration::from_str("P1Y").unwrap(),
YearMonthDuration::from_str("P12M").unwrap()
);
assert_eq!( assert_eq!(
Duration::from_str("P1Y").unwrap(), Duration::from_str("P1Y").unwrap(),
Duration::from_str("P12M").unwrap() Duration::from_str("P12M").unwrap()
); );
assert_eq!(
DayTimeDuration::from_str("PT24H").unwrap(),
DayTimeDuration::from_str("P1D").unwrap()
);
assert_eq!(
DayTimeDuration::from_str("PT24H").unwrap(),
Duration::from_str("P1D").unwrap()
);
assert_eq!(
Duration::from_str("PT24H").unwrap(),
DayTimeDuration::from_str("P1D").unwrap()
);
assert_eq!( assert_eq!(
Duration::from_str("PT24H").unwrap(), Duration::from_str("PT24H").unwrap(),
Duration::from_str("P1D").unwrap() Duration::from_str("P1D").unwrap()

@ -5,5 +5,5 @@ mod parser;
pub use self::date_time::{Date, DateTime, Time}; pub use self::date_time::{Date, DateTime, Time};
pub use self::decimal::Decimal; pub use self::decimal::Decimal;
pub use self::duration::Duration; pub use self::duration::{DayTimeDuration, Duration, YearMonthDuration};
pub use self::parser::XsdParseError; pub use self::parser::XsdParseError;

@ -13,6 +13,7 @@ use std::str::FromStr;
use super::date_time::DateTimeError; use super::date_time::DateTimeError;
use super::decimal::ParseDecimalError; use super::decimal::ParseDecimalError;
use crate::model::xsd::date_time::TimezoneOffset; use crate::model::xsd::date_time::TimezoneOffset;
use crate::model::xsd::duration::{DayTimeDuration, YearMonthDuration};
use nom::bytes::streaming::take_while_m_n; use nom::bytes::streaming::take_while_m_n;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
@ -331,6 +332,34 @@ pub fn date_lexical_rep(input: &str) -> XsdResult<'_, Date> {
)(input) )(input)
} }
// [42] yearMonthDurationLexicalRep ::= '-'? 'P' duYearMonthFrag
pub fn year_month_duration_lexical_rep(input: &str) -> XsdResult<'_, YearMonthDuration> {
map(
tuple((opt(char('-')), preceded(char('P'), du_year_month_frag))),
|(sign, duration)| {
YearMonthDuration::new(if sign == Some('-') {
-duration
} else {
duration
})
},
)(input)
}
// [43] dayTimeDurationLexicalRep ::= '-'? 'P' duDayTimeFrag
pub fn day_time_duration_lexical_rep(input: &str) -> XsdResult<'_, DayTimeDuration> {
map(
tuple((opt(char('-')), preceded(char('P'), du_day_time_frag))),
|(sign, duration)| {
DayTimeDuration::new(if sign == Some('-') {
-duration
} else {
duration
})
},
)(input)
}
// [46] unsignedNoDecimalPtNumeral ::= digit+ // [46] unsignedNoDecimalPtNumeral ::= digit+
fn unsigned_no_decimal_pt_numeral(input: &str) -> XsdResult<'_, i64> { fn unsigned_no_decimal_pt_numeral(input: &str) -> XsdResult<'_, i64> {
map_res(digit1, |i| i64::from_str(i))(input) map_res(digit1, |i| i64::from_str(i))(input)

@ -829,15 +829,34 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
NumericBinaryOperands::Integer(v1, v2) => Some(v1.checked_add(v2)?.into()), NumericBinaryOperands::Integer(v1, v2) => Some(v1.checked_add(v2)?.into()),
NumericBinaryOperands::Decimal(v1, v2) => Some(v1.checked_add(v2)?.into()), NumericBinaryOperands::Decimal(v1, v2) => Some(v1.checked_add(v2)?.into()),
NumericBinaryOperands::Duration(v1, v2) => Some(v1.checked_add(v2)?.into()), NumericBinaryOperands::Duration(v1, v2) => Some(v1.checked_add(v2)?.into()),
NumericBinaryOperands::YearMonthDuration(v1, v2) => {
Some(v1.checked_add(v2)?.into())
}
NumericBinaryOperands::DayTimeDuration(v1, v2) => Some(v1.checked_add(v2)?.into()),
NumericBinaryOperands::DateTimeDuration(v1, v2) => { NumericBinaryOperands::DateTimeDuration(v1, v2) => {
Some(v1.checked_add_duration(v2)?.into()) Some(v1.checked_add_duration(v2)?.into())
} }
NumericBinaryOperands::DateTimeYearMonthDuration(v1, v2) => {
Some(v1.checked_add_year_month_duration(v2)?.into())
}
NumericBinaryOperands::DateTimeDayTimeDuration(v1, v2) => {
Some(v1.checked_add_day_time_duration(v2)?.into())
}
NumericBinaryOperands::DateDuration(v1, v2) => { NumericBinaryOperands::DateDuration(v1, v2) => {
Some(v1.checked_add_duration(v2)?.into()) Some(v1.checked_add_duration(v2)?.into())
} }
NumericBinaryOperands::DateYearMonthDuration(v1, v2) => {
Some(v1.checked_add_year_month_duration(v2)?.into())
}
NumericBinaryOperands::DateDayTimeDuration(v1, v2) => {
Some(v1.checked_add_day_time_duration(v2)?.into())
}
NumericBinaryOperands::TimeDuration(v1, v2) => { NumericBinaryOperands::TimeDuration(v1, v2) => {
Some(v1.checked_add_duration(v2)?.into()) Some(v1.checked_add_duration(v2)?.into())
} }
NumericBinaryOperands::TimeDayTimeDuration(v1, v2) => {
Some(v1.checked_add_day_time_duration(v2)?.into())
}
_ => None, _ => None,
}, },
PlanExpression::Sub(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? { PlanExpression::Sub(a, b) => Some(match self.parse_numeric_operands(a, b, tuple)? {
@ -845,15 +864,32 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
NumericBinaryOperands::Double(v1, v2) => (v1 - v2).into(), NumericBinaryOperands::Double(v1, v2) => (v1 - v2).into(),
NumericBinaryOperands::Integer(v1, v2) => v1.checked_sub(v2)?.into(), NumericBinaryOperands::Integer(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::Decimal(v1, v2) => v1.checked_sub(v2)?.into(), NumericBinaryOperands::Decimal(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::Duration(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::DateTime(v1, v2) => v1.checked_sub(v2)?.into(), NumericBinaryOperands::DateTime(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::Date(v1, v2) => v1.checked_sub(v2)?.into(), NumericBinaryOperands::Date(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::Time(v1, v2) => v1.checked_sub(v2)?.into(), NumericBinaryOperands::Time(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::Duration(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::YearMonthDuration(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::DayTimeDuration(v1, v2) => v1.checked_sub(v2)?.into(),
NumericBinaryOperands::DateTimeDuration(v1, v2) => { NumericBinaryOperands::DateTimeDuration(v1, v2) => {
v1.checked_sub_duration(v2)?.into() v1.checked_sub_duration(v2)?.into()
} }
NumericBinaryOperands::DateTimeYearMonthDuration(v1, v2) => {
v1.checked_sub_year_month_duration(v2)?.into()
}
NumericBinaryOperands::DateTimeDayTimeDuration(v1, v2) => {
v1.checked_sub_day_time_duration(v2)?.into()
}
NumericBinaryOperands::DateDuration(v1, v2) => v1.checked_sub_duration(v2)?.into(), NumericBinaryOperands::DateDuration(v1, v2) => v1.checked_sub_duration(v2)?.into(),
NumericBinaryOperands::DateYearMonthDuration(v1, v2) => {
v1.checked_sub_year_month_duration(v2)?.into()
}
NumericBinaryOperands::DateDayTimeDuration(v1, v2) => {
v1.checked_sub_day_time_duration(v2)?.into()
}
NumericBinaryOperands::TimeDuration(v1, v2) => v1.checked_sub_duration(v2)?.into(), NumericBinaryOperands::TimeDuration(v1, v2) => v1.checked_sub_duration(v2)?.into(),
NumericBinaryOperands::TimeDayTimeDuration(v1, v2) => {
v1.checked_sub_day_time_duration(v2)?.into()
}
}), }),
PlanExpression::Mul(a, b) => match self.parse_numeric_operands(a, b, tuple)? { PlanExpression::Mul(a, b) => match self.parse_numeric_operands(a, b, tuple)? {
NumericBinaryOperands::Float(v1, v2) => Some((v1 * v2).into()), NumericBinaryOperands::Float(v1, v2) => Some((v1 * v2).into()),
@ -877,6 +913,8 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
EncodedTerm::IntegerLiteral(value) => Some(value.into()), EncodedTerm::IntegerLiteral(value) => Some(value.into()),
EncodedTerm::DecimalLiteral(value) => Some(value.into()), EncodedTerm::DecimalLiteral(value) => Some(value.into()),
EncodedTerm::DurationLiteral(value) => Some(value.into()), EncodedTerm::DurationLiteral(value) => Some(value.into()),
EncodedTerm::YearMonthDurationLiteral(value) => Some(value.into()),
EncodedTerm::DayTimeDurationLiteral(value) => Some(value.into()),
_ => None, _ => None,
}, },
PlanExpression::UnaryMinus(e) => match self.eval_expression(e, tuple)? { PlanExpression::UnaryMinus(e) => match self.eval_expression(e, tuple)? {
@ -885,6 +923,8 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
EncodedTerm::IntegerLiteral(value) => Some((-value).into()), EncodedTerm::IntegerLiteral(value) => Some((-value).into()),
EncodedTerm::DecimalLiteral(value) => Some((-value).into()), EncodedTerm::DecimalLiteral(value) => Some((-value).into()),
EncodedTerm::DurationLiteral(value) => Some((-value).into()), EncodedTerm::DurationLiteral(value) => Some((-value).into()),
EncodedTerm::YearMonthDurationLiteral(value) => Some((-value).into()),
EncodedTerm::DayTimeDurationLiteral(value) => Some((-value).into()),
_ => None, _ => None,
}, },
PlanExpression::UnaryNot(e) => self PlanExpression::UnaryNot(e) => self
@ -1368,11 +1408,33 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
}, },
PlanExpression::DurationCast(e) => match self.eval_expression(e, tuple)? { PlanExpression::DurationCast(e) => match self.eval_expression(e, tuple)? {
EncodedTerm::DurationLiteral(value) => Some(value.into()), EncodedTerm::DurationLiteral(value) => Some(value.into()),
EncodedTerm::YearMonthDurationLiteral(value) => Some(Duration::from(value).into()),
EncodedTerm::DayTimeDurationLiteral(value) => Some(Duration::from(value).into()),
EncodedTerm::StringLiteral { value_id } => { EncodedTerm::StringLiteral { value_id } => {
parse_duration_str(&*self.dataset.get_str(value_id).ok()??) parse_duration_str(&*self.dataset.get_str(value_id).ok()??)
} }
_ => None, _ => None,
}, },
PlanExpression::YearMonthDurationCast(e) => match self.eval_expression(e, tuple)? {
EncodedTerm::DurationLiteral(value) => {
Some(YearMonthDuration::try_from(value).ok()?.into())
}
EncodedTerm::YearMonthDurationLiteral(value) => Some(value.into()),
EncodedTerm::StringLiteral { value_id } => {
parse_year_month_duration_str(&*self.dataset.get_str(value_id).ok()??)
}
_ => None,
},
PlanExpression::DayTimeDurationCast(e) => match self.eval_expression(e, tuple)? {
EncodedTerm::DurationLiteral(value) => {
Some(DayTimeDuration::try_from(value).ok()?.into())
}
EncodedTerm::DayTimeDurationLiteral(value) => Some(value.into()),
EncodedTerm::StringLiteral { value_id } => {
parse_day_time_duration_str(&*self.dataset.get_str(value_id).ok()??)
}
_ => None,
},
PlanExpression::StringCast(e) => Some(EncodedTerm::StringLiteral { PlanExpression::StringCast(e) => Some(EncodedTerm::StringLiteral {
value_id: self.to_string_id(self.eval_expression(e, tuple)?)?, value_id: self.to_string_id(self.eval_expression(e, tuple)?)?,
}), }),
@ -1410,6 +1472,10 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
EncodedTerm::TimeLiteral(value) => self.build_string_id(&value.to_string()), EncodedTerm::TimeLiteral(value) => self.build_string_id(&value.to_string()),
EncodedTerm::DateTimeLiteral(value) => self.build_string_id(&value.to_string()), EncodedTerm::DateTimeLiteral(value) => self.build_string_id(&value.to_string()),
EncodedTerm::DurationLiteral(value) => self.build_string_id(&value.to_string()), EncodedTerm::DurationLiteral(value) => self.build_string_id(&value.to_string()),
EncodedTerm::YearMonthDurationLiteral(value) => {
self.build_string_id(&value.to_string())
}
EncodedTerm::DayTimeDurationLiteral(value) => self.build_string_id(&value.to_string()),
} }
} }
@ -1673,6 +1739,22 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
}, },
EncodedTerm::DurationLiteral(a) => match b { EncodedTerm::DurationLiteral(a) => match b {
EncodedTerm::DurationLiteral(b) => Some(a == b), EncodedTerm::DurationLiteral(b) => Some(a == b),
EncodedTerm::YearMonthDurationLiteral(b) => Some(a == b),
EncodedTerm::DayTimeDurationLiteral(b) => Some(a == b),
EncodedTerm::TypedLiteral { .. } => None,
_ => Some(false),
},
EncodedTerm::YearMonthDurationLiteral(a) => match b {
EncodedTerm::DurationLiteral(b) => Some(a == b),
EncodedTerm::YearMonthDurationLiteral(b) => Some(a == b),
EncodedTerm::DayTimeDurationLiteral(b) => Some(a == b),
EncodedTerm::TypedLiteral { .. } => None,
_ => Some(false),
},
EncodedTerm::DayTimeDurationLiteral(a) => match b {
EncodedTerm::DurationLiteral(b) => Some(a == b),
EncodedTerm::YearMonthDurationLiteral(b) => Some(a == b),
EncodedTerm::DayTimeDurationLiteral(b) => Some(a == b),
EncodedTerm::TypedLiteral { .. } => None, EncodedTerm::TypedLiteral { .. } => None,
_ => Some(false), _ => Some(false),
}, },
@ -1782,13 +1864,24 @@ impl<'a, S: ReadableEncodedStore + 'a> SimpleEvaluator<S> {
None None
} }
} }
EncodedTerm::DurationLiteral(a) => { EncodedTerm::DurationLiteral(a) => match b {
if let EncodedTerm::DurationLiteral(ref b) = b { EncodedTerm::DurationLiteral(ref b) => a.partial_cmp(b),
a.partial_cmp(b) EncodedTerm::YearMonthDurationLiteral(ref b) => a.partial_cmp(b),
} else { EncodedTerm::DayTimeDurationLiteral(ref b) => a.partial_cmp(b),
None _ => None,
} },
} EncodedTerm::YearMonthDurationLiteral(a) => match b {
EncodedTerm::DurationLiteral(ref b) => a.partial_cmp(b),
EncodedTerm::YearMonthDurationLiteral(ref b) => a.partial_cmp(b),
EncodedTerm::DayTimeDurationLiteral(ref b) => a.partial_cmp(b),
_ => None,
},
EncodedTerm::DayTimeDurationLiteral(a) => match b {
EncodedTerm::DurationLiteral(ref b) => a.partial_cmp(b),
EncodedTerm::YearMonthDurationLiteral(ref b) => a.partial_cmp(b),
EncodedTerm::DayTimeDurationLiteral(ref b) => a.partial_cmp(b),
_ => None,
},
_ => None, _ => None,
} }
} }
@ -1819,12 +1912,19 @@ enum NumericBinaryOperands {
Integer(i64, i64), Integer(i64, i64),
Decimal(Decimal, Decimal), Decimal(Decimal, Decimal),
Duration(Duration, Duration), Duration(Duration, Duration),
YearMonthDuration(YearMonthDuration, YearMonthDuration),
DayTimeDuration(DayTimeDuration, DayTimeDuration),
DateTime(DateTime, DateTime), DateTime(DateTime, DateTime),
Time(Time, Time), Time(Time, Time),
Date(Date, Date), Date(Date, Date),
DateTimeDuration(DateTime, Duration), DateTimeDuration(DateTime, Duration),
TimeDuration(Time, Duration), DateTimeYearMonthDuration(DateTime, YearMonthDuration),
DateTimeDayTimeDuration(DateTime, DayTimeDuration),
DateDuration(Date, Duration), DateDuration(Date, Duration),
DateYearMonthDuration(Date, YearMonthDuration),
DateDayTimeDuration(Date, DayTimeDuration),
TimeDuration(Time, Duration),
TimeDayTimeDuration(Time, DayTimeDuration),
} }
impl NumericBinaryOperands { impl NumericBinaryOperands {
@ -1882,6 +1982,33 @@ impl NumericBinaryOperands {
(EncodedTerm::DurationLiteral(v1), EncodedTerm::DurationLiteral(v2)) => { (EncodedTerm::DurationLiteral(v1), EncodedTerm::DurationLiteral(v2)) => {
Some(NumericBinaryOperands::Duration(v1, v2)) Some(NumericBinaryOperands::Duration(v1, v2))
} }
(EncodedTerm::DurationLiteral(v1), EncodedTerm::YearMonthDurationLiteral(v2)) => {
Some(NumericBinaryOperands::Duration(v1, v2.into()))
}
(EncodedTerm::DurationLiteral(v1), EncodedTerm::DayTimeDurationLiteral(v2)) => {
Some(NumericBinaryOperands::Duration(v1, v2.into()))
}
(EncodedTerm::YearMonthDurationLiteral(v1), EncodedTerm::DurationLiteral(v2)) => {
Some(NumericBinaryOperands::Duration(v1.into(), v2))
}
(
EncodedTerm::YearMonthDurationLiteral(v1),
EncodedTerm::YearMonthDurationLiteral(v2),
) => Some(NumericBinaryOperands::YearMonthDuration(v1, v2)),
(
EncodedTerm::YearMonthDurationLiteral(v1),
EncodedTerm::DayTimeDurationLiteral(v2),
) => Some(NumericBinaryOperands::Duration(v1.into(), v2.into())),
(EncodedTerm::DayTimeDurationLiteral(v1), EncodedTerm::DurationLiteral(v2)) => {
Some(NumericBinaryOperands::Duration(v1.into(), v2))
}
(
EncodedTerm::DayTimeDurationLiteral(v1),
EncodedTerm::YearMonthDurationLiteral(v2),
) => Some(NumericBinaryOperands::Duration(v1.into(), v2.into())),
(EncodedTerm::DayTimeDurationLiteral(v1), EncodedTerm::DayTimeDurationLiteral(v2)) => {
Some(NumericBinaryOperands::DayTimeDuration(v1, v2))
}
(EncodedTerm::DateTimeLiteral(v1), EncodedTerm::DateTimeLiteral(v2)) => { (EncodedTerm::DateTimeLiteral(v1), EncodedTerm::DateTimeLiteral(v2)) => {
Some(NumericBinaryOperands::DateTime(v1, v2)) Some(NumericBinaryOperands::DateTime(v1, v2))
} }
@ -1894,12 +2021,27 @@ impl NumericBinaryOperands {
(EncodedTerm::DateTimeLiteral(v1), EncodedTerm::DurationLiteral(v2)) => { (EncodedTerm::DateTimeLiteral(v1), EncodedTerm::DurationLiteral(v2)) => {
Some(NumericBinaryOperands::DateTimeDuration(v1, v2)) Some(NumericBinaryOperands::DateTimeDuration(v1, v2))
} }
(EncodedTerm::DateTimeLiteral(v1), EncodedTerm::YearMonthDurationLiteral(v2)) => {
Some(NumericBinaryOperands::DateTimeYearMonthDuration(v1, v2))
}
(EncodedTerm::DateTimeLiteral(v1), EncodedTerm::DayTimeDurationLiteral(v2)) => {
Some(NumericBinaryOperands::DateTimeDayTimeDuration(v1, v2))
}
(EncodedTerm::DateLiteral(v1), EncodedTerm::DurationLiteral(v2)) => { (EncodedTerm::DateLiteral(v1), EncodedTerm::DurationLiteral(v2)) => {
Some(NumericBinaryOperands::DateDuration(v1, v2)) Some(NumericBinaryOperands::DateDuration(v1, v2))
} }
(EncodedTerm::DateLiteral(v1), EncodedTerm::YearMonthDurationLiteral(v2)) => {
Some(NumericBinaryOperands::DateYearMonthDuration(v1, v2))
}
(EncodedTerm::DateLiteral(v1), EncodedTerm::DayTimeDurationLiteral(v2)) => {
Some(NumericBinaryOperands::DateDayTimeDuration(v1, v2))
}
(EncodedTerm::TimeLiteral(v1), EncodedTerm::DurationLiteral(v2)) => { (EncodedTerm::TimeLiteral(v1), EncodedTerm::DurationLiteral(v2)) => {
Some(NumericBinaryOperands::TimeDuration(v1, v2)) Some(NumericBinaryOperands::TimeDuration(v1, v2))
} }
(EncodedTerm::TimeLiteral(v1), EncodedTerm::DayTimeDurationLiteral(v2)) => {
Some(NumericBinaryOperands::TimeDayTimeDuration(v1, v2))
}
_ => None, _ => None,
} }
} }

@ -310,6 +310,8 @@ pub enum PlanExpression {
TimeCast(Box<PlanExpression>), TimeCast(Box<PlanExpression>),
DateTimeCast(Box<PlanExpression>), DateTimeCast(Box<PlanExpression>),
DurationCast(Box<PlanExpression>), DurationCast(Box<PlanExpression>),
YearMonthDurationCast(Box<PlanExpression>),
DayTimeDurationCast(Box<PlanExpression>),
StringCast(Box<PlanExpression>), StringCast(Box<PlanExpression>),
} }
@ -367,6 +369,8 @@ impl PlanExpression {
| PlanExpression::TimeCast(e) | PlanExpression::TimeCast(e)
| PlanExpression::DateTimeCast(e) | PlanExpression::DateTimeCast(e)
| PlanExpression::DurationCast(e) | PlanExpression::DurationCast(e)
| PlanExpression::YearMonthDurationCast(e)
| PlanExpression::DayTimeDurationCast(e)
| PlanExpression::StringCast(e) => e.add_maybe_bound_variables(set), | PlanExpression::StringCast(e) => e.add_maybe_bound_variables(set),
PlanExpression::Or(a, b) PlanExpression::Or(a, b)
| PlanExpression::And(a, b) | PlanExpression::And(a, b)

@ -643,6 +643,22 @@ impl<E: Encoder> PlanBuilder<E> {
graph_name, graph_name,
"duration", "duration",
)? )?
} else if name == "http://www.w3.org/2001/XMLSchema#yearMonthDuration" {
self.build_cast(
parameters,
PlanExpression::YearMonthDurationCast,
variables,
graph_name,
"yearMonthDuration",
)?
} else if name == "http://www.w3.org/2001/XMLSchema#dayTimeDuration" {
self.build_cast(
parameters,
PlanExpression::DayTimeDurationCast,
variables,
graph_name,
"dayTimeDuration",
)?
} else if name == "http://www.w3.org/2001/XMLSchema#string" { } else if name == "http://www.w3.org/2001/XMLSchema#string" {
self.build_cast( self.build_cast(
parameters, parameters,

@ -60,6 +60,8 @@ const XSD_DATE_TIME_ID: StrHash = StrHash::constant(0xd7496e779a321ade51e92da1a5
const XSD_DATE_ID: StrHash = StrHash::constant(0x87c4351dea4b98f59a22f7b636d4031); const XSD_DATE_ID: StrHash = StrHash::constant(0x87c4351dea4b98f59a22f7b636d4031);
const XSD_TIME_ID: StrHash = StrHash::constant(0xc7487be3f3d27d1926b27abf005a9cd2); const XSD_TIME_ID: StrHash = StrHash::constant(0xc7487be3f3d27d1926b27abf005a9cd2);
const XSD_DURATION_ID: StrHash = StrHash::constant(0x226af08ea5b7e6b08ceed6030c721228); const XSD_DURATION_ID: StrHash = StrHash::constant(0x226af08ea5b7e6b08ceed6030c721228);
const XSD_YEAR_MONTH_DURATION_ID: StrHash = StrHash::constant(0xc6dacde7afc0bd2f6e178d7229948191);
const XSD_DAY_TIME_DURATION_ID: StrHash = StrHash::constant(0xc8d6cfdf45e12c10bd711a76aae43bc6);
const TYPE_DEFAULT_GRAPH_ID: u8 = 0; const TYPE_DEFAULT_GRAPH_ID: u8 = 0;
const TYPE_NAMED_NODE_ID: u8 = 1; const TYPE_NAMED_NODE_ID: u8 = 1;
@ -78,6 +80,8 @@ const TYPE_DATE_TIME_LITERAL: u8 = 13;
const TYPE_DATE_LITERAL: u8 = 14; const TYPE_DATE_LITERAL: u8 = 14;
const TYPE_TIME_LITERAL: u8 = 15; const TYPE_TIME_LITERAL: u8 = 15;
const TYPE_DURATION_LITERAL: u8 = 16; const TYPE_DURATION_LITERAL: u8 = 16;
const TYPE_YEAR_MONTH_DURATION_LITERAL: u8 = 17;
const TYPE_DAY_TIME_DURATION_LITERAL: u8 = 18;
pub const ENCODED_DEFAULT_GRAPH: EncodedTerm = EncodedTerm::DefaultGraph; pub const ENCODED_DEFAULT_GRAPH: EncodedTerm = EncodedTerm::DefaultGraph;
pub const ENCODED_EMPTY_STRING_LITERAL: EncodedTerm = EncodedTerm::StringLiteral { pub const ENCODED_EMPTY_STRING_LITERAL: EncodedTerm = EncodedTerm::StringLiteral {
@ -116,6 +120,12 @@ pub const ENCODED_XSD_DATE_TIME_NAMED_NODE: EncodedTerm = EncodedTerm::NamedNode
pub const ENCODED_XSD_DURATION_NAMED_NODE: EncodedTerm = EncodedTerm::NamedNode { pub const ENCODED_XSD_DURATION_NAMED_NODE: EncodedTerm = EncodedTerm::NamedNode {
iri_id: XSD_DURATION_ID, iri_id: XSD_DURATION_ID,
}; };
pub const ENCODED_XSD_YEAR_MONTH_DURATION_NAMED_NODE: EncodedTerm = EncodedTerm::NamedNode {
iri_id: XSD_YEAR_MONTH_DURATION_ID,
};
pub const ENCODED_XSD_DAY_TIME_DURATION_NAMED_NODE: EncodedTerm = EncodedTerm::NamedNode {
iri_id: XSD_DAY_TIME_DURATION_ID,
};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum EncodedTerm { pub enum EncodedTerm {
@ -149,6 +159,8 @@ pub enum EncodedTerm {
TimeLiteral(Time), TimeLiteral(Time),
DateTimeLiteral(DateTime), DateTimeLiteral(DateTime),
DurationLiteral(Duration), DurationLiteral(Duration),
YearMonthDurationLiteral(YearMonthDuration),
DayTimeDurationLiteral(DayTimeDuration),
} }
impl PartialEq for EncodedTerm { impl PartialEq for EncodedTerm {
@ -216,6 +228,13 @@ impl PartialEq for EncodedTerm {
(EncodedTerm::TimeLiteral(a), EncodedTerm::TimeLiteral(b)) => a == b, (EncodedTerm::TimeLiteral(a), EncodedTerm::TimeLiteral(b)) => a == b,
(EncodedTerm::DateTimeLiteral(a), EncodedTerm::DateTimeLiteral(b)) => a == b, (EncodedTerm::DateTimeLiteral(a), EncodedTerm::DateTimeLiteral(b)) => a == b,
(EncodedTerm::DurationLiteral(a), EncodedTerm::DurationLiteral(b)) => a == b, (EncodedTerm::DurationLiteral(a), EncodedTerm::DurationLiteral(b)) => a == b,
(
EncodedTerm::YearMonthDurationLiteral(a),
EncodedTerm::YearMonthDurationLiteral(b),
) => a == b,
(EncodedTerm::DayTimeDurationLiteral(a), EncodedTerm::DayTimeDurationLiteral(b)) => {
a == b
}
(_, _) => false, (_, _) => false,
} }
} }
@ -254,6 +273,8 @@ impl Hash for EncodedTerm {
EncodedTerm::TimeLiteral(value) => value.hash(state), EncodedTerm::TimeLiteral(value) => value.hash(state),
EncodedTerm::DateTimeLiteral(value) => value.hash(state), EncodedTerm::DateTimeLiteral(value) => value.hash(state),
EncodedTerm::DurationLiteral(value) => value.hash(state), EncodedTerm::DurationLiteral(value) => value.hash(state),
EncodedTerm::YearMonthDurationLiteral(value) => value.hash(state),
EncodedTerm::DayTimeDurationLiteral(value) => value.hash(state),
} }
} }
} }
@ -286,7 +307,9 @@ impl EncodedTerm {
| EncodedTerm::DateLiteral(_) | EncodedTerm::DateLiteral(_)
| EncodedTerm::TimeLiteral(_) | EncodedTerm::TimeLiteral(_)
| EncodedTerm::DateTimeLiteral(_) | EncodedTerm::DateTimeLiteral(_)
| EncodedTerm::DurationLiteral(_) => true, | EncodedTerm::DurationLiteral(_)
| EncodedTerm::YearMonthDurationLiteral(_)
| EncodedTerm::DayTimeDurationLiteral(_) => true,
_ => false, _ => false,
} }
} }
@ -307,6 +330,12 @@ impl EncodedTerm {
EncodedTerm::TimeLiteral(..) => Some(ENCODED_XSD_TIME_NAMED_NODE), EncodedTerm::TimeLiteral(..) => Some(ENCODED_XSD_TIME_NAMED_NODE),
EncodedTerm::DateTimeLiteral(..) => Some(ENCODED_XSD_DATE_TIME_NAMED_NODE), EncodedTerm::DateTimeLiteral(..) => Some(ENCODED_XSD_DATE_TIME_NAMED_NODE),
EncodedTerm::DurationLiteral(..) => Some(ENCODED_XSD_DURATION_NAMED_NODE), EncodedTerm::DurationLiteral(..) => Some(ENCODED_XSD_DURATION_NAMED_NODE),
EncodedTerm::YearMonthDurationLiteral(..) => {
Some(ENCODED_XSD_YEAR_MONTH_DURATION_NAMED_NODE)
}
EncodedTerm::DayTimeDurationLiteral(..) => {
Some(ENCODED_XSD_DAY_TIME_DURATION_NAMED_NODE)
}
_ => None, _ => None,
} }
} }
@ -330,6 +359,8 @@ impl EncodedTerm {
EncodedTerm::TimeLiteral(_) => TYPE_TIME_LITERAL, EncodedTerm::TimeLiteral(_) => TYPE_TIME_LITERAL,
EncodedTerm::DateTimeLiteral(_) => TYPE_DATE_TIME_LITERAL, EncodedTerm::DateTimeLiteral(_) => TYPE_DATE_TIME_LITERAL,
EncodedTerm::DurationLiteral(_) => TYPE_DURATION_LITERAL, EncodedTerm::DurationLiteral(_) => TYPE_DURATION_LITERAL,
EncodedTerm::YearMonthDurationLiteral(_) => TYPE_YEAR_MONTH_DURATION_LITERAL,
EncodedTerm::DayTimeDurationLiteral(_) => TYPE_DAY_TIME_DURATION_LITERAL,
} }
} }
} }
@ -405,6 +436,18 @@ impl From<Duration> for EncodedTerm {
} }
} }
impl From<YearMonthDuration> for EncodedTerm {
fn from(value: YearMonthDuration) -> Self {
EncodedTerm::YearMonthDurationLiteral(value)
}
}
impl From<DayTimeDuration> for EncodedTerm {
fn from(value: DayTimeDuration) -> Self {
EncodedTerm::DayTimeDurationLiteral(value)
}
}
impl From<&NamedNode> for EncodedTerm { impl From<&NamedNode> for EncodedTerm {
fn from(node: &NamedNode) -> Self { fn from(node: &NamedNode) -> Self {
rio::NamedNode::from(node).into() rio::NamedNode::from(node).into()
@ -479,10 +522,12 @@ impl<'a> From<rio::Literal<'a>> for EncodedTerm {
| "http://www.w3.org/2001/XMLSchema#dateTimeStamp" => { | "http://www.w3.org/2001/XMLSchema#dateTimeStamp" => {
parse_date_time_str(value) parse_date_time_str(value)
} }
"http://www.w3.org/2001/XMLSchema#duration" "http://www.w3.org/2001/XMLSchema#duration" => parse_duration_str(value),
| "http://www.w3.org/2001/XMLSchema#yearMonthDuration" "http://www.w3.org/2001/XMLSchema#yearMonthDuration" => {
| "http://www.w3.org/2001/XMLSchema#dayTimeDuration" => { parse_year_month_duration_str(value)
parse_duration_str(value) }
"http://www.w3.org/2001/XMLSchema#dayTimeDuration" => {
parse_day_time_duration_str(value)
} }
_ => None, _ => None,
} { } {
@ -664,6 +709,20 @@ impl<R: Read> TermReader for R {
buffer, buffer,
))) )))
} }
TYPE_YEAR_MONTH_DURATION_LITERAL => {
let mut buffer = [0; 8];
self.read_exact(&mut buffer)?;
Ok(EncodedTerm::YearMonthDurationLiteral(
YearMonthDuration::from_be_bytes(buffer),
))
}
TYPE_DAY_TIME_DURATION_LITERAL => {
let mut buffer = [0; 16];
self.read_exact(&mut buffer)?;
Ok(EncodedTerm::DayTimeDurationLiteral(
DayTimeDuration::from_be_bytes(buffer),
))
}
_ => Err(Error::msg("the term buffer has an invalid type id")), _ => Err(Error::msg("the term buffer has an invalid type id")),
} }
} }
@ -780,6 +839,10 @@ pub fn write_term(sink: &mut Vec<u8>, term: EncodedTerm) {
EncodedTerm::TimeLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), EncodedTerm::TimeLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()),
EncodedTerm::DateTimeLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), EncodedTerm::DateTimeLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()),
EncodedTerm::DurationLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()), EncodedTerm::DurationLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()),
EncodedTerm::YearMonthDurationLiteral(value) => {
sink.extend_from_slice(&value.to_be_bytes())
}
EncodedTerm::DayTimeDurationLiteral(value) => sink.extend_from_slice(&value.to_be_bytes()),
} }
} }
@ -870,6 +933,11 @@ pub trait StrContainer {
self.insert_str(XSD_DATE_ID, xsd::DATE.as_str())?; self.insert_str(XSD_DATE_ID, xsd::DATE.as_str())?;
self.insert_str(XSD_TIME_ID, xsd::TIME.as_str())?; self.insert_str(XSD_TIME_ID, xsd::TIME.as_str())?;
self.insert_str(XSD_DURATION_ID, xsd::DURATION.as_str())?; self.insert_str(XSD_DURATION_ID, xsd::DURATION.as_str())?;
self.insert_str(
XSD_YEAR_MONTH_DURATION_ID,
xsd::YEAR_MONTH_DURATION.as_str(),
)?;
self.insert_str(XSD_DAY_TIME_DURATION_ID, xsd::DAY_TIME_DURATION.as_str())?;
Ok(()) Ok(())
} }
} }
@ -1100,10 +1168,12 @@ impl<S: StrContainer> Encoder for S {
| "http://www.w3.org/2001/XMLSchema#dateTimeStamp" => { | "http://www.w3.org/2001/XMLSchema#dateTimeStamp" => {
parse_date_time_str(value) parse_date_time_str(value)
} }
"http://www.w3.org/2001/XMLSchema#duration" "http://www.w3.org/2001/XMLSchema#duration" => parse_duration_str(value),
| "http://www.w3.org/2001/XMLSchema#yearMonthDuration" "http://www.w3.org/2001/XMLSchema#yearMonthDuration" => {
| "http://www.w3.org/2001/XMLSchema#dayTimeDuration" => { parse_year_month_duration_str(value)
parse_duration_str(value) }
"http://www.w3.org/2001/XMLSchema#dayTimeDuration" => {
parse_day_time_duration_str(value)
} }
_ => None, _ => None,
} { } {
@ -1164,6 +1234,17 @@ pub fn parse_duration_str(value: &str) -> Option<EncodedTerm> {
value.parse().map(EncodedTerm::DurationLiteral).ok() value.parse().map(EncodedTerm::DurationLiteral).ok()
} }
pub fn parse_year_month_duration_str(value: &str) -> Option<EncodedTerm> {
value
.parse()
.map(EncodedTerm::YearMonthDurationLiteral)
.ok()
}
pub fn parse_day_time_duration_str(value: &str) -> Option<EncodedTerm> {
value.parse().map(EncodedTerm::DayTimeDurationLiteral).ok()
}
pub trait Decoder { pub trait Decoder {
fn decode_term(&self, encoded: EncodedTerm) -> Result<Term>; fn decode_term(&self, encoded: EncodedTerm) -> Result<Term>;
@ -1251,6 +1332,8 @@ impl<S: StrLookup> Decoder for S {
EncodedTerm::TimeLiteral(value) => Ok(Literal::from(value).into()), EncodedTerm::TimeLiteral(value) => Ok(Literal::from(value).into()),
EncodedTerm::DateTimeLiteral(value) => Ok(Literal::from(value).into()), EncodedTerm::DateTimeLiteral(value) => Ok(Literal::from(value).into()),
EncodedTerm::DurationLiteral(value) => Ok(Literal::from(value).into()), EncodedTerm::DurationLiteral(value) => Ok(Literal::from(value).into()),
EncodedTerm::YearMonthDurationLiteral(value) => Ok(Literal::from(value).into()),
EncodedTerm::DayTimeDurationLiteral(value) => Ok(Literal::from(value).into()),
} }
} }
} }

Loading…
Cancel
Save