Skip to content

Commit 88f2875

Browse files
authored
Merge pull request #476 from willfindlay/pr/willfindlay/int-ids
codegen: enable ids to be deserialized from strings or integers
2 parents 381d41e + 89d0e6b commit 88f2875

File tree

6 files changed

+97
-0
lines changed

6 files changed

+97
-0
lines changed

graphql_client/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub use graphql_query_derive::*;
3030
))]
3131
pub mod reqwest;
3232

33+
pub mod serde_with;
34+
3335
use serde::{Deserialize, Serialize};
3436
use std::collections::HashMap;
3537
use std::fmt::{self, Display, Write};

graphql_client/src/serde_with.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! Helpers for overriding default serde implementations.
2+
3+
use serde::{Deserialize, Deserializer};
4+
5+
/// Deserialize an optional ID type from either a String or an Integer representation.
6+
///
7+
/// This is used by the codegen to enable String IDs to be deserialized from
8+
/// either Strings or Integers.
9+
pub fn deserialize_option_id<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
10+
where
11+
D: Deserializer<'de>,
12+
{
13+
#[derive(Deserialize)]
14+
#[serde(untagged)]
15+
enum IntOrString {
16+
Int(i64),
17+
Str(String),
18+
}
19+
20+
let res = Option::<IntOrString>::deserialize(deserializer)?;
21+
22+
Ok(match res {
23+
None => None,
24+
Some(IntOrString::Int(n)) => Some(n.to_string()),
25+
Some(IntOrString::Str(s)) => Some(s),
26+
})
27+
}

graphql_client/tests/int_id.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use graphql_client::*;
2+
use serde_json::json;
3+
4+
#[derive(GraphQLQuery)]
5+
#[graphql(
6+
schema_path = "tests/more_derives/schema.graphql",
7+
query_path = "tests/more_derives/query.graphql",
8+
response_derives = "Debug, PartialEq, Eq, std::cmp::PartialOrd"
9+
)]
10+
pub struct MoreDerives;
11+
12+
#[test]
13+
fn int_id() {
14+
let response1 = json!({
15+
"currentUser": {
16+
"id": 1,
17+
"name": "Don Draper",
18+
}
19+
});
20+
21+
let response2 = json!({
22+
"currentUser": {
23+
"id": "2",
24+
"name": "Peggy Olson",
25+
}
26+
});
27+
28+
let res1 = serde_json::from_value::<more_derives::ResponseData>(response1)
29+
.expect("should deserialize");
30+
assert_eq!(
31+
res1.current_user.expect("res1 current user").id,
32+
Some("1".into())
33+
);
34+
35+
let res2 = serde_json::from_value::<more_derives::ResponseData>(response2)
36+
.expect("should deserialize");
37+
assert_eq!(
38+
res2.current_user.expect("res2 current user").id,
39+
Some("2".into())
40+
);
41+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
query MoreDerives {
2+
currentUser {
3+
name
4+
id
5+
}
6+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
schema {
2+
query: TestQuery
3+
}
4+
5+
type TestQuery {
6+
currentUser: TestUser
7+
}
8+
9+
type TestUser {
10+
name: String
11+
id: ID
12+
}

graphql_client_codegen/src/codegen/selection.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,14 @@ impl ExpandedField<'_> {
405405
qualified_type
406406
};
407407

408+
let id_deserialize_with = if self.field_type == "ID" {
409+
Some(
410+
quote!(#[serde(deserialize_with = "graphql_client::serde_with::deserialize_option_id")]),
411+
)
412+
} else {
413+
None
414+
};
415+
408416
let optional_skip_serializing_none = if *options.skip_serializing_none()
409417
&& self
410418
.field_type_qualifiers
@@ -443,6 +451,7 @@ impl ExpandedField<'_> {
443451
#optional_flatten
444452
#optional_rename
445453
#optional_deprecation_annotation
454+
#id_deserialize_with
446455
pub #ident: #qualified_type
447456
};
448457

0 commit comments

Comments
 (0)