Skip to content

Commit 765640d

Browse files
committed
FieldsOnCorrectType, ScalarLeafs, VariablesAreInputTypes rules
+ stubs for all validation rules
1 parent 6db07e7 commit 765640d

File tree

8 files changed

+457
-92
lines changed

8 files changed

+457
-92
lines changed

graphql/core/type/definition.py

Lines changed: 10 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,91 +2,6 @@
22
from ..error import Error
33
from ..language import ast
44

5-
'''
6-
/**
7-
* These are all of the possible kinds of types.
8-
*/
9-
export type GraphQLType =
10-
GraphQLScalarType |
11-
GraphQLObjectType |
12-
GraphQLInterfaceType |
13-
GraphQLUnionType |
14-
GraphQLEnumType |
15-
GraphQLInputObjectType |
16-
GraphQLList |
17-
GraphQLNonNull;
18-
19-
// Predicates
20-
21-
/**
22-
* These types may be used as output types as the result of fields.
23-
*/
24-
export type GraphQLOutputType =
25-
GraphQLScalarType |
26-
GraphQLObjectType |
27-
GraphQLInterfaceType |
28-
GraphQLUnionType |
29-
GraphQLEnumType |
30-
GraphQLList |
31-
GraphQLNonNull;
32-
33-
export function isOutputType(type: ?GraphQLType): boolean {
34-
var nakedType = getUnmodifiedType(type);
35-
return (
36-
nakedType instanceof GraphQLScalarType ||
37-
nakedType instanceof GraphQLObjectType ||
38-
nakedType instanceof GraphQLInterfaceType ||
39-
nakedType instanceof GraphQLUnionType ||
40-
nakedType instanceof GraphQLEnumType
41-
);
42-
}
43-
44-
/**
45-
* These types may describe types which may be leaf values.
46-
*/
47-
export type GraphQLLeafType =
48-
GraphQLScalarType |
49-
GraphQLEnumType;
50-
51-
export function isLeafType(type: ?GraphQLType): boolean {
52-
var nakedType = getUnmodifiedType(type);
53-
return (
54-
nakedType instanceof GraphQLScalarType ||
55-
nakedType instanceof GraphQLEnumType
56-
);
57-
}
58-
59-
/**
60-
* These types may describe the parent context of a selection set.
61-
*/
62-
export type GraphQLAbstractType =
63-
GraphQLInterfaceType |
64-
GraphQLUnionType;
65-
66-
export function isAbstractType(type: ?GraphQLType): boolean {
67-
return (
68-
type instanceof GraphQLInterfaceType ||
69-
type instanceof GraphQLUnionType
70-
);
71-
}
72-
73-
/**
74-
* These types can all accept null as a value.
75-
*/
76-
export type GraphQLNullableType =
77-
GraphQLScalarType |
78-
GraphQLObjectType |
79-
GraphQLInterfaceType |
80-
GraphQLUnionType |
81-
GraphQLEnumType |
82-
GraphQLInputObjectType |
83-
GraphQLList;
84-
85-
export function getNullableType(type: ?GraphQLType): ?GraphQLNullableType {
86-
return type instanceof GraphQLNonNull ? type.ofType : type;
87-
}
88-
'''
89-
905

916
def is_input_type(type):
927
named_type = get_named_type(type)
@@ -98,13 +13,22 @@ def is_input_type(type):
9813

9914

