Skip to main content

tank_core/
value.rs

1use crate::{
2    AsValue, DynQuery, Expression, GenericSqlWriter, Result, TableRef, interval::Interval,
3};
4use anyhow::anyhow;
5use quote::{ToTokens, quote};
6use rust_decimal::Decimal;
7use serde_json::Value as JsonValue;
8use std::{
9    borrow::Cow,
10    collections::{HashMap, hash_map::DefaultHasher},
11    fmt::{self, Display},
12    hash::{Hash, Hasher},
13    mem::discriminant,
14};
15use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
16use uuid::Uuid;
17
18/// SQL value representation.
19///
20/// Variants correspond to database column types.
21#[derive(Default, Debug, Clone)]
22pub enum Value {
23    /// SQL NULL.
24    #[default]
25    Null,
26    /// Boolean value.
27    Boolean(Option<bool>),
28    /// 8-bit signed integer.
29    Int8(Option<i8>),
30    /// 16-bit signed integer.
31    Int16(Option<i16>),
32    /// 32-bit signed integer.
33    Int32(Option<i32>),
34    /// 64-bit signed integer.
35    Int64(Option<i64>),
36    /// 128-bit signed integer.
37    Int128(Option<i128>),
38    /// 8-bit unsigned integer.
39    UInt8(Option<u8>),
40    /// 16-bit unsigned integer.
41    UInt16(Option<u16>),
42    /// 32-bit unsigned integer.
43    UInt32(Option<u32>),
44    /// 64-bit unsigned integer.
45    UInt64(Option<u64>),
46    /// 128-bit unsigned integer.
47    UInt128(Option<u128>),
48    /// 32-bit floating point number.
49    Float32(Option<f32>),
50    /// 64-bit floating point number.
51    Float64(Option<f64>),
52    /// Decimal (value, precision, scale).
53    Decimal(Option<Decimal>, u8, u8),
54    /// Single character.
55    Char(Option<char>),
56    /// Variable-length character string.
57    Varchar(Option<Cow<'static, str>>),
58    /// Binary large object.
59    Blob(Option<Box<[u8]>>),
60    /// Date value (without time).
61    Date(Option<Date>),
62    /// Time value (without date).
63    Time(Option<Time>),
64    /// Timestamp (date and time).
65    Timestamp(Option<PrimitiveDateTime>),
66    /// Timestamp with time zone.
67    TimestampWithTimezone(Option<OffsetDateTime>),
68    /// Time interval.
69    Interval(Option<Interval>),
70    /// UUID (Universally Unique Identifier).
71    Uuid(Option<Uuid>),
72    /// Homogeneous array (values, inner type, length).
73    Array(Option<Box<[Value]>>, Box<Value>, u32),
74    /// Variable-length list (values, inner type).
75    List(Option<Vec<Value>>, Box<Value>),
76    /// Map (entries, key type, value type).
77    Map(Option<HashMap<Value, Value>>, Box<Value>, Box<Value>),
78    /// JSON value.
79    Json(Option<JsonValue>),
80    /// Named struct (fields, field types, type name).
81    Struct(Option<Vec<(String, Value)>>, Vec<(String, Value)>, TableRef),
82    /// Unknown type (usually used when no further information is available).
83    Unknown(Option<String>),
84}
85
86impl Value {
87    /// Checks if two values have the same type, ignoring their actual data.
88    pub fn same_type(&self, other: &Self) -> bool {
89        match (self, other) {
90            (Self::Decimal(.., l_width, l_scale), Self::Decimal(.., r_width, r_scale)) => {
91                (*l_width == 0 || *r_width == 0 || l_width == r_width)
92                    && (*l_scale == 0 || *r_scale == 0 || l_scale == r_scale)
93            }
94            (Self::Array(.., l_type, l_len), Self::Array(.., r_type, r_len)) => {
95                l_len == r_len && l_type.same_type(&r_type)
96            }
97            (Self::List(.., l), Self::List(.., r)) => l.same_type(r),
98            (Self::Map(.., l_key, l_value), Self::Map(.., r_key, r_value)) => {
99                l_key.same_type(r_key) && l_value.same_type(&r_value)
100            }
101            _ => discriminant(self) == discriminant(other),
102        }
103    }
104
105    /// Checks if the value is NULL.
106    pub fn is_null(&self) -> bool {
107        match self {
108            Value::Null
109            | Value::Boolean(None, ..)
110            | Value::Int8(None, ..)
111            | Value::Int16(None, ..)
112            | Value::Int32(None, ..)
113            | Value::Int64(None, ..)
114            | Value::Int128(None, ..)
115            | Value::UInt8(None, ..)
116            | Value::UInt16(None, ..)
117            | Value::UInt32(None, ..)
118            | Value::UInt64(None, ..)
119            | Value::UInt128(None, ..)
120            | Value::Float32(None, ..)
121            | Value::Float64(None, ..)
122            | Value::Decimal(None, ..)
123            | Value::Char(None, ..)
124            | Value::Varchar(None, ..)
125            | Value::Blob(None, ..)
126            | Value::Date(None, ..)
127            | Value::Time(None, ..)
128            | Value::Timestamp(None, ..)
129            | Value::TimestampWithTimezone(None, ..)
130            | Value::Interval(None, ..)
131            | Value::Uuid(None, ..)
132            | Value::Array(None, ..)
133            | Value::List(None, ..)
134            | Value::Map(None, ..)
135            | Value::Json(None, ..)
136            | Value::Json(Some(serde_json::Value::Null), ..)
137            | Value::Struct(None, ..)
138            | Value::Unknown(None, ..) => true,
139            _ => false,
140        }
141    }
142
143    /// Create a value retaining only the type information, with all data set to NULL.
144    pub fn as_null(&self) -> Value {
145        match self {
146            Value::Null => Value::Null,
147            Value::Boolean(..) => Value::Boolean(None),
148            Value::Int8(..) => Value::Int8(None),
149            Value::Int16(..) => Value::Int16(None),
150            Value::Int32(..) => Value::Int32(None),
151            Value::Int64(..) => Value::Int64(None),
152            Value::Int128(..) => Value::Int128(None),
153            Value::UInt8(..) => Value::UInt8(None),
154            Value::UInt16(..) => Value::UInt16(None),
155            Value::UInt32(..) => Value::UInt32(None),
156            Value::UInt64(..) => Value::UInt64(None),
157            Value::UInt128(..) => Value::UInt128(None),
158            Value::Float32(..) => Value::Float32(None),
159            Value::Float64(..) => Value::Float64(None),
160            Value::Decimal(.., w, s) => Value::Decimal(None, *w, *s),
161            Value::Char(..) => Value::Char(None),
162            Value::Varchar(..) => Value::Varchar(None),
163            Value::Blob(..) => Value::Blob(None),
164            Value::Date(..) => Value::Date(None),
165            Value::Time(..) => Value::Time(None),
166            Value::Timestamp(..) => Value::Timestamp(None),
167            Value::TimestampWithTimezone(..) => Value::TimestampWithTimezone(None),
168            Value::Interval(..) => Value::Interval(None),
169            Value::Uuid(..) => Value::Uuid(None),
170            Value::Array(.., t, len) => Value::Array(None, t.clone(), *len),
171            Value::List(.., t) => Value::List(None, t.clone()),
172            Value::Map(.., k, v) => Value::Map(None, k.clone(), v.clone()),
173            Value::Json(..) => Value::Json(None),
174            Value::Struct(.., ty, name) => Value::Struct(None, ty.clone(), name.clone()),
175            Value::Unknown(..) => Value::Unknown(None),
176        }
177    }
178
179    /// Attempts to convert the value to the type of another value, if they are compatible.
180    pub fn try_as(self, target_type: &Value) -> Result<Value> {
181        if self.same_type(target_type) {
182            return Ok(self);
183        }
184        match target_type {
185            Value::Boolean(..) => bool::try_from_value(self).map(AsValue::as_value),
186            Value::Int8(..) => i8::try_from_value(self).map(AsValue::as_value),
187            Value::Int16(..) => i16::try_from_value(self).map(AsValue::as_value),
188            Value::Int32(..) => i32::try_from_value(self).map(AsValue::as_value),
189            Value::Int64(..) => i64::try_from_value(self).map(AsValue::as_value),
190            Value::Int128(..) => i128::try_from_value(self).map(AsValue::as_value),
191            Value::UInt8(..) => u8::try_from_value(self).map(AsValue::as_value),
192            Value::UInt16(..) => u16::try_from_value(self).map(AsValue::as_value),
193            Value::UInt32(..) => u32::try_from_value(self).map(AsValue::as_value),
194            Value::UInt64(..) => u64::try_from_value(self).map(AsValue::as_value),
195            Value::UInt128(..) => u128::try_from_value(self).map(AsValue::as_value),
196            Value::Float32(..) => f32::try_from_value(self).map(AsValue::as_value),
197            Value::Float64(..) => f64::try_from_value(self).map(AsValue::as_value),
198            Value::Decimal(..) => Decimal::try_from_value(self).map(AsValue::as_value),
199            Value::Char(..) => char::try_from_value(self).map(AsValue::as_value),
200            Value::Varchar(..) => String::try_from_value(self).map(AsValue::as_value),
201            Value::Blob(..) => Box::<[u8]>::try_from_value(self).map(AsValue::as_value),
202            Value::Date(..) => Date::try_from_value(self).map(AsValue::as_value),
203            Value::Time(..) => Time::try_from_value(self).map(AsValue::as_value),
204            Value::Timestamp(..) => PrimitiveDateTime::try_from_value(self).map(AsValue::as_value),
205            Value::TimestampWithTimezone(..) => {
206                OffsetDateTime::try_from_value(self).map(AsValue::as_value)
207            }
208            Value::Interval(..) => Interval::try_from_value(self).map(AsValue::as_value),
209            Value::Uuid(..) => Uuid::try_from_value(self).map(AsValue::as_value),
210            // Value::Array(.., ty, len) => {
211            //     Box::<[Value]>::try_from_value(self).map(AsValue::as_value)
212            // }
213            // Value::List(..) => Box::<[Value]>::try_from_value(self).map(AsValue::as_value),
214            // Value::Map(..) => Date::try_from_value(self).map(AsValue::as_value),
215            _ => {
216                return Err(anyhow!(
217                    "Cannot convert value {:?} to {:?}",
218                    self,
219                    target_type
220                ));
221            }
222        }
223    }
224
225    /// Checks if the value is a scalar type (not an array, struct, etc.).
226    pub fn is_scalar(&self) -> bool {
227        match self {
228            Value::Boolean(..)
229            | Value::Int8(..)
230            | Value::Int16(..)
231            | Value::Int32(..)
232            | Value::Int64(..)
233            | Value::Int128(..)
234            | Value::UInt8(..)
235            | Value::UInt16(..)
236            | Value::UInt32(..)
237            | Value::UInt64(..)
238            | Value::UInt128(..)
239            | Value::Float32(..)
240            | Value::Float64(..)
241            | Value::Decimal(..)
242            | Value::Char(..)
243            | Value::Varchar(..)
244            | Value::Blob(..)
245            | Value::Date(..)
246            | Value::Time(..)
247            | Value::Timestamp(..)
248            | Value::TimestampWithTimezone(..)
249            | Value::Interval(..)
250            | Value::Uuid(..)
251            | Value::Unknown(..) => true,
252            _ => false,
253        }
254    }
255}
256
257impl PartialEq for Value {
258    fn eq(&self, other: &Self) -> bool {
259        match (self, other) {
260            (Self::Null, Self::Null) => true,
261            (Self::Boolean(l), Self::Boolean(r)) => l == r,
262            (Self::Int8(l), Self::Int8(r)) => l == r,
263            (Self::Int16(l), Self::Int16(r)) => l == r,
264            (Self::Int32(l), Self::Int32(r)) => l == r,
265            (Self::Int64(l), Self::Int64(r)) => l == r,
266            (Self::Int128(l), Self::Int128(r)) => l == r,
267            (Self::UInt8(l), Self::UInt8(r)) => l == r,
268            (Self::UInt16(l), Self::UInt16(r)) => l == r,
269            (Self::UInt32(l), Self::UInt32(r)) => l == r,
270            (Self::UInt64(l), Self::UInt64(r)) => l == r,
271            (Self::UInt128(l), Self::UInt128(r)) => l == r,
272            (Self::Float32(l), Self::Float32(r)) => {
273                l == r
274                    || l.and_then(|l| r.and_then(|r| Some(l.is_nan() && r.is_nan())))
275                        .unwrap_or_default()
276            }
277            (Self::Float64(l), Self::Float64(r)) => {
278                l == r
279                    || l.and_then(|l| r.and_then(|r| Some(l.is_nan() && r.is_nan())))
280                        .unwrap_or_default()
281            }
282            (Self::Decimal(l, l_width, l_scale), Self::Decimal(r, r_width, r_scale)) => {
283                l == r && l_width == r_width && l_scale == r_scale
284            }
285            (Self::Char(l), Self::Char(r)) => l == r,
286            (Self::Varchar(l), Self::Varchar(r)) => l == r,
287            (Self::Blob(l), Self::Blob(r)) => l == r,
288            (Self::Date(l), Self::Date(r)) => l == r,
289            (Self::Time(l), Self::Time(r)) => l == r,
290            (Self::Timestamp(l), Self::Timestamp(r)) => l == r,
291            (Self::TimestampWithTimezone(l), Self::TimestampWithTimezone(r)) => l == r,
292            (Self::Interval(l), Self::Interval(r)) => l == r,
293            (Self::Uuid(l), Self::Uuid(r)) => l == r,
294            (Self::Array(l, l_ty, l_len), Self::Array(r, r_ty, r_len)) => {
295                l_len == r_len && l_ty == r_ty && l == r
296            }
297            (Self::List(l, l_ty), Self::List(r, r_ty)) => l_ty == r_ty && l == r,
298            (Self::Map(None, l_k, l_v), Self::Map(None, r_k, r_v)) => l_k == r_k && l_v == r_v,
299            (Self::Map(Some(l), l_k, l_v), Self::Map(Some(r), r_k, r_v)) => {
300                l_k == r_k && l_v == r_v && l == r
301            }
302            (Self::Map(..), Self::Map(..)) => false,
303            (Self::Json(l), Self::Json(r)) => l == r,
304            (Self::Struct(l, l_ty, l_name), Self::Struct(r, r_ty, r_name)) => {
305                l_name == r_name && l == r && l_ty == r_ty
306            }
307            (Self::Unknown(l), Self::Unknown(r)) => l == r,
308            _ => false,
309        }
310    }
311}
312
313impl Eq for Value {}
314
315fn hash_f32_value<H: std::hash::Hasher>(value: f32, state: &mut H) {
316    let bits = if value == 0.0 {
317        0.0f32.to_bits()
318    } else if value.is_nan() {
319        f32::NAN.to_bits()
320    } else {
321        value.to_bits()
322    };
323    bits.hash(state);
324}
325
326fn hash_f64_value<H: std::hash::Hasher>(value: f64, state: &mut H) {
327    let bits = if value == 0.0 {
328        0.0f64.to_bits()
329    } else if value.is_nan() {
330        f64::NAN.to_bits()
331    } else {
332        value.to_bits()
333    };
334    bits.hash(state);
335}
336
337fn hash_map_value<H: std::hash::Hasher>(
338    value: &Option<HashMap<Value, Value>>,
339    key_ty: &Value,
340    value_ty: &Value,
341    state: &mut H,
342) {
343    value.is_some().hash(state);
344    if let Some(map) = value {
345        let mut entry_hashes = map
346            .iter()
347            .map(|(key, value)| {
348                let mut hasher = DefaultHasher::new();
349                key.hash(&mut hasher);
350                value.hash(&mut hasher);
351                hasher.finish()
352            })
353            .collect::<Vec<_>>();
354        entry_hashes.sort_unstable();
355        entry_hashes.hash(state);
356    }
357    key_ty.hash(state);
358    value_ty.hash(state);
359}
360
361impl Hash for Value {
362    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
363        use Value::*;
364        discriminant(self).hash(state);
365        match self {
366            Null => {}
367            Boolean(v) => v.hash(state),
368            Int8(v) => v.hash(state),
369            Int16(v) => v.hash(state),
370            Int32(v) => v.hash(state),
371            Int64(v) => v.hash(state),
372            Int128(v) => v.hash(state),
373
374            UInt8(v) => v.hash(state),
375            UInt16(v) => v.hash(state),
376            UInt32(v) => v.hash(state),
377            UInt64(v) => v.hash(state),
378            UInt128(v) => v.hash(state),
379            Float32(Some(v)) => hash_f32_value(*v, state),
380            Float32(None) => None::<u32>.hash(state),
381            Float64(Some(v)) => hash_f64_value(*v, state),
382            Float64(None) => None::<u64>.hash(state),
383            Decimal(v, width, scale) => {
384                v.hash(state);
385                width.hash(state);
386                scale.hash(state);
387            }
388            Char(v) => v.hash(state),
389            Varchar(v) => v.hash(state),
390            Blob(v) => v.hash(state),
391            Date(v) => v.hash(state),
392            Time(v) => v.hash(state),
393            Timestamp(v) => v.hash(state),
394            TimestampWithTimezone(v) => v.hash(state),
395            Interval(v) => v.hash(state),
396            Uuid(v) => v.hash(state),
397            Array(v, typ, len) => {
398                v.hash(state);
399                typ.hash(state);
400                len.hash(state);
401            }
402            List(v, typ) => {
403                v.hash(state);
404                typ.hash(state);
405            }
406            Map(v, key, val) => hash_map_value(v, key, val, state),
407            Json(v) => v.hash(state),
408            Struct(v, t, name) => {
409                match v {
410                    Some(v) => v.hash(state),
411                    None => {}
412                }
413                t.hash(state);
414                name.hash(state);
415            }
416            Unknown(v) => v.hash(state),
417        }
418    }
419}
420
421impl Display for Value {
422    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
423        let mut out = DynQuery::default();
424        self.write_query(&GenericSqlWriter::new(), &mut Default::default(), &mut out);
425        let _ = f.write_str(out.buffer());
426        Ok(())
427    }
428}
429
430/// Internally decoded type info for macros.
431#[derive(Default)]
432pub struct TypeDecoded {
433    /// Representative value establishing variant & metadata.
434    pub value: Value,
435    /// Nullability indicator.
436    pub nullable: bool,
437}
438
439impl ToTokens for Value {
440    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
441        let ts = match self {
442            Value::Null => quote!(::tank::Value::Null),
443            Value::Boolean(..) => quote!(::tank::Value::Boolean(None)),
444            Value::Int8(..) => quote!(::tank::Value::Int8(None)),
445            Value::Int16(..) => quote!(::tank::Value::Int16(None)),
446            Value::Int32(..) => quote!(::tank::Value::Int32(None)),
447            Value::Int64(..) => quote!(::tank::Value::Int64(None)),
448            Value::Int128(..) => quote!(::tank::Value::Int128(None)),
449            Value::UInt8(..) => quote!(::tank::Value::UInt8(None)),
450            Value::UInt16(..) => quote!(::tank::Value::UInt16(None)),
451            Value::UInt32(..) => quote!(::tank::Value::UInt32(None)),
452            Value::UInt64(..) => quote!(::tank::Value::UInt64(None)),
453            Value::UInt128(..) => quote!(::tank::Value::UInt128(None)),
454            Value::Float32(..) => quote!(::tank::Value::Float32(None)),
455            Value::Float64(..) => quote!(::tank::Value::Float64(None)),
456            Value::Decimal(.., width, scale) => {
457                quote!(::tank::Value::Decimal(None, #width, #scale))
458            }
459            Value::Char(..) => quote!(::tank::Value::Char(None)),
460            Value::Varchar(..) => quote!(::tank::Value::Varchar(None)),
461            Value::Blob(..) => quote!(::tank::Value::Blob(None)),
462            Value::Date(..) => quote!(::tank::Value::Date(None)),
463            Value::Time(..) => quote!(::tank::Value::Time(None)),
464            Value::Timestamp(..) => quote!(::tank::Value::Timestamp(None)),
465            Value::TimestampWithTimezone(..) => quote!(::tank::Value::TimestampWithTimezone(None)),
466            Value::Interval(..) => quote!(::tank::Value::Interval(None)),
467            Value::Uuid(..) => quote!(::tank::Value::Uuid(None)),
468            Value::Array(.., inner, size) => {
469                quote!(::tank::Value::Array(None, Box::new(#inner), #size))
470            }
471            Value::List(.., inner) => {
472                let inner = inner.as_ref().to_token_stream();
473                quote!(::tank::Value::List(None, Box::new(#inner)))
474            }
475            Value::Map(.., key, value) => {
476                let key = key.as_ref().to_token_stream();
477                let value = value.as_ref().to_token_stream();
478                quote!(::tank::Value::Map(None, Box::new(#key), Box::new(#value)))
479            }
480            Value::Json(..) => quote!(::tank::Value::Json(None)),
481            Value::Struct(.., ty, name) => {
482                let values = ty.into_iter().map(|(k, v)| quote!((#k.into(), #v)));
483                quote!(::tank::Value::Struct(None, vec!(#(#values),*), #name))
484            }
485            Value::Unknown(..) => quote!(::tank::Value::Unknown(None)),
486        };
487        tokens.extend(ts);
488    }
489}