Skip to content

Commit 162dea3

Browse files
committed
Improved nonnull checker
1 parent 67fad4a commit 162dea3

File tree

3 files changed

+55
-14
lines changed

3 files changed

+55
-14
lines changed

graphql/execution/querybuilder/resolver.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ def on_complete_resolver(__func, exe_context, info, __resolver, *args, **kwargs)
2727

2828

2929
def complete_list_value(inner_resolver, exe_context, info, result):
30+
if result is None:
31+
return None
32+
3033
assert isinstance(result, collections.Iterable), \
3134
('User Error: expected iterable, but did not find one ' +
3235
'for field {}.{}.').format(info.parent_type, info.field_name)
@@ -43,16 +46,22 @@ def complete_list_value(inner_resolver, exe_context, info, result):
4346
return completed_results
4447

4548

46-
def complete_nonnull_value(result):
49+
def complete_nonnull_value(exe_context, info, result):
4750
if result is None:
4851
field_asts = 'TODO'
4952
raise GraphQLError(
5053
'Cannot return null for non-nullable field {}.{}.'.format(info.parent_type, info.field_name),
51-
field_asts
54+
info.field_asts
5255
)
5356
return result
5457

5558

59+
def complete_object_value(fragment_resolve, result):
60+
if result is None:
61+
return None
62+
return fragment_resolve(result)
63+
64+
5665
def field_resolver(field, fragment=None, exe_context=None, info=None):
5766
return type_resolver(field.type, field.resolver, fragment, exe_context, info)
5867

