Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit ba48968

Browse files
committed
refactor(IncrementalGraph): use set of pending deferred grouped field set results to reduce mutation
Replicates graphql/graphql-js@15ab731
1 parent 2efb386 commit ba48968

File tree

4 files changed

+68
-62
lines changed

4 files changed

+68
-62
lines changed

‎src/graphql/execution/execute.py‎

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,15 +1626,19 @@ def execute_deferred_grouped_field_sets(
16261626
defer_usage_set, defer_map
16271627
)
16281628

1629+
deferred_grouped_field_set_record = DeferredGroupedFieldSetRecord(
1630+
deferred_fragment_records, cast("DeferredGroupedFieldSetResult", None)
1631+
)
1632+
16291633
if should_defer(parent_defer_usages, defer_usage_set):
16301634

16311635
async def executor(
1632-
deferred_fragment_records: list[DeferredFragmentRecord],
1636+
deferred_grouped_field_set_record: DeferredGroupedFieldSetRecord,
16331637
grouped_field_set: GroupedFieldSet,
16341638
defer_usage_set: DeferUsageSet,
16351639
) -> DeferredGroupedFieldSetResult:
16361640
result = self.execute_deferred_grouped_field_set(
1637-
deferred_fragment_records,
1641+
deferred_grouped_field_set_record,
16381642
parent_type,
16391643
source_value,
16401644
path,
@@ -1646,33 +1650,30 @@ async def executor(
16461650
return await result
16471651
return cast("DeferredGroupedFieldSetResult", result)
16481652

1649-
deferred_grouped_field_set_record = DeferredGroupedFieldSetRecord(
1650-
deferred_fragment_records,
1651-
executor(
1652-
deferred_fragment_records, grouped_field_set, defer_usage_set
1653-
),
1653+
deferred_grouped_field_set_record.result = executor(
1654+
deferred_grouped_field_set_record,
1655+
grouped_field_set,
1656+
defer_usage_set,
16541657
)
16551658
else:
16561659
executed = self.execute_deferred_grouped_field_set(
1657-
deferred_fragment_records,
1660+
deferred_grouped_field_set_record,
16581661
parent_type,
16591662
source_value,
16601663
path,
16611664
grouped_field_set,
16621665
IncrementalContext(defer_usage_set),
16631666
defer_map,
16641667
)
1665-
deferred_grouped_field_set_record = DeferredGroupedFieldSetRecord(
1666-
deferred_fragment_records, executed
1667-
)
1668+
deferred_grouped_field_set_record.result = executed
16681669

16691670
append_record(deferred_grouped_field_set_record)
16701671

16711672
return new_deferred_grouped_field_set_records
16721673

16731674
def execute_deferred_grouped_field_set(
16741675
self,
1675-
deferred_fragment_records: list[DeferredFragmentRecord],
1676+
deferred_grouped_field_set_record: DeferredGroupedFieldSetRecord,
16761677
parent_type: GraphQLObjectType,
16771678
source_value: Any,
16781679
path: Path | None,
@@ -1692,7 +1693,7 @@ def execute_deferred_grouped_field_set(
16921693
)
16931694
except GraphQLError as error:
16941695
return NonReconcilableDeferredGroupedFieldSetResult(
1695-
deferred_fragment_records,
1696+
deferred_grouped_field_set_record,
16961697
path.as_list() if path else [],
16971698
with_error(incremental_context.errors, error),
16981699
)
@@ -1704,13 +1705,13 @@ async def await_result() -> DeferredGroupedFieldSetResult:
17041705
awaited_result = await result
17051706
except GraphQLError as error:
17061707
return NonReconcilableDeferredGroupedFieldSetResult(
1707-
deferred_fragment_records,
1708+
deferred_grouped_field_set_record,
17081709
path.as_list() if path else [],
17091710
with_error(incremental_context.errors, error),
17101711
)
17111712
return build_deferred_grouped_field_set_result(
17121713
incremental_context.errors,
1713-
deferred_fragment_records,
1714+
deferred_grouped_field_set_record,
17141715
path,
17151716
awaited_result,
17161717
)
@@ -1719,7 +1720,7 @@ async def await_result() -> DeferredGroupedFieldSetResult:
17191720

17201721
return build_deferred_grouped_field_set_result(
17211722
incremental_context.errors,
1722-
deferred_fragment_records,
1723+
deferred_grouped_field_set_record,
17231724
path,
17241725
result, # type: ignore
17251726
)
@@ -2330,13 +2331,13 @@ def should_defer(
23302331

23312332
def build_deferred_grouped_field_set_result(
23322333
errors: list[GraphQLError] | None,
2333-
deferred_fragment_records: list[DeferredFragmentRecord],
2334+
deferred_grouped_field_set_record: DeferredGroupedFieldSetRecord,
23342335
path: Path | None,
23352336
result: GraphQLWrappedResult[dict[str, Any]],
23362337
) -> DeferredGroupedFieldSetResult:
23372338
"""Build a deferred grouped fieldset result."""
23382339
return ReconcilableDeferredGroupedFieldSetResult(
2339-
deferred_fragment_records=deferred_fragment_records,
2340+
deferred_grouped_field_set_record=deferred_grouped_field_set_record,
23402341
path=path.as_list() if path else [],
23412342
result=BareDeferredGroupedFieldSetResult(result.result, errors or None),
23422343
incremental_data_records=result.increments,

‎src/graphql/execution/incremental_graph.py‎

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
if TYPE_CHECKING:
2626
from graphql.execution.types import (
2727
DeferredFragmentRecord,
28+
DeferredGroupedFieldSetRecord,
2829
DeferredGroupedFieldSetResult,
2930
IncrementalDataRecord,
3031
IncrementalDataRecordResult,
@@ -48,23 +49,23 @@ class DeferredFragmentNode:
4849
__slots__ = (
4950
"children",
5051
"deferred_fragment_record",
51-
"expected_reconcilable_results",
52+
"deferred_grouped_field_set_records",
5253
"reconcilable_results",
5354
"results",
5455
)
5556

5657
deferred_fragment_record: DeferredFragmentRecord
57-
expected_reconcilable_results: int
58+
deferred_grouped_field_set_records: dict[DeferredGroupedFieldSetRecord, None]
5859
results: list[DeferredGroupedFieldSetResult]
59-
reconcilable_results: list[ReconcilableDeferredGroupedFieldSetResult]
60+
reconcilable_results: dict[ReconcilableDeferredGroupedFieldSetResult, None]
6061
children: list[DeferredFragmentNode]
6162

6263
def __init__(self, deferred_fragment_record: DeferredFragmentRecord) -> None:
6364
"""Initialize the DeferredFragmentNode."""
6465
self.deferred_fragment_record = deferred_fragment_record
65-
self.expected_reconcilable_results = 0
66+
self.deferred_grouped_field_set_records = {}
6667
self.results = []
67-
self.reconcilable_results = []
68+
self.reconcilable_results = {}
6869
self.children = []
6970

7071

@@ -120,7 +121,9 @@ def add_incremental_data_records(
120121
deferred_fragment_node = self._add_deferred_fragment_node(
121122
deferred_fragment_record
122123
)
123-
deferred_fragment_node.expected_reconcilable_results += 1
124+
deferred_fragment_node.deferred_grouped_field_set_records[
125+
incremental_data_record
126+
] = None
124127

125128
deferred_result = incremental_data_record.result
126129
if is_awaitable(deferred_result):
@@ -160,15 +163,17 @@ def add_completed_reconcilable_deferred_grouped_field_set(
160163
self, reconcilable_result: ReconcilableDeferredGroupedFieldSetResult
161164
) -> None:
162165
"""Add a completed reconcilable deferred grouped field set result."""
166+
record = reconcilable_result.deferred_grouped_field_set_record
163167
deferred_fragment_nodes = filter(
164168
is_deferred_fragment_node,
165169
map(
166170
self._deferred_fragment_nodes.get,
167-
reconcilable_result.deferred_fragment_records,
171+
record.deferred_fragment_records,
168172
),
169173
)
170174
for deferred_fragment_node in deferred_fragment_nodes:
171-
deferred_fragment_node.reconcilable_results.append(reconcilable_result)
175+
del deferred_fragment_node.deferred_grouped_field_set_records[record]
176+
deferred_fragment_node.reconcilable_results[reconcilable_result] = None
172177

173178
def get_new_pending(self) -> list[SubsequentResultRecord]:
174179
"""Get new pending subsequent result records."""
@@ -183,7 +188,7 @@ def get_new_pending(self) -> list[SubsequentResultRecord]:
183188
if is_stream_node(node):
184189
_pending[node] = None
185190
add_result(node)
186-
elif node.expected_reconcilable_results: # type: ignore
191+
elif node.deferred_grouped_field_set_records: # type: ignore
187192
_pending[node] = None
188193
add_result(node.deferred_fragment_record) # type: ignore
189194
else:
@@ -218,17 +223,26 @@ def complete_deferred_fragment(
218223
deferred_fragment_record: DeferredFragmentRecord,
219224
) -> list[ReconcilableDeferredGroupedFieldSetResult] | None:
220225
"""Complete a deferred fragment."""
226+
deferred_fragment_nodes = self._deferred_fragment_nodes
221227
try:
222-
deferred_fragment_node = self._deferred_fragment_nodes[
223-
deferred_fragment_record
224-
]
228+
deferred_fragment_node = deferred_fragment_nodes[deferred_fragment_record]
225229
except KeyError: # pragma: no cover
226230
return None
227-
reconcilable_results = deferred_fragment_node.reconcilable_results
228-
if deferred_fragment_node.expected_reconcilable_results != len(
229-
reconcilable_results
230-
):
231+
if deferred_fragment_node.deferred_grouped_field_set_records:
231232
return None
233+
reconcilable_results = list(deferred_fragment_node.reconcilable_results)
234+
for reconcilable_result in reconcilable_results:
235+
record = reconcilable_result.deferred_grouped_field_set_record
236+
for other_deferred_fragment_record in record.deferred_fragment_records:
237+
try:
238+
other_deferred_fragment_node = deferred_fragment_nodes[
239+
other_deferred_fragment_record
240+
]
241+
except KeyError: # pragma: no cover
242+
continue
243+
del other_deferred_fragment_node.reconcilable_results[
244+
reconcilable_result
245+
]
232246
self._remove_pending(deferred_fragment_node)
233247
new_pending = self._new_pending
234248
for child in deferred_fragment_node.children:
@@ -288,11 +302,11 @@ def _enqueue_completed_deferred_grouped_field_set(
288302
) -> None:
289303
"""Enqueue completed deferred grouped field set result."""
290304
is_pending = False
291-
for deferred_fragment_record in result.deferred_fragment_records:
305+
nodes = self._deferred_fragment_nodes
306+
record = result.deferred_grouped_field_set_record
307+
for deferred_fragment_record in record.deferred_fragment_records:
292308
try:
293-
deferred_fragment_node = self._deferred_fragment_nodes[
294-
deferred_fragment_record
295-
]
309+
deferred_fragment_node = nodes[deferred_fragment_record]
296310
except KeyError: # pragma: no cover
297311
continue
298312
if deferred_fragment_node in self._pending:

‎src/graphql/execution/incremental_publisher.py‎

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,12 @@ def _handle_completed_deferred_grouped_field_set(
215215
"""Handle completed deferred grouped field set result."""
216216
append_completed = context.completed.append
217217
append_incremental = context.incremental.append
218+
record = deferred_grouped_field_set_result.deferred_grouped_field_set_record
218219
if is_non_reconcilable_deferred_grouped_field_set_result(
219220
deferred_grouped_field_set_result
220221
):
221222
remove_deferred = self._incremental_graph.remove_deferred_fragment
222-
for deferred_fragment_record in (
223-
deferred_grouped_field_set_result.deferred_fragment_records
224-
): # pragma: no branch
223+
for deferred_fragment_record in record.deferred_fragment_records:
225224
id_ = deferred_fragment_record.id
226225
if id_ is not None: # pragma: no branch
227226
append_completed(
@@ -244,20 +243,16 @@ def _handle_completed_deferred_grouped_field_set(
244243
self._incremental_graph.add_incremental_data_records(
245244
incremental_data_records
246245
)
246+
247247
complete_deferred = self._incremental_graph.complete_deferred_fragment
248-
for deferred_fragment_record in (
249-
deferred_grouped_field_set_result.deferred_fragment_records
250-
): # pragma: no branch
248+
for deferred_fragment_record in record.deferred_fragment_records:
251249
id_ = deferred_fragment_record.id
252250
if id_ is None:
253251
continue # pragma: no cover
254252
reconcilable_results = complete_deferred(deferred_fragment_record)
255253
if reconcilable_results is None:
256254
continue
257255
for reconcilable_result in reconcilable_results:
258-
if reconcilable_result.sent:
259-
continue
260-
reconcilable_result.sent = True
261256
best_id, sub_path = self._get_best_id_and_sub_path(
262257
id_, deferred_fragment_record, reconcilable_result
263258
)
@@ -320,9 +315,8 @@ def _get_best_id_and_sub_path(
320315
path = initial_deferred_fragment_record.path
321316
max_length = len(path.as_list()) if path else 0
322317
best_id = initial_id
323-
for deferred_fragment_record in (
324-
deferred_grouped_field_set_result.deferred_fragment_records
325-
): # pragma: no branch
318+
record = deferred_grouped_field_set_result.deferred_grouped_field_set_record
319+
for deferred_fragment_record in record.deferred_fragment_records:
326320
if deferred_fragment_record is initial_deferred_fragment_record:
327321
continue
328322
id_ = deferred_fragment_record.id

‎src/graphql/execution/types.py‎

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -704,52 +704,49 @@ def is_deferred_grouped_field_set_record(
704704
class ReconcilableDeferredGroupedFieldSetResult:
705705
"""Reconcilable deferred grouped field set result"""
706706

707-
deferred_fragment_records: list[DeferredFragmentRecord]
707+
deferred_grouped_field_set_record: DeferredGroupedFieldSetRecord
708708
path: list[str | int]
709709
result: BareDeferredGroupedFieldSetResult
710710
incremental_data_records: list[IncrementalDataRecord] | None
711-
sent: bool
712711
errors: None = None
713712

714713
__slots__ = (
715-
"deferred_fragment_records",
714+
"deferred_grouped_field_set_record",
716715
"incremental_data_records",
717716
"path",
718717
"result",
719-
"sent",
720718
)
721719

722720
def __init__(
723721
self,
724-
deferred_fragment_records: list[DeferredFragmentRecord],
722+
deferred_grouped_field_set_record: DeferredGroupedFieldSetRecord,
725723
path: list[str | int],
726724
result: BareDeferredGroupedFieldSetResult,
727725
incremental_data_records: list[IncrementalDataRecord] | None = None,
728726
) -> None:
729-
self.deferred_fragment_records = deferred_fragment_records
727+
self.deferred_grouped_field_set_record = deferred_grouped_field_set_record
730728
self.path = path
731729
self.result = result
732730
self.incremental_data_records = incremental_data_records
733-
self.sent = False
734731

735732

736733
class NonReconcilableDeferredGroupedFieldSetResult:
737734
"""Non-reconcilable deferred grouped field set result"""
738735

739-
errors: list[GraphQLError]
740-
deferred_fragment_records: list[DeferredFragmentRecord]
736+
deferred_grouped_field_set_record: DeferredGroupedFieldSetRecord
741737
path: list[str | int]
738+
errors: list[GraphQLError]
742739
result: None = None
743740

744-
__slots__ = "deferred_fragment_records", "errors", "path"
741+
__slots__ = "deferred_grouped_field_set_record", "errors", "path"
745742

746743
def __init__(
747744
self,
748-
deferred_fragment_records: list[DeferredFragmentRecord],
745+
deferred_grouped_field_set_record: DeferredGroupedFieldSetRecord,
749746
path: list[str | int],
750747
errors: list[GraphQLError],
751748
) -> None:
752-
self.deferred_fragment_records = deferred_fragment_records
749+
self.deferred_grouped_field_set_record = deferred_grouped_field_set_record
753750
self.path = path
754751
self.errors = errors
755752

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /