From 844c8116792e5ddfa33799d9e34da802e0357f26 Mon Sep 17 00:00:00 2001 From: AGMBK <109393672+agmbk@users.noreply.github.com> Date: Sat, 16 Mar 2024 04:10:47 +0100 Subject: [PATCH 1/5] fix(tvshow): issue 63 Fix the issue https://github.com/jdrouet/tmdb-api/issues/63 with a custom deserializer implementation, to avoid pulling the serde_with crate. --- src/tvshow/details.rs | 2 +- src/tvshow/mod.rs | 1 + src/util/default_on_null.rs | 80 +++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/util/default_on_null.rs diff --git a/src/tvshow/details.rs b/src/tvshow/details.rs index 7cc0ffe..52e9ae1 100644 --- a/src/tvshow/details.rs +++ b/src/tvshow/details.rs @@ -165,7 +165,7 @@ mod integration_tests { let secret = std::env::var("TMDB_TOKEN_V3").unwrap(); let client = Client::new(secret); - for i in 1..5 { + for i in [1, 2, 3, 4, 5, 81040] { let result = TVShowDetails::new(i).execute(&client).await.unwrap(); assert_eq!(result.inner.id, i); } diff --git a/src/tvshow/mod.rs b/src/tvshow/mod.rs index 1fdb013..ea50621 100644 --- a/src/tvshow/mod.rs +++ b/src/tvshow/mod.rs @@ -120,6 +120,7 @@ pub struct TVShow { pub last_episode_to_air: Option, pub next_episode_to_air: Option, pub networks: Vec, + #[serde(deserialize_with = "crate::util::default_on_null::deserialize")] pub number_of_episodes: u64, pub number_of_seasons: u64, pub production_companies: Vec, diff --git a/src/util/default_on_null.rs b/src/util/default_on_null.rs new file mode 100644 index 0000000..d63ecb0 --- /dev/null +++ b/src/util/default_on_null.rs @@ -0,0 +1,80 @@ +//! Deserializes null as the default value for the type. + +use serde::{Deserialize, Deserializer, Serializer}; + +#[allow(dead_code)] +pub(crate) fn serialize(value: &T, serializer: S) -> Result + where + S: Serializer, + T: serde::Serialize, +{ + T::serialize(value, serializer) +} + +pub(crate) fn deserialize<'de, D, T>(deserializer: D) -> Result + where + D: Deserializer<'de>, + T: Deserialize<'de> + Default, +{ + Ok(Option::::deserialize(deserializer)?.unwrap_or_default()) +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + #[derive(Debug, Serialize, Deserialize)] + struct TestingStruct + where + T: for<'a> serde::Deserialize<'a> + serde::Serialize + Default, + { + #[serde(with = "super")] + value: T, + } + + + #[test] + fn should_deserialize() { + let result: TestingStruct = serde_json::from_str(r#"{"value":null}"#).unwrap(); + assert_eq!(result.value, 0); + + let result: TestingStruct = serde_json::from_str(r#"{"value":0}"#).unwrap(); + assert_eq!(result.value, 0); + + let result: TestingStruct = + serde_json::from_str(r#"{"value":10}"#).unwrap(); + assert_eq!(result.value, 10); + + let result: TestingStruct = + serde_json::from_str(r#"{"value":null}"#).unwrap(); + assert_eq!(result.value, ""); + + let result: TestingStruct> = + serde_json::from_str(r#"{"value":null}"#).unwrap(); + assert_eq!(result.value, Vec::::new()); + } + + #[test] + fn should_serialize() { + let result = serde_json::to_string(&TestingStruct:: { value: 0 }).unwrap(); + assert_eq!(result, r#"{"value":0}"#); + + let result = serde_json::to_string(&TestingStruct:: { + value: 10, + }) + .unwrap(); + assert_eq!(result, r#"{"value":10}"#); + + let result = serde_json::to_string(&TestingStruct:: { + value: "hello".to_string(), + }) + .unwrap(); + assert_eq!(result, r#"{"value":"hello"}"#); + + let result = serde_json::to_string(&TestingStruct::> { + value: vec![1, 2, 3], + }) + .unwrap(); + assert_eq!(result, r#"{"value":[1,2,3]}"#); + } +} From 16ec87f71054ebbc6cc6bd4b2bd28463096f4eaf Mon Sep 17 00:00:00 2001 From: AGMBK <109393672+agmbk@users.noreply.github.com> Date: Sat, 16 Mar 2024 04:16:10 +0100 Subject: [PATCH 2/5] test(util): default on null Removed one useless test, code formatting --- src/util/default_on_null.rs | 43 ++++++++++++------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/src/util/default_on_null.rs b/src/util/default_on_null.rs index d63ecb0..a7e1829 100644 --- a/src/util/default_on_null.rs +++ b/src/util/default_on_null.rs @@ -4,77 +4,62 @@ use serde::{Deserialize, Deserializer, Serializer}; #[allow(dead_code)] pub(crate) fn serialize(value: &T, serializer: S) -> Result - where - S: Serializer, - T: serde::Serialize, +where + S: Serializer, + T: serde::Serialize, { T::serialize(value, serializer) } pub(crate) fn deserialize<'de, D, T>(deserializer: D) -> Result - where - D: Deserializer<'de>, - T: Deserialize<'de> + Default, +where + D: Deserializer<'de>, + T: Deserialize<'de> + Default, { Ok(Option::::deserialize(deserializer)?.unwrap_or_default()) } #[cfg(test)] mod tests { - use std::str::FromStr; - #[derive(Debug, Serialize, Deserialize)] struct TestingStruct - where - T: for<'a> serde::Deserialize<'a> + serde::Serialize + Default, + where + T: for<'a> serde::Deserialize<'a> + serde::Serialize + Default, { #[serde(with = "super")] value: T, } - #[test] fn should_deserialize() { let result: TestingStruct = serde_json::from_str(r#"{"value":null}"#).unwrap(); assert_eq!(result.value, 0); - let result: TestingStruct = serde_json::from_str(r#"{"value":0}"#).unwrap(); - assert_eq!(result.value, 0); - - let result: TestingStruct = - serde_json::from_str(r#"{"value":10}"#).unwrap(); + let result: TestingStruct = serde_json::from_str(r#"{"value":10}"#).unwrap(); assert_eq!(result.value, 10); - let result: TestingStruct = - serde_json::from_str(r#"{"value":null}"#).unwrap(); + let result: TestingStruct = serde_json::from_str(r#"{"value":null}"#).unwrap(); assert_eq!(result.value, ""); - let result: TestingStruct> = - serde_json::from_str(r#"{"value":null}"#).unwrap(); + let result: TestingStruct> = serde_json::from_str(r#"{"value":null}"#).unwrap(); assert_eq!(result.value, Vec::::new()); } #[test] fn should_serialize() { - let result = serde_json::to_string(&TestingStruct:: { value: 0 }).unwrap(); - assert_eq!(result, r#"{"value":0}"#); - - let result = serde_json::to_string(&TestingStruct:: { - value: 10, - }) - .unwrap(); + let result = serde_json::to_string(&TestingStruct:: { value: 10 }).unwrap(); assert_eq!(result, r#"{"value":10}"#); let result = serde_json::to_string(&TestingStruct:: { value: "hello".to_string(), }) - .unwrap(); + .unwrap(); assert_eq!(result, r#"{"value":"hello"}"#); let result = serde_json::to_string(&TestingStruct::> { value: vec![1, 2, 3], }) - .unwrap(); + .unwrap(); assert_eq!(result, r#"{"value":[1,2,3]}"#); } } From 06bc62288ce4dea5ede2aed1d68a1655464aaeed Mon Sep 17 00:00:00 2001 From: AGMBK <109393672+agmbk@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:48:45 +0200 Subject: [PATCH 3/5] fix(util): default on null --- src/util/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/mod.rs b/src/util/mod.rs index 5adfdf0..3ce82a4 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -2,3 +2,4 @@ pub(crate) mod date; pub(crate) mod empty_date; pub(crate) mod empty_string; pub(crate) mod optional_date; +pub(crate) mod default_on_null; From 75daa9fc9c27b23f4b1f599e71192a35ab93126f Mon Sep 17 00:00:00 2001 From: AGMBK <109393672+agmbk@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:37:21 +0200 Subject: [PATCH 4/5] fix(tvshow): remove default on null, make `episodes_count` nullable --- src/tvshow/mod.rs | 6 ++-- src/util/default_on_null.rs | 65 ------------------------------------- src/util/mod.rs | 1 - 3 files changed, 4 insertions(+), 68 deletions(-) delete mode 100644 src/util/default_on_null.rs diff --git a/src/tvshow/mod.rs b/src/tvshow/mod.rs index ea50621..75b024f 100644 --- a/src/tvshow/mod.rs +++ b/src/tvshow/mod.rs @@ -120,8 +120,10 @@ pub struct TVShow { pub last_episode_to_air: Option, pub next_episode_to_air: Option, pub networks: Vec, - #[serde(deserialize_with = "crate::util::default_on_null::deserialize")] - pub number_of_episodes: u64, + /// Very unlikely to be [None], + /// but in such cases the number of episodes could be computed + /// by summing the `episodes_count` of the `seasons` field. + pub number_of_episodes: Option, pub number_of_seasons: u64, pub production_companies: Vec, pub production_countries: Vec, diff --git a/src/util/default_on_null.rs b/src/util/default_on_null.rs deleted file mode 100644 index a7e1829..0000000 --- a/src/util/default_on_null.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Deserializes null as the default value for the type. - -use serde::{Deserialize, Deserializer, Serializer}; - -#[allow(dead_code)] -pub(crate) fn serialize(value: &T, serializer: S) -> Result -where - S: Serializer, - T: serde::Serialize, -{ - T::serialize(value, serializer) -} - -pub(crate) fn deserialize<'de, D, T>(deserializer: D) -> Result -where - D: Deserializer<'de>, - T: Deserialize<'de> + Default, -{ - Ok(Option::::deserialize(deserializer)?.unwrap_or_default()) -} - -#[cfg(test)] -mod tests { - #[derive(Debug, Serialize, Deserialize)] - struct TestingStruct - where - T: for<'a> serde::Deserialize<'a> + serde::Serialize + Default, - { - #[serde(with = "super")] - value: T, - } - - #[test] - fn should_deserialize() { - let result: TestingStruct = serde_json::from_str(r#"{"value":null}"#).unwrap(); - assert_eq!(result.value, 0); - - let result: TestingStruct = serde_json::from_str(r#"{"value":10}"#).unwrap(); - assert_eq!(result.value, 10); - - let result: TestingStruct = serde_json::from_str(r#"{"value":null}"#).unwrap(); - assert_eq!(result.value, ""); - - let result: TestingStruct> = serde_json::from_str(r#"{"value":null}"#).unwrap(); - assert_eq!(result.value, Vec::::new()); - } - - #[test] - fn should_serialize() { - let result = serde_json::to_string(&TestingStruct:: { value: 10 }).unwrap(); - assert_eq!(result, r#"{"value":10}"#); - - let result = serde_json::to_string(&TestingStruct:: { - value: "hello".to_string(), - }) - .unwrap(); - assert_eq!(result, r#"{"value":"hello"}"#); - - let result = serde_json::to_string(&TestingStruct::> { - value: vec![1, 2, 3], - }) - .unwrap(); - assert_eq!(result, r#"{"value":[1,2,3]}"#); - } -} diff --git a/src/util/mod.rs b/src/util/mod.rs index 3ce82a4..5adfdf0 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -2,4 +2,3 @@ pub(crate) mod date; pub(crate) mod empty_date; pub(crate) mod empty_string; pub(crate) mod optional_date; -pub(crate) mod default_on_null; From c324f7a30297a01e3060d3976bef328f528a6c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Drouet?= Date: Tue, 2 Apr 2024 16:31:05 +0200 Subject: [PATCH 5/5] fix(tvshow): update comment --- src/tvshow/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tvshow/mod.rs b/src/tvshow/mod.rs index 75b024f..3169d22 100644 --- a/src/tvshow/mod.rs +++ b/src/tvshow/mod.rs @@ -120,9 +120,8 @@ pub struct TVShow { pub last_episode_to_air: Option, pub next_episode_to_air: Option, pub networks: Vec, - /// Very unlikely to be [None], - /// but in such cases the number of episodes could be computed - /// by summing the `episodes_count` of the `seasons` field. + /// Unlikely to be `None` but found with 81040. + /// In this case, could be computed by summing the `episodes_count` of the `seasons` field. pub number_of_episodes: Option, pub number_of_seasons: u64, pub production_companies: Vec,