@@ -68,12 +77,13 @@ def type_resolver(return_type, resolver, fragment=None, exe_context=None, info=N
6877
return type_resolver_list(return_type, resolver, fragment, exe_context, info)
6978

7079
if isinstance(return_type, (GraphQLObjectType)):
71-
assert fragment and fragment.type == return_type
72-
return partial(on_complete_resolver, fragment.resolve, exe_context, info, resolver)
80+
assert fragment and fragment.type == return_type, 'Fragment and return_type dont match'
81+
complete_object_value_resolve = partial(complete_object_value, fragment.resolve)
82+
return partial(on_complete_resolver, complete_object_value_resolve, exe_context, info, resolver)
7383
# return partial(fragment.resolver, resolver)
7484

7585
if isinstance(return_type, (GraphQLInterfaceType, GraphQLUnionType)):
76-
assert fragment
86+
assert fragment, 'You need to pass a fragment to resolve a Interface or Union'
7787
return partial(on_complete_resolver, fragment.resolve, exe_context, info, resolver)
7888
# return partial(fragment.resolver, resolver)
7989
# return partial(fragment.abstract_resolver, resolver, return_type)
@@ -82,15 +92,16 @@ def type_resolver(return_type, resolver, fragment=None, exe_context=None, info=N
8292

8393

8494
def type_resolver_non_null(return_type, resolver, fragment, exe_context, info):
85-
resolver = type_resolver(return_type.of_type, resolver)
86-
return partial(on_complete_resolver, complete_nonnull_value, exe_context, info, resolver)
95+
resolver = type_resolver(return_type.of_type, resolver, fragment, exe_context, info)
96+
nonnull_complete = partial(complete_nonnull_value, exe_context, info)
97+
return partial(on_complete_resolver, nonnull_complete, exe_context, info, resolver)
8798

8899

89100
def type_resolver_leaf(return_type, resolver, exe_context, info):
90101
return partial(on_complete_resolver, return_type.serialize, exe_context, info, resolver)
91102

92103

93104
def type_resolver_list(return_type, resolver, fragment, exe_context, info):
94-
inner_resolver = type_resolver(return_type.of_type, lambda item: item, fragment)
105+
inner_resolver = type_resolver(return_type.of_type, lambda item: item, fragment, exe_context, info)
95106
list_complete = partial(complete_list_value, inner_resolver, exe_context, info)
96107
return partial(on_complete_resolver, list_complete, exe_context, info, resolver)

graphql/execution/querybuilder/tests/test_executor.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def succeeds_resolver(*args, **kwargs):
9999

100100
def test_fragment_resolver_resolves_all_list():
101101
Query = GraphQLObjectType('Query', fields={
102-
'ints': GraphQLField(GraphQLList(GraphQLNonNull(GraphQLInt)), resolver=lambda *args: [1, "2", "NaN"]),
102+
'ints': GraphQLField(GraphQLList(GraphQLNonNull(GraphQLInt)), resolver=lambda *args: [1, "2", "non"]),
103103
})
104104

105105
document_ast = parse('''query {
@@ -109,9 +109,39 @@ def test_fragment_resolver_resolves_all_list():
109109
schema = GraphQLSchema(query=Query)
110110
# partial_execute = partial(execute, schema, document_ast, context_value="1")
111111
# resolved = benchmark(partial_execute)
112-
resolved = execute(schema, document_ast, context_value="1")
112+
resolved = execute(schema, document_ast)
113113
assert len(resolved.errors) == 1
114-
# assert str(resolved.errors[0]) == 'Cant convert NaN to int'
114+
assert str(resolved.errors[0]) == 'could not convert string to float: non'
115115
assert resolved.data == {
116116
'ints': [1, 2, None]
117117
}
118+
119+
120+
def test_fragment_resolver_resolves_all_list():
121+
Person = GraphQLObjectType('Person', fields={
122+
'id': GraphQLField(GraphQLInt, resolver=lambda obj, *_, **__: 1),
123+
})
124+
Query = GraphQLObjectType('Query', fields={
125+
'persons': GraphQLField(GraphQLList(GraphQLNonNull(Person)), resolver=lambda *args: [1, 2, None]),
126+
})
127+
128+
document_ast = parse('''query {
129+
persons {
130+
id
131+
}
132+
}''')
133+
# node_fragment = Fragment(type=Node, field_asts=node_field_asts)
134+
schema = GraphQLSchema(query=Query, types=[Person])
135+
# partial_execute = partial(execute, schema, document_ast, context_value="1")
136+
# resolved = benchmark(partial_execute)
137+
resolved = execute(schema, document_ast)
138+
assert len(resolved.errors) == 1
139+
assert str(resolved.errors[0]) == 'Cannot return null for non-nullable field Query.persons.'
140+
# assert str(resolved.errors[0]) == 'could not convert string to float: non'
141+
assert resolved.data == {
142+
'persons': [{
143+
'id': 1
144+
}, {
145+
'id': 1
146+
}, None]
147+
}

graphql/execution/querybuilder/tests/test_fragment.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def test_fragment_resolver_nested():
8080
])
8181
# node_fragment = Fragment(type=Node, field_asts=node_field_asts)
8282
query_fragment = Fragment(type=Query, selection_set=selection_set)
83-
resolver = type_resolver(Query, lambda: None, fragment=query_fragment)
83+
resolver = type_resolver(Query, lambda: object(), fragment=query_fragment)
8484
resolved = resolver()
8585
assert resolved == {
8686
'node': {
@@ -130,7 +130,7 @@ def test_fragment_resolver_abstract():
130130
)
131131

132132
query_fragment = Fragment(type=Query, selection_set=selection_set, context=context)
133-
resolver = type_resolver(Query, lambda: None, fragment=query_fragment)
133+
resolver = type_resolver(Query, lambda: object(), fragment=query_fragment)
134134
resolved = resolver()
135135
assert resolved == {
136136
'node': {
@@ -155,7 +155,7 @@ def test_fragment_resolver_nested_list():
155155
])
156156
# node_fragment = Fragment(type=Node, field_asts=node_field_asts)
157157
query_fragment = Fragment(type=Query, selection_set=selection_set)
158-
resolver = type_resolver(Query, lambda: None, fragment=query_fragment)
158+
resolver = type_resolver(Query, lambda: object(), fragment=query_fragment)
159159
resolved = resolver()
160160
assert resolved == {
161161
'nodes': [{

0 commit comments

Comments
 (0)