partiql_value/
value.rs

1use ordered_float::OrderedFloat;
2use std::borrow::Cow;
3use std::fmt::{Debug, Display, Formatter};
4use std::hash::Hash;
5
6use rust_decimal::Decimal as RustDecimal;
7
8use crate::variant::Variant;
9use crate::{tuple, Bag, BindingIntoIter, BindingIter, DateTime, Graph, List, Tuple};
10use rust_decimal::prelude::FromPrimitive;
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14mod iter;
15mod logic;
16mod math;
17
18use crate::datum::{
19    Datum, DatumCategory, DatumCategoryOwned, DatumCategoryRef, DatumLower, DatumLowerResult,
20    DatumTupleOwned, DatumTupleRef, DatumValue,
21};
22pub use iter::*;
23pub use logic::*;
24pub use math::*;
25use partiql_common::pretty::ToPretty;
26use std::cmp::Ordering;
27
28#[derive(Hash, PartialEq, Eq, Clone, Default)]
29#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
30pub enum Value {
31    Null,
32    #[default]
33    Missing,
34    Boolean(bool),
35    Integer(i64),
36    Real(OrderedFloat<f64>),
37    Decimal(Box<RustDecimal>),
38    String(Box<String>),
39    Blob(Box<Vec<u8>>),
40    DateTime(Box<DateTime>),
41    List(Box<List>),
42    Bag(Box<Bag>),
43    Tuple(Box<Tuple>),
44    Graph(Box<Graph>),
45    Variant(Box<Variant>),
46}
47
48impl Value {
49    #[inline]
50    #[must_use]
51    pub fn is_tuple(&self) -> bool {
52        matches!(self, Value::Tuple(_))
53    }
54
55    #[inline]
56    #[must_use]
57    pub fn is_list(&self) -> bool {
58        matches!(self, Value::List(_))
59    }
60
61    #[inline]
62    #[must_use]
63    pub fn is_bag(&self) -> bool {
64        matches!(self, Value::Bag(_))
65    }
66
67    #[inline]
68    /// Returns true if and only if Value is an integer, real, or decimal
69    #[must_use]
70    pub fn is_number(&self) -> bool {
71        matches!(self, Value::Integer(_) | Value::Real(_) | Value::Decimal(_))
72    }
73
74    #[inline]
75    #[must_use]
76    pub fn coerce_into_tuple(self) -> Tuple {
77        let coerce = |non_tuple: Value| {
78            non_tuple
79                .into_bindings()
80                .map(|(k, v)| (k.unwrap_or_else(|| "_1".to_string()), v))
81                .collect()
82        };
83
84        match self {
85            Value::Tuple(t) => *t,
86            Value::Variant(ref v) => match v.category() {
87                DatumCategoryRef::Tuple(_) => self
88                    .into_lower()
89                    .expect("variant lower")
90                    .coerce_into_tuple(),
91                _ => coerce(self),
92            },
93            _ => coerce(self),
94        }
95    }
96
97    #[inline]
98    #[must_use]
99    pub fn coerce_to_tuple(&self) -> Tuple {
100        self.clone().coerce_into_tuple()
101    }
102
103    #[inline]
104    #[must_use]
105    pub fn as_datum_tuple_ref(&self) -> DatumTupleRef<'_> {
106        match self.category() {
107            DatumCategoryRef::Tuple(t) => t,
108            _ => DatumTupleRef::CoercedValue(1, self),
109        }
110    }
111
112    #[inline]
113    #[must_use]
114    pub fn as_tuple_ref(&self) -> Cow<'_, Tuple> {
115        match self.category() {
116            DatumCategoryRef::Tuple(t) => match t {
117                DatumTupleRef::Tuple(t) => Cow::Borrowed(t),
118                DatumTupleRef::Dynamic(_) => match self.lower().expect("variant lower") {
119                    Cow::Borrowed(Value::Tuple(t)) => Cow::Borrowed(t.as_ref()),
120                    Cow::Owned(Value::Tuple(t)) => Cow::Owned(*t),
121                    _ => unreachable!(),
122                },
123                DatumTupleRef::Empty => Cow::Owned(tuple![]),
124                DatumTupleRef::CoercedValue(_, v) => Cow::Owned(tuple![("_1", v.clone())]),
125                DatumTupleRef::SingleKey(k, v) => Cow::Owned(tuple![(k.as_ref(), v.clone())]),
126                DatumTupleRef::Bindings(map) => Cow::Owned(Tuple::from_iter(
127                    map.iter().map(|(k, &v)| (k.as_ref(), v.clone())),
128                )),
129            },
130            _ => Cow::Owned(self.coerce_to_tuple()),
131        }
132    }
133
134    #[inline]
135    #[must_use]
136    pub fn as_bindings(&self) -> BindingIter<'_> {
137        match self.category() {
138            DatumCategoryRef::Missing => BindingIter::Empty,
139            DatumCategoryRef::Tuple(t) => match t {
140                DatumTupleRef::Tuple(t) => BindingIter::Tuple(t.pairs()),
141                DatumTupleRef::Dynamic(_) => unreachable!(),
142                DatumTupleRef::Empty => BindingIter::Empty,
143                DatumTupleRef::CoercedValue(_, value) => {
144                    BindingIter::Single(std::iter::once(value))
145                }
146                DatumTupleRef::SingleKey(_, value) => BindingIter::Single(std::iter::once(value)),
147                DatumTupleRef::Bindings(map) => {
148                    let entries = map.iter().map(|(k, &v)| (Some(k.as_ref()), v));
149                    BindingIter::Dynamic(Box::new(entries))
150                }
151            },
152            _ => BindingIter::Single(std::iter::once(self)),
153        }
154    }
155
156    #[inline]
157    #[must_use]
158    pub fn into_bindings(self) -> BindingIntoIter {
159        match self {
160            Value::Tuple(t) => BindingIntoIter::Tuple(t.into_pairs()),
161            Value::Missing => BindingIntoIter::Empty,
162            Value::Variant(v) => match v.category() {
163                DatumCategoryRef::Missing => BindingIntoIter::Empty,
164                DatumCategoryRef::Tuple(_) => match v.into_category() {
165                    DatumCategoryOwned::Tuple(DatumTupleOwned::Tuple(t)) => {
166                        BindingIntoIter::Tuple(t.into_pairs())
167                    }
168                    DatumCategoryOwned::Tuple(DatumTupleOwned::Dynamic(d)) => {
169                        BindingIntoIter::DynTuple(d.into_iter_boxed())
170                    }
171                    _ => unreachable!(),
172                },
173                _ => BindingIntoIter::Single(std::iter::once(Value::Variant(v))),
174            },
175            _ => BindingIntoIter::Single(std::iter::once(self)),
176        }
177    }
178
179    #[inline]
180    #[must_use]
181    pub fn coerce_into_bag(self) -> Bag {
182        if let Value::Bag(b) = self {
183            *b
184        } else {
185            Bag::from(vec![self])
186        }
187    }
188
189    #[inline]
190    #[must_use]
191    pub fn as_bag_ref(&self) -> Cow<'_, Bag> {
192        if let Value::Bag(b) = self {
193            Cow::Borrowed(b)
194        } else {
195            Cow::Owned(self.clone().coerce_into_bag())
196        }
197    }
198
199    #[inline]
200    #[must_use]
201    pub fn coerce_into_list(self) -> List {
202        if let Value::List(b) = self {
203            *b
204        } else {
205            List::from(vec![self])
206        }
207    }
208
209    #[inline]
210    #[must_use]
211    pub fn as_list_ref(&self) -> Cow<'_, List> {
212        if let Value::List(l) = self {
213            Cow::Borrowed(l)
214        } else {
215            Cow::Owned(self.clone().coerce_into_list())
216        }
217    }
218
219    #[inline]
220    #[must_use]
221    pub fn iter(&self) -> ValueIter<'_> {
222        match self {
223            Value::Null | Value::Missing => ValueIter::Single(None),
224            Value::List(list) => ValueIter::List(list.iter()),
225            Value::Bag(bag) => ValueIter::Bag(bag.iter()),
226            other => ValueIter::Single(Some(other)),
227        }
228    }
229
230    #[inline]
231    #[must_use]
232    pub fn sequence_iter(&self) -> Option<ValueIter<'_>> {
233        if self.is_sequence() {
234            Some(self.iter())
235        } else {
236            None
237        }
238    }
239}
240
241impl DatumValue<Value> for Value {}
242
243impl DatumLower<Value> for Value {
244    fn into_lower(self) -> DatumLowerResult<Value> {
245        match self {
246            Value::Variant(variant) => variant.into_lower(),
247            _ => Ok(self),
248        }
249    }
250
251    fn into_lower_boxed(self: Box<Self>) -> DatumLowerResult<Value> {
252        self.into_lower()
253    }
254
255    fn lower(&self) -> DatumLowerResult<Cow<'_, Value>> {
256        match self {
257            Value::Variant(variant) => variant.lower(),
258            _ => Ok(Cow::Borrowed(self)),
259        }
260    }
261}
262
263impl Datum<Value> for Value {
264    #[inline]
265    fn is_null(&self) -> bool {
266        match self {
267            Value::Null => true,
268            Value::Variant(variant) => variant.is_null(),
269            _ => false,
270        }
271    }
272
273    #[inline]
274    fn is_missing(&self) -> bool {
275        match self {
276            Value::Missing => true,
277            Value::Variant(variant) => variant.is_missing(),
278            _ => false,
279        }
280    }
281
282    #[inline]
283    fn is_sequence(&self) -> bool {
284        match self {
285            Value::List(_) => true,
286            Value::Bag(_) => true,
287            Value::Variant(variant) => variant.is_sequence(),
288            _ => false,
289        }
290    }
291
292    #[inline]
293    fn is_ordered(&self) -> bool {
294        match self {
295            Value::List(_) => true,
296            Value::Variant(variant) => variant.is_ordered(),
297            _ => false,
298        }
299    }
300}
301
302impl Display for Value {
303    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
304        match self.to_pretty_string(f.width().unwrap_or(80)) {
305            Ok(pretty) => f.write_str(&pretty),
306            Err(_) => f.write_str("<internal value error occurred>"),
307        }
308    }
309}
310
311impl Debug for Value {
312    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
313        match self {
314            Value::Null => write!(f, "NULL"),
315            Value::Missing => write!(f, "MISSING"),
316            Value::Boolean(b) => write!(f, "{b}"),
317            Value::Integer(i) => write!(f, "{i}"),
318            Value::Real(r) => write!(f, "{}", r.0),
319            Value::Decimal(d) => write!(f, "{d}"),
320            Value::String(s) => write!(f, "'{s}'"),
321            Value::Blob(blob) => {
322                write!(f, "x'")?;
323                for byte in blob.as_ref() {
324                    f.write_str(&format!("{byte:02x}"))?;
325                }
326                write!(f, "'")
327            }
328            Value::DateTime(t) => Debug::fmt(&t, f),
329            Value::List(l) => Debug::fmt(&l, f),
330            Value::Bag(b) => Debug::fmt(&b, f),
331            Value::Tuple(t) => Debug::fmt(&t, f),
332            Value::Graph(g) => Debug::fmt(&g, f),
333            Value::Variant(v) => Debug::fmt(&v, f),
334        }
335    }
336}
337
338impl PartialOrd for Value {
339    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
340        Some(self.cmp(other))
341    }
342}
343
344/// Implementation of spec's `order-by less-than` assuming nulls first.
345/// TODO: more tests for Ord on Value
346impl Ord for Value {
347    fn cmp(&self, other: &Self) -> Ordering {
348        // **NOTE** The Order of these match arms defines the proper comparisons; Do not reorder
349        match (self, other) {
350            (Value::Null, Value::Null) => Ordering::Equal,
351            (Value::Missing, Value::Null) => Ordering::Equal,
352
353            (Value::Null, Value::Missing) => Ordering::Equal,
354            (Value::Null, _) => Ordering::Less,
355            (_, Value::Null) => Ordering::Greater,
356
357            (Value::Missing, Value::Missing) => Ordering::Equal,
358            (Value::Missing, _) => Ordering::Less,
359            (_, Value::Missing) => Ordering::Greater,
360
361            (Value::Boolean(l), Value::Boolean(r)) => match (l, r) {
362                (false, true) => Ordering::Less,
363                (true, false) => Ordering::Greater,
364                (_, _) => Ordering::Equal,
365            },
366            (Value::Boolean(_), _) => Ordering::Less,
367            (_, Value::Boolean(_)) => Ordering::Greater,
368
369            // TODO: `OrderedFloat`'s implementation of `Ord` slightly differs from what we want in
370            //  the PartiQL spec. See https://partiql.org/assets/PartiQL-Specification.pdf#subsection.12.2
371            //  point 3. In PartiQL, `nan`, comes before `-inf` which comes before all numeric
372            //  values, which are followed by `+inf`. `OrderedFloat` places `NaN` as greater than
373            //  all other `OrderedFloat` values. We could consider creating our own float type
374            //  to get around this annoyance.
375            (Value::Real(l), Value::Real(r)) => {
376                if l.is_nan() {
377                    if r.is_nan() {
378                        Ordering::Equal
379                    } else {
380                        Ordering::Less
381                    }
382                } else if r.is_nan() {
383                    Ordering::Greater
384                } else {
385                    l.cmp(r)
386                }
387            }
388            (Value::Integer(l), Value::Integer(r)) => l.cmp(r),
389            (Value::Decimal(l), Value::Decimal(r)) => l.cmp(r),
390            (Value::Integer(l), Value::Real(_)) => {
391                Value::Real(ordered_float::OrderedFloat(*l as f64)).cmp(other)
392            }
393            (Value::Real(_), Value::Integer(r)) => {
394                self.cmp(&Value::Real(ordered_float::OrderedFloat(*r as f64)))
395            }
396            (Value::Integer(l), Value::Decimal(r)) => RustDecimal::from(*l).cmp(r),
397            (Value::Decimal(l), Value::Integer(r)) => l.as_ref().cmp(&RustDecimal::from(*r)),
398            (Value::Real(l), Value::Decimal(r)) => {
399                if l.is_nan() || l.0 == f64::NEG_INFINITY {
400                    Ordering::Less
401                } else if l.0 == f64::INFINITY {
402                    Ordering::Greater
403                } else {
404                    match RustDecimal::from_f64(l.0) {
405                        Some(l_d) => l_d.cmp(r),
406                        None => todo!(
407                            "Decide default behavior when f64 can't be converted to RustDecimal"
408                        ),
409                    }
410                }
411            }
412            (Value::Decimal(l), Value::Real(r)) => {
413                if r.is_nan() || r.0 == f64::NEG_INFINITY {
414                    Ordering::Greater
415                } else if r.0 == f64::INFINITY {
416                    Ordering::Less
417                } else {
418                    match RustDecimal::from_f64(r.0) {
419                        Some(r_d) => l.as_ref().cmp(&r_d),
420                        None => todo!(
421                            "Decide default behavior when f64 can't be converted to RustDecimal"
422                        ),
423                    }
424                }
425            }
426            (Value::Integer(_), _) => Ordering::Less,
427            (Value::Real(_), _) => Ordering::Less,
428            (Value::Decimal(_), _) => Ordering::Less,
429            (_, Value::Integer(_)) => Ordering::Greater,
430            (_, Value::Real(_)) => Ordering::Greater,
431            (_, Value::Decimal(_)) => Ordering::Greater,
432
433            (Value::DateTime(l), Value::DateTime(r)) => l.cmp(r),
434            (Value::DateTime(_), _) => Ordering::Less,
435            (_, Value::DateTime(_)) => Ordering::Greater,
436
437            (Value::String(l), Value::String(r)) => l.cmp(r),
438            (Value::String(_), _) => Ordering::Less,
439            (_, Value::String(_)) => Ordering::Greater,
440
441            (Value::Blob(l), Value::Blob(r)) => l.cmp(r),
442            (Value::Blob(_), _) => Ordering::Less,
443            (_, Value::Blob(_)) => Ordering::Greater,
444
445            (Value::List(l), Value::List(r)) => l.cmp(r),
446            (Value::List(_), _) => Ordering::Less,
447            (_, Value::List(_)) => Ordering::Greater,
448
449            (Value::Tuple(l), Value::Tuple(r)) => l.cmp(r),
450            (Value::Tuple(_), _) => Ordering::Less,
451            (_, Value::Tuple(_)) => Ordering::Greater,
452
453            (Value::Bag(l), Value::Bag(r)) => l.cmp(r),
454            (Value::Bag(_), _) => Ordering::Less,
455            (_, Value::Bag(_)) => Ordering::Greater,
456
457            // TODO need to RFC graph comparison behavior
458            (Value::Graph(l), Value::Graph(r)) => l.cmp(r),
459            (Value::Graph(_), _) => Ordering::Less,
460            (_, Value::Graph(_)) => Ordering::Greater,
461
462            (Value::Variant(l), Value::Variant(r)) => l.cmp(r),
463        }
464    }
465}
466
467impl From<bool> for Value {
468    #[inline]
469    fn from(b: bool) -> Self {
470        Value::Boolean(b)
471    }
472}
473
474impl From<String> for Value {
475    #[inline]
476    fn from(s: String) -> Self {
477        Value::String(Box::new(s))
478    }
479}
480
481impl From<&str> for Value {
482    #[inline]
483    fn from(s: &str) -> Self {
484        Value::String(Box::new(s.to_string()))
485    }
486}
487
488impl From<i128> for Value {
489    #[inline]
490    fn from(n: i128) -> Self {
491        Value::from(RustDecimal::from(n))
492    }
493}
494
495impl From<i64> for Value {
496    #[inline]
497    fn from(n: i64) -> Self {
498        Value::Integer(n)
499    }
500}
501
502impl From<i32> for Value {
503    #[inline]
504    fn from(n: i32) -> Self {
505        i64::from(n).into()
506    }
507}
508
509impl From<i16> for Value {
510    #[inline]
511    fn from(n: i16) -> Self {
512        i64::from(n).into()
513    }
514}
515
516impl From<i8> for Value {
517    #[inline]
518    fn from(n: i8) -> Self {
519        i64::from(n).into()
520    }
521}
522
523impl From<usize> for Value {
524    #[inline]
525    fn from(n: usize) -> Self {
526        if n > i64::MAX as usize {
527            Value::from(RustDecimal::from(n))
528        } else {
529            Value::Integer(n as i64)
530        }
531    }
532}
533
534impl From<u8> for Value {
535    #[inline]
536    fn from(n: u8) -> Self {
537        (n as usize).into()
538    }
539}
540
541impl From<u16> for Value {
542    #[inline]
543    fn from(n: u16) -> Self {
544        (n as usize).into()
545    }
546}
547
548impl From<u32> for Value {
549    #[inline]
550    fn from(n: u32) -> Self {
551        (n as usize).into()
552    }
553}
554
555impl From<u64> for Value {
556    #[inline]
557    fn from(n: u64) -> Self {
558        (n as usize).into()
559    }
560}
561
562impl From<u128> for Value {
563    #[inline]
564    fn from(n: u128) -> Self {
565        Value::from(RustDecimal::from(n))
566    }
567}
568
569impl From<f64> for Value {
570    #[inline]
571    fn from(f: f64) -> Self {
572        Value::from(OrderedFloat(f))
573    }
574}
575
576impl From<OrderedFloat<f64>> for Value {
577    #[inline]
578    fn from(f: OrderedFloat<f64>) -> Self {
579        Value::Real(f)
580    }
581}
582
583impl From<RustDecimal> for Value {
584    #[inline]
585    fn from(d: RustDecimal) -> Self {
586        Value::Decimal(Box::new(d))
587    }
588}
589
590impl From<DateTime> for Value {
591    #[inline]
592    fn from(t: DateTime) -> Self {
593        Value::DateTime(Box::new(t))
594    }
595}
596
597impl From<List> for Value {
598    #[inline]
599    fn from(v: List) -> Self {
600        Value::List(Box::new(v))
601    }
602}
603
604impl From<Tuple> for Value {
605    #[inline]
606    fn from(v: Tuple) -> Self {
607        Value::Tuple(Box::new(v))
608    }
609}
610
611impl From<Bag> for Value {
612    #[inline]
613    fn from(v: Bag) -> Self {
614        Value::Bag(Box::new(v))
615    }
616}
617
618impl From<Graph> for Value {
619    #[inline]
620    fn from(g: Graph) -> Self {
621        Value::Graph(Box::new(g))
622    }
623}
624
625impl From<Variant> for Value {
626    #[inline]
627    fn from(v: Variant) -> Self {
628        Value::Variant(Box::new(v))
629    }
630}