10015
def is_composite_type(type):
101-
return isinstance(type, (
16+
named_type = get_named_type(type)
17+
return isinstance(named_type, (
10218
GraphQLObjectType,
10319
GraphQLInterfaceType,
10420
GraphQLUnionType,
10521
))
10622

10723

24+
def is_leaf_type(type):
25+
named_type = get_named_type(type)
26+
return isinstance(named_type, (
27+
GraphQLScalarType,
28+
GraphQLEnumType,
29+
))
30+
31+
10832
def get_named_type(type):
10933
unmodified_type = type
11034
while isinstance(unmodified_type, (GraphQLList, GraphQLNonNull)):

graphql/core/validation/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@
1010
Rules.LoneAnonymousOperation,
1111
Rules.KnownTypeNames,
1212
Rules.FragmentsOnCompositeTypes,
13+
Rules.VariablesAreInputTypes,
14+
Rules.ScalarLeafs,
15+
Rules.FieldsOnCorrectType,
16+
Rules.UniqueFragmentNames,
17+
Rules.KnownFragmentNames,
18+
Rules.NoUnusedFragments,
19+
Rules.PossibleFragmentSpreads,
20+
Rules.NoFragmentCycles,
21+
Rules.NoUndefinedVariables,
22+
Rules.NoUnusedVariables,
23+
Rules.KnownDirectives,
24+
Rules.KnownArgumentNames,
25+
Rules.UniqueArgumentNames,
26+
Rules.ArgumentsOfCorrectType,
27+
Rules.ProvidedNonNullArguments,
28+
Rules.DefaultValuesOfCorrectType,
29+
Rules.VariablesInAllowedPosition,
30+
Rules.OverlappingFieldsCanBeMerged,
1331
]
1432

1533

@@ -55,8 +73,11 @@ def enter(self, node, key, parent, path, ancestors):
5573
visit(fragment, self)
5674

5775
if result is False:
76+
print 'leave', node
5877
self.type_info.leave(node)
5978

79+
return result
80+
6081
def leave(self, node, key, parent, path, ancestors):
6182
result = self.instance.leave(node, key, parent, path, ancestors)
6283

graphql/core/validation/rules.py

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
from ..utils import type_from_ast
12
from ..error import GraphQLError
2-
from ..type.definition import is_composite_type
3+
from ..type.definition import is_composite_type, is_input_type, is_leaf_type
34
from ..language.ast import OperationDefinition
45
from ..language.visitor import Visitor
56
from ..language.printer import print_ast
@@ -87,3 +88,120 @@ def inline_message(type):
8788
@staticmethod
8889
def message(frag_name, type):
8990
return 'Fragment "{}" cannot condition on non composite type "{}".'.format(frag_name, type)
91+
92+
93+
class VariablesAreInputTypes(ValidationRule):
94+
def enter_VariableDefinition(self, node, *args):
95+
type = type_from_ast(self.context.get_schema(), node.type)
96+
97+
if type and not is_input_type(type):
98+
variable_name = node.variable.name.value
99+
return GraphQLError(
100+
self.message(variable_name, print_ast(node.type)),
101+
[node.type]
102+
)
103+
104+
@staticmethod
105+
def message(variable_name, type_name):
106+
return 'Variable "${}" cannot be non-input type "{}".'.format(variable_name, type_name)
107+
108+
109+
class ScalarLeafs(ValidationRule):
110+
def enter_Field(self, node, *args):
111+
type = self.context.get_type()
112+
if type:
113+
if is_leaf_type(type):
114+
if node.selection_set:
115+
return GraphQLError(
116+
self.not_allowed_message(node.name.value, type),
117+
[node.selection_set]
118+
)
119+
elif not node.selection_set:
120+
return GraphQLError(
121+
self.required_message(node.name.value, type),
122+
[node]
123+
)
124+
125+
@staticmethod
126+
def not_allowed_message(field, type):
127+
return 'Field "{}" of type "{}" must not have a sub selection.'.format(field, type)
128+
129+
@staticmethod
130+
def required_message(field, type):
131+
return 'Field "{}" of type "{}" must have a sub selection.'.format(field, type)
132+
133+
134+
class FieldsOnCorrectType(ValidationRule):
135+
def enter_Field(self, node, *args):
136+
type = self.context.get_parent_type()
137+
if type:
138+
field_def = self.context.get_field_def()
139+
if not field_def:
140+
return GraphQLError(
141+
self.message(node.name.value, type.name),
142+
[node]
143+
)
144+
145+
@staticmethod
146+
def message(field_name, type):
147+
return 'Cannot query field "{}" on "{}".'.format(field_name, type)
148+
149+
150+
class UniqueFragmentNames(ValidationRule):
151+
pass
152+
153+
154+
class KnownFragmentNames(ValidationRule):
155+
pass
156+
157+
158+
class NoUnusedFragments(ValidationRule):
159+
pass
160+
161+
162+
class PossibleFragmentSpreads(ValidationRule):
163+
pass
164+
165+
166+
class NoFragmentCycles(ValidationRule):
167+
pass
168+
169+
170+
class NoUndefinedVariables(ValidationRule):
171+
pass
172+
173+
174+
class NoUnusedVariables(ValidationRule):
175+
pass
176+
177+
178+
class KnownDirectives(ValidationRule):
179+
pass
180+
181+
182+
class KnownArgumentNames(ValidationRule):
183+
pass
184+
185+
186+
class UniqueArgumentNames(ValidationRule):
187+
pass
188+
189+
190+
class ArgumentsOfCorrectType(ValidationRule):
191+
pass
192+
193+
194+
class ProvidedNonNullArguments(ValidationRule):
195+
pass
196+
197+
198+
class DefaultValuesOfCorrectType(ValidationRule):
199+
pass
200+
201+
202+
class VariablesInAllowedPosition(ValidationRule):
203+
pass
204+
205+
206+
class OverlappingFieldsCanBeMerged(ValidationRule):
207+
pass

0 commit comments

Comments
 (0)