@@ -3,20 +3,28 @@ use query::QueryContext;
33use std:: collections:: BTreeSet ;
44use selection:: { Selection , SelectionItem } ;
55use heck:: SnakeCase ;
6+ use failure;
67
78#[ derive( Debug , PartialEq ) ]
89pub struct GqlUnion ( pub BTreeSet < String > ) ;
910
11+ #[ derive( Debug , Fail ) ]
12+ #[ fail( display = "UnionError" ) ]
13+ enum UnionError {
14+ #[ fail( display = "Unknown type: {}" , ty) ]
15+ UnknownType { ty : String } ,
16+ }
17+
1018impl GqlUnion {
1119 pub fn response_for_selection (
1220 & self ,
1321 query_context : & QueryContext ,
1422 selection : & Selection ,
1523 prefix : & str ,
16- ) -> TokenStream {
24+ ) -> Result < TokenStream , failure :: Error > {
1725 let struct_name = Ident :: new ( prefix, Span :: call_site ( ) ) ;
18- let mut children_definitions = Vec :: new ( ) ;
19- let fields = selection. 0 . iter ( ) . map ( |item| {
26+ let mut children_definitions: Vec < TokenStream > = Vec :: new ( ) ;
27+ let fields: Result < Vec < TokenStream > , failure :: Error > = selection. 0 . iter ( ) . map ( |item| {
2028 match item {
2129 SelectionItem :: Field ( _) => unreachable ! ( "field selection on union" ) ,
2230 SelectionItem :: FragmentSpread ( _) => unreachable ! ( "fragment spread on union" ) ,
@@ -38,35 +46,123 @@ impl GqlUnion {
3846 let field_union_type = query_context. schema . unions . get ( & frag. on )
3947 . map ( |f| query_context. maybe_expand_field ( & frag. on , & frag. fields , & new_prefix) ) ;
4048
41- if let Some ( tokens) = field_object_type. or ( field_interface) . or ( field_union_type) {
42- children_definitions. push ( tokens)
43- }
49+ match field_object_type. or ( field_interface) . or ( field_union_type) {
50+ Some ( tokens) => children_definitions. push ( tokens?) ,
51+ None => Err ( UnionError :: UnknownType { ty : frag. on . to_string ( ) } ) ?,
52+ } ;
4453
45- // query_context.maybe_expand_field(
46-
47- // );
48- quote ! {
54+ Ok ( quote ! {
4955 #field_name: #field_type
50- }
56+ } )
5157 }
5258 }
53- } ) ;
59+ } ) . collect ( ) ;
60+
61+ let fields = fields?;
62+
63+ Ok ( quote ! {
64+ #( #children_definitions) *
5465
55- quote ! {
5666 #[ derive( Deserialize ) ]
5767 pub struct #struct_name {
5868 #( #fields) , *
5969 }
60- }
70+ } )
6171 }
6272}
6373
6474#[ cfg( test) ]
6575mod tests {
76+ use selection:: * ;
77+ use super :: * ;
78+ use objects:: { GqlObject , GqlObjectField } ;
79+ use field_type:: FieldType ;
6680
6781 #[ test]
6882 fn union_response_for_selection_works ( ) {
69- // unimplemented!()
70- }
83+ let fields = vec ! [
84+ SelectionItem :: InlineFragment ( SelectionInlineFragment {
85+ on: "User" . to_string( ) ,
86+ fields: Selection ( vec![ SelectionItem :: Field ( SelectionField {
87+ name: "first_name" . to_string( ) ,
88+ fields: Selection ( vec![ ] ) ,
89+ } ) ] ) ,
90+ } ) ,
91+ SelectionItem :: InlineFragment ( SelectionInlineFragment {
92+ on: "Organization" . to_string( ) ,
93+ fields: Selection ( vec![ SelectionItem :: Field ( SelectionField {
94+ name: "title" . to_string( ) ,
95+ fields: Selection ( vec![ ] ) ,
96+ } ) ] ) ,
97+ } ) ,
98+ ] ;
99+ let mut context = QueryContext :: new_empty ( ) ;
100+ let selection = Selection ( fields) ;
101+ let prefix = "Meow" ;
102+ let union = GqlUnion ( BTreeSet :: new ( ) ) ;
103+
104+ let result = union. response_for_selection (
105+ & context,
106+ & selection,
107+ & prefix,
108+ ) ;
109+
71110
111+ assert ! ( result. is_err( ) ) ;
112+
113+ context. schema . objects . insert (
114+ "User" . to_string ( ) , GqlObject {
115+ name : "User" . to_string ( ) ,
116+ fields : vec ! [
117+ GqlObjectField {
118+ name: "first_name" . to_string( ) ,
119+ type_: FieldType :: Named ( Ident :: new( "String" , Span :: call_site( ) ) ) ,
120+ } ,
121+ GqlObjectField {
122+ name: "last_name" . to_string( ) ,
123+ type_: FieldType :: Named ( Ident :: new( "String" , Span :: call_site( ) ) ) ,
124+ } ,
125+ GqlObjectField {
126+ name: "created_at" . to_string( ) ,
127+ type_: FieldType :: Named ( Ident :: new( "Date" , Span :: call_site( ) ) ) ,
128+ }
129+ ] ,
130+ }
131+ ) ;
132+
133+ context. schema . objects . insert (
134+ "Organization" . to_string ( ) , GqlObject {
135+ name : "Organization" . to_string ( ) ,
136+ fields : vec ! [
137+ GqlObjectField {
138+ name: "title" . to_string( ) ,
139+ type_: FieldType :: Named ( Ident :: new( "String" , Span :: call_site( ) ) ) ,
140+ } ,
141+ GqlObjectField {
142+ name: "created_at" . to_string( ) ,
143+ type_: FieldType :: Named ( Ident :: new( "Date" , Span :: call_site( ) ) ) ,
144+ }
145+ ] ,
146+ }
147+ ) ;
148+
149+ let result = union. response_for_selection (
150+ & context,
151+ & selection,
152+ & prefix,
153+ ) ;
154+
155+ assert ! ( result. is_ok( ) ) ;
156+
157+ assert_eq ! (
158+ result. unwrap( ) . to_string( ) ,
159+ vec![
160+ "# [ derive ( Debug , Serialize , Deserialize ) ] " ,
161+ "pub struct MeowOnUser { first_name : String , } " ,
162+ "# [ derive ( Debug , Serialize , Deserialize ) ] " ,
163+ "pub struct MeowOnOrganization { title : String , } " ,
164+ "# [ derive ( Deserialize ) ] pub struct Meow { on_user : MeowOnUser , on_organization : MeowOnOrganization }" ,
165+ ] . into_iter( ) . collect:: <String >( ) ,
166+ ) ;
167+ }
72168}
0 commit comments