Skip to content

Commit fc123fe

Browse files
authored
Merge pull request #7 from tomhoule/unions
Convert usages of graphql_parser SelectionSet to internal Selection
2 parents 108e49c + 3c351ab commit fc123fe

File tree

7 files changed

+89
-39
lines changed

7 files changed

+89
-39
lines changed

graphql_query_derive/src/fragments.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use graphql_parser::query::SelectionSet;
1+
use selection::Selection;
22
use proc_macro2::{Ident, Span, TokenStream};
33
use query::QueryContext;
44

55
#[derive(Debug, PartialEq)]
66
pub struct GqlFragment {
77
pub name: String,
88
pub on: String,
9-
pub selection: SelectionSet,
9+
pub selection: Selection,
1010
}
1111

1212
impl GqlFragment {

graphql_query_derive/src/interfaces.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use graphql_parser::query;
1+
use selection::Selection;
22
use objects::GqlObjectField;
33
use proc_macro2::{Ident, Span, TokenStream};
44
use query::QueryContext;
@@ -14,7 +14,7 @@ impl GqlInterface {
1414
pub fn response_for_selection(
1515
&self,
1616
_query_context: &QueryContext,
17-
_selection: &query::SelectionSet,
17+
_selection: &Selection,
1818
prefix: &str,
1919
) -> TokenStream {
2020
let name = Ident::new(&prefix, Span::call_site());

graphql_query_derive/src/objects.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use failure;
22
use field_type::FieldType;
3-
use graphql_parser::query;
43
use heck::{CamelCase, SnakeCase};
54
use proc_macro2::{Ident, Span, TokenStream};
65
use query::QueryContext;
76
use shared::render_object_field;
7+
use selection::*;
88

99
#[derive(Debug, PartialEq)]
1010
pub struct GqlObject {
@@ -22,7 +22,7 @@ impl GqlObject {
2222
pub fn response_for_selection(
2323
&self,
2424
query_context: &QueryContext,
25-
selection: &query::SelectionSet,
25+
selection: &Selection,
2626
prefix: &str,
2727
) -> Result<TokenStream, failure::Error> {
2828
let name = Ident::new(prefix, Span::call_site());
@@ -41,14 +41,14 @@ impl GqlObject {
4141
pub fn field_impls_for_selection(
4242
&self,
4343
query_context: &QueryContext,
44-
selection: &query::SelectionSet,
44+
selection: &Selection,
4545
prefix: &str,
4646
) -> Result<Vec<TokenStream>, failure::Error> {
4747
selection
48-
.items
48+
.0
4949
.iter()
5050
.map(|selected| {
51-
if let query::Selection::Field(selected) = selected {
51+
if let SelectionItem::Field(selected) = selected {
5252
let ty = self
5353
.fields
5454
.iter()
@@ -61,7 +61,7 @@ impl GqlObject {
6161
prefix.to_camel_case(),
6262
selected.name.to_camel_case()
6363
);
64-
query_context.maybe_expand_field(&selected, &ty, &prefix)
64+
query_context.maybe_expand_field(&ty, &selected.fields, &prefix)
6565
} else {
6666
Ok(quote!())
6767
}
@@ -72,14 +72,14 @@ impl GqlObject {
7272
pub fn response_fields_for_selection(
7373
&self,
7474
query_context: &QueryContext,
75-
selection: &query::SelectionSet,
75+
selection: &Selection,
7676
prefix: &str,
7777
) -> Vec<TokenStream> {
7878
let mut fields = Vec::new();
7979

80-
for item in selection.items.iter() {
80+
for item in selection.0.iter() {
8181
match item {
82-
query::Selection::Field(f) => {
82+
SelectionItem::Field(f) => {
8383
let name = &f.name;
8484
let ty = &self
8585
.fields
@@ -93,7 +93,7 @@ impl GqlObject {
9393
);
9494
fields.push(render_object_field(name, ty));
9595
}
96-
query::Selection::FragmentSpread(fragment) => {
96+
SelectionItem::FragmentSpread(fragment) => {
9797
let field_name =
9898
Ident::new(&fragment.fragment_name.to_snake_case(), Span::call_site());
9999
let type_name = Ident::new(&fragment.fragment_name, Span::call_site());
@@ -102,7 +102,7 @@ impl GqlObject {
102102
#field_name: #type_name
103103
})
104104
}
105-
query::Selection::InlineFragment(_) => {
105+
SelectionItem::InlineFragment(_) => {
106106
unreachable!("inline fragment on object field")
107107
}
108108
}

graphql_query_derive/src/query.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use failure;
22
use field_type::FieldType;
33
use fragments::GqlFragment;
4-
use graphql_parser::query;
54
use proc_macro2::TokenStream;
65
use schema::Schema;
76
use std::collections::BTreeMap;
7+
use selection::Selection;
88

99
pub struct QueryContext {
1010
pub _subscription_root: Option<Vec<TokenStream>>,
@@ -42,18 +42,18 @@ impl QueryContext {
4242

4343
pub fn maybe_expand_field(
4444
&self,
45-
field: &query::Field,
4645
ty: &str,
46+
selection: &Selection,
4747
prefix: &str,
4848
) -> Result<TokenStream, failure::Error> {
4949
if let Some(_enm) = self.schema.enums.get(ty) {
5050
Ok(quote!()) // we already expand enums separately
5151
} else if let Some(obj) = self.schema.objects.get(ty) {
52-
obj.response_for_selection(self, &field.selection_set, prefix)
52+
obj.response_for_selection(self, &selection, prefix)
5353
} else if let Some(iface) = self.schema.interfaces.get(ty) {
54-
Ok(iface.response_for_selection(self, &field.selection_set, prefix))
54+
Ok(iface.response_for_selection(self, &selection, prefix))
5555
} else if let Some(unn) = self.schema.unions.get(ty) {
56-
Ok(unn.response_for_selection(self, &field.selection_set, prefix))
56+
Ok(unn.response_for_selection(self, &selection, prefix))
5757
} else {
5858
Ok(quote!())
5959
}

graphql_query_derive/src/schema.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use objects::{GqlObject, GqlObjectField};
99
use proc_macro2::TokenStream;
1010
use query::QueryContext;
1111
use std::collections::{BTreeMap, BTreeSet};
12+
use selection::Selection;
1213
use unions::GqlUnion;
1314

1415
pub const DEFAULT_SCALARS: &[&'static str] = &["ID", "String", "Int", "Float", "Boolean"];
@@ -57,14 +58,16 @@ impl Schema {
5758
.expect("query type is defined");
5859
let prefix = &q.name.expect("unnamed operation");
5960
let prefix = format!("RUST_{}", prefix);
61+
let selection = Selection::from(&q.selection_set);
62+
6063
definitions.extend(definition.field_impls_for_selection(
6164
&context,
62-
&q.selection_set,
65+
&selection,
6366
&prefix,
6467
)?);
6568
Some(definition.response_fields_for_selection(
6669
&context,
67-
&q.selection_set,
70+
&selection,
6871
&prefix,
6972
))
7073
};
@@ -79,15 +82,16 @@ impl Schema {
7982
.expect("mutation type is defined");
8083
let prefix = &q.name.expect("unnamed operation");
8184
let prefix = format!("RUST_{}", prefix);
85+
let selection = Selection::from(&q.selection_set);
8286

8387
definitions.extend(definition.field_impls_for_selection(
8488
&context,
85-
&q.selection_set,
89+
&selection,
8690
&prefix,
8791
)?);
8892
Some(definition.response_fields_for_selection(
8993
&context,
90-
&q.selection_set,
94+
&selection,
9195
&prefix,
9296
))
9397
};
@@ -104,14 +108,16 @@ impl Schema {
104108
.expect("subscription type is defined");
105109
let prefix = &q.name.expect("unnamed operation");
106110
let prefix = format!("RUST_{}", prefix);
111+
let selection = Selection::from(&q.selection_set);
112+
107113
definitions.extend(definition.field_impls_for_selection(
108114
&context,
109-
&q.selection_set,
115+
&selection,
110116
&prefix,
111117
)?);
112118
Some(definition.response_fields_for_selection(
113119
&context,
114-
&q.selection_set,
120+
&selection,
115121
&prefix,
116122
))
117123
};
@@ -125,7 +131,7 @@ impl Schema {
125131
fragment.name.clone(),
126132
GqlFragment {
127133
name: fragment.name,
128-
selection: fragment.selection_set,
134+
selection: Selection::from(&fragment.selection_set),
129135
on,
130136
},
131137
);

graphql_query_derive/src/selection.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@ use graphql_parser::query::SelectionSet;
22

33
#[derive(Debug, PartialEq)]
44
pub struct SelectionField {
5-
name: String,
6-
fields: Selection,
5+
pub name: String,
6+
pub fields: Selection,
77
}
88

99
#[derive(Debug, PartialEq)]
1010
pub struct SelectionFragmentSpread {
11-
fragment_name: String,
11+
pub fragment_name: String,
1212
}
1313

1414
#[derive(Debug, PartialEq)]
1515
pub struct SelectionInlineFragment {
16-
on: String,
17-
fields: Selection,
16+
pub on: String,
17+
pub fields: Selection,
1818
}
1919

2020
#[derive(Debug, PartialEq)]
@@ -25,7 +25,7 @@ pub enum SelectionItem {
2525
}
2626

2727
#[derive(Debug, PartialEq)]
28-
pub struct Selection(Vec<SelectionItem>);
28+
pub struct Selection(pub Vec<SelectionItem>);
2929

3030
impl<'a> ::std::convert::From<&'a SelectionSet> for Selection {
3131
fn from(selection_set: &SelectionSet) -> Selection {

graphql_query_derive/src/unions.rs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,63 @@
1-
use graphql_parser::query;
2-
use proc_macro2::TokenStream;
1+
use proc_macro2::{Ident, Span, TokenStream};
32
use query::QueryContext;
43
use std::collections::BTreeSet;
4+
use selection::{Selection, SelectionItem};
5+
use heck::SnakeCase;
56

67
#[derive(Debug, PartialEq)]
78
pub struct GqlUnion(pub BTreeSet<String>);
89

910
impl GqlUnion {
1011
pub fn response_for_selection(
1112
&self,
12-
_query_context: &QueryContext,
13-
_selection: &query::SelectionSet,
14-
_prefix: &str,
13+
query_context: &QueryContext,
14+
selection: &Selection,
15+
prefix: &str,
1516
) -> TokenStream {
16-
unimplemented!("union generation")
17+
let struct_name = Ident::new(prefix, Span::call_site());
18+
let mut children_definitions = Vec::new();
19+
let fields = selection.0.iter().map(|item| {
20+
match item {
21+
SelectionItem::Field(_) => unreachable!("field selection on union"),
22+
SelectionItem::FragmentSpread(_) => unreachable!("fragment spread on union"),
23+
SelectionItem::InlineFragment(frag) => {
24+
let field_name = Ident::new(
25+
&format!("on_{}", frag.on).to_snake_case(),
26+
Span::call_site(),
27+
);
28+
29+
let field_type = Ident::new(&format!("{}On{}", prefix, frag.on), Span::call_site());
30+
31+
let new_prefix = format!("{}On{}", prefix, frag.on);
32+
33+
let field_object_type = query_context.schema.objects.get(&frag.on)
34+
.map(|f| query_context.maybe_expand_field(&frag.on, &frag.fields, &new_prefix));
35+
let field_interface = query_context.schema.interfaces.get(&frag.on)
36+
.map(|f| query_context.maybe_expand_field(&frag.on, &frag.fields, &new_prefix));
37+
// nested unions, is that even a thing?
38+
let field_union_type = query_context.schema.unions.get(&frag.on)
39+
.map(|f| query_context.maybe_expand_field(&frag.on, &frag.fields, &new_prefix));
40+
41+
if let Some(tokens) = field_object_type.or(field_interface).or(field_union_type) {
42+
children_definitions.push(tokens)
43+
}
44+
45+
// query_context.maybe_expand_field(
46+
47+
// );
48+
quote! {
49+
#field_name: #field_type
50+
}
51+
}
52+
}
53+
});
54+
55+
quote!{
56+
#[derive(Deserialize)]
57+
pub struct #struct_name {
58+
#(#fields),*
59+
}
60+
}
1761
}
1862
}
1963

0 commit comments

Comments
 (0)