1
+ use constants:: * ;
1
2
use failure;
2
3
use heck:: SnakeCase ;
3
4
use proc_macro2:: { Ident , Span , TokenStream } ;
@@ -13,6 +14,8 @@ pub struct GqlUnion(pub BTreeSet<String>);
13
14
enum UnionError {
14
15
#[ fail( display = "Unknown type: {}" , ty) ]
15
16
UnknownType { ty : String } ,
17
+ #[ fail( display = "Missing __typename in selection for {}" , union_name) ]
18
+ MissingTypename { union_name : String }
16
19
}
17
20
18
21
impl GqlUnion {
@@ -24,13 +27,34 @@ impl GqlUnion {
24
27
) -> Result < TokenStream , failure:: Error > {
25
28
let struct_name = Ident :: new ( prefix, Span :: call_site ( ) ) ;
26
29
let mut children_definitions: Vec < TokenStream > = Vec :: new ( ) ;
30
+
31
+ let typename_field = selection. 0 . iter ( ) . find ( |f| {
32
+ if let SelectionItem :: Field ( f) = f {
33
+ f. name == TYPENAME_FIELD
34
+ } else {
35
+ false
36
+ }
37
+ } ) ;
38
+
39
+ if typename_field. is_none ( ) {
40
+ Err ( UnionError :: MissingTypename { union_name : prefix. into ( ) } ) ?;
41
+ }
42
+
27
43
let variants: Result < Vec < TokenStream > , failure:: Error > = selection
28
44
. 0
29
45
. iter ( )
46
+ // ignore __typename
47
+ . filter ( |item| {
48
+ if let SelectionItem :: Field ( f) = item {
49
+ f. name != TYPENAME_FIELD
50
+ } else {
51
+ true
52
+ }
53
+ } )
30
54
. map ( |item| {
31
55
match item {
32
- SelectionItem :: Field ( _ ) => unreachable ! ( "field selection on union" ) ,
33
- SelectionItem :: FragmentSpread ( _) => unreachable ! ( "fragment spread on union" ) ,
56
+ SelectionItem :: Field ( f ) => panic ! ( "field selection on union" ) ,
57
+ SelectionItem :: FragmentSpread ( _) => panic ! ( "fragment spread on union" ) ,
34
58
SelectionItem :: InlineFragment ( frag) => {
35
59
let variant_name = Ident :: new ( & frag. on , Span :: call_site ( ) ) ;
36
60
@@ -160,23 +184,23 @@ mod tests {
160
184
161
185
assert ! ( result. is_err( ) ) ;
162
186
163
- assert_eq ! ( format!( "{}" , result. unwrap_err( ) ) , "" ) ;
187
+ assert_eq ! ( format!( "{}" , result. unwrap_err( ) ) , "Missing __typename in selection for Meow " ) ;
164
188
}
165
189
166
190
#[ test]
167
191
fn union_response_for_selection_works ( ) {
168
192
let fields = vec ! [
193
+ SelectionItem :: Field ( SelectionField {
194
+ name: "__typename" . to_string( ) ,
195
+ fields: Selection ( vec![ ] ) ,
196
+ } ) ,
169
197
SelectionItem :: InlineFragment ( SelectionInlineFragment {
170
198
on: "User" . to_string( ) ,
171
199
fields: Selection ( vec![
172
200
SelectionItem :: Field ( SelectionField {
173
201
name: "first_name" . to_string( ) ,
174
202
fields: Selection ( vec![ ] ) ,
175
203
} ) ,
176
- SelectionItem :: Field ( SelectionField {
177
- name: "__typename" . to_string( ) ,
178
- fields: Selection ( vec![ ] ) ,
179
- } ) ,
180
204
] ) ,
181
205
} ) ,
182
206
SelectionItem :: InlineFragment ( SelectionInlineFragment {
@@ -186,10 +210,6 @@ mod tests {
186
210
name: "title" . to_string( ) ,
187
211
fields: Selection ( vec![ ] ) ,
188
212
} ) ,
189
- SelectionItem :: Field ( SelectionField {
190
- name: "__typename" . to_string( ) ,
191
- fields: Selection ( vec![ ] ) ,
192
- } ) ,
193
213
] ) ,
194
214
} ) ,
195
215
] ;
@@ -207,13 +227,17 @@ mod tests {
207
227
GqlObject {
208
228
name : "User" . to_string ( ) ,
209
229
fields : vec ! [
230
+ GqlObjectField {
231
+ name: "__typename" . to_string( ) ,
232
+ type_: FieldType :: Named ( string_type( ) ) ,
233
+ } ,
210
234
GqlObjectField {
211
235
name: "first_name" . to_string( ) ,
212
- type_: FieldType :: Named ( Ident :: new ( "String" , Span :: call_site ( ) ) ) ,
236
+ type_: FieldType :: Named ( string_type ( ) ) ,
213
237
} ,
214
238
GqlObjectField {
215
239
name: "last_name" . to_string( ) ,
216
- type_: FieldType :: Named ( Ident :: new ( "String" , Span :: call_site ( ) ) ) ,
240
+ type_: FieldType :: Named ( string_type ( ) ) ,
217
241
} ,
218
242
GqlObjectField {
219
243
name: "created_at" . to_string( ) ,
@@ -228,6 +252,10 @@ mod tests {
228
252
GqlObject {
229
253
name : "Organization" . to_string ( ) ,
230
254
fields : vec ! [
255
+ GqlObjectField {
256
+ name: "__typename" . to_string( ) ,
257
+ type_: FieldType :: Named ( string_type( ) ) ,
258
+ } ,
231
259
GqlObjectField {
232
260
name: "title" . to_string( ) ,
233
261
type_: FieldType :: Named ( Ident :: new( "String" , Span :: call_site( ) ) ) ,
@@ -242,6 +270,8 @@ mod tests {
242
270
243
271
let result = union. response_for_selection ( & context, & selection, & prefix) ;
244
272
273
+ println ! ( "{:?}" , result) ;
274
+
245
275
assert ! ( result. is_ok( ) ) ;
246
276
247
277
assert_eq ! (
0 commit comments