@@ -159,11 +159,13 @@ where
159159 ) )
160160}
161161
162+ #[ derive( Debug ) ]
162163struct AsyncField < S > {
163164 name : String ,
164165 value : Option < Value < S > > ,
165166}
166167
168+ #[ derive( Debug ) ]
167169enum AsyncValue < S > {
168170 Field ( AsyncField < S > ) ,
169171 Nested ( Value < S > ) ,
@@ -184,16 +186,17 @@ where
184186 use futures:: stream:: { FuturesOrdered , StreamExt as _} ;
185187
186188 #[ enum_derive( Future ) ]
187- enum AsyncValueFuture < A , B , C , D > {
188- Field ( A ) ,
189- FragmentSpread ( B ) ,
190- InlineFragment1 ( C ) ,
191- InlineFragment2 ( D ) ,
189+ enum AsyncValueFuture < F1 , F2 , FS , IF1 , IF2 > {
190+ Field1 ( F1 ) ,
191+ Field2 ( F2 ) ,
192+ FragmentSpread ( FS ) ,
193+ InlineFragment1 ( IF1 ) ,
194+ InlineFragment2 ( IF2 ) ,
192195 }
193196
194197 let mut object = Object :: with_capacity ( selection_set. len ( ) ) ;
195198
196- let mut async_values = FuturesOrdered :: < AsyncValueFuture < _ , _ , _ , _ > > :: new ( ) ;
199+ let mut async_values = FuturesOrdered :: < AsyncValueFuture < _ , _ , _ , _ , _ > > :: new ( ) ;
197200
198201 let meta_type = executor
199202 . schema ( )
@@ -258,7 +261,7 @@ where
258261 let is_non_null = meta_field. field_type . is_non_null ( ) ;
259262
260263 let response_name = response_name. to_string ( ) ;
261- async_values. push_back ( AsyncValueFuture :: Field ( async move {
264+ async_values. push_back ( AsyncValueFuture :: Field1 ( async move {
262265 // TODO: implement custom future type instead of
263266 // two-level boxing.
264267 let res = instance
@@ -327,6 +330,19 @@ where
327330 } ) ) ,
328331 ) ) ;
329332 }
333+ } else if let Ok ( Value :: Null ) = sub_result {
334+ // NOTE: Executing a fragment cannot really result in a `Value::Null`,
335+ // because it represents a set of fields, so normal execution always
336+ // results in a `Value::Object`. However, a `Value::Null` is used here
337+ // to indicate that fragment execution failed somewhere and, because
338+ // of non-`null` types involved, its error should be propagated to the
339+ // parent field.
340+ async_values. push_back ( AsyncValueFuture :: Field2 ( future:: ready (
341+ AsyncValue :: Field ( AsyncField {
342+ name : String :: new ( ) , // doesn't matter here
343+ value : None ,
344+ } ) ,
345+ ) ) ) ;
330346 } else if let Err ( e) = sub_result {
331347 sub_exec. push_error_at ( e, span. start ) ;
332348 }
@@ -371,6 +387,19 @@ where
371387 } ) ) ,
372388 ) ) ;
373389 }
390+ } else if let Ok ( Value :: Null ) = sub_result {
391+ // NOTE: Executing a fragment cannot really result in a `Value::Null`,
392+ // because it represents a set of fields, so normal execution
393+ // always results in a `Value::Object`. However, a `Value::Null`
394+ // is used here to indicate that fragment execution failed
395+ // somewhere and, because of non-`null` types involved, its error
396+ // should be propagated to the parent field.
397+ async_values. push_back ( AsyncValueFuture :: Field2 ( future:: ready (
398+ AsyncValue :: Field ( AsyncField {
399+ name : String :: new ( ) , // doesn't matter here
400+ value : None ,
401+ } ) ,
402+ ) ) ) ;
374403 } else if let Err ( e) = sub_result {
375404 sub_exec. push_error_at ( e, span. start ) ;
376405 }
0 commit comments