Skip to content

Commit

Permalink
RUST-1987 Add serde helper module for Option<DateTime> (#482)
Browse files Browse the repository at this point in the history
  • Loading branch information
lazureykis authored Jul 15, 2024
1 parent 0ed3635 commit b554142
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/serde_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ pub use chrono_datetime_as_bson_datetime::{
deserialize as deserialize_chrono_datetime_from_bson_datetime,
serialize as serialize_chrono_datetime_as_bson_datetime,
};
#[cfg(feature = "chrono-0_4")]
#[doc(inline)]
pub use chrono_datetime_as_bson_datetime_optional::{
deserialize as deserialize_chrono_datetime_from_bson_datetime_optional,
serialize as serialize_chrono_datetime_as_bson_datetime_optional,
};
#[doc(inline)]
pub use hex_string_as_object_id::{
deserialize as deserialize_hex_string_from_object_id,
Expand Down Expand Up @@ -307,6 +313,51 @@ pub mod chrono_datetime_as_bson_datetime {
}
}

/// Contains functions to serialize an [`Option<chrono::DateTime>`] as an
/// [`Option<crate::DateTime>`] and deserialize an [`Option<chrono::DateTime>`] from an
/// [`Option<crate::DateTime>`].
///
/// ```rust
/// # #[cfg(feature = "chrono-0_4")]
/// # {
/// # use serde::{Serialize, Deserialize};
/// # use bson::serde_helpers::chrono_datetime_as_bson_datetime_optional;
/// #[derive(Serialize, Deserialize)]
/// struct Event {
/// #[serde(with = "chrono_datetime_as_bson_datetime_optional")]
/// pub date: Option<chrono::DateTime<chrono::Utc>>,
/// }
/// # }
/// ```
#[cfg(feature = "chrono-0_4")]
#[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
pub mod chrono_datetime_as_bson_datetime_optional {
use crate::DateTime;
use chrono::Utc;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::result::Result;

/// Deserializes a [`chrono::DateTime`] from a [`crate::DateTime`].
#[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<chrono::DateTime<Utc>>, D::Error>
where
D: Deserializer<'de>,
{
let val = Option::deserialize(deserializer)?.map(|datetime: DateTime| datetime.to_chrono());
Ok(val)
}

/// Serializes a [`Option<chrono::DateTime>`] as a [`Option<crate::DateTime>`].
#[cfg_attr(docsrs, doc(cfg(feature = "chrono-0_4")))]
pub fn serialize<S: Serializer>(
val: &Option<chrono::DateTime<Utc>>,
serializer: S,
) -> Result<S::Ok, S::Error> {
let datetime = val.map(DateTime::from_chrono);
datetime.serialize(serializer)
}
}

/// Contains functions to serialize an RFC 3339 (ISO 8601) formatted string as a [`crate::DateTime`]
/// and deserialize an RFC 3339 (ISO 8601) formatted string from a [`crate::DateTime`].
///
Expand Down
53 changes: 53 additions & 0 deletions src/tests/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,59 @@ fn test_datetime_helpers() {
assert_eq!(b.date, expected);
}

#[cfg(feature = "chrono-0_4")]
{
use std::str::FromStr;
#[derive(Deserialize, Serialize)]
struct B {
#[serde(with = "serde_helpers::chrono_datetime_as_bson_datetime_optional")]
pub date: Option<chrono::DateTime<chrono::Utc>>,
}

let date = r#"
{
"date": {
"$date": {
"$numberLong": "1591700287095"
}
}
}"#;
let json: serde_json::Value = serde_json::from_str(date).unwrap();
let b: B = serde_json::from_value(json).unwrap();
let expected: Option<chrono::DateTime<chrono::Utc>> =
Some(chrono::DateTime::from_str("2020-06-09 10:58:07.095 UTC").unwrap());
assert_eq!(b.date, expected);
let doc = to_document(&b).unwrap();
assert_eq!(
Some(doc.get_datetime("date").unwrap().to_chrono()),
expected
);
let b: B = from_document(doc).unwrap();
assert_eq!(b.date, expected);
}

#[cfg(feature = "chrono-0_4")]
{
#[derive(Deserialize, Serialize)]
struct B {
#[serde(with = "serde_helpers::chrono_datetime_as_bson_datetime_optional")]
pub date: Option<chrono::DateTime<chrono::Utc>>,
}

let date = r#"
{
"date": null
}"#;
let json: serde_json::Value = serde_json::from_str(date).unwrap();
let b: B = serde_json::from_value(json).unwrap();
let expected = None;
assert_eq!(b.date, expected);
let doc = to_document(&b).unwrap();
assert_eq!(None, expected);
let b: B = from_document(doc).unwrap();
assert_eq!(b.date, expected);
}

#[derive(Deserialize, Serialize)]
struct C {
#[serde(with = "rfc3339_string_as_bson_datetime")]
Expand Down

0 comments on commit b554142

Please sign in to comment.