8686 IncrementalDataRecord ,
8787 IncrementalPublisher ,
8888 IncrementalResult ,
89+ InitialResultRecord ,
8990 StreamItemsRecord ,
91+ SubsequentDataRecord ,
9092 SubsequentIncrementalExecutionResult ,
9193)
9294from .middleware import MiddlewareManager
@@ -352,7 +354,6 @@ class ExecutionContext:
352354 field_resolver : GraphQLFieldResolver
353355 type_resolver : GraphQLTypeResolver
354356 subscribe_field_resolver : GraphQLFieldResolver
355- errors : list [GraphQLError ]
356357 incremental_publisher : IncrementalPublisher
357358 middleware_manager : MiddlewareManager | None
358359
@@ -371,7 +372,6 @@ def __init__(
371372 field_resolver : GraphQLFieldResolver ,
372373 type_resolver : GraphQLTypeResolver ,
373374 subscribe_field_resolver : GraphQLFieldResolver ,
374- errors : list [GraphQLError ],
375375 incremental_publisher : IncrementalPublisher ,
376376 middleware_manager : MiddlewareManager | None ,
377377 is_awaitable : Callable [[Any ], bool ] | None ,
@@ -385,7 +385,6 @@ def __init__(
385385 self .field_resolver = field_resolver
386386 self .type_resolver = type_resolver
387387 self .subscribe_field_resolver = subscribe_field_resolver
388- self .errors = errors
389388 self .incremental_publisher = incremental_publisher
390389 self .middleware_manager = middleware_manager
391390 if is_awaitable :
@@ -478,7 +477,6 @@ def build(
478477 field_resolver or default_field_resolver ,
479478 type_resolver or default_type_resolver ,
480479 subscribe_field_resolver or default_field_resolver ,
481- [],
482480 IncrementalPublisher (),
483481 middleware_manager ,
484482 is_awaitable ,
@@ -514,15 +512,14 @@ def build_per_event_execution_context(self, payload: Any) -> ExecutionContext:
514512 self .field_resolver ,
515513 self .type_resolver ,
516514 self .subscribe_field_resolver ,
517- [],
518- # no need to update incrementalPublisher,
519- # incremental delivery is not supported for subscriptions
520515 self .incremental_publisher ,
521516 self .middleware_manager ,
522517 self .is_awaitable ,
523518 )
524519
525- def execute_operation (self ) -> AwaitableOrValue [dict [str , Any ]]:
520+ def execute_operation (
521+ self , initial_result_record : InitialResultRecord
522+ ) -> AwaitableOrValue [dict [str , Any ]]:
526523 """Execute an operation.
527524
528525 Implements the "Executing operations" section of the spec.
@@ -551,12 +548,17 @@ def execute_operation(self) -> AwaitableOrValue[dict[str, Any]]:
551548 self .execute_fields_serially
552549 if operation .operation == OperationType .MUTATION
553550 else self .execute_fields
554- )(root_type , root_value , None , grouped_field_set ) # type: ignore
551+ )(root_type , root_value , None , grouped_field_set , initial_result_record )
555552
556553 for patch in patches :
557554 label , patch_grouped_filed_set = patch
558555 self .execute_deferred_fragment (
559- root_type , root_value , patch_grouped_filed_set , label , None
556+ root_type ,
557+ root_value ,
558+ patch_grouped_filed_set ,
559+ initial_result_record ,
560+ label ,
561+ None ,
560562 )
561563
562564 return result
@@ -567,6 +569,7 @@ def execute_fields_serially(
567569 source_value : Any ,
568570 path : Path | None ,
569571 grouped_field_set : GroupedFieldSet ,
572+ incremental_data_record : IncrementalDataRecord ,
570573 ) -> AwaitableOrValue [dict [str , Any ]]:
571574 """Execute the given fields serially.
572575
@@ -581,7 +584,11 @@ def reducer(
581584 response_name , field_group = field_item
582585 field_path = Path (path , response_name , parent_type .name )
583586 result = self .execute_field (
584- parent_type , source_value , field_group , field_path
587+ parent_type ,
588+ source_value ,
589+ field_group ,
590+ field_path ,
591+ incremental_data_record ,
585592 )
586593 if result is Undefined :
587594 return results
@@ -607,7 +614,7 @@ def execute_fields(
607614 source_value : Any ,
608615 path : Path | None ,
609616 grouped_field_set : GroupedFieldSet ,
610- incremental_data_record : IncrementalDataRecord | None = None ,
617+ incremental_data_record : IncrementalDataRecord ,
611618 ) -> AwaitableOrValue [dict [str , Any ]]:
612619 """Execute the given fields concurrently.
613620
@@ -662,7 +669,7 @@ def execute_field(
662669 source : Any ,
663670 field_group : FieldGroup ,
664671 path : Path ,
665- incremental_data_record : IncrementalDataRecord | None = None ,
672+ incremental_data_record : IncrementalDataRecord ,
666673 ) -> AwaitableOrValue [Any ]:
667674 """Resolve the field on the given source object.
668675
@@ -774,7 +781,7 @@ def handle_field_error(
774781 return_type : GraphQLOutputType ,
775782 field_group : FieldGroup ,
776783 path : Path ,
777- incremental_data_record : IncrementalDataRecord | None = None ,
784+ incremental_data_record : IncrementalDataRecord ,
778785 ) -> None :
779786 """Handle error properly according to the field type."""
780787 error = located_error (raw_error , field_group , path .as_list ())
@@ -784,13 +791,9 @@ def handle_field_error(
784791 if is_non_null_type (return_type ):
785792 raise error
786793
787- errors = (
788- incremental_data_record .errors if incremental_data_record else self .errors
789- )
790-
791794 # Otherwise, error protection is applied, logging the error and resolving a
792795 # null value for this field if one is encountered.
793- errors . append ( error )
796+ self . incremental_publisher . add_field_error ( incremental_data_record , error )
794797
795798 def complete_value (
796799 self ,
@@ -799,7 +802,7 @@ def complete_value(
799802 info : GraphQLResolveInfo ,
800803 path : Path ,
801804 result : Any ,
802- incremental_data_record : IncrementalDataRecord | None ,
805+ incremental_data_record : IncrementalDataRecord ,
803806 ) -> AwaitableOrValue [Any ]:
804807 """Complete a value.
805808
@@ -888,7 +891,7 @@ async def complete_awaitable_value(
888891 info : GraphQLResolveInfo ,
889892 path : Path ,
890893 result : Any ,
891- incremental_data_record : IncrementalDataRecord | None = None ,
894+ incremental_data_record : IncrementalDataRecord ,
892895 ) -> Any :
893896 """Complete an awaitable value."""
894897 try :
@@ -955,7 +958,7 @@ async def complete_async_iterator_value(
955958 info : GraphQLResolveInfo ,
956959 path : Path ,
957960 async_iterator : AsyncIterator [Any ],
958- incremental_data_record : IncrementalDataRecord | None ,
961+ incremental_data_record : IncrementalDataRecord ,
959962 ) -> list [Any ]:
960963 """Complete an async iterator.
961964
@@ -984,8 +987,8 @@ async def complete_async_iterator_value(
984987 info ,
985988 item_type ,
986989 path ,
987- stream .label ,
988990 incremental_data_record ,
991+ stream .label ,
989992 )
990993 ),
991994 timeout = ASYNC_DELAY ,
@@ -1039,7 +1042,7 @@ def complete_list_value(
10391042 info : GraphQLResolveInfo ,
10401043 path : Path ,
10411044 result : AsyncIterable [Any ] | Iterable [Any ],
1042- incremental_data_record : IncrementalDataRecord | None ,
1045+ incremental_data_record : IncrementalDataRecord ,
10431046 ) -> AwaitableOrValue [list [Any ]]:
10441047 """Complete a list value.
10451048
@@ -1093,8 +1096,8 @@ def complete_list_value(
10931096 field_group ,
10941097 info ,
10951098 item_type ,
1096- stream .label ,
10971099 previous_incremental_data_record ,
1100+ stream .label ,
10981101 )
10991102 continue
11001103
@@ -1138,7 +1141,7 @@ def complete_list_item_value(
11381141 field_group : FieldGroup ,
11391142 info : GraphQLResolveInfo ,
11401143 item_path : Path ,
1141- incremental_data_record : IncrementalDataRecord | None ,
1144+ incremental_data_record : IncrementalDataRecord ,
11421145 ) -> bool :
11431146 """Complete a list item value by adding it to the completed results.
11441147
@@ -1229,7 +1232,7 @@ def complete_abstract_value(
12291232 info : GraphQLResolveInfo ,
12301233 path : Path ,
12311234 result : Any ,
1232- incremental_data_record : IncrementalDataRecord | None ,
1235+ incremental_data_record : IncrementalDataRecord ,
12331236 ) -> AwaitableOrValue [Any ]:
12341237 """Complete an abstract value.
12351238
@@ -1344,7 +1347,7 @@ def complete_object_value(
13441347 info : GraphQLResolveInfo ,
13451348 path : Path ,
13461349 result : Any ,
1347- incremental_data_record : IncrementalDataRecord | None ,
1350+ incremental_data_record : IncrementalDataRecord ,
13481351 ) -> AwaitableOrValue [dict [str , Any ]]:
13491352 """Complete an Object value by executing all sub-selections."""
13501353 # If there is an `is_type_of()` predicate function, call it with the current
@@ -1379,7 +1382,7 @@ def collect_and_execute_subfields(
13791382 field_group : FieldGroup ,
13801383 path : Path ,
13811384 result : Any ,
1382- incremental_data_record : IncrementalDataRecord | None ,
1385+ incremental_data_record : IncrementalDataRecord ,
13831386 ) -> AwaitableOrValue [dict [str , Any ]]:
13841387 """Collect sub-fields to execute to complete this value."""
13851388 sub_grouped_field_set , sub_patches = self .collect_subfields (
@@ -1396,9 +1399,9 @@ def collect_and_execute_subfields(
13961399 return_type ,
13971400 result ,
13981401 sub_patch_grouped_field_set ,
1402+ incremental_data_record ,
13991403 label ,
14001404 path ,
1401- incremental_data_record ,
14021405 )
14031406
14041407 return sub_fields
@@ -1474,9 +1477,9 @@ def execute_deferred_fragment(
14741477 parent_type : GraphQLObjectType ,
14751478 source_value : Any ,
14761479 fields : GroupedFieldSet ,
1480+ parent_context : IncrementalDataRecord ,
14771481 label : str | None = None ,
14781482 path : Path | None = None ,
1479- parent_context : IncrementalDataRecord | None = None ,
14801483 ) -> None :
14811484 """Execute deferred fragment."""
14821485 incremental_publisher = self .incremental_publisher
@@ -1529,9 +1532,9 @@ def execute_stream_field(
15291532 field_group : FieldGroup ,
15301533 info : GraphQLResolveInfo ,
15311534 item_type : GraphQLOutputType ,
1535+ parent_context : IncrementalDataRecord ,
15321536 label : str | None = None ,
1533- parent_context : IncrementalDataRecord | None = None ,
1534- ) -> IncrementalDataRecord :
1537+ ) -> SubsequentDataRecord :
15351538 """Execute stream field."""
15361539 is_awaitable = self .is_awaitable
15371540 incremental_publisher = self .incremental_publisher
@@ -1678,8 +1681,8 @@ async def execute_stream_async_iterator(
16781681 info : GraphQLResolveInfo ,
16791682 item_type : GraphQLOutputType ,
16801683 path : Path ,
1684+ parent_context : IncrementalDataRecord ,
16811685 label : str | None = None ,
1682- parent_context : IncrementalDataRecord | None = None ,
16831686 ) -> None :
16841687 """Execute stream iterator."""
16851688 incremental_publisher = self .incremental_publisher
@@ -1877,21 +1880,24 @@ def execute_impl(
18771880 # Errors from sub-fields of a NonNull type may propagate to the top level,
18781881 # at which point we still log the error and null the parent field, which
18791882 # in this case is the entire response.
1880- errors = context .errors
18811883 incremental_publisher = context .incremental_publisher
1884+ initial_result_record = incremental_publisher .prepare_initial_result_record ()
18821885 build_response = context .build_response
18831886 try :
1884- result = context .execute_operation ()
1887+ result = context .execute_operation (initial_result_record )
18851888
18861889 if context .is_awaitable (result ):
18871890 # noinspection PyShadowingNames
18881891 async def await_result () -> Any :
18891892 try :
1893+ errors = incremental_publisher .get_initial_errors (
1894+ initial_result_record
1895+ )
18901896 initial_result = build_response (
18911897 await result , # type: ignore
18921898 errors ,
18931899 )
1894- incremental_publisher .publish_initial ()
1900+ incremental_publisher .publish_initial (initial_result_record )
18951901 if incremental_publisher .has_next ():
18961902 return ExperimentalIncrementalExecutionResults (
18971903 initial_result = InitialIncrementalExecutionResult (
@@ -1902,14 +1908,17 @@ async def await_result() -> Any:
19021908 subsequent_results = incremental_publisher .subscribe (),
19031909 )
19041910 except GraphQLError as error :
1905- errors .append (error )
1911+ incremental_publisher .add_field_error (initial_result_record , error )
1912+ errors = incremental_publisher .get_initial_errors (
1913+ initial_result_record
1914+ )
19061915 return build_response (None , errors )
19071916 return initial_result
19081917
19091918 return await_result ()
19101919
1911- initial_result = build_response (result , errors ) # type: ignore
1912- incremental_publisher .publish_initial ()
1920+ initial_result = build_response (result , initial_result_record . errors ) # type: ignore
1921+ incremental_publisher .publish_initial (initial_result_record )
19131922 if incremental_publisher .has_next ():
19141923 return ExperimentalIncrementalExecutionResults (
19151924 initial_result = InitialIncrementalExecutionResult (
@@ -1920,7 +1929,8 @@ async def await_result() -> Any:
19201929 subsequent_results = incremental_publisher .subscribe (),
19211930 )
19221931 except GraphQLError as error :
1923- errors .append (error )
1932+ incremental_publisher .add_field_error (initial_result_record , error )
1933+ errors = incremental_publisher .get_initial_errors (initial_result_record )
19241934 return build_response (None , errors )
19251935 return initial_result
19261936
0 commit comments