Skip to content

Porting various commits for 0.5.0 #58

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 21, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 63 additions & 33 deletions graphql/execution/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
If the field type is a Scalar or Enum, ensures the completed value is a legal value of the type by calling the
`serialize` method of GraphQL type definition.

If the field is an abstract type, determine the runtime type of the value and then complete based on that type.

Otherwise, the field type expects a sub-selection set, and will complete the value by evaluating all
sub-selections.
"""
Expand Down Expand Up @@ -251,49 +253,56 @@ def complete_value(self, ctx, return_type, field_asts, info, result):

# If field type is List, complete each item in the list with the inner type
if isinstance(return_type, GraphQLList):
assert isinstance(result, collections.Iterable), \
('User Error: expected iterable, but did not find one' +
'for field {}.{}').format(info.parent_type, info.field_name)
return self.complete_list_value(ctx, return_type, field_asts, info, result)

item_type = return_type.of_type
completed_results = []
contains_deferred = False
for item in result:
completed_item = self.complete_value_catching_error(ctx, item_type, field_asts, info, item)
if not contains_deferred and isinstance(completed_item, Deferred):
contains_deferred = True
# If field type is Scalar or Enum, serialize to a valid value, returning null if coercion is not possible.
if isinstance(return_type, (GraphQLScalarType, GraphQLEnumType)):
return self.complete_leaf_value(ctx, return_type, field_asts, info, result)

completed_results.append(completed_item)
if isinstance(return_type, GraphQLObjectType):
return self.complete_object_value(ctx, return_type, field_asts, info, result)

return DeferredList(completed_results) if contains_deferred else completed_results
if isinstance(return_type, (GraphQLInterfaceType, GraphQLUnionType)):
return self.complete_abstract_value(ctx, return_type, field_asts, info, result)

# If field type is Scalar or Enum, serialize to a valid value, returning null if coercion is not possible.
if isinstance(return_type, (GraphQLScalarType, GraphQLEnumType)):
serialized_result = return_type.serialize(result)
assert False, u'Cannot complete value of unexpected type "{}"'.format(return_type)

if serialized_result is None:
return None
def complete_list_value(self, ctx, return_type, field_asts, info, result):
"""
Complete a list value by completing each item in the list with the inner type
"""
assert isinstance(result, collections.Iterable), \
('User Error: expected iterable, but did not find one' +
'for field {}.{}').format(info.parent_type, info.field_name)

return serialized_result
item_type = return_type.of_type
completed_results = []
contains_deferred = False
for item in result:
completed_item = self.complete_value_catching_error(ctx, item_type, field_asts, info, item)
if not contains_deferred and isinstance(completed_item, Deferred):
contains_deferred = True

runtime_type = None
completed_results.append(completed_item)

# Field type must be Object, Interface or Union and expect sub-selections.
if isinstance(return_type, GraphQLObjectType):
runtime_type = return_type
return DeferredList(completed_results) if contains_deferred else completed_results

elif isinstance(return_type, (GraphQLInterfaceType, GraphQLUnionType)):
runtime_type = return_type.resolve_type(result, info)
if runtime_type and not return_type.is_possible_type(runtime_type):
raise GraphQLError(
u'Runtime Object type "{}" is not a possible type for "{}".'.format(runtime_type, return_type),
field_asts
)
def complete_leaf_value(self, ctx, return_type, field_asts, info, result):
"""
Complete a Scalar or Enum by serializing to a valid value, returning null if serialization is not possible.
"""
serialized_result = return_type.serialize(result)

if not runtime_type:
if serialized_result is None:
return None

if runtime_type.is_type_of and not runtime_type.is_type_of(result, info):
return serialized_result

def complete_object_value(self, ctx, return_type, field_asts, info, result):
"""
Complete an Object value by evaluating all sub-selections.
"""
if return_type.is_type_of and not return_type.is_type_of(result, info):
raise GraphQLError(
u'Expected value of type "{}" but got {}.'.format(return_type, type(result).__name__),
field_asts
Expand All @@ -306,11 +315,32 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
selection_set = field_ast.selection_set
if selection_set:
subfield_asts = collect_fields(
ctx, runtime_type, selection_set,
ctx, return_type, selection_set,
subfield_asts, visited_fragment_names
)

return self._execute_fields(ctx, runtime_type, result, subfield_asts)
return self._execute_fields(ctx, return_type, result, subfield_asts)

def complete_abstract_value(self, ctx, return_type, field_asts, info, result):
"""
Complete an value of an abstract type by determining the runtime type of that value, then completing based
on that type.
"""
# Field type must be Object, Interface or Union and expect sub-selections.
runtime_type = None

if isinstance(return_type, (GraphQLInterfaceType, GraphQLUnionType)):
runtime_type = return_type.resolve_type(result, info)
if runtime_type and not return_type.is_possible_type(runtime_type):
raise GraphQLError(
u'Runtime Object type "{}" is not a possible type for "{}".'.format(runtime_type, return_type),
field_asts
)

if not runtime_type:
return None

return self.complete_object_value(ctx, runtime_type, field_asts, info, result)

def resolve_or_error(self, resolve_fn, source, args, info):
curried_resolve_fn = functools.partial(resolve_fn, source, args, info)
Expand Down