1515
1616
1717class Executor (object ):
18- def __init__ (self , execution_middlewares = None , default_resolver = default_resolve_fn ):
19- self .execution_middlewares = execution_middlewares or []
20- self .default_resolve_fn = default_resolver
18+ def __init__ (self , execution_middlewares = None , default_resolver = default_resolve_fn , map_type = dict ):
19+ assert issubclass (map_type , collections .MutableMapping )
20+
21+ self ._execution_middlewares = execution_middlewares or []
22+ self ._default_resolve_fn = default_resolver
23+ self ._map_type = map_type
24+ self ._enforce_strict_ordering = issubclass (map_type , collections .OrderedDict )
25+
26+ @property
27+ def enforce_strict_ordering (self ):
28+ return self ._enforce_strict_ordering
29+
30+ @property
31+ def map_type (self ):
32+ return self ._map_type
2133
2234 def execute (self , schema , request = '' , root = None , args = None , operation_name = None , request_context = None ,
2335 execute_serially = False , validate_ast = True ):
@@ -34,7 +46,7 @@ def execute(self, schema, request='', root=None, args=None, operation_name=None,
3446 validate_ast
3547 )
3648
37- for middleware in self .execution_middlewares :
49+ for middleware in self ._execution_middlewares :
3850 if hasattr (middleware , 'execution_result' ):
3951 curried_execution_function = functools .partial (middleware .execution_result , curried_execution_function )
4052
@@ -81,7 +93,10 @@ def _execute_operation(self, ctx, root, operation, execute_serially):
8193 if operation .operation == 'mutation' or execute_serially :
8294 execute_serially = True
8395
84- fields = DefaultOrderedDict (list ) if execute_serially else collections .defaultdict (list )
96+ fields = DefaultOrderedDict (list ) \
97+ if (execute_serially or self ._enforce_strict_ordering ) \
98+ else collections .defaultdict (list )
99+
85100 fields = collect_fields (ctx , type , operation .selection_set , fields , set ())
86101
87102 if execute_serially :
@@ -101,20 +116,20 @@ def collect_result(resolved_result):
101116 return results
102117
103118 if isinstance (result , Deferred ):
104- return result .add_callback (collect_result )
119+ return succeed ( result ) .add_callback (collect_result )
105120
106121 else :
107122 return collect_result (result )
108123
109124 def execute_field (prev_deferred , response_name ):
110125 return prev_deferred .add_callback (execute_field_callback , response_name )
111126
112- return functools .reduce (execute_field , fields .keys (), succeed ({} ))
127+ return functools .reduce (execute_field , fields .keys (), succeed (self . _map_type () ))
113128
114129 def _execute_fields (self , execution_context , parent_type , source_value , fields ):
115130 contains_deferred = False
116131
117- results = {}
132+ results = self . _map_type ()
118133 for response_name , field_asts in fields .items ():
119134 result = self ._resolve_field (execution_context , parent_type , source_value , field_asts )
120135 if result is Undefined :
@@ -138,7 +153,7 @@ def _resolve_field(self, execution_context, parent_type, source, field_asts):
138153 return Undefined
139154
140155 return_type = field_def .type
141- resolve_fn = field_def .resolver or self .default_resolve_fn
156+ resolve_fn = field_def .resolver or self ._default_resolve_fn
142157
143158 # Build a dict of arguments from the field.arguments AST, using the variables scope to
144159 # fulfill any variable references.
@@ -283,7 +298,7 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
283298 )
284299
285300 # Collect sub-fields to execute to complete this value.
286- subfield_asts = collections .defaultdict (list )
301+ subfield_asts = DefaultOrderedDict ( list ) if self . _enforce_strict_ordering else collections .defaultdict (list )
287302 visited_fragment_names = set ()
288303 for field_ast in field_asts :
289304 selection_set = field_ast .selection_set
@@ -298,7 +313,7 @@ def run_resolve_fn(self, resolve_fn, source, args, info):
298313 curried_resolve_fn = functools .partial (resolve_fn , source , args , info )
299314
300315 try :
301- for middleware in self .execution_middlewares :
316+ for middleware in self ._execution_middlewares :
302317 if hasattr (middleware , 'run_resolve_fn' ):
303318 curried_resolve_fn = functools .partial (middleware .run_resolve_fn , curried_resolve_fn , resolve_fn )
304319
0 commit comments