Skip to content

Commit 52d8175

Browse files
committed
Finish implementing Variable validation
1 parent 60589e1 commit 52d8175

12 files changed

+1103
-135
lines changed

include/Validation.h

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,31 @@ struct ValidateField
137137
ValidateFieldArguments arguments;
138138
};
139139

140+
using ValidateTypeKinds = std::map<std::string, introspection::TypeKind>;
141+
142+
// ValidateVariableTypeVisitor visits the AST and builds a ValidateType structure representing
143+
// a variable type in an operation definition as if it came from an Introspection query.
144+
class ValidateVariableTypeVisitor
145+
{
146+
public:
147+
ValidateVariableTypeVisitor(const ValidateTypeKinds& typeKinds);
148+
149+
void visit(const peg::ast_node& typeName);
150+
151+
bool isInputType() const;
152+
ValidateType getType();
153+
154+
private:
155+
void visitNamedType(const peg::ast_node& namedType);
156+
void visitListType(const peg::ast_node& listType);
157+
void visitNonNullType(const peg::ast_node& nonNullType);
158+
159+
const ValidateTypeKinds& _typeKinds;
160+
161+
bool _isInputType = false;
162+
ValidateType _variableType;
163+
};
164+
140165
// ValidateExecutableVisitor visits the AST and validates that it is executable against the service schema.
141166
class ValidateExecutableVisitor
142167
{
@@ -185,22 +210,26 @@ class ValidateExecutableVisitor
185210

186211
void visitDirectives(introspection::DirectiveLocation location, const peg::ast_node& directives);
187212

188-
bool validateInputValue(const ValidateArgumentValuePtr& argument, const ValidateType& type);
213+
bool validateInputValue(bool hasNonNullDefaultValue, const ValidateArgumentValuePtr& argument, const ValidateType& type);
214+
bool validateVariableType(bool isNonNull, const ValidateType& variableType, const schema_location& position, const ValidateType& inputType);
215+
189216

190217
const Request& _service;
191218
std::vector<schema_error> _errors;
192219

193220
using OperationTypes = std::map<std::string_view, std::string>;
194-
using TypeKinds = std::map<std::string, introspection::TypeKind>;
195221
using Directives = std::map<std::string, ValidateDirective>;
196222
using ExecutableNodes = std::map<std::string, const peg::ast_node&>;
197223
using FragmentSet = std::unordered_set<std::string>;
198224
using MatchingTypes = std::map<std::string, std::set<std::string>>;
199-
using VariableTypes = std::map<std::string, std::vector<ValidateArgument>>;
200225
using ScalarTypes = std::set<std::string>;
226+
using VariableDefinitions = std::map<std::string, const peg::ast_node&>;
227+
using VariableTypes = std::map<std::string, ValidateArgument>;
228+
using OperationVariables = std::optional<VariableTypes>;
229+
using VariableSet = std::set<std::string>;
201230

202231
OperationTypes _operationTypes;
203-
TypeKinds _typeKinds;
232+
ValidateTypeKinds _typeKinds;
204233
MatchingTypes _matchingTypes;
205234
Directives _directives;
206235
EnumValues _enumValues;
@@ -209,6 +238,9 @@ class ValidateExecutableVisitor
209238
ExecutableNodes _fragmentDefinitions;
210239
ExecutableNodes _operationDefinitions;
211240

241+
OperationVariables _operationVariables;
242+
VariableDefinitions _variableDefinitions;
243+
VariableSet _referencedVariables;
212244
FragmentSet _referencedFragments;
213245
FragmentSet _fragmentStack;
214246
FragmentSet _fragmentCycles;

samples/introspection/IntrospectionSchema.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -618,13 +618,13 @@ void AddTypesToSchema(const std::shared_ptr<introspection::Schema>& schema)
618618
std::make_shared<introspection::Field>("description", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("String")),
619619
std::make_shared<introspection::Field>("fields", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>({
620620
std::make_shared<introspection::InputValue>("includeDeprecated", R"md()md", schema->LookupType("Boolean"), R"gql(false)gql")
621-
}), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Field"))))),
622-
std::make_shared<introspection::Field>("interfaces", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))))),
623-
std::make_shared<introspection::Field>("possibleTypes", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))))),
621+
}), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Field")))),
622+
std::make_shared<introspection::Field>("interfaces", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type")))),
623+
std::make_shared<introspection::Field>("possibleTypes", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type")))),
624624
std::make_shared<introspection::Field>("enumValues", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>({
625625
std::make_shared<introspection::InputValue>("includeDeprecated", R"md()md", schema->LookupType("Boolean"), R"gql(false)gql")
626-
}), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__EnumValue"))))),
627-
std::make_shared<introspection::Field>("inputFields", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue"))))),
626+
}), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__EnumValue")))),
627+
std::make_shared<introspection::Field>("inputFields", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue")))),
628628
std::make_shared<introspection::Field>("ofType", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("__Type"))
629629
});
630630
typeField->AddFields({

samples/schema.validation.graphql

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,26 +89,32 @@ type Arguments {
8989
floatArgField(floatArg: Float): Float
9090
intArgField(intArg: Int): Int
9191
nonNullBooleanArgField(nonNullBooleanArg: Boolean!): Boolean!
92+
nonNullBooleanListField(nonNullBooleanListArg: [Boolean!]): [Boolean!]
9293
booleanListArgField(booleanListArg: [Boolean]!): [Boolean]
9394
optionalNonNullBooleanArgField(optionalBooleanArg: Boolean! = false): Boolean!
9495
}
9596

9697
# http://spec.graphql.org/June2018/#example-1891c
9798
extend type Query {
99+
"Support for [Example 120](http://spec.graphql.org/June2018/#example-1891c)"
98100
arguments: Arguments
99101
}
100102

101103
# http://spec.graphql.org/June2018/#example-6bbad
102104
extend type Human {
105+
"Support for [Counter Example 136](http://spec.graphql.org/June2018/#example-6bbad)"
103106
pets: [Pet!]!
104107
}
105108

106-
"Support for [Example 145](http://spec.graphql.org/June2018/#example-7ee0e) - [Counter Example 146](http://spec.graphql.org/June2018/#example-3a7c1)"
109+
"[Example 155](http://spec.graphql.org/June2018/#example-f3185)"
107110
input ComplexInput {
108-
name: String!
111+
name: String
112+
owner: String
109113
}
110114

111-
# http://spec.graphql.org/June2018/#example-7ee0e - http://spec.graphql.org/June2018/#example-3a7c1
112115
extend type Query {
113-
findDog(complex: ComplexInput!): String
116+
"[Example 155](http://spec.graphql.org/June2018/#example-f3185)"
117+
findDog(complex: ComplexInput): Dog
118+
"[Example 155](http://spec.graphql.org/June2018/#example-f3185)"
119+
booleanList(booleanListArg: [Boolean!]): Boolean
114120
}

samples/separate/AppointmentConnectionObject.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void AddAppointmentConnectionDetails(std::shared_ptr<introspection::ObjectType>
6464
{
6565
typeAppointmentConnection->AddFields({
6666
std::make_shared<introspection::Field>("pageInfo", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))),
67-
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))))
67+
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge")))
6868
});
6969
}
7070

