2727
2828__all__ = [
2929 "CollectFieldsContext" ,
30+ "CollectedFields" ,
3031 "DeferUsage" ,
3132 "FieldDetails" ,
3233 "collect_fields" ,
@@ -69,13 +70,20 @@ class CollectFieldsContext(NamedTuple):
6970 visited_fragment_names : set [str ]
7071
7172
73+ class CollectedFields (NamedTuple ):
74+ """Collected fields with new defer usages."""
75+
76+ fields : dict [str , list [FieldDetails ]]
77+ new_defer_usages : list [DeferUsage ]
78+
79+
7280def collect_fields (
7381 schema : GraphQLSchema ,
7482 fragments : dict [str , FragmentDefinitionNode ],
7583 variable_values : dict [str , Any ],
7684 runtime_type : GraphQLObjectType ,
7785 operation : OperationDefinitionNode ,
78- ) -> dict [ str , list [ FieldDetails ]] :
86+ ) -> CollectedFields :
7987 """Collect fields.
8088
8189 Given a selection_set, collects all the fields and returns them.
@@ -87,6 +95,7 @@ def collect_fields(
8795 For internal use only.
8896 """
8997 grouped_field_set : dict [str , list [FieldDetails ]] = defaultdict (list )
98+ new_defer_usages : list [DeferUsage ] = []
9099 context = CollectFieldsContext (
91100 schema ,
92101 fragments ,
@@ -96,8 +105,10 @@ def collect_fields(
96105 set (),
97106 )
98107
99- collect_fields_impl (context , operation .selection_set , grouped_field_set )
100- return grouped_field_set
108+ collect_fields_impl (
109+ context , operation .selection_set , grouped_field_set , new_defer_usages
110+ )
111+ return CollectedFields (grouped_field_set , new_defer_usages )
101112
102113
103114def collect_subfields (
@@ -107,7 +118,7 @@ def collect_subfields(
107118 operation : OperationDefinitionNode ,
108119 return_type : GraphQLObjectType ,
109120 field_details : list [FieldDetails ],
110- ) -> dict [ str , list [ FieldDetails ]] :
121+ ) -> CollectedFields :
111122 """Collect subfields.
112123
113124 Given a list of field nodes, collects all the subfields of the passed in fields,
@@ -128,6 +139,7 @@ def collect_subfields(
128139 set (),
129140 )
130141 sub_grouped_field_set : dict [str , list [FieldDetails ]] = defaultdict (list )
142+ new_defer_usages : list [DeferUsage ] = []
131143
132144 for field_detail in field_details :
133145 node = field_detail .node
@@ -136,17 +148,18 @@ def collect_subfields(
136148 context ,
137149 node .selection_set ,
138150 sub_grouped_field_set ,
151+ new_defer_usages ,
139152 field_detail .defer_usage ,
140153 )
141154
142- return sub_grouped_field_set
155+ return CollectedFields ( sub_grouped_field_set , new_defer_usages )
143156
144157
145158def collect_fields_impl (
146159 context : CollectFieldsContext ,
147160 selection_set : SelectionSetNode ,
148161 grouped_field_set : dict [str , list [FieldDetails ]],
149- parent_defer_usage : DeferUsage | None = None ,
162+ new_defer_usages : list [ DeferUsage ] ,
150163 defer_usage : DeferUsage | None = None ,
151164) -> None :
152165 """Collect fields (internal implementation)."""
@@ -164,31 +177,39 @@ def collect_fields_impl(
164177 if not should_include_node (variable_values , selection ):
165178 continue
166179 key = get_field_entry_key (selection )
167- grouped_field_set [key ].append (
168- FieldDetails (selection , defer_usage or parent_defer_usage )
169- )
180+ grouped_field_set [key ].append (FieldDetails (selection , defer_usage ))
170181 elif isinstance (selection , InlineFragmentNode ):
171182 if not should_include_node (
172183 variable_values , selection
173184 ) or not does_fragment_condition_match (schema , selection , runtime_type ):
174185 continue
175186
176187 new_defer_usage = get_defer_usage (
177- operation , variable_values , selection , parent_defer_usage
188+ operation , variable_values , selection , defer_usage
178189 )
179190
180- collect_fields_impl (
181- context ,
182- selection .selection_set ,
183- grouped_field_set ,
184- parent_defer_usage ,
185- new_defer_usage or defer_usage ,
186- )
191+ if new_defer_usage is None :
192+ collect_fields_impl (
193+ context ,
194+ selection .selection_set ,
195+ grouped_field_set ,
196+ new_defer_usages ,
197+ defer_usage ,
198+ )
199+ else :
200+ new_defer_usages .append (new_defer_usage )
201+ collect_fields_impl (
202+ context ,
203+ selection .selection_set ,
204+ grouped_field_set ,
205+ new_defer_usages ,
206+ new_defer_usage ,
207+ )
187208 elif isinstance (selection , FragmentSpreadNode ): # pragma: no cover else
188209 frag_name = selection .name .value
189210
190211 new_defer_usage = get_defer_usage (
191- operation , variable_values , selection , parent_defer_usage
212+ operation , variable_values , selection , defer_usage
192213 )
193214
194215 if new_defer_usage is None and (
@@ -205,14 +226,22 @@ def collect_fields_impl(
205226
206227 if new_defer_usage is None :
207228 visited_fragment_names .add (frag_name )
208-
209- collect_fields_impl (
210- context ,
211- fragment .selection_set ,
212- grouped_field_set ,
213- parent_defer_usage ,
214- new_defer_usage or defer_usage ,
215- )
229+ collect_fields_impl (
230+ context ,
231+ fragment .selection_set ,
232+ grouped_field_set ,
233+ new_defer_usages ,
234+ defer_usage ,
235+ )
236+ else :
237+ new_defer_usages .append (new_defer_usage )
238+ collect_fields_impl (
239+ context ,
240+ fragment .selection_set ,
241+ grouped_field_set ,
242+ new_defer_usages ,
243+ new_defer_usage ,
244+ )
216245
217246
218247def get_defer_usage (
0 commit comments