Skip to content

Commit c182772

Browse files
Support directives on variable definitions
This adds language support for directives on variable definitions following graphql/graphql-spec#510. This is **only** language support so servers don't choke when receiving queries using this feature.
1 parent 055e735 commit c182772

File tree

6 files changed

+111
-7
lines changed

6 files changed

+111
-7
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Unreleased
1919
- Added `ResolveInfo.get_directive_arguments`
2020
- Added `ResolveInfo.selected_fields` and `utilities.selected_fields`.
2121

22+
- Support directives on variable definitions: this adds language support for directives on variable definitions following [graphql/graphql-spec#510](https://github.com/graphql/graphql-spec/pull/510). This is **only** language support so servers don't choke when receiving queries using this feature.
23+
2224
### Fixed
2325

2426
- Introducing `pyproject.toml` broke Cython integration through build isolation. This is now fixed by always requiring cython as a a build dependency (through `build-system.requires`) and only enabling support behind the `PY_GQL_USE_CYTHON` env variable.

py_gql/lang/ast.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,20 +232,29 @@ def __init__(
232232
self.loc = loc
233233

234234

235-
class VariableDefinition(Node):
236-
__slots__ = ("source", "loc", "variable", "type", "default_value")
235+
class VariableDefinition(SupportDirectives, Node):
236+
__slots__ = (
237+
"source",
238+
"loc",
239+
"variable",
240+
"type",
241+
"default_value",
242+
"directives",
243+
)
237244

238245
def __init__(
239246
self,
240247
variable: Variable,
241248
type: Type,
242249
default_value=None, # type: Optional[Value]
250+
directives=None, # type: Optional[List[Directive]]
243251
source: Optional[str] = None,
244252
loc: Optional[Tuple[int, int]] = None,
245253
):
246254
self.variable = variable
247255
self.type = type
248256
self.default_value = default_value
257+
self.directives = directives or [] # type: List[Directive]
249258
self.source = source
250259
self.loc = loc
251260

py_gql/lang/parser.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"FRAGMENT_DEFINITION",
5353
"FRAGMENT_SPREAD",
5454
"INLINE_FRAGMENT",
55+
"VARIABLE_DEFINITION",
5556
# Type System Definitions
5657
"SCHEMA",
5758
"SCALAR",
@@ -553,7 +554,7 @@ def parse_variable_definitions(self) -> List[_ast.VariableDefinition]:
553554

554555
def parse_variable_definition(self) -> _ast.VariableDefinition:
555556
"""
556-
VariableDefinition : Variable : Type DefaultValue?
557+
VariableDefinition : Variable : Type DefaultValue? Directives[Const]?
557558
"""
558559
start = self.peek()
559560
return _ast.VariableDefinition(
@@ -566,6 +567,7 @@ def parse_variable_definition(self) -> _ast.VariableDefinition:
566567
if self.skip(Equals)
567568
else None
568569
),
570+
directives=self.parse_directives(True),
569571
loc=self._loc(start),
570572
source=self._source,
571573
)

py_gql/lang/printer.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,17 @@ def print_operation_definition(self, node: _ast.OperationDefinition) -> str:
132132
)
133133

134134
def print_variable_definition(self, node: _ast.VariableDefinition) -> str:
135-
return "%s: %s%s" % (
136-
self.print_variable(node.variable),
137-
self(node.type),
138-
_wrap(" = ", self(node.default_value)),
135+
return _join(
136+
[
137+
"%s: %s%s"
138+
% (
139+
self.print_variable(node.variable),
140+
self(node.type),
141+
_wrap(" = ", self(node.default_value)),
142+
),
143+
self.print_directives(node),
144+
],
145+
" ",
139146
)
140147

141148
def print_variable_definitions(

tests/test_lang/test_ast_printer.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,3 +403,30 @@ def test_custom_indentation_object():
403403
"""
404404
)
405405
)
406+
407+
408+
def test_variable_definitions():
409+
assert (
410+
print_ast(
411+
parse(
412+
"""
413+
query Query(
414+
$a: ComplexType,
415+
$b: Boolean = false,
416+
$c: String @foo,
417+
$d: Int! = 42 @bar(value: 42)
418+
) {
419+
id
420+
}
421+
""",
422+
)
423+
)
424+
== dedent(
425+
"""
426+
query Query($a: ComplexType, $b: Boolean = false, $c: String @foo, \
427+
$d: Int! = 42 @bar(value: 42)) {
428+
id
429+
}
430+
"""
431+
)
432+
)

tests/test_lang/test_parser.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,60 @@ def test_it_parses_inline_fragment_without_type():
467467
],
468468
),
469469
)
470+
471+
472+
def test_it_parses_variable_definition_with_directives():
473+
assert_node_equal(
474+
parse("query ($foo: Int @bar @baz) { foo }", no_location=True),
475+
_ast.Document(
476+
definitions=[
477+
_ast.OperationDefinition(
478+
"query",
479+
_ast.SelectionSet(
480+
selections=[_ast.Field(name=_ast.Name(value="foo"),)],
481+
),
482+
variable_definitions=[
483+
_ast.VariableDefinition(
484+
variable=_ast.Variable(
485+
name=_ast.Name(value="foo"),
486+
),
487+
type=_ast.NamedType(name=_ast.Name(value="Int"),),
488+
directives=[
489+
_ast.Directive(name=_ast.Name(value="bar")),
490+
_ast.Directive(name=_ast.Name(value="baz")),
491+
],
492+
)
493+
],
494+
)
495+
],
496+
),
497+
)
498+
499+
500+
def test_it_parses_variable_definition_with_default_and_directives():
501+
assert_node_equal(
502+
parse("query ($foo: Int = 42 @bar @baz) { foo }", no_location=True),
503+
_ast.Document(
504+
definitions=[
505+
_ast.OperationDefinition(
506+
"query",
507+
_ast.SelectionSet(
508+
selections=[_ast.Field(name=_ast.Name(value="foo"),)],
509+
),
510+
variable_definitions=[
511+
_ast.VariableDefinition(
512+
variable=_ast.Variable(
513+
name=_ast.Name(value="foo"),
514+
),
515+
type=_ast.NamedType(name=_ast.Name(value="Int"),),
516+
default_value=_ast.IntValue(value="42"),
517+
directives=[
518+
_ast.Directive(name=_ast.Name(value="bar")),
519+
_ast.Directive(name=_ast.Name(value="baz")),
520+
],
521+
)
522+
],
523+
)
524+
],
525+
),
526+
)

0 commit comments

Comments
 (0)