11import functools
22
3- from promise import Promise , promise_for_dict
3+ from promise import Promise , is_thenable , promise_for_dict
44
55from ...pyutils .cached_property import cached_property
66from ...pyutils .default_ordered_dict import DefaultOrderedDict
1010from ..base import ResolveInfo , Undefined , collect_fields , get_field_def
1111from ..values import get_argument_values
1212from ...error import GraphQLError
13-
14-
15- def is_promise (obj ):
16- return isinstance (obj , Promise )
13+ from .utils import imap , normal_map
1714
1815
1916def get_base_type (type ):
@@ -78,7 +75,20 @@ def get_resolvers(context, type, field_asts):
7875 field_ast .arguments ,
7976 context and context .variable_values
8077 )
81- yield (response_name , resolver , args , context and context .context_value , info )
78+ yield (response_name , Field (resolver , args , context and context .context_value , info ))
79+
80+
81+ class Field (object ):
82+ __slots__ = ('fn' , 'args' , 'context' , 'info' )
83+
84+ def __init__ (self , fn , args , context , info ):
85+ self .fn = fn
86+ self .args = args
87+ self .context = context
88+ self .info = info
89+
90+ def execute (self , root ):
91+ return self .fn (root , self .args , self .context , self .info )
8292
8393
8494class Fragment (object ):
@@ -97,6 +107,22 @@ def partial_resolvers(self):
97107 self .field_asts
98108 ))
99109
110+ @cached_property
111+ def fragment_container (self ):
112+ fields = zip (* self .partial_resolvers )[0 ]
113+ class FragmentInstance (dict ):
114+ # def __init__(self):
115+ # self.fields = fields
116+ # _fields = ('c','b','a')
117+ set = dict .__setitem__
118+ # def set(self, name, value):
119+ # self[name] = value
120+
121+ def __iter__ (self ):
122+ return iter (fields )
123+
124+ return FragmentInstance
125+
100126 def have_type (self , root ):
101127 return not self .type .is_type_of or self .type .is_type_of (root , self .context .context_value , self .info )
102128
@@ -109,18 +135,18 @@ def resolve(self, root):
109135
110136 contains_promise = False
111137
112- final_results = OrderedDict ()
138+ final_results = self . fragment_container ()
113139 # return OrderedDict(
114140 # ((field_name, field_resolver(root, field_args, context, info))
115141 # for field_name, field_resolver, field_args, context, info in self.partial_resolvers)
116142 # )
117- for response_name , field_resolver , field_args , context , info in self .partial_resolvers :
143+ for response_name , field_resolver in self .partial_resolvers :
118144
119- result = field_resolver (root , field_args , context , info )
145+ result = field_resolver . execute (root )
120146 if result is Undefined :
121147 continue
122148
123- if not contains_promise and is_promise (result ):
149+ if not contains_promise and is_thenable (result ):
124150 contains_promise = True
125151
126152 final_results [response_name ] = result
@@ -136,14 +162,14 @@ def resolve(self, root):
136162
137163 def resolve_serially (self , root ):
138164 def execute_field_callback (results , resolver ):
139- response_name , field_resolver , field_args , context , info = resolver
165+ response_name , field_resolver = resolver
140166
141- result = field_resolver (root , field_args , context , info )
167+ result = field_resolver . execute (root )
142168
143169 if result is Undefined :
144170 return results
145171
146- if is_promise (result ):
172+ if is_thenable (result ):
147173 def collect_result (resolved_result ):
148174 results [response_name ] = resolved_result
149175 return results
@@ -156,7 +182,7 @@ def collect_result(resolved_result):
156182 def execute_field (prev_promise , resolver ):
157183 return prev_promise .then (lambda results : execute_field_callback (results , resolver ))
158184
159- return functools .reduce (execute_field , self .partial_resolvers , Promise .resolve (OrderedDict ()))
185+ return functools .reduce (execute_field , self .partial_resolvers , Promise .resolve (self . fragment_container ()))
160186
161187 def __eq__ (self , other ):
162188 return isinstance (other , Fragment ) and (
@@ -180,6 +206,12 @@ def __init__(self, abstract_type, field_asts, context=None, info=None):
180206 def possible_types (self ):
181207 return self .context .schema .get_possible_types (self .abstract_type )
182208
209+ @cached_property
210+ def possible_types_with_is_type_of (self ):
211+ return [
212+ (type , type .is_type_of ) for type in self .possible_types if callable (type .is_type_of )
213+ ]
214+
183215 def get_fragment (self , type ):
184216 if isinstance (type , str ):
185217 type = self .context .schema .get_type (type )
@@ -194,6 +226,7 @@ def get_fragment(self, type):
194226 self .context ,
195227 self .info
196228 )
229+
197230 return self ._fragments [type ]
198231
199232 def resolve_type (self , result ):
@@ -202,10 +235,10 @@ def resolve_type(self, result):
202235
203236 if return_type .resolve_type :
204237 return return_type .resolve_type (result , context , self .info )
205- else :
206- for type in self .possible_types :
207- if callable ( type . is_type_of ) and type . is_type_of (result , context , self .info ):
208- return type
238+
239+ for type , is_type_of in self .possible_types_with_is_type_of :
240+ if is_type_of (result , context , self .info ):
241+ return type
209242
210243 def resolve (self , root ):
211244 _type = self .resolve_type (root )
0 commit comments