Skip to content

Commit 883babd

Browse files
authored
Merge pull request #84 from tomhoule/introspection-query-bug
Fix issues from #83
2 parents 96e2f98 + 93bb6ba commit 883babd

14 files changed

+6232
-37
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ language: rust
22
rust:
33
- stable
44
- beta
5-
- nightly
5+
# - nightly
66
cache: cargo
77
before_script:
88
- if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then (rustup component add rustfmt-preview clippy-preview) fi

CHANGELOG.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## Unreleased
99

10+
There are a number of breaking new features, read the `Added` section attentively if you are upgrading.
11+
1012
### Added
1113

1214
- (breaking) Control over which types custom scalars deserialize to is given to the user: you now have to provide type aliases for the custom scalars in the scope of the struct under derive.
1315
- (breaking) Support for multi-operations documents. You can select a particular operation by naming the struct under derive after it. In case there is no match, we revert to the current behaviour: select the first operation.
14-
- Support arbitrary derives on the generated response types via the `response_derives` option on the `graphql` attribute.
16+
- (breaking) Support arbitrary derives on the generated response types via the `response_derives` option on the `graphql` attribute. If you were relying on the `Debug` impl on generated structs before, you need to add `response_derives = "Debug"` in the `#[graphql()]` attributes in your structs.
17+
18+
### Fixed
19+
20+
- Fixed codegen of fields with leading underscores - they were ignored, leading to wrong derived types for deserialization.
21+
- Made the CLI dump introspected schemas directly without trying to validate them.
1522

1623
## [0.3.0] - 2018-07-24
1724

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,12 @@ A typed GraphQL client library for Rust.
6262
extern crate graphql_client;
6363
extern crate reqwest;
6464

65+
use graphql_client::{GraphQLQuery, GraphQLResponse};
66+
6567
fn perform_my_query(variables: &my_query::Variables) -> Result<(), failure::Error> {
6668

6769
// this is the important line
68-
let request_body = MyQuery::expand(variables);
70+
let request_body = MyQuery::build_query(variables);
6971

7072
let client = reqwest::Client::new();
7173
let mut res = client.post("/graphql").json(&request_body).send()?;

graphql_client_cli/src/main.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use structopt::StructOpt;
1616
#[graphql(
1717
schema_path = "src/introspection_schema.graphql",
1818
query_path = "src/introspection_query.graphql",
19-
response_derives = "Serialize",
19+
response_derives = "Serialize"
2020
)]
2121
struct IntrospectionQuery;
2222

@@ -86,10 +86,6 @@ fn introspect_schema(location: String, output: Option<PathBuf>) -> Result<(), fa
8686
println!("Something else happened. Status: {:?}", res.status());
8787
}
8888

89-
let json: graphql_client::GraphQLResponse<introspection_query::ResponseData> = res.json()?;
90-
let json = serde_json::to_string(&json)?;
91-
92-
write!(out, "{}", json)?;
93-
94-
Ok(())
89+
let json: serde_json::Value = res.json()?;
90+
Ok(serde_json::to_writer_pretty(out, &json)?)
9591
}

graphql_query_derive/src/codegen.rs

