pull/745/head
Yuri Astrakhan 11 months ago
parent b41b90cd6b
commit 338a76b324
  1. 8
      lib/oxigraph/src/sparql/eval.rs
  2. 11
      lib/oxigraph/src/storage/binary_encoder.rs
  3. 9
      lib/oxigraph/src/storage/error.rs
  4. 33
      lib/oxigraph/src/storage/numeric_encoder.rs
  5. 29
      lib/oxsdatatypes/src/geopoint.rs

@ -13,6 +13,7 @@ use json_event_parser::{JsonEvent, ToWriteJsonWriter};
use md5::Md5;
use oxilangtag::LanguageTag;
use oxiri::Iri;
use oxrdf::vocab::geosparql;
use oxrdf::{TermRef, Variable};
use oxsdatatypes::*;
use rand::random;
@ -2930,6 +2931,7 @@ fn to_string_id(dataset: &DatasetView, term: &EncodedTerm) -> Option<SmallString
EncodedTerm::DayTimeDurationLiteral(value) => {
Some(build_string_id(dataset, &value.to_string()))
}
EncodedTerm::GeoPoint(value) => Some(build_string_id(dataset, &value.to_string())),
}
}
@ -3318,6 +3320,11 @@ fn equals(a: &EncodedTerm, b: &EncodedTerm) -> Option<bool> {
_ if b.is_unknown_typed_literal() => None,
_ => Some(false),
},
EncodedTerm::GeoPoint(a) => match b {
EncodedTerm::GeoPoint(b) => Some(a == b),
_ if b.is_unknown_typed_literal() => None,
_ => Some(false),
},
EncodedTerm::Triple(a) => {
if let EncodedTerm::Triple(b) = b {
Some(
@ -3672,6 +3679,7 @@ fn datatype(dataset: &DatasetView, value: &EncodedTerm) -> Option<EncodedTerm> {
EncodedTerm::DayTimeDurationLiteral(..) => {
Some(encode_named_node(dataset, xsd::DAY_TIME_DURATION))
}
EncodedTerm::GeoPoint(..) => Some(encode_named_node(dataset, geosparql::WKT_LITERAL)),
}
}

@ -46,6 +46,7 @@ const TYPE_G_MONTH_LITERAL: u8 = 41;
const TYPE_DURATION_LITERAL: u8 = 42;
const TYPE_YEAR_MONTH_DURATION_LITERAL: u8 = 43;
const TYPE_DAY_TIME_DURATION_LITERAL: u8 = 44;
const TYPE_GEO_POINT_LITERAL: u8 = 45;
const TYPE_TRIPLE: u8 = 48;
#[derive(Clone, Copy)]
@ -388,6 +389,11 @@ impl<R: Read> TermReader for R {
self.read_exact(&mut buffer)?;
Ok(DayTimeDuration::from_be_bytes(buffer).into())
}
TYPE_GEO_POINT_LITERAL => {
let mut buffer = [0; 16];
self.read_exact(&mut buffer)?;
Ok(DayTimeDuration::from_be_bytes(buffer).into())
}
TYPE_TRIPLE => Ok(EncodedTriple {
subject: self.read_term()?,
predicate: self.read_term()?,
@ -622,6 +628,11 @@ pub fn write_term(sink: &mut Vec<u8>, term: &EncodedTerm) {
sink.push(TYPE_DAY_TIME_DURATION_LITERAL);
sink.extend_from_slice(&value.to_be_bytes())
}
EncodedTerm::GeoPoint(value) => {
sink.push(TYPE_GEO_POINT_LITERAL);
sink.extend_from_slice(&value.x.to_be_bytes());
sink.extend_from_slice(&value.y.to_be_bytes());
}
EncodedTerm::Triple(value) => {
sink.push(TYPE_TRIPLE);
write_term(sink, &value.subject);

@ -1,5 +1,7 @@
use crate::io::{ParseError, RdfFormat};
use crate::storage::numeric_encoder::EncodedTerm;
use oxiri::IriParseError;
use oxrdf::TermRef;
use std::error::Error;
use std::io;
@ -45,6 +47,13 @@ impl CorruptionError {
Self::Other(error.into())
}
/// Builds an error from encoding and the term.
#[inline]
pub(crate) fn from_encoded_term(encoded: &EncodedTerm, term: &TermRef<'_>) -> Self {
// TODO: eventually use a dedicated error enum value
Self::new(format!("Invalid term encoding {encoded:?} for {term}"))
}
/// Builds an error from a printable error message.
#[inline]
pub(crate) fn msg(msg: impl Into<String>) -> Self {

@ -95,6 +95,7 @@ pub enum EncodedTerm {
DurationLiteral(Duration),
YearMonthDurationLiteral(YearMonthDuration),
DayTimeDurationLiteral(DayTimeDuration),
GeoPoint(GeoPoint),
Triple(Arc<EncodedTriple>),
}
@ -266,6 +267,7 @@ impl Hash for EncodedTerm {
Self::YearMonthDurationLiteral(value) => value.hash(state),
Self::DayTimeDurationLiteral(value) => value.hash(state),
Self::Triple(value) => value.hash(state),
EncodedTerm::GeoPoint(_) => {}
}
}
}
@ -713,19 +715,13 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
if let EncodedTerm::NamedNode { iri_id } = encoded {
insert_str(iri_id, node.as_str())
} else {
Err(
CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}"))
.into(),
)
Err(CorruptionError::from_encoded_term(encoded, &term).into())
}
}
TermRef::BlankNode(node) => match encoded {
EncodedTerm::BigBlankNode { id_id } => insert_str(id_id, node.as_str()),
EncodedTerm::SmallBlankNode(..) | EncodedTerm::NumericalBlankNode { .. } => Ok(()),
_ => Err(
CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}"))
.into(),
),
_ => Err(CorruptionError::from_encoded_term(encoded, &term).into()),
},
TermRef::Literal(literal) => match encoded {
EncodedTerm::BigStringLiteral { value_id }
@ -736,10 +732,7 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
if let Some(language) = literal.language() {
insert_str(language_id, language)
} else {
Err(CorruptionError::new(format!(
"Invalid term encoding {encoded:?} for {term}"
))
.into())
Err(CorruptionError::from_encoded_term(encoded, &term).into())
}
}
EncodedTerm::BigBigLangStringLiteral {
@ -750,10 +743,7 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
if let Some(language) = literal.language() {
insert_str(language_id, language)
} else {
Err(CorruptionError::new(format!(
"Invalid term encoding {encoded:?} for {term}"
))
.into())
Err(CorruptionError::from_encoded_term(encoded, &term).into())
}
}
EncodedTerm::SmallTypedLiteral { datatype_id, .. } => {
@ -784,10 +774,7 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
| EncodedTerm::DurationLiteral(..)
| EncodedTerm::YearMonthDurationLiteral(..)
| EncodedTerm::DayTimeDurationLiteral(..) => Ok(()),
_ => Err(
CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}"))
.into(),
),
_ => Err(CorruptionError::from_encoded_term(encoded, &term).into()),
},
TermRef::Triple(triple) => {
if let EncodedTerm::Triple(encoded) = encoded {
@ -799,10 +786,7 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
)?;
insert_term(triple.object.as_ref(), &encoded.object, insert_str)
} else {
Err(
CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}"))
.into(),
)
Err(CorruptionError::from_encoded_term(encoded, &term).into())
}
}
}
@ -1035,6 +1019,7 @@ impl<S: StrLookup> Decoder for S {
EncodedTerm::DurationLiteral(value) => Ok(Literal::from(*value).into()),
EncodedTerm::YearMonthDurationLiteral(value) => Ok(Literal::from(*value).into()),
EncodedTerm::DayTimeDurationLiteral(value) => Ok(Literal::from(*value).into()),
EncodedTerm::GeoPoint(value) => Ok(Literal::from(*value).into()),
EncodedTerm::Triple(triple) => Ok(self.decode_triple(triple)?.into()),
}
}

