sqlint/ast/
values.rs

1use crate::ast::*;
2use crate::error::{Error, ErrorKind};
3
4#[cfg(feature = "bigdecimal")]
5use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive};
6#[cfg(feature = "chrono")]
7use chrono::{DateTime, NaiveDate, NaiveTime, Utc};
8#[cfg(feature = "json")]
9use serde_json::{Number, Value as JsonValue};
10use std::{
11    borrow::{Borrow, Cow},
12    convert::TryFrom,
13    fmt,
14    str::FromStr,
15};
16#[cfg(feature = "uuid")]
17use uuid::Uuid;
18
19/// A value written to the query as-is without parameterization.
20#[derive(Debug, Clone, PartialEq)]
21pub struct Raw<'a>(pub(crate) Value<'a>);
22
23/// Converts the value into a state to skip parameterization.
24///
25/// Must be used carefully to avoid SQL injections.
26pub trait IntoRaw<'a> {
27    fn raw(self) -> Raw<'a>;
28}
29
30impl<'a, T> IntoRaw<'a> for T
31where
32    T: Into<Value<'a>>,
33{
34    fn raw(self) -> Raw<'a> {
35        Raw(self.into())
36    }
37}
38
39/// A value we must parameterize for the prepared statement. Null values should be
40/// defined by their corresponding type variants with a `None` value for best
41/// compatibility.
42#[derive(Debug, Clone, PartialEq)]
43pub enum Value<'a> {
44    /// 32-bit signed integer.
45    Int32(Option<i32>),
46    /// 64-bit signed integer.
47    Int64(Option<i64>),
48    /// 32-bit floating point.
49    Float(Option<f32>),
50    /// 64-bit floating point.
51    Double(Option<f64>),
52    /// String value.
53    Text(Option<Cow<'a, str>>),
54    /// Database enum value.
55    Enum(Option<Cow<'a, str>>),
56    /// Bytes value.
57    Bytes(Option<Cow<'a, [u8]>>),
58    /// Boolean value.
59    Boolean(Option<bool>),
60    /// A single character.
61    Char(Option<char>),
62    /// An array value (PostgreSQL).
63    Array(Option<Vec<Value<'a>>>),
64    /// A numeric value.
65    #[cfg(feature = "bigdecimal")]
66    #[cfg_attr(feature = "docs", doc(cfg(feature = "bigdecimal")))]
67    Numeric(Option<BigDecimal>),
68    #[cfg(feature = "json")]
69    #[cfg_attr(feature = "docs", doc(cfg(feature = "json")))]
70    /// A JSON value.
71    Json(Option<serde_json::Value>),
72    /// A XML value.
73    Xml(Option<Cow<'a, str>>),
74    #[cfg(feature = "uuid")]
75    #[cfg_attr(feature = "docs", doc(cfg(feature = "uuid")))]
76    /// An UUID value.
77    Uuid(Option<Uuid>),
78    #[cfg(feature = "chrono")]
79    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
80    /// A datetime value.
81    DateTime(Option<DateTime<Utc>>),
82    #[cfg(feature = "chrono")]
83    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
84    /// A date value.
85    Date(Option<NaiveDate>),
86    #[cfg(feature = "chrono")]
87    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
88    /// A time value.
89    Time(Option<NaiveTime>),
90}
91
92pub(crate) struct Params<'a>(pub(crate) &'a [Value<'a>]);
93
94impl<'a> fmt::Display for Params<'a> {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        let len = self.0.len();
97
98        write!(f, "[")?;
99        for (i, val) in self.0.iter().enumerate() {
100            write!(f, "{val}")?;
101
102            if i < (len - 1) {
103                write!(f, ",")?;
104            }
105        }
106        write!(f, "]")
107    }
108}
109
110impl<'a> fmt::Display for Value<'a> {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        let res = match self {
113            Value::Int32(val) => val.map(|v| write!(f, "{v}")),
114            Value::Int64(val) => val.map(|v| write!(f, "{v}")),
115            Value::Float(val) => val.map(|v| write!(f, "{v}")),
116            Value::Double(val) => val.map(|v| write!(f, "{v}")),
117            Value::Text(val) => val.as_ref().map(|v| write!(f, "\"{v}\"")),
118            Value::Bytes(val) => val.as_ref().map(|v| write!(f, "<{} bytes blob>", v.len())),
119            Value::Enum(val) => val.as_ref().map(|v| write!(f, "\"{v}\"")),
120            Value::Boolean(val) => val.map(|v| write!(f, "{v}")),
121            Value::Char(val) => val.map(|v| write!(f, "'{v}'")),
122            Value::Array(vals) => vals.as_ref().map(|vals| {
123                let len = vals.len();
124
125                write!(f, "[")?;
126                for (i, val) in vals.iter().enumerate() {
127                    write!(f, "{val}")?;
128
129                    if i < (len - 1) {
130                        write!(f, ",")?;
131                    }
132                }
133                write!(f, "]")
134            }),
135            Value::Xml(val) => val.as_ref().map(|v| write!(f, "{v}")),
136            #[cfg(feature = "bigdecimal")]
137            Value::Numeric(val) => val.as_ref().map(|v| write!(f, "{v}")),
138            #[cfg(feature = "json")]
139            Value::Json(val) => val.as_ref().map(|v| write!(f, "{v}")),
140            #[cfg(feature = "uuid")]
141            Value::Uuid(val) => val.map(|v| write!(f, "\"{v}\"")),
142            #[cfg(feature = "chrono")]
143            Value::DateTime(val) => val.map(|v| write!(f, "\"{v}\"")),
144            #[cfg(feature = "chrono")]
145            Value::Date(val) => val.map(|v| write!(f, "\"{v}\"")),
146            #[cfg(feature = "chrono")]
147            Value::Time(val) => val.map(|v| write!(f, "\"{v}\"")),
148        };
149
150        match res {
151            Some(r) => r,
152            None => write!(f, "null"),
153        }
154    }
155}
156
157#[cfg(feature = "json")]
158#[cfg_attr(feature = "docs", doc(cfg(feature = "json")))]
159impl<'a> From<Value<'a>> for serde_json::Value {
160    fn from(pv: Value<'a>) -> Self {
161        let res = match pv {
162            Value::Int32(i) => i.map(|i| serde_json::Value::Number(Number::from(i))),
163            Value::Int64(i) => i.map(|i| serde_json::Value::Number(Number::from(i))),
164            Value::Float(f) => f.map(|f| match Number::from_f64(f as f64) {
165                Some(number) => serde_json::Value::Number(number),
166                None => serde_json::Value::Null,
167            }),
168            Value::Double(f) => f.map(|f| match Number::from_f64(f) {
169                Some(number) => serde_json::Value::Number(number),
170                None => serde_json::Value::Null,
171            }),
172            Value::Text(cow) => cow.map(|cow| serde_json::Value::String(cow.into_owned())),
173            Value::Bytes(bytes) => bytes.map(|bytes| serde_json::Value::String(base64::encode(bytes))),
174            Value::Enum(cow) => cow.map(|cow| serde_json::Value::String(cow.into_owned())),
175            Value::Boolean(b) => b.map(serde_json::Value::Bool),
176            Value::Char(c) => c.map(|c| {
177                let bytes = [c as u8];
178                let s = std::str::from_utf8(&bytes).expect("interpret byte as UTF-8").to_string();
179                serde_json::Value::String(s)
180            }),
181            Value::Xml(cow) => cow.map(|cow| serde_json::Value::String(cow.into_owned())),
182            Value::Array(v) => {
183                v.map(|v| serde_json::Value::Array(v.into_iter().map(serde_json::Value::from).collect()))
184            }
185            #[cfg(feature = "bigdecimal")]
186            Value::Numeric(d) => d.map(|d| serde_json::to_value(d.to_f64().unwrap()).unwrap()),
187            #[cfg(feature = "json")]
188            Value::Json(v) => v,
189            #[cfg(feature = "uuid")]
190            Value::Uuid(u) => u.map(|u| serde_json::Value::String(u.hyphenated().to_string())),
191            #[cfg(feature = "chrono")]
192            Value::DateTime(dt) => dt.map(|dt| serde_json::Value::String(dt.to_rfc3339())),
193            #[cfg(feature = "chrono")]
194            Value::Date(date) => date.map(|date| serde_json::Value::String(format!("{date}"))),
195            #[cfg(feature = "chrono")]
196            Value::Time(time) => time.map(|time| serde_json::Value::String(format!("{time}"))),
197        };
198
199        match res {
200            Some(val) => val,
201            None => serde_json::Value::Null,
202        }
203    }
204}
205
206impl<'a> Value<'a> {
207    /// Creates a new 32-bit signed integer.
208    pub fn int32<I>(value: I) -> Self
209    where
210        I: Into<i32>,
211    {
212        Value::Int32(Some(value.into()))
213    }
214
215    /// Creates a new 64-bit signed integer.
216    pub fn int64<I>(value: I) -> Self
217    where
218        I: Into<i64>,
219    {
220        Value::Int64(Some(value.into()))
221    }
222
223    /// Creates a new 32-bit signed integer.
224    pub fn integer<I>(value: I) -> Self
225    where
226        I: Into<i32>,
227    {
228        Value::Int32(Some(value.into()))
229    }
230
231    /// Creates a new decimal value.
232    #[cfg(feature = "bigdecimal")]
233    #[cfg_attr(feature = "docs", doc(cfg(feature = "bigdecimal")))]
234    pub const fn numeric(value: BigDecimal) -> Self {
235        Value::Numeric(Some(value))
236    }
237
238    /// Creates a new float value.
239    pub const fn float(value: f32) -> Self {
240        Self::Float(Some(value))
241    }
242
243    /// Creates a new double value.
244    pub const fn double(value: f64) -> Self {
245        Self::Double(Some(value))
246    }
247
248    /// Creates a new string value.
249    pub fn text<T>(value: T) -> Self
250    where
251        T: Into<Cow<'a, str>>,
252    {
253        Value::Text(Some(value.into()))
254    }
255
256    /// Creates a new enum value.
257    pub fn enum_variant<T>(value: T) -> Self
258    where
259        T: Into<Cow<'a, str>>,
260    {
261        Value::Enum(Some(value.into()))
262    }
263
264    /// Creates a new bytes value.
265    pub fn bytes<B>(value: B) -> Self
266    where
267        B: Into<Cow<'a, [u8]>>,
268    {
269        Value::Bytes(Some(value.into()))
270    }
271
272    /// Creates a new boolean value.
273    pub fn boolean<B>(value: B) -> Self
274    where
275        B: Into<bool>,
276    {
277        Value::Boolean(Some(value.into()))
278    }
279
280    /// Creates a new character value.
281    pub fn character<C>(value: C) -> Self
282    where
283        C: Into<char>,
284    {
285        Value::Char(Some(value.into()))
286    }
287
288    /// Creates a new array value.
289    pub fn array<I, V>(value: I) -> Self
290    where
291        I: IntoIterator<Item = V>,
292        V: Into<Value<'a>>,
293    {
294        Value::Array(Some(value.into_iter().map(|v| v.into()).collect()))
295    }
296
297    /// Creates a new uuid value.
298    #[cfg(feature = "uuid")]
299    #[cfg_attr(feature = "docs", doc(cfg(feature = "uuid")))]
300    pub const fn uuid(value: Uuid) -> Self {
301        Value::Uuid(Some(value))
302    }
303
304    /// Creates a new datetime value.
305    #[cfg(feature = "chrono")]
306    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
307    pub const fn datetime(value: DateTime<Utc>) -> Self {
308        Value::DateTime(Some(value))
309    }
310
311    /// Creates a new date value.
312    #[cfg(feature = "chrono")]
313    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
314    pub const fn date(value: NaiveDate) -> Self {
315        Value::Date(Some(value))
316    }
317
318    /// Creates a new time value.
319    #[cfg(feature = "chrono")]
320    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
321    pub const fn time(value: NaiveTime) -> Self {
322        Value::Time(Some(value))
323    }
324
325    /// Creates a new JSON value.
326    #[cfg(feature = "json")]
327    #[cfg_attr(feature = "docs", doc(cfg(feature = "json")))]
328    pub const fn json(value: serde_json::Value) -> Self {
329        Value::Json(Some(value))
330    }
331
332    /// Creates a new XML value.
333    pub fn xml<T>(value: T) -> Self
334    where
335        T: Into<Cow<'a, str>>,
336    {
337        Value::Xml(Some(value.into()))
338    }
339
340    /// `true` if the `Value` is null.
341    pub const fn is_null(&self) -> bool {
342        match self {
343            Value::Int32(i) => i.is_none(),
344            Value::Int64(i) => i.is_none(),
345            Value::Float(i) => i.is_none(),
346            Value::Double(i) => i.is_none(),
347            Value::Text(t) => t.is_none(),
348            Value::Enum(e) => e.is_none(),
349            Value::Bytes(b) => b.is_none(),
350            Value::Boolean(b) => b.is_none(),
351            Value::Char(c) => c.is_none(),
352            Value::Array(v) => v.is_none(),
353            Value::Xml(s) => s.is_none(),
354            #[cfg(feature = "bigdecimal")]
355            Value::Numeric(r) => r.is_none(),
356            #[cfg(feature = "uuid")]
357            Value::Uuid(u) => u.is_none(),
358            #[cfg(feature = "chrono")]
359            Value::DateTime(dt) => dt.is_none(),
360            #[cfg(feature = "chrono")]
361            Value::Date(d) => d.is_none(),
362            #[cfg(feature = "chrono")]
363            Value::Time(t) => t.is_none(),
364            #[cfg(feature = "json")]
365            Value::Json(json) => json.is_none(),
366        }
367    }
368
369    /// `true` if the `Value` is text.
370    pub const fn is_text(&self) -> bool {
371        matches!(self, Value::Text(_))
372    }
373
374    /// Returns a &str if the value is text, otherwise `None`.
375    pub fn as_str(&self) -> Option<&str> {
376        match self {
377            Value::Text(Some(cow)) => Some(cow.borrow()),
378            Value::Bytes(Some(cow)) => std::str::from_utf8(cow.as_ref()).ok(),
379            _ => None,
380        }
381    }
382
383    /// Returns a char if the value is a char, otherwise `None`.
384    pub const fn as_char(&self) -> Option<char> {
385        match self {
386            Value::Char(c) => *c,
387            _ => None,
388        }
389    }
390
391    /// Returns a cloned String if the value is text, otherwise `None`.
392    pub fn to_string(&self) -> Option<String> {
393        match self {
394            Value::Text(Some(cow)) => Some(cow.to_string()),
395            Value::Bytes(Some(cow)) => std::str::from_utf8(cow.as_ref()).map(|s| s.to_owned()).ok(),
396            _ => None,
397        }
398    }
399
400    /// Transforms the `Value` to a `String` if it's text,
401    /// otherwise `None`.
402    pub fn into_string(self) -> Option<String> {
403        match self {
404            Value::Text(Some(cow)) => Some(cow.into_owned()),
405            Value::Bytes(Some(cow)) => String::from_utf8(cow.into_owned()).ok(),
406            _ => None,
407        }
408    }
409
410    /// Returns whether this value is the `Bytes` variant.
411    pub const fn is_bytes(&self) -> bool {
412        matches!(self, Value::Bytes(_))
413    }
414
415    /// Returns a bytes slice if the value is text or a byte slice, otherwise `None`.
416    pub fn as_bytes(&self) -> Option<&[u8]> {
417        match self {
418            Value::Text(Some(cow)) => Some(cow.as_ref().as_bytes()),
419            Value::Bytes(Some(cow)) => Some(cow.as_ref()),
420            _ => None,
421        }
422    }
423
424    /// Returns a cloned `Vec<u8>` if the value is text or a byte slice, otherwise `None`.
425    pub fn to_bytes(&self) -> Option<Vec<u8>> {
426        match self {
427            Value::Text(Some(cow)) => Some(cow.to_string().into_bytes()),
428            Value::Bytes(Some(cow)) => Some(cow.to_vec()),
429            _ => None,
430        }
431    }
432
433    /// `true` if the `Value` is a 32-bit signed integer.
434    pub const fn is_i32(&self) -> bool {
435        matches!(self, Value::Int32(_))
436    }
437
438    /// `true` if the `Value` is a 64-bit signed integer.
439    pub const fn is_i64(&self) -> bool {
440        matches!(self, Value::Int64(_))
441    }
442
443    /// `true` if the `Value` is a signed integer.
444    pub const fn is_integer(&self) -> bool {
445        matches!(self, Value::Int32(_) | Value::Int64(_))
446    }
447
448    /// Returns an `i64` if the value is a 64-bit signed integer, otherwise `None`.
449    pub const fn as_i64(&self) -> Option<i64> {
450        match self {
451            Value::Int64(i) => *i,
452            _ => None,
453        }
454    }
455
456    /// Returns an `i32` if the value is a 32-bit signed integer, otherwise `None`.
457    pub const fn as_i32(&self) -> Option<i32> {
458        match self {
459            Value::Int32(i) => *i,
460            _ => None,
461        }
462    }
463
464    /// Returns an `i64` if the value is a signed integer, otherwise `None`.
465    pub fn as_integer(&self) -> Option<i64> {
466        match self {
467            Value::Int32(i) => i.map(|i| i as i64),
468            Value::Int64(i) => *i,
469            _ => None,
470        }
471    }
472
473    /// Returns a `f64` if the value is a double, otherwise `None`.
474    pub const fn as_f64(&self) -> Option<f64> {
475        match self {
476            Value::Double(Some(f)) => Some(*f),
477            _ => None,
478        }
479    }
480
481    /// Returns a `f32` if the value is a double, otherwise `None`.
482    pub const fn as_f32(&self) -> Option<f32> {
483        match self {
484            Value::Float(Some(f)) => Some(*f),
485            _ => None,
486        }
487    }
488
489    /// `true` if the `Value` is a numeric value or can be converted to one.
490    #[cfg(feature = "bigdecimal")]
491    #[cfg_attr(feature = "docs", doc(cfg(feature = "bigdecimal")))]
492    pub const fn is_numeric(&self) -> bool {
493        matches!(self, Value::Numeric(_) | Value::Float(_) | Value::Double(_))
494    }
495
496    /// Returns a bigdecimal, if the value is a numeric, float or double value,
497    /// otherwise `None`.
498    #[cfg(feature = "bigdecimal")]
499    #[cfg_attr(feature = "docs", doc(cfg(feature = "bigdecimal")))]
500    pub fn into_numeric(self) -> Option<BigDecimal> {
501        match self {
502            Value::Numeric(d) => d,
503            Value::Float(f) => f.and_then(BigDecimal::from_f32),
504            Value::Double(f) => f.and_then(BigDecimal::from_f64),
505            _ => None,
506        }
507    }
508
509    /// Returns a reference to a bigdecimal, if the value is a numeric.
510    /// Otherwise `None`.
511    #[cfg(feature = "bigdecimal")]
512    #[cfg_attr(feature = "docs", doc(cfg(feature = "bigdecimal")))]
513    pub const fn as_numeric(&self) -> Option<&BigDecimal> {
514        match self {
515            Value::Numeric(d) => d.as_ref(),
516            _ => None,
517        }
518    }
519
520    /// `true` if the `Value` is a boolean value.
521    pub const fn is_bool(&self) -> bool {
522        match self {
523            Value::Boolean(_) => true,
524            // For schemas which don't tag booleans
525            Value::Int32(Some(i)) if *i == 0 || *i == 1 => true,
526            Value::Int64(Some(i)) if *i == 0 || *i == 1 => true,
527            _ => false,
528        }
529    }
530
531    /// Returns a bool if the value is a boolean, otherwise `None`.
532    pub const fn as_bool(&self) -> Option<bool> {
533        match self {
534            Value::Boolean(b) => *b,
535            // For schemas which don't tag booleans
536            Value::Int32(Some(i)) if *i == 0 || *i == 1 => Some(*i == 1),
537            Value::Int64(Some(i)) if *i == 0 || *i == 1 => Some(*i == 1),
538            _ => None,
539        }
540    }
541
542    /// `true` if the `Value` is an Array.
543    pub const fn is_array(&self) -> bool {
544        matches!(self, Value::Array(_))
545    }
546
547    /// `true` if the `Value` is of UUID type.
548    #[cfg(feature = "uuid")]
549    #[cfg_attr(feature = "docs", doc(cfg(feature = "uuid")))]
550    pub const fn is_uuid(&self) -> bool {
551        matches!(self, Value::Uuid(_))
552    }
553
554    /// Returns an UUID if the value is of UUID type, otherwise `None`.
555    #[cfg(feature = "uuid")]
556    #[cfg_attr(feature = "docs", doc(cfg(feature = "uuid")))]
557    pub const fn as_uuid(&self) -> Option<Uuid> {
558        match self {
559            Value::Uuid(u) => *u,
560            _ => None,
561        }
562    }
563
564    /// `true` if the `Value` is a DateTime.
565    #[cfg(feature = "chrono")]
566    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
567    pub const fn is_datetime(&self) -> bool {
568        matches!(self, Value::DateTime(_))
569    }
570
571    /// Returns a `DateTime` if the value is a `DateTime`, otherwise `None`.
572    #[cfg(feature = "chrono")]
573    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
574    pub const fn as_datetime(&self) -> Option<DateTime<Utc>> {
575        match self {
576            Value::DateTime(dt) => *dt,
577            _ => None,
578        }
579    }
580
581    /// `true` if the `Value` is a Date.
582    #[cfg(feature = "chrono")]
583    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
584    pub const fn is_date(&self) -> bool {
585        matches!(self, Value::Date(_))
586    }
587
588    /// Returns a `NaiveDate` if the value is a `Date`, otherwise `None`.
589    #[cfg(feature = "chrono")]
590    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
591    pub const fn as_date(&self) -> Option<NaiveDate> {
592        match self {
593            Value::Date(dt) => *dt,
594            _ => None,
595        }
596    }
597
598    /// `true` if the `Value` is a `Time`.
599    #[cfg(feature = "chrono")]
600    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
601    pub const fn is_time(&self) -> bool {
602        matches!(self, Value::Time(_))
603    }
604
605    /// Returns a `NaiveTime` if the value is a `Time`, otherwise `None`.
606    #[cfg(feature = "chrono")]
607    #[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
608    pub const fn as_time(&self) -> Option<NaiveTime> {
609        match self {
610            Value::Time(time) => *time,
611            _ => None,
612        }
613    }
614
615    /// `true` if the `Value` is a JSON value.
616    #[cfg(feature = "json")]
617    #[cfg_attr(feature = "docs", doc(cfg(feature = "json")))]
618    pub const fn is_json(&self) -> bool {
619        matches!(self, Value::Json(_))
620    }
621
622    /// Returns a reference to a JSON Value if of Json type, otherwise `None`.
623    #[cfg(feature = "json")]
624    #[cfg_attr(feature = "docs", doc(cfg(feature = "json")))]
625    pub const fn as_json(&self) -> Option<&serde_json::Value> {
626        match self {
627            Value::Json(Some(j)) => Some(j),
628            _ => None,
629        }
630    }
631
632    /// Transforms to a JSON Value if of Json type, otherwise `None`.
633    #[cfg(feature = "json")]
634    #[cfg_attr(feature = "docs", doc(cfg(feature = "json")))]
635    pub fn into_json(self) -> Option<serde_json::Value> {
636        match self {
637            Value::Json(Some(j)) => Some(j),
638            _ => None,
639        }
640    }
641
642    /// Returns a `Vec<T>` if the value is an array of `T`, otherwise `None`.
643    pub fn into_vec<T>(self) -> Option<Vec<T>>
644    where
645        // Implement From<Value>
646        T: TryFrom<Value<'a>>,
647    {
648        match self {
649            Value::Array(Some(vec)) => {
650                let rslt: Result<Vec<_>, _> = vec.into_iter().map(T::try_from).collect();
651                match rslt {
652                    Err(_) => None,
653                    Ok(values) => Some(values),
654                }
655            }
656            _ => None,
657        }
658    }
659
660    /// Returns a cloned Vec<T> if the value is an array of T, otherwise `None`.
661    pub fn to_vec<T>(&self) -> Option<Vec<T>>
662    where
663        T: TryFrom<Value<'a>>,
664    {
665        match self {
666            Value::Array(Some(vec)) => {
667                let rslt: Result<Vec<_>, _> = vec.clone().into_iter().map(T::try_from).collect();
668                match rslt {
669                    Err(_) => None,
670                    Ok(values) => Some(values),
671                }
672            }
673            _ => None,
674        }
675    }
676}
677
678value!(val: i64, Int64, val);
679value!(val: i32, Int32, val);
680value!(val: bool, Boolean, val);
681value!(val: &'a str, Text, val.into());
682value!(val: String, Text, val.into());
683value!(val: usize, Int64, i64::try_from(val).unwrap());
684value!(val: &'a [u8], Bytes, val.into());
685value!(val: f64, Double, val);
686value!(val: f32, Float, val);
687
688#[cfg(feature = "chrono")]
689value!(val: DateTime<Utc>, DateTime, val);
690#[cfg(feature = "chrono")]
691value!(val: chrono::NaiveTime, Time, val);
692#[cfg(feature = "chrono")]
693value!(val: chrono::NaiveDate, Date, val);
694#[cfg(feature = "bigdecimal")]
695value!(val: BigDecimal, Numeric, val);
696#[cfg(feature = "json")]
697value!(val: JsonValue, Json, val);
698#[cfg(feature = "uuid")]
699value!(val: Uuid, Uuid, val);
700
701impl<'a> TryFrom<Value<'a>> for i64 {
702    type Error = Error;
703
704    fn try_from(value: Value<'a>) -> Result<i64, Self::Error> {
705        value.as_i64().ok_or_else(|| Error::builder(ErrorKind::conversion("Not an i64")).build())
706    }
707}
708
709impl<'a> TryFrom<Value<'a>> for i32 {
710    type Error = Error;
711
712    fn try_from(value: Value<'a>) -> Result<i32, Self::Error> {
713        value.as_i32().ok_or_else(|| Error::builder(ErrorKind::conversion("Not an i32")).build())
714    }
715}
716
717#[cfg(feature = "bigdecimal")]
718impl<'a> TryFrom<Value<'a>> for BigDecimal {
719    type Error = Error;
720
721    fn try_from(value: Value<'a>) -> Result<BigDecimal, Self::Error> {
722        value.into_numeric().ok_or_else(|| Error::builder(ErrorKind::conversion("Not a decimal")).build())
723    }
724}
725
726impl<'a> TryFrom<Value<'a>> for f64 {
727    type Error = Error;
728
729    fn try_from(value: Value<'a>) -> Result<f64, Self::Error> {
730        value.as_f64().ok_or_else(|| Error::builder(ErrorKind::conversion("Not a f64")).build())
731    }
732}
733
734impl<'a> TryFrom<Value<'a>> for String {
735    type Error = Error;
736
737    fn try_from(value: Value<'a>) -> Result<String, Self::Error> {
738        value.into_string().ok_or_else(|| Error::builder(ErrorKind::conversion("Not a string")).build())
739    }
740}
741
742impl<'a> TryFrom<Value<'a>> for bool {
743    type Error = Error;
744
745    fn try_from(value: Value<'a>) -> Result<bool, Self::Error> {
746        value.as_bool().ok_or_else(|| Error::builder(ErrorKind::conversion("Not a bool")).build())
747    }
748}
749
750#[cfg(feature = "chrono")]
751#[cfg_attr(feature = "docs", doc(cfg(feature = "chrono")))]
752impl<'a> TryFrom<Value<'a>> for DateTime<Utc> {
753    type Error = Error;
754
755    fn try_from(value: Value<'a>) -> Result<DateTime<Utc>, Self::Error> {
756        value.as_datetime().ok_or_else(|| Error::builder(ErrorKind::conversion("Not a datetime")).build())
757    }
758}
759
760impl<'a> TryFrom<&Value<'a>> for Option<std::net::IpAddr> {
761    type Error = Error;
762
763    fn try_from(value: &Value<'a>) -> Result<Option<std::net::IpAddr>, Self::Error> {
764        match value {
765            val @ Value::Text(Some(_)) => {
766                let text = val.as_str().unwrap();
767
768                match std::net::IpAddr::from_str(text) {
769                    Ok(ip) => Ok(Some(ip)),
770                    Err(e) => Err(e.into()),
771                }
772            }
773            val @ Value::Bytes(Some(_)) => {
774                let text = val.as_str().unwrap();
775
776                match std::net::IpAddr::from_str(text) {
777                    Ok(ip) => Ok(Some(ip)),
778                    Err(e) => Err(e.into()),
779                }
780            }
781            v if v.is_null() => Ok(None),
782            v => {
783                let kind =
784                    ErrorKind::conversion(format!("Couldn't convert value of type `{v:?}` to std::net::IpAddr."));
785
786                Err(Error::builder(kind).build())
787            }
788        }
789    }
790}
791
792#[cfg(feature = "uuid")]
793impl<'a> TryFrom<&Value<'a>> for Option<uuid::Uuid> {
794    type Error = Error;
795
796    fn try_from(value: &Value<'a>) -> Result<Option<uuid::Uuid>, Self::Error> {
797        match value {
798            Value::Uuid(uuid) => Ok(*uuid),
799            val @ Value::Text(Some(_)) => {
800                let text = val.as_str().unwrap();
801
802                match uuid::Uuid::from_str(text) {
803                    Ok(ip) => Ok(Some(ip)),
804                    Err(e) => Err(e.into()),
805                }
806            }
807            val @ Value::Bytes(Some(_)) => {
808                let text = val.as_str().unwrap();
809
810                match uuid::Uuid::from_str(text) {
811                    Ok(ip) => Ok(Some(ip)),
812                    Err(e) => Err(e.into()),
813                }
814            }
815            v if v.is_null() => Ok(None),
816            v => {
817                let kind = ErrorKind::conversion(format!("Couldn't convert value of type `{v:?}` to uuid::Uuid."));
818
819                Err(Error::builder(kind).build())
820            }
821        }
822    }
823}
824
825/// An in-memory temporary table. Can be used in some of the databases in a
826/// place of an actual table. Doesn't work in MySQL 5.7.
827#[derive(Debug, Clone, Default, PartialEq)]
828pub struct Values<'a> {
829    pub(crate) rows: Vec<Row<'a>>,
830}
831
832impl<'a> Values<'a> {
833    /// Create a new empty in-memory set of values.
834    pub fn empty() -> Self {
835        Self { rows: Vec::new() }
836    }
837
838    /// Create a new in-memory set of values.
839    pub fn new(rows: Vec<Row<'a>>) -> Self {
840        Self { rows }
841    }
842
843    /// Create a new in-memory set of values with an allocated capacity.
844    pub fn with_capacity(capacity: usize) -> Self {
845        Self { rows: Vec::with_capacity(capacity) }
846    }
847
848    /// Add value to the temporary table.
849    pub fn push<T>(&mut self, row: T)
850    where
851        T: Into<Row<'a>>,
852    {
853        self.rows.push(row.into());
854    }
855
856    /// The number of rows in the in-memory table.
857    pub fn len(&self) -> usize {
858        self.rows.len()
859    }
860
861    /// True if has no rows.
862    pub fn is_empty(&self) -> bool {
863        self.len() == 0
864    }
865
866    pub fn row_len(&self) -> usize {
867        match self.rows.split_first() {
868            Some((row, _)) => row.len(),
869            None => 0,
870        }
871    }
872
873    pub fn flatten_row(self) -> Option<Row<'a>> {
874        let mut result = Row::with_capacity(self.len());
875
876        for mut row in self.rows.into_iter() {
877            match row.pop() {
878                Some(value) => result.push(value),
879                None => return None,
880            }
881        }
882
883        Some(result)
884    }
885}
886
887impl<'a, I, R> From<I> for Values<'a>
888where
889    I: Iterator<Item = R>,
890    R: Into<Row<'a>>,
891{
892    fn from(rows: I) -> Self {
893        Self { rows: rows.map(|r| r.into()).collect() }
894    }
895}
896
897impl<'a> IntoIterator for Values<'a> {
898    type Item = Row<'a>;
899    type IntoIter = std::vec::IntoIter<Self::Item>;
900
901    fn into_iter(self) -> Self::IntoIter {
902        self.rows.into_iter()
903    }
904}
905
906#[cfg(test)]
907mod tests {
908    use super::*;
909    #[cfg(feature = "chrono")]
910    use std::str::FromStr;
911
912    #[test]
913    fn a_parameterized_value_of_ints32_can_be_converted_into_a_vec() {
914        let pv = Value::array(vec![1]);
915        let values: Vec<i32> = pv.into_vec().expect("convert into Vec<i32>");
916        assert_eq!(values, vec![1]);
917    }
918
919    #[test]
920    fn a_parameterized_value_of_ints64_can_be_converted_into_a_vec() {
921        let pv = Value::array(vec![1_i64]);
922        let values: Vec<i64> = pv.into_vec().expect("convert into Vec<i64>");
923        assert_eq!(values, vec![1]);
924    }
925
926    #[test]
927    fn a_parameterized_value_of_reals_can_be_converted_into_a_vec() {
928        let pv = Value::array(vec![1.0]);
929        let values: Vec<f64> = pv.into_vec().expect("convert into Vec<f64>");
930        assert_eq!(values, vec![1.0]);
931    }
932
933    #[test]
934    fn a_parameterized_value_of_texts_can_be_converted_into_a_vec() {
935        let pv = Value::array(vec!["test"]);
936        let values: Vec<String> = pv.into_vec().expect("convert into Vec<String>");
937        assert_eq!(values, vec!["test"]);
938    }
939
940    #[test]
941    fn a_parameterized_value_of_booleans_can_be_converted_into_a_vec() {
942        let pv = Value::array(vec![true]);
943        let values: Vec<bool> = pv.into_vec().expect("convert into Vec<bool>");
944        assert_eq!(values, vec![true]);
945    }
946
947    #[test]
948    #[cfg(feature = "chrono")]
949    fn a_parameterized_value_of_datetimes_can_be_converted_into_a_vec() {
950        let datetime = DateTime::from_str("2019-07-27T05:30:30Z").expect("parsing date/time");
951        let pv = Value::array(vec![datetime]);
952        let values: Vec<DateTime<Utc>> = pv.into_vec().expect("convert into Vec<DateTime>");
953        assert_eq!(values, vec![datetime]);
954    }
955
956    #[test]
957    fn a_parameterized_value_of_an_array_cant_be_converted_into_a_vec_of_the_wrong_type() {
958        let pv = Value::array(vec![1]);
959        let rslt: Option<Vec<f64>> = pv.into_vec();
960        assert!(rslt.is_none());
961    }
962
963    #[test]
964    #[cfg(feature = "chrono")]
965    fn display_format_for_datetime() {
966        let dt: DateTime<Utc> = DateTime::from_str("2019-07-27T05:30:30Z").expect("failed while parsing date");
967        let pv = Value::datetime(dt);
968
969        assert_eq!(format!("{pv}"), "\"2019-07-27 05:30:30 UTC\"");
970    }
971
972    #[test]
973    #[cfg(feature = "chrono")]
974    fn display_format_for_date() {
975        let date = NaiveDate::from_ymd_opt(2022, 8, 11).unwrap();
976        let pv = Value::date(date);
977
978        assert_eq!(format!("{pv}"), "\"2022-08-11\"");
979    }
980
981    #[test]
982    #[cfg(feature = "chrono")]
983    fn display_format_for_time() {
984        let time = NaiveTime::from_hms_opt(16, 17, 00).unwrap();
985        let pv = Value::time(time);
986
987        assert_eq!(format!("{pv}"), "\"16:17:00\"");
988    }
989
990    #[test]
991    #[cfg(feature = "uuid")]
992    fn display_format_for_uuid() {
993        let id = Uuid::from_str("67e5504410b1426f9247bb680e5fe0c8").unwrap();
994        let pv = Value::uuid(id);
995
996        assert_eq!(format!("{pv}"), "\"67e55044-10b1-426f-9247-bb680e5fe0c8\"");
997    }
998}