Skip to main content

tank_core/
value.rs

1use crate::{
2    AsValue, DynQuery, Error, Expression, GenericSqlWriter, Result, TableRef, interval::Interval,
3};
4use proc_macro2::TokenStream;
5use quote::{ToTokens, quote};
6use rust_decimal::Decimal;
7use serde_json::Value as JsonValue;
8use std::{
9    borrow::Cow,
10    collections::HashMap,
11    fmt::{self, Display},
12    hash::Hash,
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(Option<bool>),
27    Int8(Option<i8>),
28    Int16(Option<i16>),
29    Int32(Option<i32>),
30    Int64(Option<i64>),
31    Int128(Option<i128>),
32    UInt8(Option<u8>),
33    UInt16(Option<u16>),
34    UInt32(Option<u32>),
35    UInt64(Option<u64>),
36    UInt128(Option<u128>),
37    Float32(Option<f32>),
38    Float64(Option<f64>),
39    /// Decimal (value, precision, scale).
40    Decimal(Option<Decimal>, u8, u8),
41    Char(Option<char>),
42    Varchar(Option<Cow<'static, str>>),
43    Blob(Option<Box<[u8]>>),
44    Date(Option<Date>),
45    Time(Option<Time>),
46    Timestamp(Option<PrimitiveDateTime>),
47    TimestampWithTimezone(Option<OffsetDateTime>),
48    Interval(Option<Interval>),
49    Uuid(Option<Uuid>),
50    /// Homogeneous array (values, inner type, length).
51    Array(Option<Box<[Value]>>, Box<Value>, u32),
52    /// Variable-length list (values, inner type).
53    List(Option<Vec<Value>>, Box<Value>),
54    /// Map (entries, key type, value type).
55    Map(Option<HashMap<Value, Value>>, Box<Value>, Box<Value>),
56    Json(Option<JsonValue>),
57    /// Named struct (fields, field types, type name).
58    Struct(Option<Vec<(String, Value)>>, Vec<(String, Value)>, TableRef),
59    /// Unknown type (usually used when no further information is available).
60    Unknown(Option<String>),
61}
62
63impl Value {
64    pub fn same_type(&self, other: &Self) -> bool {
65        match (self, other) {
66            (Self::Decimal(.., l_width, l_scale), Self::Decimal(.., r_width, r_scale)) => {
67                (*l_width == 0 || *r_width == 0 || l_width == r_width)
68                    && (*l_scale == 0 || *r_scale == 0 || l_scale == r_scale)
69            }
70            (Self::Array(.., l_type, l_len), Self::Array(.., r_type, r_len)) => {
71                l_len == r_len && l_type.same_type(&r_type)
72            }
73            (Self::List(.., l), Self::List(.., r)) => l.same_type(r),
74            (Self::Map(.., l_key, l_value), Self::Map(.., r_key, r_value)) => {
75                l_key.same_type(r_key) && l_value.same_type(&r_value)
76            }
77            _ => discriminant(self) == discriminant(other),
78        }
79    }
80
81    pub fn is_null(&self) -> bool {
82        match self {
83            Value::Null
84            | Value::Boolean(None, ..)
85            | Value::Int8(None, ..)
86            | Value::Int16(None, ..)
87            | Value::Int32(None, ..)
88            | Value::Int64(None, ..)
89            | Value::Int128(None, ..)
90            | Value::UInt8(None, ..)
91            | Value::UInt16(None, ..)
92            | Value::UInt32(None, ..)
93            | Value::UInt64(None, ..)
94            | Value::UInt128(None, ..)
95            | Value::Float32(None, ..)
96            | Value::Float64(None, ..)
97            | Value::Decimal(None, ..)
98            | Value::Char(None, ..)
99            | Value::Varchar(None, ..)
100            | Value::Blob(None, ..)
101            | Value::Date(None, ..)
102            | Value::Time(None, ..)
103            | Value::Timestamp(None, ..)
104            | Value::TimestampWithTimezone(None, ..)
105            | Value::Interval(None, ..)
106            | Value::Uuid(None, ..)
107            | Value::Array(None, ..)
108            | Value::List(None, ..)
109            | Value::Map(None, ..)
110            | Value::Json(None, ..)
111            | Value::Json(Some(serde_json::Value::Null), ..)
112            | Value::Struct(None, ..)
113            | Value::Unknown(None, ..) => true,
114            _ => false,
115        }
116    }
117
118    pub fn as_null(&self) -> Value {
119        match self {
120            Value::Null => Value::Null,
121            Value::Boolean(..) => Value::Boolean(None),
122            Value::Int8(..) => Value::Int8(None),
123            Value::Int16(..) => Value::Int16(None),
124            Value::Int32(..) => Value::Int32(None),
125            Value::Int64(..) => Value::Int64(None),
126            Value::Int128(..) => Value::Int128(None),
127            Value::UInt8(..) => Value::UInt8(None),
128            Value::UInt16(..) => Value::UInt16(None),
129            Value::UInt32(..) => Value::UInt32(None),
130            Value::UInt64(..) => Value::UInt64(None),
131            Value::UInt128(..) => Value::UInt128(None),
132            Value::Float32(..) => Value::Float32(None),
133            Value::Float64(..) => Value::Float64(None),
134            Value::Decimal(.., w, s) => Value::Decimal(None, *w, *s),
135            Value::Char(..) => Value::Char(None),
136            Value::Varchar(..) => Value::Varchar(None),
137            Value::Blob(..) => Value::Blob(None),
138            Value::Date(..) => Value::Date(None),
139            Value::Time(..) => Value::Time(None),
140            Value::Timestamp(..) => Value::Timestamp(None),
141            Value::TimestampWithTimezone(..) => Value::TimestampWithTimezone(None),
142            Value::Interval(..) => Value::Interval(None),
143            Value::Uuid(..) => Value::Uuid(None),
144            Value::Array(.., t, len) => Value::Array(None, t.clone(), *len),
145            Value::List(.., t) => Value::List(None, t.clone()),
146            Value::Map(.., k, v) => Value::Map(None, k.clone(), v.clone()),
147            Value::Json(..) => Value::Json(None),
148            Value::Struct(.., ty, name) => Value::Struct(None, ty.clone(), name.clone()),
149            Value::Unknown(..) => Value::Unknown(None),
150        }
151    }
152
153    pub fn try_as(self, value: &Value) -> Result<Value> {
154        if self.same_type(value) {
155            return Ok(self);
156        }
157        match value {
158            Value::Boolean(..) => bool::try_from_value(self).map(AsValue::as_value),
159            Value::Int8(..) => i8::try_from_value(self).map(AsValue::as_value),
160            Value::Int16(..) => i16::try_from_value(self).map(AsValue::as_value),
161            Value::Int32(..) => i32::try_from_value(self).map(AsValue::as_value),
162            Value::Int64(..) => i64::try_from_value(self).map(AsValue::as_value),
163            Value::Int128(..) => i128::try_from_value(self).map(AsValue::as_value),
164            Value::UInt8(..) => u8::try_from_value(self).map(AsValue::as_value),
165            Value::UInt16(..) => u16::try_from_value(self).map(AsValue::as_value),
166            Value::UInt32(..) => u32::try_from_value(self).map(AsValue::as_value),
167            Value::UInt64(..) => u64::try_from_value(self).map(AsValue::as_value),
168            Value::UInt128(..) => u128::try_from_value(self).map(AsValue::as_value),
169            Value::Float32(..) => f32::try_from_value(self).map(AsValue::as_value),
170            Value::Float64(..) => f64::try_from_value(self).map(AsValue::as_value),
171            Value::Decimal(..) => Decimal::try_from_value(self).map(AsValue::as_value),
172            Value::Char(..) => char::try_from_value(self).map(AsValue::as_value),
173            Value::Varchar(..) => String::try_from_value(self).map(AsValue::as_value),
174            Value::Blob(..) => Box::<[u8]>::try_from_value(self).map(AsValue::as_value),
175            Value::Date(..) => Date::try_from_value(self).map(AsValue::as_value),
176            Value::Time(..) => Time::try_from_value(self).map(AsValue::as_value),
177            Value::Timestamp(..) => PrimitiveDateTime::try_from_value(self).map(AsValue::as_value),
178            Value::TimestampWithTimezone(..) => {
179                OffsetDateTime::try_from_value(self).map(AsValue::as_value)
180            }
181            Value::Interval(..) => Interval::try_from_value(self).map(AsValue::as_value),
182            Value::Uuid(..) => Uuid::try_from_value(self).map(AsValue::as_value),
183            // Value::Array(.., ty, len) => {
184            //     Box::<[Value]>::try_from_value(self).map(AsValue::as_value)
185            // }
186            // Value::List(..) => Box::<[Value]>::try_from_value(self).map(AsValue::as_value),
187            // Value::Map(..) => Date::try_from_value(self).map(AsValue::as_value),
188            _ => {
189                return Err(Error::msg(format!(
190                    "Cannot convert value {:?} into value {:?}",
191                    self, value
192                )));
193            }
194        }
195    }
196
197    pub fn is_scalar(&self) -> bool {
198        match self {
199            Value::Boolean(..)
200            | Value::Int8(..)
201            | Value::Int16(..)
202            | Value::Int32(..)
203            | Value::Int64(..)
204            | Value::Int128(..)
205            | Value::UInt8(..)
206            | Value::UInt16(..)
207            | Value::UInt32(..)
208            | Value::UInt64(..)
209            | Value::UInt128(..)
210            | Value::Float32(..)
211            | Value::Float64(..)
212            | Value::Decimal(..)
213            | Value::Char(..)
214            | Value::Varchar(..)
215            | Value::Blob(..)
216            | Value::Date(..)
217            | Value::Time(..)
218            | Value::Timestamp(..)
219            | Value::TimestampWithTimezone(..)
220            | Value::Interval(..)
221            | Value::Uuid(..)
222            | Value::Unknown(..) => true,
223            _ => false,
224        }
225    }
226}
227
228impl PartialEq for Value {
229    fn eq(&self, other: &Self) -> bool {
230        match (self, other) {
231            (Self::Boolean(l), Self::Boolean(r)) => l == r,
232            (Self::Int8(l), Self::Int8(r)) => l == r,
233            (Self::Int16(l), Self::Int16(r)) => l == r,
234            (Self::Int32(l), Self::Int32(r)) => l == r,
235            (Self::Int64(l), Self::Int64(r)) => l == r,
236            (Self::Int128(l), Self::Int128(r)) => l == r,
237            (Self::UInt8(l), Self::UInt8(r)) => l == r,
238            (Self::UInt16(l), Self::UInt16(r)) => l == r,
239            (Self::UInt32(l), Self::UInt32(r)) => l == r,
240            (Self::UInt64(l), Self::UInt64(r)) => l == r,
241            (Self::UInt128(l), Self::UInt128(r)) => l == r,
242            (Self::Float32(l), Self::Float32(r)) => {
243                l == r
244                    || l.and_then(|l| r.and_then(|r| Some(l.is_nan() && r.is_nan())))
245                        .unwrap_or_default()
246            }
247            (Self::Float64(l), Self::Float64(r)) => {
248                l == r
249                    || l.and_then(|l| r.and_then(|r| Some(l.is_nan() && r.is_nan())))
250                        .unwrap_or_default()
251            }
252            (Self::Decimal(l, l_width, l_scale), Self::Decimal(r, r_width, r_scale)) => {
253                l == r && l_width == r_width && l_scale == r_scale
254            }
255            (Self::Char(l), Self::Char(r)) => l == r,
256            (Self::Varchar(l), Self::Varchar(r)) => l == r,
257            (Self::Blob(l), Self::Blob(r)) => l == r,
258            (Self::Date(l), Self::Date(r)) => l == r,
259            (Self::Time(l), Self::Time(r)) => l == r,
260            (Self::Timestamp(l), Self::Timestamp(r)) => l == r,
261            (Self::TimestampWithTimezone(l), Self::TimestampWithTimezone(r)) => l == r,
262            (Self::Interval(l), Self::Interval(r)) => l == r,
263            (Self::Uuid(l), Self::Uuid(r)) => l == r,
264            (Self::Array(l, ..), Self::Array(r, ..)) => l == r && self.same_type(other),
265            (Self::List(l, ..), Self::List(r, ..)) => l == r && self.same_type(other),
266            (Self::Map(None, ..), Self::Map(None, ..)) => self.same_type(other),
267            (Self::Map(Some(l), ..), Self::Map(Some(r), ..)) => {
268                l.is_empty() == r.is_empty() && self.same_type(other)
269            }
270            (Self::Map(..), Self::Map(..)) => self.same_type(other),
271            (Self::Json(l), Self::Json(r)) => l == r,
272            (Self::Struct(l, l_ty, l_name), Self::Struct(r, r_ty, r_name)) => {
273                l_name == r_name && l == r && l_ty == r_ty
274            }
275            (Self::Unknown(..), Self::Unknown(..)) => false,
276            _ => false,
277        }
278    }
279}
280
281impl Eq for Value {}
282
283impl Hash for Value {
284    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
285        use Value::*;
286        discriminant(self).hash(state);
287        match self {
288            Null => {}
289            Boolean(v) => v.hash(state),
290            Int8(v) => v.hash(state),
291            Int16(v) => v.hash(state),
292            Int32(v) => v.hash(state),
293            Int64(v) => v.hash(state),
294            Int128(v) => v.hash(state),
295
296            UInt8(v) => v.hash(state),
297            UInt16(v) => v.hash(state),
298            UInt32(v) => v.hash(state),
299            UInt64(v) => v.hash(state),
300            UInt128(v) => v.hash(state),
301            Float32(Some(v)) => {
302                v.to_bits().hash(state);
303            }
304            Float32(None) => None::<u32>.hash(state),
305            Float64(Some(v)) => {
306                v.to_bits().hash(state);
307            }
308            Float64(None) => None::<u64>.hash(state),
309            Decimal(v, width, scale) => {
310                v.hash(state);
311                width.hash(state);
312                scale.hash(state);
313            }
314            Char(v) => v.hash(state),
315            Varchar(v) => v.hash(state),
316            Blob(v) => v.hash(state),
317            Date(v) => v.hash(state),
318            Time(v) => v.hash(state),
319            Timestamp(v) => v.hash(state),
320            TimestampWithTimezone(v) => v.hash(state),
321            Interval(v) => v.hash(state),
322            Uuid(v) => v.hash(state),
323            Array(v, typ, len) => {
324                v.hash(state);
325                typ.hash(state);
326                len.hash(state);
327            }
328            List(v, typ) => {
329                v.hash(state);
330                typ.hash(state);
331            }
332            Map(v, key, val) => {
333                match v {
334                    Some(map) => {
335                        for (key, val) in map {
336                            key.hash(state);
337                            val.hash(state);
338                        }
339                    }
340                    None => {}
341                }
342                key.hash(state);
343                val.hash(state);
344            }
345            Json(v) => v.hash(state),
346            Struct(v, t, name) => {
347                match v {
348                    Some(v) => v.hash(state),
349                    None => {}
350                }
351                t.hash(state);
352                name.hash(state);
353            }
354            Unknown(v) => v.hash(state),
355        }
356    }
357}
358
359impl Display for Value {
360    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361        let mut out = DynQuery::default();
362        self.write_query(&GenericSqlWriter::new(), &mut Default::default(), &mut out);
363        let _ = f.write_str(out.buffer());
364        Ok(())
365    }
366}
367
368/// Internally decoded type info for macros.
369#[derive(Default)]
370pub struct TypeDecoded {
371    /// Representative value establishing variant & metadata.
372    pub value: Value,
373    /// Nullability indicator.
374    pub nullable: bool,
375    /// Passive flag (exclude from INSERT column/value list).
376    pub passive: bool,
377}
378
379pub type CheckPassive = Box<dyn Fn(TokenStream) -> TokenStream>;
380
381impl ToTokens for Value {
382    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
383        let ts = match self {
384            Value::Null => quote!(::tank::Value::Null),
385            Value::Boolean(..) => quote!(::tank::Value::Boolean(None)),
386            Value::Int8(..) => quote!(::tank::Value::Int8(None)),
387            Value::Int16(..) => quote!(::tank::Value::Int16(None)),
388            Value::Int32(..) => quote!(::tank::Value::Int32(None)),
389            Value::Int64(..) => quote!(::tank::Value::Int64(None)),
390            Value::Int128(..) => quote!(::tank::Value::Int128(None)),
391            Value::UInt8(..) => quote!(::tank::Value::UInt8(None)),
392            Value::UInt16(..) => quote!(::tank::Value::UInt16(None)),
393            Value::UInt32(..) => quote!(::tank::Value::UInt32(None)),
394            Value::UInt64(..) => quote!(::tank::Value::UInt64(None)),
395            Value::UInt128(..) => quote!(::tank::Value::UInt128(None)),
396            Value::Float32(..) => quote!(::tank::Value::Float32(None)),
397            Value::Float64(..) => quote!(::tank::Value::Float64(None)),
398            Value::Decimal(.., width, scale) => {
399                quote!(::tank::Value::Decimal(None, #width, #scale))
400            }
401            Value::Char(..) => quote!(tank::Value::Char(None)),
402            Value::Varchar(..) => quote!(::tank::Value::Varchar(None)),
403            Value::Blob(..) => quote!(::tank::Value::Blob(None)),
404            Value::Date(..) => quote!(::tank::Value::Date(None)),
405            Value::Time(..) => quote!(::tank::Value::Time(None)),
406            Value::Timestamp(..) => quote!(::tank::Value::Timestamp(None)),
407            Value::TimestampWithTimezone(..) => quote!(::tank::Value::TimestampWithTimezone(None)),
408            Value::Interval(..) => quote!(::tank::Value::Interval(None)),
409            Value::Uuid(..) => quote!(::tank::Value::Uuid(None)),
410            Value::Array(.., inner, size) => {
411                quote!(::tank::Value::Array(None, Box::new(#inner), #size))
412            }
413            Value::List(.., inner) => {
414                let inner = inner.as_ref().to_token_stream();
415                quote!(::tank::Value::List(None, Box::new(#inner)))
416            }
417            Value::Map(.., key, value) => {
418                let key = key.as_ref().to_token_stream();
419                let value = value.as_ref().to_token_stream();
420                quote!(::tank::Value::Map(None, Box::new(#key), Box::new(#value)))
421            }
422            Value::Json(..) => quote!(::tank::Value::Json(None)),
423            Value::Struct(.., ty, name) => {
424                let values = ty.into_iter().map(|(k, v)| quote!((#k.into(), #v)));
425                quote!(::tank::Value::Struct(None, vec!(#(#values),*), #name))
426            }
427            Value::Unknown(..) => quote!(::tank::Value::Unknown(None)),
428        };
429        tokens.extend(ts);
430    }
431}