odbc_iter/
value.rs

1use crate::row::{Configuration, DatumType, Column, TryFromColumn, ColumnConvertError};
2use odbc::{SqlDate, SqlSsTime2, SqlTime, SqlTimestamp};
3use std::convert::{Infallible, TryInto};
4use std::error::Error;
5use std::fmt;
6
7#[cfg(feature = "chrono")]
8pub use chrono::naive::{NaiveDate, NaiveDateTime, NaiveTime};
9#[cfg(feature = "chrono")]
10pub use chrono::{Datelike, Timelike};
11#[cfg(feature = "rust_decimal")]
12pub use rust_decimal::Decimal;
13#[cfg(feature = "serde_json")]
14pub use serde_json::Value as Json;
15
16/// Representation of every supported column value.
17#[derive(Clone, PartialEq)]
18pub enum Value {
19    Bit(bool),
20    Tinyint(i8),
21    Smallint(i16),
22    Integer(i32),
23    Bigint(i64),
24    Float(f32),
25    Double(f64),
26    #[cfg(feature = "rust_decimal")]
27    Decimal(Decimal),
28    String(String),
29    Timestamp(SqlTimestamp),
30    Date(SqlDate),
31    Time(SqlSsTime2),
32    #[cfg(feature = "serde_json")]
33    Json(Json),
34}
35
36/// Note that `as_` methods return reference so values can be parameter-bound to a query.
37/// Use `to_` or `into_` methods to get values cheaply.
38impl Value {
39    pub fn as_bool(&self) -> Option<&bool> {
40        match self {
41            Value::Bit(value) => Some(value),
42            _ => None,
43        }
44    }
45
46    pub fn to_bool(&self) -> Option<bool> {
47        self.as_bool().cloned()
48    }
49
50    pub fn as_i8(&self) -> Option<&i8> {
51        match self {
52            Value::Tinyint(value) => Some(value),
53            _ => None,
54        }
55    }
56
57    pub fn to_i8(&self) -> Option<i8> {
58        self.as_i8().cloned()
59    }
60
61    pub fn as_i16(&self) -> Option<&i16> {
62        match self {
63            Value::Smallint(value) => Some(value),
64            _ => None,
65        }
66    }
67
68    pub fn to_i16(&self) -> Option<i16> {
69        self.as_i16().cloned()
70    }
71
72    pub fn as_i32(&self) -> Option<&i32> {
73        match self {
74            Value::Integer(value) => Some(value),
75            _ => None,
76        }
77    }
78
79    pub fn to_i32(&self) -> Option<i32> {
80        self.as_i32().cloned()
81    }
82
83    pub fn as_i64(&self) -> Option<&i64> {
84        match self {
85            Value::Bigint(value) => Some(value),
86            _ => None,
87        }
88    }
89
90    pub fn to_i64(&self) -> Option<i64> {
91        self.as_i64().cloned()
92    }
93
94    pub fn as_f32(&self) -> Option<&f32> {
95        match self {
96            Value::Float(value) => Some(value),
97            _ => None,
98        }
99    }
100
101    pub fn to_f32(&self) -> Option<f32> {
102        self.as_f32().cloned()
103    }
104
105    pub fn as_f64(&self) -> Option<&f64> {
106        match self {
107            Value::Double(value) => Some(value),
108            _ => None,
109        }
110    }
111
112    #[cfg(feature = "rust_decimal")]
113    pub fn as_decimal(&self) -> Option<&Decimal> {
114        match self {
115            Value::Decimal(value) => Some(value),
116            _ => None,
117        }
118    }
119
120    pub fn to_f64(&self) -> Option<f64> {
121        self.as_f64().cloned()
122    }
123
124    pub fn as_str(&self) -> Option<&str> {
125        match self {
126            Value::String(value) => Some(value),
127            _ => None,
128        }
129    }
130
131    pub fn into_string(self) -> Result<String, Value> {
132        match self {
133            Value::String(value) => Ok(value),
134            _ => Err(self),
135        }
136    }
137
138    pub fn as_timestamp(&self) -> Option<&SqlTimestamp> {
139        match self {
140            Value::Timestamp(value) => Some(value),
141            _ => None,
142        }
143    }
144
145    pub fn into_timestamp(self) -> Result<SqlTimestamp, Value> {
146        match self {
147            Value::Timestamp(value) => Ok(value),
148            _ => Err(self),
149        }
150    }
151
152    #[cfg(feature = "chrono")]
153    pub fn to_naive_date_time(&self) -> Option<NaiveDateTime> {
154        self.as_timestamp().map(|value| {
155            NaiveDate::from_ymd(
156                i32::from(value.year),
157                u32::from(value.month),
158                u32::from(value.day),
159            )
160            .and_hms_nano(
161                u32::from(value.hour),
162                u32::from(value.minute),
163                u32::from(value.second),
164                value.fraction,
165            )
166        })
167    }
168
169    pub fn as_date(&self) -> Option<&SqlDate> {
170        match self {
171            Value::Date(value) => Some(value),
172            _ => None,
173        }
174    }
175
176    pub fn into_date(self) -> Result<SqlDate, Value> {
177        match self {
178            Value::Date(value) => Ok(value),
179            _ => Err(self),
180        }
181    }
182
183    #[cfg(feature = "chrono")]
184    pub fn to_naive_date(&self) -> Option<NaiveDate> {
185        self.as_date().map(|value| {
186            NaiveDate::from_ymd(
187                i32::from(value.year),
188                u32::from(value.month),
189                u32::from(value.day),
190            )
191        })
192    }
193
194    pub fn as_time(&self) -> Option<&SqlSsTime2> {
195        match self {
196            Value::Time(value) => Some(value),
197            _ => None,
198        }
199    }
200
201    pub fn into_time(self) -> Result<SqlSsTime2, Value> {
202        match self {
203            Value::Time(value) => Ok(value),
204            _ => Err(self),
205        }
206    }
207
208    #[cfg(feature = "chrono")]
209    pub fn to_naive_time(&self) -> Option<NaiveTime> {
210        self.as_time().map(|value| {
211            NaiveTime::from_hms_nano(
212                u32::from(value.hour),
213                u32::from(value.minute),
214                u32::from(value.second),
215                value.fraction,
216            )
217        })
218    }
219
220    #[cfg(feature = "serde_json")]
221    pub fn as_json(&self) -> Option<&Json> {
222        match self {
223            Value::Json(value) => Some(value),
224            _ => None,
225        }
226    }
227
228    #[cfg(feature = "serde_json")]
229    pub fn into_json(self) -> Result<Json, Value> {
230        match self {
231            Value::Json(value) => Ok(value),
232            _ => Err(self),
233        }
234    }
235
236    /// Type of this value.
237    pub fn datum_type(&self) -> DatumType {
238        match self {
239            Value::Bit(_) => DatumType::Bit,
240            Value::Tinyint(_) => DatumType::Tinyint,
241            Value::Smallint(_) => DatumType::Smallint,
242            Value::Integer(_) => DatumType::Integer,
243            Value::Bigint(_) => DatumType::Bigint,
244            Value::Float(_) => DatumType::Float,
245            Value::Double(_) => DatumType::Double,
246            #[cfg(feature = "rust_decimal")]
247            Value::Decimal(_) => DatumType::Decimal,
248            Value::String(_) => DatumType::String,
249            Value::Timestamp(_) => DatumType::Timestamp,
250            Value::Date(_) => DatumType::Date,
251            Value::Time(_) => DatumType::Time,
252            #[cfg(feature = "serde_json")]
253            Value::Json(_) => DatumType::Json,
254        }
255    }
256}
257
258impl From<bool> for Value {
259    fn from(value: bool) -> Value {
260        Value::Bit(value)
261    }
262}
263
264impl From<i8> for Value {
265    fn from(value: i8) -> Value {
266        Value::Tinyint(value)
267    }
268}
269
270impl From<i16> for Value {
271    fn from(value: i16) -> Value {
272        Value::Smallint(value)
273    }
274}
275
276impl From<i32> for Value {
277    fn from(value: i32) -> Value {
278        Value::Integer(value)
279    }
280}
281
282impl From<i64> for Value {
283    fn from(value: i64) -> Value {
284        Value::Bigint(value)
285    }
286}
287
288impl From<f32> for Value {
289    fn from(value: f32) -> Value {
290        Value::Float(value)
291    }
292}
293
294impl From<f64> for Value {
295    fn from(value: f64) -> Value {
296        Value::Double(value)
297    }
298}
299
300#[cfg(feature = "rust_decimal")]
301impl From<Decimal> for Value {
302    fn from(value: Decimal) -> Value {
303        Value::Decimal(value)
304    }
305}
306
307impl From<String> for Value {
308    fn from(value: String) -> Value {
309        Value::String(value)
310    }
311}
312
313#[cfg(feature = "chrono")]
314impl From<NaiveDateTime> for Value {
315    fn from(value: NaiveDateTime) -> Value {
316        Value::Timestamp(SqlTimestamp {
317            day: value.day() as u16,
318            month: value.month() as u16,
319            year: value.year() as i16,
320            hour: value.hour() as u16,
321            minute: value.minute() as u16,
322            second: value.second() as u16,
323            fraction: value.nanosecond(),
324        })
325    }
326}
327
328impl From<SqlTimestamp> for Value {
329    fn from(value: SqlTimestamp) -> Value {
330        Value::Timestamp(value)
331    }
332}
333
334#[cfg(feature = "chrono")]
335use crate::odbc_type::UnixTimestamp;
336#[cfg(feature = "chrono")]
337impl From<UnixTimestamp> for Value {
338    fn from(value: UnixTimestamp) -> Value {
339        Value::Timestamp(value.into_inner())
340    }
341}
342
343#[cfg(feature = "chrono")]
344impl From<NaiveDate> for Value {
345    fn from(value: NaiveDate) -> Value {
346        Value::Date(SqlDate {
347            day: value.day() as u16,
348            month: value.month() as u16,
349            year: value.year() as i16,
350        })
351    }
352}
353
354impl From<SqlDate> for Value {
355    fn from(value: SqlDate) -> Value {
356        Value::Date(value)
357    }
358}
359
360#[cfg(feature = "chrono")]
361impl From<NaiveTime> for Value {
362    fn from(value: NaiveTime) -> Value {
363        Value::Time(SqlSsTime2 {
364            hour: value.hour() as u16,
365            minute: value.minute() as u16,
366            second: value.second() as u16,
367            fraction: value.nanosecond(),
368        })
369    }
370}
371
372impl From<SqlTime> for Value {
373    fn from(value: SqlTime) -> Value {
374        Value::Time(SqlSsTime2 {
375            hour: value.hour,
376            minute: value.minute,
377            second: value.second,
378            fraction: 0,
379        })
380    }
381}
382
383impl From<SqlSsTime2> for Value {
384    fn from(value: SqlSsTime2) -> Value {
385        Value::Time(value)
386    }
387}
388
389#[cfg(feature = "serde_json")]
390impl From<Json> for Value {
391    fn from(value: Json) -> Value {
392        Value::Json(value)
393    }
394}
395
396impl<C: Configuration> TryFromColumn<C> for Option<Value> {
397    type Error = ColumnConvertError;
398
399    fn try_from_column<'i, 's, 'c, S>(column: Column<'i, 's, 'c, S, C>) -> Result<Self, Self::Error> {
400        Ok(match column.column_type.datum_type {
401            DatumType::Bit => column.into_bool()?.map(Value::from),
402            DatumType::Tinyint => column.into_i8()?.map(Value::from),
403            DatumType::Smallint => column.into_i16()?.map(Value::from),
404            DatumType::Integer => column.into_i32()?.map(Value::from),
405            DatumType::Bigint => column.into_i64()?.map(Value::from),
406            DatumType::Float => column.into_f32()?.map(Value::from),
407            DatumType::Double => column.into_f64()?.map(Value::from),
408            #[cfg(feature = "rust_decimal")]
409            DatumType::Decimal => column.into_decimal()?.map(Value::from),
410            DatumType::String => column.into_string()?.map(Value::from),
411            DatumType::Timestamp => column.into_timestamp()?.map(Value::from),
412            DatumType::Date => column.into_date()?.map(Value::from),
413            DatumType::Time => column.into_time()?.map(Value::from),
414            #[cfg(feature = "serde_json")]
415            DatumType::Json => column.into_json()?.map(Value::from),
416        })
417    }
418}
419
420impl<C: Configuration> TryFromColumn<C> for Value {
421    type Error = ColumnConvertError;
422
423    fn try_from_column<'i, 's, 'c, S>(column: Column<'i, 's, 'c, S, C>) -> Result<Self, Self::Error> {
424        let value: Option<Value> = TryFromColumn::try_from_column(column)?;
425        value.ok_or_else(|| ColumnConvertError::UnexpectedNullValue("Value"))
426    }
427}
428
429impl fmt::Display for Value {
430    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
431        match self {
432            Value::Bit(ref b) => fmt::Display::fmt(b, f),
433            Value::Tinyint(ref n) => fmt::Display::fmt(n, f),
434            Value::Smallint(ref n) => fmt::Display::fmt(n, f),
435            Value::Integer(ref n) => fmt::Display::fmt(n, f),
436            Value::Bigint(ref n) => fmt::Display::fmt(n, f),
437            Value::Float(ref n) => fmt::Display::fmt(n, f),
438            Value::Double(ref n) => fmt::Display::fmt(n, f),
439            #[cfg(feature = "rust_decimal")]
440            Value::Decimal(ref n) => fmt::Display::fmt(n, f),
441            Value::String(ref s) => fmt::Display::fmt(s, f),
442            Value::Timestamp(ref timestamp) => write!(
443                f,
444                "{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}",
445                timestamp.year,
446                timestamp.month,
447                timestamp.day,
448                timestamp.hour,
449                timestamp.minute,
450                timestamp.second,
451                timestamp.fraction / 1_000_000
452            ),
453            Value::Date(ref date) => {
454                write!(f, "{:04}-{:02}-{:02}", date.year, date.month, date.day)
455            }
456            Value::Time(ref time) => write!(
457                f,
458                "{:02}:{:02}:{:02}.{:03}",
459                time.hour,
460                time.minute,
461                time.second,
462                time.fraction / 1_000_000
463            ),
464            #[cfg(feature = "serde_json")]
465            Value::Json(ref json) => write!(f, "{}", json),
466        }
467    }
468}
469
470impl fmt::Debug for Value {
471    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
472        match self {
473            Value::Bit(ref b) => f.debug_tuple("Bit").field(b).finish(),
474            Value::Tinyint(ref n) => f.debug_tuple("Tinyint").field(n).finish(),
475            Value::Smallint(ref n) => f.debug_tuple("Smallint").field(n).finish(),
476            Value::Integer(ref n) => f.debug_tuple("Integer").field(n).finish(),
477            Value::Bigint(ref n) => f.debug_tuple("Bigint").field(n).finish(),
478            Value::Float(ref n) => f.debug_tuple("Float").field(n).finish(),
479            Value::Double(ref n) => f.debug_tuple("Double").field(n).finish(),
480            #[cfg(feature = "rust_decimal")]
481            Value::Decimal(ref n) => f.debug_tuple("Decimal").field(n).finish(),
482            Value::String(ref s) => f.debug_tuple("String").field(s).finish(),
483            timestamp @ Value::Timestamp(_) => f
484                .debug_tuple("Timestamp")
485                .field(&format_args!("{}", timestamp))
486                .finish(),
487            date @ Value::Date(_) => f
488                .debug_tuple("Date")
489                .field(&format_args!("{}", date))
490                .finish(),
491            time @ Value::Time(_) => f
492                .debug_tuple("Time")
493                .field(&format_args!("{}", time))
494                .finish(),
495            #[cfg(feature = "serde_json")]
496            Value::Json(ref j) => f.debug_tuple("Json").field(j).finish(),
497        }
498    }
499}
500
501/// Wrapper type that can be used to display nullable column value represented as `Option<Value>`.
502#[derive(Debug, Clone, PartialEq)]
503pub struct NullableValue<'i>(&'i Option<Value>, &'static str);
504
505impl<'i> fmt::Display for NullableValue<'i> {
506    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
507        match self.0 {
508            Some(ref v) => fmt::Display::fmt(v, f),
509            None => write!(f, "{}", self.1),
510        }
511    }
512}
513
514pub trait AsNullable {
515    /// Convert to `NullableValue` that implements `Display` representing no value as "NULL".
516    fn as_nullable(&self) -> NullableValue {
517        self.as_nullable_as("NULL")
518    }
519
520    /// Convert to `NullableValue` that implements `Display` representing no value as given string.
521    fn as_nullable_as(&self, null: &'static str) -> NullableValue;
522}
523
524/// Represent `None` as "NULL" and `Some(Value)` as value.
525impl AsNullable for Option<Value> {
526    fn as_nullable_as(&self, null: &'static str) -> NullableValue {
527        NullableValue(&self, null)
528    }
529}
530
531/// Column values can be converted to types implementing this trait.
532///
533/// This trait is implemented for primitive Rust types, `String` and `chrono` date and time types.
534pub trait TryFromValue: Sized {
535    type Error: Error + 'static;
536    fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error>;
537}
538
539/// Error type that represents different problems when converting column values to specific types.
540#[derive(Debug)]
541pub enum ValueConvertError {
542    UnexpectedNullValue(&'static str),
543    UnexpectedType {
544        expected: &'static str,
545        got: &'static str,
546    },
547    ValueOutOfRange {
548        expected: &'static str,
549    },
550}
551
552impl fmt::Display for ValueConvertError {
553    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
554        match self {
555            ValueConvertError::UnexpectedNullValue(t) => {
556                write!(f, "expecting value of type {} but got NULL", t)
557            }
558            ValueConvertError::UnexpectedType { expected, got } => {
559                write!(f, "expecting value of type {} but got {}", expected, got)
560            }
561            ValueConvertError::ValueOutOfRange { expected } => {
562                write!(f, "value is out of range for type {}", expected)
563            }
564        }
565    }
566}
567
568impl Error for ValueConvertError {}
569
570impl TryFromValue for Value {
571    type Error = ValueConvertError;
572    fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error> {
573        value.ok_or_else(|| ValueConvertError::UnexpectedNullValue("Value"))
574    }
575}
576
577impl TryFromValue for Option<Value> {
578    type Error = Infallible;
579    fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error> {
580        Ok(value)
581    }
582}
583
584macro_rules! try_from_value_copy {
585    ($t:ty, $f:ident) => {
586        impl TryFromValue for $t {
587            type Error = ValueConvertError;
588            fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error> {
589                let value =
590                    value.ok_or_else(|| ValueConvertError::UnexpectedNullValue(stringify!($t)))?;
591                value.$f().ok_or_else(|| ValueConvertError::UnexpectedType {
592                    expected: stringify!($t),
593                    got: value.datum_type().description(),
594                })
595            }
596        }
597
598        impl TryFromValue for Option<$t> {
599            type Error = ValueConvertError;
600            fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error> {
601                value
602                    .map(|value| TryFromValue::try_from_value(Some(value)))
603                    .transpose()
604            }
605        }
606    };
607}
608
609macro_rules! try_from_value_unsigned {
610    ($it:ty, $t:ty) => {
611        impl TryFromValue for $t {
612            type Error = ValueConvertError;
613            fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error> {
614                let value: $it = TryFromValue::try_from_value(value)?;
615                value
616                    .try_into()
617                    .map_err(|_| ValueConvertError::ValueOutOfRange {
618                        expected: stringify!($t),
619                    })
620            }
621        }
622
623        impl TryFromValue for Option<$t> {
624            type Error = ValueConvertError;
625            fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error> {
626                value
627                    .map(|value| TryFromValue::try_from_value(Some(value)))
628                    .transpose()
629            }
630        }
631    };
632}
633
634macro_rules! try_from_value_owned {
635    ($t:ty, $f:ident) => {
636        impl TryFromValue for $t {
637            type Error = ValueConvertError;
638            fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error> {
639                let value =
640                    value.ok_or_else(|| ValueConvertError::UnexpectedNullValue(stringify!($t)))?;
641                value
642                    .$f()
643                    .map_err(|value| ValueConvertError::UnexpectedType {
644                        expected: stringify!($t),
645                        got: value.datum_type().description(),
646                    })
647            }
648        }
649
650        impl TryFromValue for Option<$t> {
651            type Error = ValueConvertError;
652            fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error> {
653                value
654                    .map(|value| {
655                        value
656                            .$f()
657                            .map_err(|value| ValueConvertError::UnexpectedType {
658                                expected: stringify!($t),
659                                got: value.datum_type().description(),
660                            })
661                    })
662                    .transpose()
663            }
664        }
665    };
666}
667
668try_from_value_copy![bool, to_bool];
669try_from_value_copy![i8, to_i8];
670try_from_value_unsigned![i8, u8];
671try_from_value_copy![i16, to_i16];
672try_from_value_unsigned![i16, u16];
673try_from_value_copy![i32, to_i32];
674try_from_value_unsigned![i32, u32];
675try_from_value_copy![i64, to_i64];
676try_from_value_unsigned![i64, u64];
677try_from_value_copy![f32, to_f32];
678try_from_value_copy![f64, to_f64];
679try_from_value_owned![String, into_string];
680try_from_value_owned![SqlTimestamp, into_timestamp];
681#[cfg(feature = "chrono")]
682try_from_value_copy![NaiveDateTime, to_naive_date_time];
683try_from_value_owned![SqlDate, into_date];
684#[cfg(feature = "chrono")]
685try_from_value_copy![NaiveDate, to_naive_date];
686try_from_value_owned![SqlSsTime2, into_time];
687#[cfg(feature = "chrono")]
688try_from_value_copy![NaiveTime, to_naive_time];
689#[cfg(feature = "serde_json")]
690try_from_value_owned![Json, into_json];
691
692#[cfg(feature = "serde")]
693mod ser {
694    use super::*;
695    use serde::{self, Serialize};
696
697    impl Serialize for Value {
698        #[inline]
699        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
700        where
701            S: ::serde::Serializer,
702        {
703            match *self {
704                Value::Bit(b) => serializer.serialize_bool(b),
705                Value::Tinyint(n) => serializer.serialize_i8(n),
706                Value::Smallint(n) => serializer.serialize_i16(n),
707                Value::Integer(n) => serializer.serialize_i32(n),
708                Value::Bigint(n) => serializer.serialize_i64(n),
709                Value::Float(n) => serializer.serialize_f32(n),
710                Value::Double(n) => serializer.serialize_f64(n),
711                #[cfg(feature = "rust_decimal")]
712                Value::Decimal(n) => Serialize::serialize(&n, serializer),
713                Value::String(ref s) => serializer.serialize_str(s),
714                ref value @ Value::Timestamp(_)
715                | ref value @ Value::Date(_)
716                | ref value @ Value::Time(_) => serializer.serialize_str(&value.to_string()),
717                #[cfg(feature = "serde_json")]
718                Value::Json(ref j) => j.serialize(serializer),
719            }
720        }
721    }
722
723    #[cfg(test)]
724    mod tests {
725        use super::*;
726
727        #[test]
728        fn serialize_value_primitive() {
729            assert_eq!(&serde_json::to_string(&Value::Bit(true)).unwrap(), "true");
730            assert_eq!(&serde_json::to_string(&Value::Bit(false)).unwrap(), "false");
731
732            assert_eq!(&serde_json::to_string(&Value::Integer(-1)).unwrap(), "-1");
733            assert_eq!(&serde_json::to_string(&Value::Integer(22)).unwrap(), "22");
734
735            assert_eq!(
736                &serde_json::to_string(&Value::Double(-1.1)).unwrap(),
737                "-1.1"
738            );
739            assert_eq!(
740                &serde_json::to_string(&Value::Double(33.22)).unwrap(),
741                "33.22"
742            );
743
744            assert_eq!(
745                &serde_json::to_string(&Value::String("foo".to_owned())).unwrap(),
746                "\"foo\""
747            );
748            assert_eq!(
749                &serde_json::to_string(&Value::String("bar baz".to_owned())).unwrap(),
750                "\"bar baz\""
751            );
752        }
753
754        #[cfg(feature = "rust_decimal")]
755        #[test]
756        fn serialize_value_decimal() {
757            use std::str::FromStr;
758
759            assert_eq!(
760                &serde_json::to_string(&Value::Decimal(Decimal::from_str("-1.1").unwrap())).unwrap(),
761                "\"-1.1\""
762            );
763            assert_eq!(
764                &serde_json::to_string(&Value::Decimal(Decimal::from_str("33.22").unwrap())).unwrap(),
765                "\"33.22\""
766            );
767            assert_eq!(
768                &serde_json::to_string(&Value::Decimal(Decimal::from_str("10.9231213232423424323423234234").unwrap())).unwrap(),
769                "\"10.923121323242342432342323423\""
770            );
771        }
772
773        #[cfg(feature = "chrono")]
774        #[test]
775        fn serialize_value_timestamp() {
776            assert_eq!(
777                &serde_json::to_string(&Value::from(
778                    NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 11, 23)
779                ))
780                .unwrap(),
781                "\"2016-07-08 09:10:11.023\""
782            );
783            assert_eq!(
784                &serde_json::to_string(&Value::from(
785                    NaiveDate::from_ymd(2016, 12, 8).and_hms_milli(19, 1, 1, 0)
786                ))
787                .unwrap(),
788                "\"2016-12-08 19:01:01.000\""
789            );
790        }
791
792        #[cfg(feature = "chrono")]
793        #[test]
794        fn serialize_value_date() {
795            assert_eq!(
796                &serde_json::to_string(&Value::from(NaiveDate::from_ymd(2016, 7, 8))).unwrap(),
797                "\"2016-07-08\""
798            );
799            assert_eq!(
800                &serde_json::to_string(&Value::from(NaiveDate::from_ymd(2016, 12, 8))).unwrap(),
801                "\"2016-12-08\""
802            );
803        }
804
805        #[cfg(feature = "chrono")]
806        #[test]
807        fn serialize_value_time() {
808            assert_eq!(
809                &serde_json::to_string(&Value::from(NaiveTime::from_hms_milli(9, 10, 11, 23)))
810                    .unwrap(),
811                "\"09:10:11.023\""
812            );
813            assert_eq!(
814                &serde_json::to_string(&Value::from(NaiveTime::from_hms_milli(19, 1, 1, 0)))
815                    .unwrap(),
816                "\"19:01:01.000\""
817            );
818        }
819    }
820}