Skip to main content

stam/
datavalue.rs

1/*
2    STAM Library (Stand-off Text Annotation Model)
3        by Maarten van Gompel <proycon@anaproy.nl>
4        Digital Infrastucture, KNAW Humanities Cluster
5
6        Licensed under the GNU General Public License v3
7
8        https://github.com/annotation/stam-rust
9*/
10
11//! This module contains the API for [`DataValue`]. It defines and implements the
12//! struct, the handle, and things like serialisation, deserialisation to STAM JSON.
13//! It also implements the [`DataOperator`].
14//! This API is used both on high and low levels.
15
16use chrono::{DateTime, FixedOffset};
17use minicbor::{Decode, Encode};
18use serde::{Deserialize, Serialize};
19use std::borrow::Cow;
20use std::collections::BTreeMap;
21use std::fmt;
22
23use crate::cbor::{cbor_decode_datetime, cbor_encode_datetime};
24use crate::error::StamError;
25use crate::types::*;
26use datasize::{data_size, DataSize};
27use sealed::sealed;
28use std::ops::Deref;
29
30#[sealed]
31impl TypeInfo for DataValue {
32    fn typeinfo() -> Type {
33        Type::DataValue
34    }
35}
36
37#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Encode, Decode)]
38#[serde(tag = "@type", content = "value")]
39/// This type encapsulates a value and its type.
40/// It is held by [`AnnotationData`](crate::AnnotationData) alongside a reference to a [`DataKey`](crate::DataKey), resulting in a key/value pair.
41pub enum DataValue {
42    /// No value
43    #[n(0)]
44    Null,
45
46    /// A string value
47    #[n(1)]
48    String(#[n(0)] String),
49
50    /// A boolean value
51    #[n(2)]
52    Bool(#[n(0)] bool),
53
54    /// A numeric integer value
55    #[n(3)]
56    Int(#[n(0)] isize),
57
58    /// A numeric floating-point value
59    #[n(4)]
60    Float(#[n(0)] f64),
61
62    /// Value is an unordered set
63    //Set(HashSet<DataValue>),
64
65    /// The value is an ordered list
66    #[n(5)]
67    List(#[n(0)] Vec<DataValue>),
68
69    /// The value is a date/timestamp
70    #[cbor(n(6))]
71    Datetime(
72        #[cbor(
73            n(0),
74            decode_with = "cbor_decode_datetime",
75            encode_with = "cbor_encode_datetime"
76        )]
77        DateTime<FixedOffset>,
78    ),
79
80    /// The value is a map
81    #[cbor(n(7))]
82    Map(#[n(0)] BTreeMap<String, DataValue>),
83}
84
85impl DataSize for DataValue {
86    // `MyType` contains a `Vec` and a `String`, so `IS_DYNAMIC` is set to true.
87    const IS_DYNAMIC: bool = true;
88    const STATIC_HEAP_SIZE: usize = 8; //the descriminator/tag of the enum (worst case estimate)
89
90    #[inline]
91    fn estimate_heap_size(&self) -> usize {
92        match self {
93            Self::Null => 8, //discriminator base size only
94            Self::Bool(v) => 8 + data_size(v),
95            Self::String(v) => 8 + data_size(v),
96            Self::Int(v) => 8 + data_size(v),
97            Self::Float(v) => 8 + data_size(v),
98            Self::List(v) => 8 + data_size(v),
99            Self::Map(v) => 8 + data_size(v),
100            Self::Datetime(_) => 8 + (4 * 4), //4*u32, guessed based on chrono source code, may not be accurate
101        }
102    }
103}
104
105#[derive(Clone, Debug, PartialEq)]
106/// This type defines a test that can be done on a [`DataValue`] (via [`DataValue::test()`]).
107/// The operator does not merely consist of the operator-part, but also holds the value that is tested against, which may
108/// be one of various types, hence the many variants of this type.
109///
110/// [`DataOperator::Any`] is a special variant of this operator that will always pass.
111pub enum DataOperator<'a> {
112    Null,
113    Any,
114    /// Tests against a string
115    Equals(Cow<'a, str>),
116    /// Tests against a numeric integer
117    EqualsInt(isize),
118    /// Tests against a numeric floating-point value
119    EqualsFloat(f64),
120    True,
121    False,
122    /// The datavalue must be numeric and greater than the value with the operator
123    GreaterThan(isize),
124    /// The datavalue must be numeric and greater than or equal to the value with the operator
125    GreaterThanOrEqual(isize),
126    /// The datavalue must be numeric and greater than the value with the operator
127    GreaterThanFloat(f64),
128    /// The datavalue must be numeric and greater than or equal to the value with the operator
129    GreaterThanOrEqualFloat(f64),
130    /// The datavalue must be numeric and less than the value with the operator
131    LessThan(isize),
132    /// The datavalue must be numeric and less than or equal to the value with the operator
133    LessThanOrEqual(isize),
134    /// The datavalue must be numeric and less than or equal to the value with the operator
135    LessThanFloat(f64),
136    /// The datavalue must be numeric and less than or equal to the value with the operator
137    LessThanOrEqualFloat(f64),
138    /// The datavalue must be a datetime and match this reference exactly
139    ExactDatetime(DateTime<FixedOffset>),
140    /// The datavalue must be a datetime and come after this reference datetime
141    AfterDatetime(DateTime<FixedOffset>),
142    /// The datavalue must be a datetime and come before this reference datetime
143    BeforeDatetime(DateTime<FixedOffset>),
144    /// The datavalue must be a datetime and come at or after this reference datetime
145    AtOrAfterDatetime(DateTime<FixedOffset>),
146    /// The datavalue must be a datetime and come at or before this reference datetime
147    AtOrBeforeDatetime(DateTime<FixedOffset>),
148
149    HasElement(Cow<'a, str>),
150    HasElementInt(isize),
151    HasElementFloat(f64),
152
153    /// Get an item from a List
154    GetIndex(isize, Option<Box<DataOperator<'a>>>),
155    /// Get an item from a map
156    GetKey(Cow<'a, str>, Option<Box<DataOperator<'a>>>),
157
158    /// Logical negation, reverses the operator
159    Not(Box<DataOperator<'a>>),
160    /// Logical AND operator (conjunction) to combine multiple operators into one
161    And(Vec<DataOperator<'a>>),
162    /// Logical OR operator (disjunction) to combine multiple operators into one
163    Or(Vec<DataOperator<'a>>),
164}
165
166impl<'a> DataValue {
167    /// This applies a [`DataOperator`] to the data value, and returns a boolean if the values passes the constraints posed by the operator.
168    /// Note that the [`DataOperator`] itself holds the value that is tested against.
169    pub fn test(&self, operator: &DataOperator<'a>) -> bool {
170        match (self, operator) {
171            (_, DataOperator::Any) => true,
172            (Self::Null, DataOperator::Null) => true,
173            (Self::Bool(true), DataOperator::True) => true,
174            (Self::Bool(false), DataOperator::False) => true,
175            (Self::Bool(true), DataOperator::Equals(s2)) => match s2.to_lowercase().as_str() {
176                "yes" | "1" | "enable" | "enabled" | "on" | "true" => true,
177                _ => false,
178            },
179            (Self::Bool(false), DataOperator::Equals(s2)) => match s2.to_lowercase().as_str() {
180                "yes" | "1" | "enable" | "enabled" | "on" | "true" => false,
181                _ => true,
182            },
183            (Self::String(s), DataOperator::Equals(s2)) => &s.as_str() == s2,
184            (Self::Int(n), DataOperator::EqualsInt(n2)) => *n == *n2,
185            (Self::Int(n), DataOperator::GreaterThan(n2)) => *n > *n2,
186            (Self::Int(n), DataOperator::GreaterThanOrEqual(n2)) => *n >= *n2,
187            (Self::Int(n), DataOperator::LessThan(n2)) => *n < *n2,
188            (Self::Int(n), DataOperator::LessThanOrEqual(n2)) => *n <= *n2,
189            (Self::Int(n), DataOperator::Equals(s2)) => {
190                if let Ok(n2) = s2.parse::<isize>() {
191                    *n == n2
192                } else {
193                    false
194                }
195            }
196            (Self::Float(n), DataOperator::EqualsFloat(n2)) => *n == *n2,
197            (Self::Float(n), DataOperator::GreaterThanFloat(n2)) => *n > *n2,
198            (Self::Float(n), DataOperator::GreaterThanOrEqualFloat(n2)) => *n >= *n2,
199            (Self::Float(n), DataOperator::LessThanFloat(n2)) => *n < *n2,
200            (Self::Float(n), DataOperator::LessThanOrEqualFloat(n2)) => *n <= *n2,
201            (Self::Float(n), DataOperator::Equals(s2)) => {
202                if let Ok(n2) = s2.parse::<f64>() {
203                    *n == n2
204                } else {
205                    false
206                }
207            }
208            (Self::Datetime(v), DataOperator::ExactDatetime(v2)) => v == v2,
209            (Self::Datetime(v), DataOperator::AfterDatetime(v2)) => v > v2,
210            (Self::Datetime(v), DataOperator::BeforeDatetime(v2)) => v < v2,
211            (Self::Datetime(v), DataOperator::AtOrAfterDatetime(v2)) => v >= v2,
212            (Self::Datetime(v), DataOperator::AtOrBeforeDatetime(v2)) => v <= v2,
213            (Self::Datetime(v), DataOperator::Equals(s2)) => {
214                if let Ok(v2) = DateTime::parse_from_rfc3339(s2) {
215                    *v == v2
216                } else {
217                    false
218                }
219            }
220            (Self::List(v), DataOperator::HasElement(s)) => {
221                v.iter().any(|e| e.test(&DataOperator::Equals(s.clone())))
222            }
223            (Self::List(v), DataOperator::HasElementInt(n)) => {
224                v.iter().any(|e| e.test(&DataOperator::EqualsInt(*n)))
225            }
226            (Self::List(v), DataOperator::HasElementFloat(f)) => {
227                v.iter().any(|e| e.test(&DataOperator::EqualsFloat(*f)))
228            }
229            (Self::Map(v), DataOperator::HasElement(s)) => v.contains_key(s.as_ref()),
230            (Self::Map(v), DataOperator::GetKey(s, Some(op))) => {
231                v.get(s.as_ref()).map(|e| e.test(&op)).unwrap_or(false)
232            }
233            (Self::Map(v), DataOperator::GetKey(s, None)) => v.contains_key(s.as_ref()),
234            (Self::List(v), DataOperator::GetIndex(i, Some(op))) => v
235                .iter()
236                .nth(*i as usize)
237                .map(|e| e.test(&op))
238                .unwrap_or(false),
239            (Self::List(v), DataOperator::GetIndex(i, None)) => v.len() > *i as usize,
240            (value, DataOperator::Not(operator)) => !value.test(operator),
241            (value, DataOperator::And(operators)) => {
242                operators.iter().all(|operator| value.test(operator))
243            }
244            (value, DataOperator::Or(operators)) => {
245                operators.iter().any(|operator| value.test(operator))
246            }
247            _ => false,
248        }
249    }
250
251    /// Writes a datavalue to one STAM JSON string, with appropriate formatting
252    pub fn to_json(&self) -> Result<String, StamError> {
253        //note: this function is not invoked during regular serialisation via the store
254        serde_json::to_string_pretty(&self).map_err(|e| {
255            StamError::SerializationError(format!("Writing datavalue to string: {}", e))
256        })
257    }
258
259    /// Writes a datavalue to one STAM JSON string, without any indentation
260    pub fn to_json_compact(&self) -> Result<String, StamError> {
261        //note: this function is not invoked during regular serialisation via the store
262        serde_json::to_string(&self).map_err(|e| {
263            StamError::SerializationError(format!("Writing datavalue to string: {}", e))
264        })
265    }
266}
267
268impl fmt::Display for DataValue {
269    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
270        match self {
271            Self::Null => write!(f, "null"),
272            Self::String(v) => write!(f, "{}", v),
273            Self::Bool(v) => write!(f, "{}", v),
274            Self::Int(v) => write!(f, "{}", v),
275            Self::Float(v) => write!(f, "{}", v),
276            Self::Datetime(v) => write!(f, "{}", v.to_rfc3339()),
277            Self::List(v) => {
278                for (i, item) in v.iter().enumerate() {
279                    if i < v.len() - 1 {
280                        write!(f, ", ")?;
281                    }
282                    write!(f, "{}", item)?;
283                }
284                Ok(())
285            }
286            Self::Map(v) => {
287                for (i, (key, item)) in v.iter().enumerate() {
288                    if i < v.len() - 1 {
289                        write!(f, ", ")?;
290                    }
291                    write!(f, "{}: {}", key, item)?;
292                }
293                Ok(())
294            }
295        }
296    }
297}
298
299impl From<&str> for DataValue {
300    fn from(item: &str) -> Self {
301        Self::String(item.to_string())
302    }
303}
304
305impl From<String> for DataValue {
306    fn from(item: String) -> Self {
307        Self::String(item)
308    }
309}
310
311impl From<f64> for DataValue {
312    fn from(item: f64) -> Self {
313        Self::Float(item)
314    }
315}
316
317impl From<f32> for DataValue {
318    fn from(item: f32) -> Self {
319        Self::Float(item as f64)
320    }
321}
322
323impl From<isize> for DataValue {
324    fn from(item: isize) -> Self {
325        Self::Int(item)
326    }
327}
328
329impl From<i64> for DataValue {
330    fn from(item: i64) -> Self {
331        Self::Int(item as isize)
332    }
333}
334
335impl From<i32> for DataValue {
336    fn from(item: i32) -> Self {
337        Self::Int(item as isize)
338    }
339}
340
341impl From<i16> for DataValue {
342    fn from(item: i16) -> Self {
343        Self::Int(item as isize)
344    }
345}
346
347impl From<i8> for DataValue {
348    fn from(item: i8) -> Self {
349        Self::Int(item as isize)
350    }
351}
352
353impl From<usize> for DataValue {
354    fn from(item: usize) -> Self {
355        Self::Int(
356            item.try_into()
357                .expect("integer out of bounds (u64 -> i64 failed)"),
358        )
359    }
360}
361
362impl From<u64> for DataValue {
363    fn from(item: u64) -> Self {
364        Self::Int(
365            item.try_into()
366                .expect("integer out of bounds (u64 -> i64 failed)"),
367        )
368    }
369}
370
371impl From<u32> for DataValue {
372    fn from(item: u32) -> Self {
373        Self::Int(item.try_into().unwrap())
374    }
375}
376
377impl From<u16> for DataValue {
378    fn from(item: u16) -> Self {
379        Self::Int(item.try_into().unwrap())
380    }
381}
382
383impl From<u8> for DataValue {
384    fn from(item: u8) -> Self {
385        Self::Int(item.try_into().unwrap())
386    }
387}
388
389impl From<bool> for DataValue {
390    fn from(item: bool) -> Self {
391        Self::Bool(item)
392    }
393}
394
395impl From<Vec<DataValue>> for DataValue {
396    fn from(item: Vec<DataValue>) -> Self {
397        Self::List(item)
398    }
399}
400
401impl From<BTreeMap<String, DataValue>> for DataValue {
402    fn from(item: BTreeMap<String, DataValue>) -> Self {
403        Self::Map(item)
404    }
405}
406
407impl From<Vec<(String, DataValue)>> for DataValue {
408    fn from(item: Vec<(String, DataValue)>) -> Self {
409        let mut map = BTreeMap::new();
410        for (k, v) in item {
411            map.insert(k, v);
412        }
413        Self::Map(map)
414    }
415}
416
417impl From<DateTime<FixedOffset>> for DataValue {
418    fn from(item: DateTime<FixedOffset>) -> Self {
419        Self::Datetime(item)
420    }
421}
422
423// These PartialEq implementation allow for more direct comparisons
424
425impl PartialEq<str> for DataValue {
426    fn eq(&self, other: &str) -> bool {
427        match self {
428            Self::String(v) => v == other,
429            _ => false,
430        }
431    }
432}
433
434impl PartialEq<&str> for DataValue {
435    fn eq(&self, other: &&str) -> bool {
436        match self {
437            Self::String(v) => v == other,
438            _ => false,
439        }
440    }
441}
442
443impl PartialEq<DataValue> for str {
444    fn eq(&self, other: &DataValue) -> bool {
445        match other {
446            DataValue::String(v) => v.as_str() == self,
447            _ => false,
448        }
449    }
450}
451
452impl PartialEq<DataValue> for &str {
453    fn eq(&self, other: &DataValue) -> bool {
454        match other {
455            DataValue::String(v) => v.as_str() == *self,
456            _ => false,
457        }
458    }
459}
460
461impl PartialEq<f64> for DataValue {
462    fn eq(&self, other: &f64) -> bool {
463        match self {
464            Self::Float(v) => v == other,
465            _ => false,
466        }
467    }
468}
469
470impl PartialEq<DataValue> for f64 {
471    fn eq(&self, other: &DataValue) -> bool {
472        match other {
473            DataValue::Float(v) => v == self,
474            _ => false,
475        }
476    }
477}
478
479impl PartialEq<isize> for DataValue {
480    fn eq(&self, other: &isize) -> bool {
481        match self {
482            Self::Int(v) => v == other,
483            _ => false,
484        }
485    }
486}
487
488impl PartialEq<DataValue> for isize {
489    fn eq(&self, other: &DataValue) -> bool {
490        match other {
491            DataValue::Int(v) => v == self,
492            _ => false,
493        }
494    }
495}
496
497impl PartialEq<DataValue> for BTreeMap<String, DataValue> {
498    fn eq(&self, other: &DataValue) -> bool {
499        match other {
500            DataValue::Map(v) => v == self,
501            _ => false,
502        }
503    }
504}
505
506impl PartialEq<DataValue> for DateTime<FixedOffset> {
507    fn eq(&self, other: &DataValue) -> bool {
508        match other {
509            DataValue::Datetime(v) => v == self,
510            _ => false,
511        }
512    }
513}
514
515impl<'a> TryFrom<DataOperator<'a>> for DataValue {
516    type Error = StamError;
517
518    fn try_from(operator: DataOperator<'a>) -> Result<Self, Self::Error> {
519        match operator {
520            DataOperator::Null => Ok(Self::Null),
521            DataOperator::Equals(s) => Ok(Self::String(s.to_string())),
522            DataOperator::EqualsFloat(f) => Ok(Self::Float(f)),
523            DataOperator::EqualsInt(i) => Ok(Self::Int(i)),
524            DataOperator::True => Ok(Self::Bool(true)),
525            DataOperator::False => Ok(Self::Bool(false)),
526            DataOperator::ExactDatetime(v) => Ok(Self::Datetime(v)),
527            _ => Err(StamError::OtherError(
528                "Data operator can not be converted to a single DataValue",
529            )),
530        }
531    }
532}
533
534impl<'a> From<&'a DataValue> for DataOperator<'a> {
535    fn from(v: &'a DataValue) -> Self {
536        match v {
537            DataValue::Null => DataOperator::Null,
538            DataValue::String(s) => DataOperator::Equals(s.as_str().into()),
539            DataValue::Int(v) => DataOperator::EqualsInt(*v),
540            DataValue::Float(v) => DataOperator::EqualsFloat(*v),
541            DataValue::Bool(true) => DataOperator::True,
542            DataValue::Bool(false) => DataOperator::False,
543            DataValue::Datetime(v) => DataOperator::ExactDatetime(*v),
544            DataValue::List(_) => {
545                eprintln!("STAM warning: Automatic conversion from list values to operators is not supported!");
546                DataOperator::Null
547            }
548            DataValue::Map(_) => {
549                eprintln!("STAM warning: Automatic conversion from map values to operators is not supported!");
550                DataOperator::Null
551            }
552        }
553    }
554}
555
556impl<'a> From<&'a str> for DataOperator<'a> {
557    fn from(s: &'a str) -> Self {
558        DataOperator::Equals(s.into())
559    }
560}
561
562impl<'a> From<isize> for DataOperator<'a> {
563    fn from(v: isize) -> Self {
564        DataOperator::EqualsInt(v)
565    }
566}
567
568impl<'a> From<usize> for DataOperator<'a> {
569    fn from(v: usize) -> Self {
570        DataOperator::EqualsInt(v as isize)
571    }
572}
573
574impl<'a> From<f64> for DataOperator<'a> {
575    fn from(v: f64) -> Self {
576        DataOperator::EqualsFloat(v)
577    }
578}
579
580impl<'a> From<DateTime<FixedOffset>> for DataOperator<'a> {
581    fn from(v: DateTime<FixedOffset>) -> Self {
582        DataOperator::ExactDatetime(v)
583    }
584}
585
586impl<'a> From<bool> for DataOperator<'a> {
587    fn from(v: bool) -> Self {
588        if v {
589            DataOperator::True
590        } else {
591            DataOperator::False
592        }
593    }
594}
595
596impl<'a> DataOperator<'a> {
597    /// Turns the DataOperator to a string, compatible with STAMQL
598    pub fn to_string(&self) -> Result<String, StamError> {
599        match self {
600            DataOperator::Any => Ok(format!("= any")),
601            DataOperator::Null => Ok(format!("= null")),
602            DataOperator::True => Ok(format!("= true")),
603            DataOperator::False => Ok(format!("= false")),
604            DataOperator::Equals(s) => Ok(format!("= \"{}\"", s)),
605            DataOperator::Not(expr) => match expr.deref() {
606                DataOperator::Equals(..)
607                | DataOperator::EqualsInt(..)
608                | DataOperator::EqualsFloat(..)
609                | DataOperator::Any
610                | DataOperator::Null
611                | DataOperator::True
612                | DataOperator::False => Ok(format!("!{}", expr.to_string()?)),
613                _ => Err(StamError::QuerySyntaxError(
614                    format!(
615                        "There is no query syntax yet for this dataoperator expression: {:?}",
616                        self
617                    ),
618                    "DataOperator::to_string()",
619                )),
620            },
621            DataOperator::EqualsInt(n) => Ok(format!("= {}", n)),
622            DataOperator::EqualsFloat(n) => Ok(format!("= {}", n)),
623            DataOperator::GreaterThan(n) => Ok(format!("> {}", n)),
624            DataOperator::GreaterThanOrEqual(n) => Ok(format!(">= {}", n)),
625            DataOperator::LessThan(n) => Ok(format!("< {}", n)),
626            DataOperator::LessThanOrEqual(n) => Ok(format!("<= {}", n)),
627            DataOperator::GreaterThanFloat(n) => Ok(format!("> {}", n)),
628            DataOperator::GreaterThanOrEqualFloat(n) => Ok(format!(">= {}", n)),
629            DataOperator::LessThanOrEqualFloat(n) => Ok(format!("<= {}", n)),
630            DataOperator::LessThanFloat(n) => Ok(format!("< {}", n)),
631            DataOperator::ExactDatetime(d) => Ok(format!("= {}", d.to_rfc3339())),
632            DataOperator::AfterDatetime(d) => Ok(format!("> {}", d.to_rfc3339())),
633            DataOperator::AtOrAfterDatetime(d) => Ok(format!(">= {}", d.to_rfc3339())),
634            DataOperator::BeforeDatetime(d) => Ok(format!("< {}", d.to_rfc3339())),
635            DataOperator::AtOrBeforeDatetime(d) => Ok(format!("<= {}", d.to_rfc3339())),
636            DataOperator::HasElement(s) => Ok(format!("HAS {}", s)),
637            DataOperator::HasElementInt(n) => Ok(format!("HAS {}", n)),
638            DataOperator::HasElementFloat(n) => Ok(format!("HAS {}", n)),
639            DataOperator::GetKey(s, None) => Ok(format!(". {}", s)),
640            DataOperator::GetIndex(n, None) => Ok(format!(". {}", n)),
641            DataOperator::GetKey(s, Some(op)) => Ok(format!(". {} {}", s, &op.to_string()?)),
642            DataOperator::GetIndex(n, Some(op)) => Ok(format!(". {} {}", n, &op.to_string()?)),
643            _ => {
644                //And, Or //TODO: implement
645                Err(StamError::QuerySyntaxError(
646                    format!(
647                        "There is no query syntax yet for this dataoperator expression: {:?}",
648                        self
649                    ),
650                    "DataOperator::to_string()",
651                ))
652            }
653        }
654    }
655}