-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ pub(crate) fn response_for_query(
132132
#variables_struct
133133

134134
#response_derives
135-
#[serde(rename_all = "camelCase")]
136135
pub struct ResponseData {
137136
#(#response_data_fields,)*
138137
}

graphql_query_derive/src/inputs.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@ impl GqlInput {
2222
fields.sort_unstable_by(|a, b| a.name.cmp(&b.name));
2323
let fields = fields.iter().map(|field| {
2424
let ty = field.type_.to_rust(&context, "");
25-
let name = Ident::new(&field.name.to_snake_case(), Span::call_site());
26-
quote!(pub #name: #ty)
25+
let original_name = &field.name;
26+
let snake_case_name = field.name.to_snake_case();
27+
let rename = ::shared::field_rename_annotation(&original_name, &snake_case_name);
28+
let name = Ident::new(&snake_case_name, Span::call_site());
29+
30+
quote!(#rename pub #name: #ty)
2731
});
2832

2933
Ok(quote! {
3034
#[derive(Debug, Serialize)]
31-
#[serde(rename_all = "camelCase")]
3235
pub struct #name {
3336
#(#fields,)*
3437
}
@@ -132,9 +135,9 @@ mod tests {
132135

133136
let expected: String = vec![
134137
"# [ derive ( Debug , Serialize ) ] ",
135-
"# [ serde ( rename_all = \"camelCase\" ) ] ",
136138
"pub struct Cat { ",
137139
"pub offsprings : Vec < Cat > , ",
140+
"# [ serde ( rename = \"pawsCount\" ) ] ",
138141
"pub paws_count : Float , ",
139142
"pub requirements : Option < CatRequirements > , ",
140143
"}",

graphql_query_derive/src/objects.rs

-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ impl GqlObject {
7676
#(#field_impls)*
7777

7878
#derives
79-
#[serde(rename_all = "camelCase")]
8079
#description
8180
pub struct #name {
8281
#(#fields,)*

graphql_query_derive/src/operations.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,11 @@ impl Operation {
5050
let fields = variables.iter().map(|variable| {
5151
let name = &variable.name;
5252
let ty = variable.ty.to_rust(context, "");
53-
let name = Ident::new(&name.to_snake_case(), Span::call_site());
54-
quote!(pub #name: #ty)
53+
let snake_case_name = name.to_snake_case();
54+
let rename = ::shared::field_rename_annotation(&name, &snake_case_name);
55+
let name = Ident::new(&snake_case_name, Span::call_site());
56+
57+
quote!(#rename pub #name: #ty)
5558
});
5659

5760
let default_constructors = variables
@@ -60,7 +63,6 @@ impl Operation {
6063

6164
quote! {
6265
#[derive(Serialize)]
63-
#[serde(rename_all = "camelCase")]
6466
pub struct Variables {
6567
#(#fields,)*
6668
}

graphql_query_derive/src/shared.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ pub(crate) fn render_object_field(
2020
};
2121
}
2222

23-
let name_ident = Ident::new(&field_name.to_snake_case(), Span::call_site());
23+
let snake_case_name = field_name.to_snake_case();
24+
let rename = ::shared::field_rename_annotation(&field_name, &snake_case_name);
25+
let name_ident = Ident::new(&snake_case_name, Span::call_site());
2426

25-
quote!(#description pub #name_ident: #field_type)
27+
quote!(#description #rename pub #name_ident: #field_type)
2628
}
2729

2830
pub(crate) fn field_impls_for_selection(
@@ -96,3 +98,14 @@ pub(crate) fn response_fields_for_selection(
9698
}
9799
}).collect()
98100
}
101+
102+
/// Given the GraphQL schema name for an object/interface/input object field and
103+
/// the equivalent rust name, produces a serde annotation to map them during
104+
/// (de)serialization if it is necessary, otherwise an empty TokenStream.
105+
pub(crate) fn field_rename_annotation(graphql_name: &str, rust_name: &str) -> TokenStream {
106+
if graphql_name != rust_name {
107+
quote!(#[serde(rename = #graphql_name)])
108+
} else {
109+
quote!()
110+
}
111+
}

graphql_query_derive/src/unions.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ mod tests {
150150
SelectionItem::InlineFragment(SelectionInlineFragment {
151151
on: "User".to_string(),
152152
fields: Selection(vec![SelectionItem::Field(SelectionField {
153-
name: "first_name".to_string(),
153+
name: "firstName".to_string(),
154154
fields: Selection(vec![]),
155155
})]),
156156
}),
@@ -178,17 +178,17 @@ mod tests {
178178
fields: vec![
179179
GqlObjectField {
180180
description: None,
181-
name: "first_name".to_string(),
181+
name: "firstName".to_string(),
182182
type_: FieldType::Named(Ident::new("String", Span::call_site())),
183183
},
184184
GqlObjectField {
185185
description: None,
186-
name: "last_name".to_string(),
186+
name: "lastName".to_string(),
187187
type_: FieldType::Named(Ident::new("String", Span::call_site())),
188188
},
189189
GqlObjectField {
190190
description: None,
191-
name: "created_at".to_string(),
191+
name: "createdAt".to_string(),
192192
type_: FieldType::Named(Ident::new("Date", Span::call_site())),
193193
},
194194
],
@@ -235,7 +235,7 @@ mod tests {
235235
SelectionItem::InlineFragment(SelectionInlineFragment {
236236
on: "User".to_string(),
237237
fields: Selection(vec![SelectionItem::Field(SelectionField {
238-
name: "first_name".to_string(),
238+
name: "firstName".to_string(),
239239
fields: Selection(vec![]),
240240
})]),
241241
}),
@@ -272,17 +272,17 @@ mod tests {
272272
},
273273
GqlObjectField {
274274
description: None,
275-
name: "first_name".to_string(),
275+
name: "firstName".to_string(),
276276
type_: FieldType::Named(string_type()),
277277
},
278278
GqlObjectField {
279279
description: None,
280-
name: "last_name".to_string(),
280+
name: "lastName".to_string(),
281281
type_: FieldType::Named(string_type()),
282282
},
283283
GqlObjectField {
284284
description: None,
285-
name: "created_at".to_string(),
285+
name: "createdAt".to_string(),
286286
type_: FieldType::Named(Ident::new("Date", Span::call_site())),
287287
},
288288
],
@@ -307,7 +307,7 @@ mod tests {
307307
},
308308
GqlObjectField {
309309
description: None,
310-
name: "created_at".to_string(),
310+
name: "createdAt".to_string(),
311311
type_: FieldType::Named(Ident::new("Date", Span::call_site())),
312312
},
313313
],
@@ -324,16 +324,14 @@ mod tests {
324324
result.unwrap().to_string(),
325325
vec![
326326
"# [ derive ( Deserialize ) ] ",
327-
"# [ serde ( rename_all = \"camelCase\" ) ] ",
328-
"pub struct MeowOnUser { pub first_name : String , } ",
327+
"pub struct MeowOnUser { # [ serde ( rename = \"firstName\" ) ] pub first_name : String , } ",
329328
"# [ derive ( Deserialize ) ] ",
330-
"# [ serde ( rename_all = \"camelCase\" ) ] ",
331329
"pub struct MeowOnOrganization { pub title : String , } ",
332330
"# [ derive ( Deserialize ) ] ",
333331
"# [ serde ( tag = \"__typename\" ) ] ",
334332
"pub enum Meow { User ( MeowOnUser ) , Organization ( MeowOnOrganization ) }",
335333
].into_iter()
336-
.collect::<String>(),
334+
.collect::<String>(),
337335
);
338336
}
339337
}

tests/introspection.rs

+13
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ extern crate graphql_client;
33
#[macro_use]
44
extern crate serde_derive;
55
extern crate serde;
6+
extern crate serde_json;
67

78
#[derive(GraphQLQuery)]
89
#[graphql(
910
query_path = "tests/introspection/introspection_query.graphql",
1011
schema_path = "tests/introspection/introspection_schema.graphql",
12+
response_derives = "Debug,PartialEq"
1113
)]
1214
#[allow(dead_code)]
1315
struct IntrospectionQuery;
@@ -16,3 +18,14 @@ struct IntrospectionQuery;
1618
fn introspection_schema() {
1719
()
1820
}
21+
22+
const INTROSPECTION_RESPONSE: &'static str =
23+
include_str!("./introspection/introspection_response.json");
24+
25+
#[test]
26+
fn leading_underscores_are_preserved() {
27+
let deserialized: graphql_client::GraphQLResponse<introspection_query::ResponseData> =
28+
serde_json::from_str(INTROSPECTION_RESPONSE).unwrap();
29+
assert!(deserialized.data.is_some());
30+
assert!(deserialized.data.unwrap().schema.is_some());
31+
}

tests/introspection/introspection_query.graphql

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
query IntrospectionQuery {
2-
__Schema {
2+
__schema {
33
queryType {
44
name
55
}

0 commit comments

Comments
 (0)