@@ -417,13 +417,13 @@ First, the selection set is turned into a grouped field set; then, each
417
417
represented field in the grouped field set produces an entry into a response
418
418
map.
419
419
420
- ExecuteSelectionSet(selectionSet, objectType, objectValue, variableValues,
421
- subsequentPayloads, parentPath ):
420
+ ExecuteSelectionSet(selectionSet, objectType, objectValue, variableValues, path,
421
+ subsequentPayloads, asyncRecord ):
422
422
423
+ - If {path} is not provided, initialize it to an empty list.
423
424
- If {subsequentPayloads} is not provided, initialize it to the empty set.
424
- - If {parentPath} is not provided, initialize it to an empty list.
425
425
- Let {groupedFieldSet} be the result of {CollectFields(objectType, objectValue,
426
- selectionSet, variableValues, subsequentPayloads, parentPath )}.
426
+ selectionSet, variableValues, path subsequentPayloads, asyncRecord )}.
427
427
- Initialize {resultMap} to an empty ordered map.
428
428
- For each {groupedFieldSet} as {responseKey} and {fields}:
429
429
- Let {fieldName} be the name of the first entry in {fields}. Note: This value
@@ -432,7 +432,7 @@ subsequentPayloads, parentPath):
432
432
{objectType}.
433
433
- If {fieldType} is defined:
434
434
- Let {responseValue} be {ExecuteField(objectType, objectValue, fieldType,
435
- fields, variableValues, subsequentPayloads, parentPath )}.
435
+ fields, variableValues, path, subsequentPayloads, asyncRecord )}.
436
436
- Set {responseValue} as the value for {responseKey} in {resultMap}.
437
437
- Return {resultMap}.
438
438
@@ -584,8 +584,8 @@ The depth-first-search order of the field groups produced by {CollectFields()}
584
584
is maintained through execution, ensuring that fields appear in the executed
585
585
response in a stable and predictable order.
586
586
587
- CollectFields(objectType, objectValue, selectionSet, variableValues,
588
- deferredFragments, parentPath , visitedFragments):
587
+ CollectFields(objectType, objectValue, selectionSet, variableValues, path,
588
+ subsequentPayloads, asyncRecord , visitedFragments):
589
589
590
590
- If {visitedFragments} is not provided, initialize it to the empty set.
591
591
- Initialize {groupedFields} to an empty ordered map of lists.
@@ -624,14 +624,16 @@ deferredFragments, parentPath, visitedFragments):
624
624
with the next {selection} in {selectionSet}.
625
625
- Let {fragmentSelectionSet} be the top-level selection set of {fragment}.
626
626
- If {deferDirective} is defined:
627
- - Let {deferredFragment} be the result of calling
628
- {DeferFragment(objectType, objectValue, fragmentSelectionSet,
629
- parentPath)}.
630
- - Append {deferredFragment} to {deferredFragments}.
627
+ - Let {label} be the value or the variable to {deferDirective}'s {label}
628
+ argument.
629
+ - Let {deferredFragmentRecord} be the result of calling
630
+ {CreateDeferredFragmentRecord(label, objectType, objectValue,
631
+ fragmentSelectionSet, path, asyncRecord)}.
632
+ - Append {deferredFragmentRecord} to {subsequentPayloads}.
631
633
- Continue with the next {selection} in {selectionSet}.
632
634
- Let {fragmentGroupedFieldSet} be the result of calling
633
- {CollectFields(objectType, fragmentSelectionSet, variableValues ,
634
- visitedFragments)}.
635
+ {CollectFields(objectType, objectValue, fragmentSelectionSet ,
636
+ variableValues, path, subsequentPayloads, asyncRecord, visitedFragments)}.
635
637
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
636
638
- Let {responseKey} be the response key shared by all fields in
637
639
{fragmentGroup}.
@@ -648,14 +650,16 @@ deferredFragments, parentPath, visitedFragments):
648
650
be that directive.
649
651
- If {deferDirective}'s {if} argument is {true} or is a variable in
650
652
{variableValues} with the value {true}:
651
- - Let {deferredFragment} be the result of calling
652
- {DeferFragment(objectType, objectValue, fragmentSelectionSet,
653
- parentPath)}.
654
- - Append {deferredFragment} to {deferredFragments}.
653
+ - Let {label} be the value or the variable to {deferDirective}'s {label}
654
+ argument.
655
+ - Let {deferredFragmentRecord} be the result of calling
656
+ {CreateDeferredFragmentRecord(label, objectType, objectValue,
657
+ fragmentSelectionSet, path, asyncRecord)}.
658
+ - Append {deferredFragmentRecord} to {subsequentPayloads}.
655
659
- Continue with the next {selection} in {selectionSet}.
656
660
- Let {fragmentGroupedFieldSet} be the result of calling
657
- {CollectFields(objectType, fragmentSelectionSet, variableValues ,
658
- visitedFragments, parentPath )}.
661
+ {CollectFields(objectType, objectValue, fragmentSelectionSet ,
662
+ variableValues, path, subsequentPayloads, asyncRecord, visitedFragments )}.
659
663
- For each {fragmentGroup} in {fragmentGroupedFieldSet}:
660
664
- Let {responseKey} be the response key shared by all fields in
661
665
{fragmentGroup}.
@@ -679,44 +683,53 @@ DoesFragmentTypeApply(objectType, fragmentType):
679
683
- if {objectType} is a possible type of {fragmentType}, return {true}
680
684
otherwise return {false}.
681
685
682
- DeferFragment(objectType, objectValue, fragmentSelectionSet, parentPath):
686
+ #### Async Payload Record
687
+
688
+ An Async Payload Record is either a Deferred Fragment Record or a Stream Record.
689
+ All Async Payload Records are structures containing:
683
690
684
- - Let {label} be the value or the variable to {deferDirective}'s {label}
685
- argument.
686
- - Let {deferredFragmentRecord} be the result of calling
687
- {CreateDeferredFragmentRecord(label, objectType, objectValue,
688
- fragmentSelectionSet, parentPath)}.
689
- - return {deferredFragmentRecord}.
691
+ - {label}: value derived from the corresponding ` @defer ` or ` @stream ` directive.
692
+ - {parentRecord}: optionally an Async Payload Record.
693
+ - {errors}: a list of field errors encountered during execution.
694
+ - {dataExecution}: A result that can notify when the corresponding execution has
695
+ completed.
696
+ - {path}: a list of field names and indices from root to the location of the
697
+ corresponding ` @defer ` or ` @stream ` directive.
690
698
691
699
#### Deferred Fragment Record
692
700
693
701
Let {deferredFragmentRecord} be an inline fragment or fragment spread with
694
702
` @defer ` provided.
695
703
696
- Deferred Fragment Record is a structure containing:
704
+ Deferred Fragment Record is a structure containing all the entries of Async
705
+ Payload Record, and additionally:
697
706
698
- - {label}: value derived from the ` @defer ` directive.
699
707
- {objectType}: of the {deferredFragmentRecord}.
700
708
- {objectValue}: of the {deferredFragmentRecord}.
701
709
- {fragmentSelectionSet}: the top level selection set of
702
710
{deferredFragmentRecord}.
703
- - {path}: a list of field names and indices from root to
704
- {deferredFragmentRecord}.
705
711
706
712
CreateDeferredFragmentRecord(label, objectType, objectValue,
707
- fragmentSelectionSet, path):
713
+ fragmentSelectionSet, path, parentRecord ):
708
714
709
- - If {path} is not provided, initialize it to an empty list.
710
715
- Construct a deferred fragment record based on the parameters passed in.
716
+ - Initialize {errors} to an empty list.
711
717
712
718
ResolveDeferredFragmentRecord(deferredFragmentRecord, variableValues,
713
719
subsequentPayloads):
714
720
715
- - Let {label}, {objectType}, {objectValue}, {fragmentSelectionSet}, {path} be
716
- the corresponding fields in the deferred fragment record structure.
717
- - Let {payload} be the result of calling
718
- {ExecuteSelectionSet(fragmentSelectionSet, objectType, objectValue,
719
- variableValues, subsequentPayloads, path)}.
721
+ - Let {label}, {objectType}, {objectValue}, {fragmentSelectionSet}, {path},
722
+ {parentRecord} be the corresponding fields in the deferred fragment record
723
+ structure.
724
+ - Let {dataExecution} be the asynchronous future value of:
725
+ - Let {payload} be the result of {ExecuteSelectionSet(fragmentSelectionSet,
726
+ objectType, objectValue, variableValues, path, subsequentPayloads,
727
+ deferredFragmentRecord)}.
728
+ - If {parentRecord} is defined:
729
+ - Wait for the result of {dataExecution} on {parentRecord}.
730
+ - Return {payload}.
731
+ - Set {dataExecution} on {deferredFragmentRecord}.
732
+ - Let {payload} be the result of waiting for {dataExecution}.
720
733
- Add an entry to {payload} named ` label ` with the value {label}.
721
734
- Add an entry to {payload} named ` path ` with the value {path}.
722
735
- Return {payload}.
@@ -729,28 +742,27 @@ coerces any provided argument values, then resolves a value for the field, and
729
742
finally completes that value either by recursively executing another selection
730
743
set or coercing a scalar value.
731
744
732
- ExecuteField(objectType, objectValue, fieldType, fields, variableValues,
733
- subsequentPayloads, parentPath ):
745
+ ExecuteField(objectType, objectValue, fieldType, fields, variableValues, path,
746
+ subsequentPayloads, asyncRecord ):
734
747
735
748
- Let {field} be the first entry in {fields}.
736
749
- Let {fieldName} be the field name of {field}.
750
+ - Append {fieldName} to {path}.
737
751
- Let {argumentValues} be the result of {CoerceArgumentValues(objectType, field,
738
752
variableValues)}
739
753
- If {field} provides the directive ` @stream ` , let {streamDirective} be that
740
754
directive.
741
755
- Let {initialCount} be the value or variable provided to {streamDirective}'s
742
756
{initialCount} argument.
743
757
- Let {resolvedValue} be {ResolveFieldGenerator(objectType, objectValue,
744
- fieldName, argumentValues, initialCount )}.
758
+ fieldName, argumentValues)}.
745
759
- Let {result} be the result of calling {CompleteValue(fieldType, fields,
746
- resolvedValue, variableValues, subsequentPayloads, parentPath)}.
747
- - Append {fieldName} to the {path} field of every {subsequentPayloads}.
760
+ resolvedValue, variableValues, path, subsequentPayloads, asyncRecord)}.
748
761
- Return {result}.
749
762
- Let {resolvedValue} be {ResolveFieldValue(objectType, objectValue, fieldName,
750
763
argumentValues)}.
751
764
- Let {result} be the result of calling {CompleteValue(fieldType, fields,
752
- resolvedValue, variableValues, subsequentPayloads)}.
753
- - Append {fieldName} to the {path} for every {subsequentPayloads}.
765
+ resolvedValue, variableValues, path, subsequentPayloads, asyncRecord)}.
754
766
- Return {result}.
755
767
756
768
### Coercing Field Arguments
@@ -836,14 +848,13 @@ ResolveFieldValue(objectType, objectValue, fieldName, argumentValues):
836
848
- Return the result of calling {resolver}, providing {objectValue} and
837
849
{argumentValues}.
838
850
839
- ResolveFieldGenerator(objectType, objectValue, fieldName, argumentValues,
840
- initialCount):
851
+ ResolveFieldGenerator(objectType, objectValue, fieldName, argumentValues):
841
852
842
853
- If {objectType} provide an internal function {generatorResolver} for
843
854
generating partially resolved value of a list field named {fieldName}:
844
855
- Let {generatorResolver} be the internal function.
845
856
- Return the iterator from calling {generatorResolver}, providing
846
- {objectValue}, {argumentValues} and {initialCount }.
857
+ {objectValue} and {argumentValues }.
847
858
- Create {generator} from {ResolveFieldValue(objectType, objectValue, fieldName,
848
859
argumentValues)}.
849
860
- Return {generator}.
@@ -863,52 +874,58 @@ field execution process continues recursively. In the case where a value
863
874
returned for a list type field is an iterator due to ` @stream ` specified on the
864
875
field, value completion iterates over the iterator until the number of items
865
876
yield by the iterator satisfies ` initialCount ` specified on the ` @stream `
866
- directive. Unresolved items in the iterator will be stored in a stream record
867
- which the executor resumes to execute after the initial execution finishes.
877
+ directive.
868
878
869
879
#### Stream Record
870
880
871
881
Let {streamField} be a list field with a ` @stream ` directive provided.
872
882
873
- A Stream Record is a structure containing:
883
+ A Stream Record is a structure containing all the entries of Async Payload
884
+ Record, and additionally:
874
885
875
- - {label}: value derived from the ` @stream ` directive's ` label ` argument.
876
886
- {iterator}: created by {ResolveFieldGenerator}.
877
- - {resolvedItems}: items resolved from the {iterator} but not yet delivered.
878
887
- {index}: indicating the position of the item in the complete list.
879
- - {path}: a list of field names and indices from root to {streamField}.
880
888
- {fields}: the group of fields grouped by CollectFields() for {streamField}.
881
889
- {innerType}: inner type of {streamField}'s type.
882
890
883
- CreateStreamRecord(label, initialCount, iterator, resolvedItems, index, fields ,
884
- innerType ):
891
+ CreateStreamRecord(label, iterator, index, fields, innerType, path ,
892
+ parentRecord ):
885
893
886
894
- Construct a stream record based on the parameters passed in.
895
+ - Initialize {errors} to an empty list.
887
896
888
897
ResolveStreamRecord(streamRecord, variableValues, subsequentPayloads):
889
898
890
- - Let {label}, {iterator }, {resolvedItems }, {index}, {path}, {fields},
899
+ - Let {label}, {parentRecord }, {iterator }, {index}, {path}, {fields},
891
900
{innerType} be the correspondent fields on the Stream Record structure.
892
- - Wait for the next item from {iterator}.
893
- - If an item is not retrieved because {iterator} has completed:
894
- - Return {null}
895
- - Let {item} be the item retrieved from {iterator}.
896
- - Append {index} to {path}.
897
- - Increment {index}.
898
- - Let {payload} be the result of calling CompleteValue(innerType, fields, item,
899
- variableValues, subsequentPayloads, path)}.
901
+ - Let {indexPath} be {path} with {index} appended.
902
+ - Let {dataExecution} be the asynchronous future value of:
903
+ - Wait for the next item from {iterator}.
904
+ - If an item is not retrieved because {iterator} has completed:
905
+ - Return {null}.
906
+ - Let {item} be the item retrieved from {iterator}.
907
+ - Let {payload} be the result of calling {CompleteValue(innerType, fields,
908
+ item, variableValues, indexPath, subsequentPayloads, parentRecord)}.
909
+ - Increment {index}.
910
+ - Let {nextStreamRecord} be the result of calling {CreateStreamRecord(label,
911
+ iterator, index, fields, innerType, path, streamRecord)}.
912
+ - Append {nextStreamRecord} to {subsequentPayloads}.
913
+ - If {parentRecord} is defined:
914
+ - Wait for the result of {dataExecution} on {parentRecord}.
915
+ - Return {payload}.
916
+ - Set {dataExecution} on {streamRecord}.
917
+ - Let {payload} be the result of waiting for {dataExecution}.
900
918
- Add an entry to {payload} named ` label ` with the value {label}.
901
- - Add an entry to {payload} named ` path ` with the value {path}.
902
- - Append {streamRecord} to {subsequentPayloads}.
919
+ - Add an entry to {payload} named ` path ` with the value {indexPath}.
903
920
- Return {payload}.
904
921
905
- CompleteValue(fieldType, fields, result, variableValues, subsequentPayloads ,
906
- parentPath ):
922
+ CompleteValue(fieldType, fields, result, variableValues, path ,
923
+ subsequentPayloads, asyncRecord ):
907
924
908
925
- If the {fieldType} is a Non-Null type:
909
926
- Let {innerType} be the inner type of {fieldType}.
910
927
- Let {completedResult} be the result of calling {CompleteValue(innerType,
911
- fields, result, variableValues)}.
928
+ fields, result, variableValues, path )}.
912
929
- If {completedResult} is {null}, raise a _ field error_ .
913
930
- Return {completedResult}.
914
931
- If {result} is {null} (or another internal value similar to {null} such as
@@ -923,26 +940,33 @@ parentPath):
923
940
- If {initialCount} is less than zero, raise a _ field error_ .
924
941
- Let {label} be the value or variable provided to {streamDirective}'s
925
942
{label} argument.
926
- - Let {resolvedItems} be an empty list
927
- - For each {members} in {result}:
928
- - Append all items from {members} to {resolvedItems}.
929
- - If the length of {resolvedItems} is greater or equal to {initialCount}:
930
- - Let {initialItems} be the sublist of the first {initialCount} items
931
- from {resolvedItems}.
932
- - Let {remainingItems} be the sublist of the items in {resolvedItems}
933
- after the first {initialCount} items.
943
+ - Let {initialItems} be an empty list
944
+ - Let {index} be zero.
945
+ - While {result} is not closed:
946
+ - If {streamDirective} was not provided or {index} is not greater than or
947
+ equal to {initialCount}:
948
+ - Wait for the next item from {result}.
949
+ - Let {resultItem} be the item retrieved from {result}.
950
+ - Let {indexPath} be {path} with {index} appended.
951
+ - Let {resolvedItem} be the result of calling {CompleteValue(innerType,
952
+ fields, resultItem, variableValues, indexPath, subsequentPayloads,
953
+ asyncRecord)}.
954
+ - Append {resolvedItem} to {initialItems}.
955
+ - Increment {index}.
956
+ - If {streamDirective} was provided and {index} is greater than or equal
957
+ to {initialCount}:
934
958
- Let {streamRecord} be the result of calling {CreateStreamRecord(label,
935
- initialCount, result, remainingItems, initialCount, fields, innerType,
936
- parentPath)}
959
+ result, index, fields, innerType, path, asyncRecord)}.
937
960
- Append {streamRecord} to {subsequentPayloads}.
938
961
- Let {result} be {initialItems}.
939
- - Exit for each loop.
962
+ - Exit while loop.
963
+ - Return {initialItems}.
940
964
- If {result} is not a collection of values, raise a _ field error_ .
941
965
- Let {innerType} be the inner type of {fieldType}.
942
966
- Return a list where each list item is the result of calling
943
- {CompleteValue(innerType, fields, resultItem, variableValues,
944
- subsequentPayloads, parentPath )}, where {resultItem} is each item in
945
- {result}.
967
+ {CompleteValue(innerType, fields, resultItem, variableValues, indexPath,
968
+ subsequentPayloads, asyncRecord )}, where {resultItem} is each item in
969
+ {result} and {indexPath} is {path} with the index of the item appended .
946
970
- If {fieldType} is a Scalar or Enum type:
947
971
- Return the result of {CoerceResult(fieldType, result)}.
948
972
- If {fieldType} is an Object, Interface, or Union type:
@@ -952,7 +976,7 @@ parentPath):
952
976
- Let {objectType} be {ResolveAbstractType(fieldType, result)}.
953
977
- Let {subSelectionSet} be the result of calling {MergeSelectionSets(fields)}.
954
978
- Return the result of evaluating {ExecuteSelectionSet(subSelectionSet,
955
- objectType, result, variableValues, subsequentPayloads, parentPath )}
979
+ objectType, result, variableValues, path, subsequentPayloads, asyncRecord )}
956
980
_ normally_ (allowing for parallelization).
957
981
958
982
** Coercing Results**
0 commit comments