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