Skip to content

Commit a8c8655

Browse files
committed
propagate explicit null args to resolvers
1 parent d60ff58 commit a8c8655

File tree

4 files changed

+65
-18
lines changed

4 files changed

+65
-18
lines changed

graphql/execution/tests/test_execute_schema.py

+23-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# type: ignore
22

3+
from itertools import starmap, repeat
4+
from typing import Union
35
from graphql.execution import execute
46
from graphql.language.parser import parse
57
from graphql.type import (
@@ -51,36 +53,44 @@ def test_executes_using_a_schema():
5153
{
5254
"id": GraphQLField(GraphQLNonNull(GraphQLString)),
5355
"isPublished": GraphQLField(GraphQLBoolean),
56+
"topic": GraphQLField(GraphQLString),
5457
"author": GraphQLField(BlogAuthor),
5558
"title": GraphQLField(GraphQLString),
5659
"body": GraphQLField(GraphQLString),
5760
"keywords": GraphQLField(GraphQLList(GraphQLString)),
5861
},
5962
)
6063

64+
def _resolve_article(obj, info, id, topic):
65+
return Article(id, topic)
66+
67+
def _resolve_feed(*_):
68+
return list(starmap(Article, zip(range(1, 10 + 1), repeat("food"))))
69+
6170
BlogQuery = GraphQLObjectType(
6271
"Query",
6372
{
6473
"article": GraphQLField(
6574
BlogArticle,
66-
args={"id": GraphQLArgument(GraphQLID)},
67-
resolver=lambda obj, info, **args: Article(args["id"]),
68-
),
69-
"feed": GraphQLField(
70-
GraphQLList(BlogArticle),
71-
resolver=lambda *_: map(Article, range(1, 10 + 1)),
75+
args={
76+
"id": GraphQLArgument(GraphQLID),
77+
"topic": GraphQLArgument(GraphQLNonNull(GraphQLString)),
78+
},
79+
resolver=_resolve_article,
7280
),
81+
"feed": GraphQLField(GraphQLList(BlogArticle), resolver=_resolve_feed),
7382
},
7483
)
7584

7685
BlogSchema = GraphQLSchema(BlogQuery)
7786

7887
class Article(object):
79-
def __init__(self, id):
80-
# type: (int) -> None
88+
def __init__(self, id, topic):
89+
# type: (int, Union[str, None]) -> None
8190
self.id = id
8291
self.isPublished = True
8392
self.author = Author()
93+
self.topic = "My topic is {}".format(topic or "null")
8494
self.title = "My Article {}".format(id)
8595
self.body = "This is a post"
8696
self.hidden = "This data is not exposed in the schema"
@@ -97,7 +107,7 @@ def pic(self, width, height):
97107
@property
98108
def recentArticle(self):
99109
# type: () -> Article
100-
return Article(1)
110+
return Article(1, "food")
101111

102112
class Pic(object):
103113
def __init__(self, uid, width, height):
@@ -112,7 +122,7 @@ def __init__(self, uid, width, height):
112122
id,
113123
title
114124
},
115-
article(id: "1") {
125+
article(id: "1", topic: null) {
116126
...articleFields,
117127
author {
118128
id,
@@ -132,6 +142,7 @@ def __init__(self, uid, width, height):
132142
fragment articleFields on Article {
133143
id,
134144
isPublished,
145+
topic,
135146
title,
136147
body,
137148
hidden,
@@ -159,6 +170,7 @@ def __init__(self, uid, width, height):
159170
"article": {
160171
"id": "1",
161172
"isPublished": True,
173+
"topic": "My topic is null",
162174
"title": "My Article 1",
163175
"body": "This is a post",
164176
"author": {
@@ -168,6 +180,7 @@ def __init__(self, uid, width, height):
168180
"recentArticle": {
169181
"id": "1",
170182
"isPublished": True,
183+
"topic": "My topic is food",
171184
"title": "My Article 1",
172185
"body": "This is a post",
173186
"keywords": ["foo", "bar", "1", "true", None],

graphql/execution/tests/test_mutations.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,16 @@ def assert_evaluate_mutations_serially(executor=None):
107107
},
108108
fifth: immediatelyChangeTheNumber(newNumber: 5) {
109109
theNumber
110-
}
110+
},
111+
sixth: immediatelyChangeTheNumber(newNumber: null) {
112+
theNumber
113+
},
114+
seventh: immediatelyChangeTheNumber(newNumber: 100) {
115+
theNumber
116+
},
117+
eighth: immediatelyChangeTheNumber(newNumber: null) {
118+
theNumber
119+
},
111120
}"""
112121
ast = parse(doc)
113122
result = execute(schema, ast, Root(6), operation_name="M", executor=executor)
@@ -118,6 +127,9 @@ def assert_evaluate_mutations_serially(executor=None):
118127
"third": {"theNumber": 3},
119128
"fourth": {"theNumber": 4},
120129
"fifth": {"theNumber": 5},
130+
"sixth": {"theNumber": None},
131+
"seventh": {"theNumber": 100},
132+
"eighth": {"theNumber": None},
121133
}
122134

123135

graphql/execution/tests/test_resolve.py

+21
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,27 @@ def _test_schema(test_field):
4949
)
5050

5151

52+
def test_explicit_null_is_passed_to_resolver():
53+
def resolver(_, __, maybe_string):
54+
return 'maybe_string is "{}"'.format(maybe_string or "null")
55+
56+
schema = _test_schema(
57+
GraphQLField(
58+
GraphQLString,
59+
args=OrderedDict([("maybe_string", GraphQLArgument(GraphQLString))]),
60+
resolver=resolver,
61+
)
62+
)
63+
64+
result = graphql(schema, '{ test(maybe_string: "Cool") }')
65+
assert not result.errors
66+
assert result.data == {"test": 'maybe_string is "Cool"'}
67+
68+
result = graphql(schema, "{ test(maybe_string: null) }")
69+
assert not result.errors
70+
assert result.data == {"test": 'maybe_string is "null"'}
71+
72+
5273
def test_default_function_accesses_properties():
5374
# type: () -> None
5475
schema = _test_schema(GraphQLField(GraphQLString))

graphql/execution/values.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,16 @@ def get_argument_values(
134134
continue
135135

136136
else:
137-
value = value_from_ast(arg_ast.value, arg_type, variables) # type: ignore
138-
if value is None:
137+
arg_name = arg_def.out_name or name # type: ignore
138+
arg_ast_value = arg_ast.value # type: ignore
139+
value = value_from_ast(arg_ast_value, arg_type, variables) # type: ignore
140+
if value is None and not isinstance(arg_ast_value, ast.NullValue):
139141
if arg_def.default_value is not Undefined:
140-
value = arg_def.default_value
141-
result[arg_def.out_name or name] = value
142+
result[arg_name] = arg_def.default_value
143+
else:
144+
result[arg_name] = None
142145
else:
143-
# We use out_name as the output name for the
144-
# dict if exists
145-
result[arg_def.out_name or name] = value
146+
result[arg_name] = value
146147

147148
return result
148149

0 commit comments

Comments
 (0)