Skip to content

Commit 3a6ca10

Browse files
authored
Merge pull request #104 from mathstuf/support-aliases
graphql_query_derive: support aliases in queries
2 parents f495ee7 + 723e948 commit 3a6ca10

File tree

7 files changed

+89
-5
lines changed

7 files changed

+89
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
4040

4141
- Improved some codegen error messages, giving more context. Thank @mathstuf!
4242

43+
- Aliases in queries are now supported.
44+
4345
### Fixed
4446

4547
- Handle all Rust keywords as field names in codegen by appending `_` to the generated names, so a field called `type` in a GraphQL query will become a `type_` field in the generated struct. Thanks to @scrogson!

graphql_query_derive/src/selection.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use graphql_parser::query::SelectionSet;
33

44
#[derive(Clone, Debug, PartialEq)]
55
pub struct SelectionField {
6+
pub alias: Option<String>,
67
pub name: String,
78
pub fields: Selection,
89
}
@@ -54,6 +55,7 @@ impl<'a> ::std::convert::From<&'a SelectionSet> for Selection {
5455
for item in &selection_set.items {
5556
let converted = match item {
5657
Selection::Field(f) => SelectionItem::Field(SelectionField {
58+
alias: f.alias.as_ref().map(|alias| alias.to_string()),
5759
name: f.name.to_string(),
5860
fields: (&f.selection_set).into(),
5961
}),
@@ -99,6 +101,7 @@ mod tests {
99101
rating
100102
}
101103
pawsCount
104+
aliased: sillyName
102105
}
103106
}
104107
"##;
@@ -123,34 +126,45 @@ mod tests {
123126
assert_eq!(
124127
selection,
125128
Selection(vec![SelectionItem::Field(SelectionField {
129+
alias: None,
126130
name: "animal".to_string(),
127131
fields: Selection(vec![
128132
SelectionItem::Field(SelectionField {
133+
alias: None,
129134
name: "isCat".to_string(),
130135
fields: Selection(Vec::new()),
131136
}),
132137
SelectionItem::Field(SelectionField {
138+
alias: None,
133139
name: "isHorse".to_string(),
134140
fields: Selection(Vec::new()),
135141
}),
136142
SelectionItem::FragmentSpread(SelectionFragmentSpread {
137143
fragment_name: "Timestamps".to_string(),
138144
}),
139145
SelectionItem::Field(SelectionField {
146+
alias: None,
140147
name: "barks".to_string(),
141148
fields: Selection(Vec::new()),
142149
}),
143150
SelectionItem::InlineFragment(SelectionInlineFragment {
144151
on: "Dog".to_string(),
145152
fields: Selection(vec![SelectionItem::Field(SelectionField {
153+
alias: None,
146154
name: "rating".to_string(),
147155
fields: Selection(Vec::new()),
148156
})]),
149157
}),
150158
SelectionItem::Field(SelectionField {
159+
alias: None,
151160
name: "pawsCount".to_string(),
152161
fields: Selection(Vec::new()),
153162
}),
163+
SelectionItem::Field(SelectionField {
164+
alias: Some("aliased".to_string()),
165+
name: "sillyName".to_string(),
166+
fields: Selection(Vec::new()),
167+
}),
154168
]),
155169
})])
156170
);

graphql_query_derive/src/shared.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,19 @@ pub(crate) fn field_impls_for_selection(
7272
.iter()
7373
.map(|selected| {
7474
if let SelectionItem::Field(selected) = selected {
75+
let name = &selected.name;
76+
let alias = selected.alias.as_ref().unwrap_or(name);
77+
7578
let ty = fields
7679
.iter()
77-
.find(|f| f.name == selected.name)
78-
.ok_or_else(|| format_err!("could not find field `{}`", selected.name))?
80+
.find(|f| &f.name == name)
81+
.ok_or_else(|| format_err!("could not find field `{}`", name))?
7982
.type_
8083
.inner_name_string();
8184
let prefix = format!(
8285
"{}{}",
8386
prefix.to_camel_case(),
84-
selected.name.to_camel_case()
87+
alias.to_camel_case()
8588
);
8689
context.maybe_expand_field(&ty, &selected.fields, &prefix)
8790
} else {
@@ -103,18 +106,19 @@ pub(crate) fn response_fields_for_selection(
103106
.map(|item| match item {
104107
SelectionItem::Field(f) => {
105108
let name = &f.name;
109+
let alias = f.alias.as_ref().unwrap_or(name);
106110

107111
let schema_field = &schema_fields
108112
.iter()
109113
.find(|field| field.name.as_str() == name.as_str())
110114
.ok_or_else(|| format_err!("Could not find field: {}", name.as_str()))?;
111115
let ty = schema_field.type_.to_rust(
112116
context,
113-
&format!("{}{}", prefix.to_camel_case(), name.to_camel_case()),
117+
&format!("{}{}", prefix.to_camel_case(), alias.to_camel_case()),
114118
);
115119

116120
Ok(render_object_field(
117-
name,
121+
alias,
118122
&ty,
119123
schema_field.description.as_ref().map(|s| s.as_str()),
120124
&schema_field.deprecation,

graphql_query_derive/src/unions.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,15 @@ mod tests {
151151
SelectionItem::InlineFragment(SelectionInlineFragment {
152152
on: "User".to_string(),
153153
fields: Selection(vec![SelectionItem::Field(SelectionField {
154+
alias: None,
154155
name: "firstName".to_string(),
155156
fields: Selection(vec![]),
156157
})]),
157158
}),
158159
SelectionItem::InlineFragment(SelectionInlineFragment {
159160
on: "Organization".to_string(),
160161
fields: Selection(vec![SelectionItem::Field(SelectionField {
162+
alias: None,
161163
name: "title".to_string(),
162164
fields: Selection(vec![]),
163165
})]),
@@ -236,19 +238,22 @@ mod tests {
236238
fn union_response_for_selection_works() {
237239
let fields = vec![
238240
SelectionItem::Field(SelectionField {
241+
alias: None,
239242
name: "__typename".to_string(),
240243
fields: Selection(vec![]),
241244
}),
242245
SelectionItem::InlineFragment(SelectionInlineFragment {
243246
on: "User".to_string(),
244247
fields: Selection(vec![SelectionItem::Field(SelectionField {
248+
alias: None,
245249
name: "firstName".to_string(),
246250
fields: Selection(vec![]),
247251
})]),
248252
}),
249253
SelectionItem::InlineFragment(SelectionInlineFragment {
250254
on: "Organization".to_string(),
251255
fields: Selection(vec![SelectionItem::Field(SelectionField {
256+
alias: None,
252257
name: "title".to_string(),
253258
fields: Selection(vec![]),
254259
})]),

tests/alias.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#[macro_use]
2+
extern crate graphql_client;
3+
extern crate serde;
4+
#[macro_use]
5+
extern crate serde_derive;
6+
#[macro_use]
7+
extern crate serde_json;
8+
9+
#[derive(GraphQLQuery)]
10+
#[graphql(
11+
query_path = "tests/alias/query.graphql",
12+
schema_path = "tests/alias/schema.graphql"
13+
)]
14+
#[allow(dead_code)]
15+
struct AliasQuery;
16+
17+
#[test]
18+
fn alias() {
19+
let valid_response = json!({
20+
"alias": "127.0.1.2",
21+
"outer_alias": {
22+
"inner_alias": "inner value",
23+
},
24+
});
25+
26+
let _type_name_test = alias_query::RustAliasQueryOuterAlias {
27+
inner_alias: None,
28+
};
29+
30+
let valid_alias =
31+
serde_json::from_value::<alias_query::ResponseData>(valid_response).unwrap();
32+
33+
assert_eq!(
34+
valid_alias.alias.unwrap(),
35+
"127.0.1.2"
36+
);
37+
assert_eq!(
38+
valid_alias.outer_alias.unwrap().inner_alias.unwrap(),
39+
"inner value"
40+
);
41+
}

tests/alias/query.graphql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
query AliasQuery {
2+
alias: address
3+
outer_alias: nested {
4+
inner_alias: inner
5+
}
6+
}

tests/alias/schema.graphql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
schema {
2+
query: QueryRoot
3+
}
4+
5+
type QueryNest {
6+
inner: String
7+
}
8+
9+
type QueryRoot {
10+
address: String
11+
nested: QueryNest
12+
}

0 commit comments

Comments
 (0)