@ -2,7 +2,7 @@ use std::fmt;
use std::fmt::Formatter;
use std::str::FromStr;
use thiserror::Error;
use wkt::types::Point;
use wkt::types::{Coord, Point};
use wkt::{Geometry, Wkt};
// use std::time::Geo as StdDuration;
@ -10,8 +10,11 @@ use wkt::{Geometry, Wkt};
/// [XML Schema `duration` datatype](https://www.w3.org/TR/xmlschema11-2/#duration)
///
/// It stores the duration using a pair of a [`YearMonthDuration`] and a [`DayTimeDuration`].
#[derive(Debug, Clone)]
pub struct GeoPoint(Point<f64>);
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct GeoPoint {
pub x: f32,
pub y: f32,
}
#[derive(Error, Debug)]
pub enum GeoPointError {
@ -26,6 +29,14 @@ impl GeoPoint {
pub fn new() -> Result<Self, GeoPointError> {
Self::from_str("POINT(0 0)")
}
#[inline]
pub fn from_be_bytes(bytes: [u8; 8]) -> Self {
Self {
x: f32::from_be_bytes(bytes[0..4].try_into().unwrap()),
y: f32::from_be_bytes(bytes[4..8].try_into().unwrap()),
}
}
}
impl FromStr for GeoPoint {
@ -33,16 +44,22 @@ impl FromStr for GeoPoint {
fn from_str(input: &str) -> Result<Self, Self::Err> {
let geo = Wkt::from_str(input).map_err(GeoPointError::WktParsingError)?;
let Geometry::Point(point) = geo.item else {
let Geometry::Point(Point(Some(Coord {
x,
y,
z: None,
m: None,
}))) = geo.item
else {
return Err(GeoPointError::UnsupportedWktType(geo.item.to_string()));
};
Ok(Self(point))
Ok(Self { x, y })
}
}
impl fmt::Display for GeoPoint {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
write!(f, "POINT({} {})", self.x, self.y)
}
}
#[cfg(test)]

Loading…
Cancel
Save