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#[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
36impl 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 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#[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 fn as_nullable(&self) -> NullableValue {
517 self.as_nullable_as("NULL")
518 }
519
520 fn as_nullable_as(&self, null: &'static str) -> NullableValue;
522}
523
524impl AsNullable for Option<Value> {
526 fn as_nullable_as(&self, null: &'static str) -> NullableValue {
527 NullableValue(&self, null)
528 }
529}
530
531pub trait TryFromValue: Sized {
535 type Error: Error + 'static;
536 fn try_from_value(value: Option<Value>) -> Result<Self, Self::Error>;
537}
538
539#[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}