1
1
import arrayFrom from '../polyfills/arrayFrom' ;
2
+ import { SYMBOL_ASYNC_ITERATOR } from '../polyfills/symbols' ;
2
3
3
4
import type { Path } from '../jsutils/Path' ;
4
5
import type { ObjMap } from '../jsutils/ObjMap' ;
@@ -8,6 +9,7 @@ import memoize3 from '../jsutils/memoize3';
8
9
import invariant from '../jsutils/invariant' ;
9
10
import devAssert from '../jsutils/devAssert' ;
10
11
import isPromise from '../jsutils/isPromise' ;
12
+ import isAsyncIterable from '../jsutils/isAsyncIterable' ;
11
13
import isObjectLike from '../jsutils/isObjectLike' ;
12
14
import isCollection from '../jsutils/isCollection' ;
13
15
import promiseReduce from '../jsutils/promiseReduce' ;
@@ -855,6 +857,48 @@ function completeValue(
855
857
) ;
856
858
}
857
859
860
+ /**
861
+ * Complete a async iterator value by completing the result and calling
862
+ * recursively until all the results are completed.
863
+ */
864
+ function completeAsyncIteratorValue (
865
+ exeContext : ExecutionContext ,
866
+ itemType : GraphQLOutputType ,
867
+ fieldNodes : $ReadOnlyArray < FieldNode > ,
868
+ info : GraphQLResolveInfo ,
869
+ path : Path ,
870
+ index : number ,
871
+ completedResults : Array < mixed > ,
872
+ iterator : AsyncIterator < mixed > ,
873
+ ) : Promise < $ReadOnlyArray < mixed >> {
874
+ const fieldPath = addPath ( path , index , undefined ) ;
875
+ return iterator . next ( ) . then (
876
+ ( { value, done } ) => {
877
+ if ( done ) {
878
+ return completedResults ;
879
+ }
880
+ completedResults . push (
881
+ completeValue ( exeContext , itemType , fieldNodes , info , fieldPath , value ) ,
882
+ ) ;
883
+ return completeAsyncIteratorValue (
884
+ exeContext ,
885
+ itemType ,
886
+ fieldNodes ,
887
+ info ,
888
+ path ,
889
+ index + 1 ,
890
+ completedResults ,
891
+ iterator ,
892
+ ) ;
893
+ } ,
894
+ ( error ) => {
895
+ completedResults . push ( null ) ;
896
+ handleFieldError ( error , fieldNodes , fieldPath , itemType , exeContext ) ;
897
+ return completedResults ;
898
+ } ,
899
+ ) ;
900
+ }
901
+
858
902
/**
859
903
* Complete a list value by completing each item in the list with the
860
904
* inner type
@@ -867,6 +911,23 @@ function completeListValue(
867
911
path : Path ,
868
912
result : mixed ,
869
913
) : PromiseOrValue < $ReadOnlyArray < mixed >> {
914
+ const itemType = returnType . ofType ;
915
+
916
+ if ( isAsyncIterable ( result ) ) {
917
+ const iterator = result [ SYMBOL_ASYNC_ITERATOR ] ( ) ;
918
+
919
+ return completeAsyncIteratorValue (
920
+ exeContext ,
921
+ itemType ,
922
+ fieldNodes ,
923
+ info ,
924
+ path ,
925
+ 0 ,
926
+ [ ] ,
927
+ iterator ,
928
+ ) ;
929
+ }
930
+
870
931
if ( ! isCollection ( result ) ) {
871
932
throw new GraphQLError (
872
933
`Expected Iterable, but did not find one for field "${ info . parentType . name } .${ info . fieldName } ".` ,
@@ -875,7 +936,6 @@ function completeListValue(
875
936
876
937
// This is specified as a simple map, however we're optimizing the path
877
938
// where the list contains no Promises by avoiding creating another Promise.
878
- const itemType = returnType . ofType ;
879
939
let containsPromise = false ;
880
940
const completedResults = arrayFrom ( result , ( item , index ) => {
881
941
// No need to modify the info object containing the path,
0 commit comments