Skip to main content

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