1+ use constants:: * ;
12use failure;
23use heck:: SnakeCase ;
34use proc_macro2:: { Ident , Span , TokenStream } ;
@@ -13,6 +14,8 @@ pub struct GqlUnion(pub BTreeSet<String>);
1314enum UnionError {
1415 #[ fail( display = "Unknown type: {}" , ty) ]
1516 UnknownType { ty : String } ,
17+ #[ fail( display = "Missing __typename in selection for {}" , union_name) ]
18+ MissingTypename { union_name : String }
1619}
1720
1821impl GqlUnion {
@@ -24,13 +27,34 @@ impl GqlUnion {
2427 ) -> Result < TokenStream , failure:: Error > {
2528 let struct_name = Ident :: new ( prefix, Span :: call_site ( ) ) ;
2629 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+
2743 let variants: Result < Vec < TokenStream > , failure:: Error > = selection
2844 . 0
2945 . 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+ } )
3054 . map ( |item| {
3155 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" ) ,
3458 SelectionItem :: InlineFragment ( frag) => {
3559 let variant_name = Ident :: new ( & frag. on , Span :: call_site ( ) ) ;
3660
@@ -160,23 +184,23 @@ mod tests {
160184
161185 assert ! ( result. is_err( ) ) ;
162186
163- assert_eq ! ( format!( "{}" , result. unwrap_err( ) ) , "" ) ;
187+ assert_eq ! ( format!( "{}" , result. unwrap_err( ) ) , "Missing __typename in selection for Meow " ) ;
164188 }
165189
166190 #[ test]
167191 fn union_response_for_selection_works ( ) {
168192 let fields = vec ! [
193+ SelectionItem :: Field ( SelectionField {
194+ name: "__typename" . to_string( ) ,
195+ fields: Selection ( vec![ ] ) ,
196+ } ) ,
169197 SelectionItem :: InlineFragment ( SelectionInlineFragment {
170198 on: "User" . to_string( ) ,
171199 fields: Selection ( vec![
172200 SelectionItem :: Field ( SelectionField {
173201 name: "first_name" . to_string( ) ,
174202 fields: Selection ( vec![ ] ) ,
175203 } ) ,
176- SelectionItem :: Field ( SelectionField {
177- name: "__typename" . to_string( ) ,
178- fields: Selection ( vec![ ] ) ,
179- } ) ,
180204 ] ) ,
181205 } ) ,
182206 SelectionItem :: InlineFragment ( SelectionInlineFragment {
@@ -186,10 +210,6 @@ mod tests {
186210 name: "title" . to_string( ) ,
187211 fields: Selection ( vec![ ] ) ,
188212 } ) ,
189- SelectionItem :: Field ( SelectionField {
190- name: "__typename" . to_string( ) ,
191- fields: Selection ( vec![ ] ) ,
192- } ) ,
193213 ] ) ,
194214 } ) ,
195215 ] ;
@@ -207,13 +227,17 @@ mod tests {
207227 GqlObject {
208228 name : "User" . to_string ( ) ,
209229 fields : vec ! [
230+ GqlObjectField {
231+ name: "__typename" . to_string( ) ,
232+ type_: FieldType :: Named ( string_type( ) ) ,
233+ } ,
210234 GqlObjectField {
211235 name: "first_name" . to_string( ) ,
212- type_: FieldType :: Named ( Ident :: new ( "String" , Span :: call_site ( ) ) ) ,
236+ type_: FieldType :: Named ( string_type ( ) ) ,
213237 } ,
214238 GqlObjectField {
215239 name: "last_name" . to_string( ) ,
216- type_: FieldType :: Named ( Ident :: new ( "String" , Span :: call_site ( ) ) ) ,
240+ type_: FieldType :: Named ( string_type ( ) ) ,
217241 } ,
218242 GqlObjectField {
219243 name: "created_at" . to_string( ) ,
@@ -228,6 +252,10 @@ mod tests {
228252 GqlObject {
229253 name : "Organization" . to_string ( ) ,
230254 fields : vec ! [
255+ GqlObjectField {
256+ name: "__typename" . to_string( ) ,
257+ type_: FieldType :: Named ( string_type( ) ) ,
258+ } ,
231259 GqlObjectField {
232260 name: "title" . to_string( ) ,
233261 type_: FieldType :: Named ( Ident :: new( "String" , Span :: call_site( ) ) ) ,
@@ -242,6 +270,8 @@ mod tests {
242270
243271 let result = union. response_for_selection ( & context, & selection, & prefix) ;
244272
273+ println ! ( "{:?}" , result) ;
274+
245275 assert ! ( result. is_ok( ) ) ;
246276
247277 assert_eq ! (
0 commit comments