samples/separate/FolderConnectionObject.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void AddFolderConnectionDetails(std::shared_ptr<introspection::ObjectType> typeF
6464
{
6565
typeFolderConnection->AddFields({
6666
std::make_shared<introspection::Field>("pageInfo", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))),
67-
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))))
67+
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge")))
6868
});
6969
}
7070

samples/separate/TaskConnectionObject.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void AddTaskConnectionDetails(std::shared_ptr<introspection::ObjectType> typeTas
6464
{
6565
typeTaskConnection->AddFields({
6666
std::make_shared<introspection::Field>("pageInfo", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))),
67-
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))))
67+
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge")))
6868
});
6969
}
7070

samples/unified/TodaySchema.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,23 +1128,23 @@ void AddTypesToSchema(const std::shared_ptr<introspection::Schema>& schema)
11281128
});
11291129
typeAppointmentConnection->AddFields({
11301130
std::make_shared<introspection::Field>("pageInfo", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))),
1131-
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))))
1131+
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge")))
11321132
});
11331133
typeTaskEdge->AddFields({
11341134
std::make_shared<introspection::Field>("node", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("Task")),
11351135
std::make_shared<introspection::Field>("cursor", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor")))
11361136
});
11371137
typeTaskConnection->AddFields({
11381138
std::make_shared<introspection::Field>("pageInfo", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))),
1139-
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))))
1139+
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge")))
11401140
});
11411141
typeFolderEdge->AddFields({
11421142
std::make_shared<introspection::Field>("node", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("Folder")),
11431143
std::make_shared<introspection::Field>("cursor", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor")))
11441144
});
11451145
typeFolderConnection->AddFields({
11461146
std::make_shared<introspection::Field>("pageInfo", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))),
1147-
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))))
1147+
std::make_shared<introspection::Field>("edges", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge")))
11481148
});
11491149
typeCompleteTaskPayload->AddFields({
11501150
std::make_shared<introspection::Field>("task", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("Task")),

0 commit comments

Comments
 (0)