From 0d7685e1854c819ecafe94d8afb6eb9f87863b45 Mon Sep 17 00:00:00 2001 From: Andrew Werner Date: Mon, 10 Feb 2025 17:30:47 -0500 Subject: [PATCH] codegen: fix required ID deserialization Fixes #522 --- graphql_client/src/serde_with.rs | 40 +++++++++++++------ .../src/codegen/selection.rs | 10 +++-- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/graphql_client/src/serde_with.rs b/graphql_client/src/serde_with.rs index c408fac1..dcd5cd98 100644 --- a/graphql_client/src/serde_with.rs +++ b/graphql_client/src/serde_with.rs @@ -2,6 +2,22 @@ use serde::{Deserialize, Deserializer}; +#[derive(Deserialize)] +#[serde(untagged)] +enum IntOrString { + Int(i64), + Str(String), +} + +impl From for String { + fn from(value: IntOrString) -> Self { + match value { + IntOrString::Int(n) => n.to_string(), + IntOrString::Str(s) => s, + } + } +} + /// Deserialize an optional ID type from either a String or an Integer representation. /// /// This is used by the codegen to enable String IDs to be deserialized from @@ -10,18 +26,16 @@ pub fn deserialize_option_id<'de, D>(deserializer: D) -> Result, where D: Deserializer<'de>, { - #[derive(Deserialize)] - #[serde(untagged)] - enum IntOrString { - Int(i64), - Str(String), - } - - let res = Option::::deserialize(deserializer)?; + Option::::deserialize(deserializer).map(|opt| opt.map(String::from)) +} - Ok(match res { - None => None, - Some(IntOrString::Int(n)) => Some(n.to_string()), - Some(IntOrString::Str(s)) => Some(s), - }) +/// Deserialize an ID type from either a String or an Integer representation. +/// +/// This is used by the codegen to enable String IDs to be deserialized from +/// either Strings or Integers. +pub fn deserialize_id<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + IntOrString::deserialize(deserializer).map(String::from) } diff --git a/graphql_client_codegen/src/codegen/selection.rs b/graphql_client_codegen/src/codegen/selection.rs index 400cbe21..04e276d4 100644 --- a/graphql_client_codegen/src/codegen/selection.rs +++ b/graphql_client_codegen/src/codegen/selection.rs @@ -405,10 +405,12 @@ impl ExpandedField<'_> { qualified_type }; - let id_deserialize_with = if self.field_type == "ID" { - Some( - quote!(#[serde(deserialize_with = "graphql_client::serde_with::deserialize_option_id")]), - ) + let is_id = self.field_type == "ID"; + let is_required = self.field_type_qualifiers.contains(&GraphqlTypeQualifier::Required); + let id_deserialize_with = if is_id && is_required { + Some(quote!(#[serde(deserialize_with = "graphql_client::serde_with::deserialize_id")])) + } else if is_id { + Some(quote!(#[serde(deserialize_with = "graphql_client::serde_with::deserialize_option_id")])) } else { None };