Skip to content

Commit 6a37104

Browse files
committed
Validate: Unique variable names
Related GraphQL-js commit: graphql/graphql-js@089caad
1 parent c733527 commit 6a37104

File tree

3 files changed

+61
-1
lines changed

3 files changed

+61
-1
lines changed

graphql/core/validation/rules/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from .unique_fragment_names import UniqueFragmentNames
2020
from .unique_input_field_names import UniqueInputFieldNames
2121
from .unique_operation_names import UniqueOperationNames
22+
from .unique_variable_names import UniqueVariableNames
2223
from .variables_are_input_types import VariablesAreInputTypes
2324
from .variables_in_allowed_position import VariablesInAllowedPosition
2425

@@ -45,7 +46,8 @@
4546
DefaultValuesOfCorrectType,
4647
VariablesInAllowedPosition,
4748
OverlappingFieldsCanBeMerged,
48-
UniqueInputFieldNames
49+
UniqueInputFieldNames,
50+
UniqueVariableNames
4951
]
5052

5153
__all__ = [
@@ -59,6 +61,7 @@
5961
'KnownTypeNames',
6062
'LoneAnonymousOperation',
6163
'NoFragmentCycles',
64+
'UniqueVariableNames',
6265
'NoUndefinedVariables',
6366
'NoUnusedFragments',
6467
'NoUnusedVariables',
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from ...error import GraphQLError
2+
from .base import ValidationRule
3+
4+
5+
class UniqueVariableNames(ValidationRule):
6+
__slots__ = 'known_variable_names',
7+
8+
def __init__(self, context):
9+
super(UniqueVariableNames, self).__init__(context)
10+
self.known_variable_names = {}
11+
12+
def enter_OperationDefinition(self, node, key, parent, path, ancestors):
13+
self.known_variable_names = {}
14+
15+
def enter_VariableDefinition(self, node, key, parent, path, ancestors):
16+
variable_name = node.variable.name.value
17+
if variable_name in self.known_variable_names:
18+
self.context.report_error(GraphQLError(
19+
self.duplicate_variable_message(variable_name),
20+
[self.known_variable_names[variable_name], node.variable.name]
21+
))
22+
else:
23+
self.known_variable_names[variable_name] = node.variable.name
24+
25+
@staticmethod
26+
def duplicate_variable_message(operation_name):
27+
return 'There can be only one variable named "{}".'.format(operation_name)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from graphql.core.language.location import SourceLocation
2+
from graphql.core.validation.rules import UniqueVariableNames
3+
from .utils import expect_fails_rule, expect_passes_rule
4+
5+
6+
def duplicate_var(op_name, l1, c1, l2, c2):
7+
return {
8+
'message': UniqueVariableNames.duplicate_variable_message(op_name),
9+
'locations': [SourceLocation(l1, c1), SourceLocation(l2, c2)]
10+
}
11+
12+
13+
def test_unique_variable_names():
14+
expect_passes_rule(UniqueVariableNames, '''
15+
query A($x: Int, $y: String) { __typename }
16+
query B($x: String, $y: Int) { __typename }
17+
''')
18+
19+
20+
def test_duplicate_variable_names():
21+
expect_fails_rule(UniqueVariableNames, '''
22+
query A($x: Int, $x: Int, $x: String) { __typename }
23+
query B($x: String, $x: Int) { __typename }
24+
query C($x: Int, $x: Int) { __typename }
25+
''', [
26+
duplicate_var('x', 2, 16, 2, 25),
27+
duplicate_var('x', 2, 16, 2, 34),
28+
duplicate_var('x', 3, 16, 3, 28),
29+
duplicate_var('x', 4, 16, 4, 25),
30+
])

0 commit comments

Comments
 (0)