Skip to content

Commit b12a87a

Browse files
committed
Implement Value validation
1 parent 1e215b4 commit b12a87a

File tree

6 files changed

+682
-44
lines changed

6 files changed

+682
-44
lines changed

include/Validation.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ struct ValidateArgumentValue
102102
class ValidateArgumentValueVisitor
103103
{
104104
public:
105-
ValidateArgumentValueVisitor();
105+
ValidateArgumentValueVisitor(std::vector<schema_error>& errors);
106106

107107
void visit(const peg::ast_node& value);
108108

@@ -120,6 +120,7 @@ class ValidateArgumentValueVisitor
120120
void visitObjectValue(const peg::ast_node& objectValue);
121121

122122
ValidateArgumentValuePtr _argumentValue;
123+
std::vector<schema_error>& _errors;
123124
};
124125

125126
using ValidateFieldArguments = std::map<std::string, ValidateArgumentValuePtr>;
@@ -153,6 +154,9 @@ class ValidateExecutableVisitor
153154

154155
using FieldTypes = std::map<std::string, ValidateTypeField>;
155156
using TypeFields = std::map<std::string, FieldTypes>;
157+
using InputFieldTypes = ValidateTypeFieldArguments;
158+
using InputTypeFields = std::map<std::string, InputFieldTypes>;
159+
using EnumValues = std::map<std::string, std::set<std::string>>;
156160

157161
std::optional<introspection::TypeKind> getTypeKind(const std::string& name) const;
158162
std::optional<introspection::TypeKind> getScopedTypeKind() const;
@@ -161,8 +165,13 @@ class ValidateExecutableVisitor
161165
bool matchesScopedType(const std::string& name) const;
162166

163167
TypeFields::const_iterator getScopedTypeFields();
164-
static std::string getFieldType(const FieldTypes& fields, const std::string& name);
165-
static std::string getWrappedFieldType(const FieldTypes& fields, const std::string& name);
168+
InputTypeFields::const_iterator getInputTypeFields(const std::string& name);
169+
static const ValidateType& getValidateFieldType(const FieldTypes::mapped_type& value);
170+
static const ValidateType& getValidateFieldType(const InputFieldTypes::mapped_type& value);
171+
template <class _FieldTypes>
172+
static std::string getFieldType(const _FieldTypes& fields, const std::string& name);
173+
template <class _FieldTypes>
174+
static std::string getWrappedFieldType(const _FieldTypes& fields, const std::string& name);
166175
static std::string getWrappedFieldType(const ValidateType& returnType);
167176

168177
void visitFragmentDefinition(const peg::ast_node& fragmentDefinition);
@@ -176,6 +185,8 @@ class ValidateExecutableVisitor
176185

177186
void visitDirectives(introspection::DirectiveLocation location, const peg::ast_node& directives);
178187

188+
bool validateInputValue(const ValidateArgumentValuePtr& argument, const ValidateType& type);
189+
179190
const Request& _service;
180191
std::vector<schema_error> _errors;
181192

@@ -185,11 +196,15 @@ class ValidateExecutableVisitor
185196
using ExecutableNodes = std::map<std::string, const peg::ast_node&>;
186197
using FragmentSet = std::unordered_set<std::string>;
187198
using MatchingTypes = std::map<std::string, std::set<std::string>>;
199+
using VariableTypes = std::map<std::string, std::vector<ValidateArgument>>;
200+
using ScalarTypes = std::set<std::string>;
188201

189202
OperationTypes _operationTypes;
190203
TypeKinds _typeKinds;
191204
MatchingTypes _matchingTypes;
192205
Directives _directives;
206+
EnumValues _enumValues;
207+
ScalarTypes _scalarTypes;
193208

194209
ExecutableNodes _fragmentDefinitions;
195210
ExecutableNodes _operationDefinitions;
@@ -199,6 +214,7 @@ class ValidateExecutableVisitor
199214
FragmentSet _fragmentCycles;
200215
size_t _fieldCount = 0;
201216
TypeFields _typeFields;
217+
InputTypeFields _inputTypeFields;
202218
std::string _scopedType;
203219
std::map<std::string, ValidateField> _selectionFields;
204220
};

samples/schema.validation.graphql

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,14 @@ extend type Query {
101101
# http://spec.graphql.org/June2018/#example-6bbad
102102
extend type Human {
103103
pets: [Pet!]!
104-
}
104+
}
105+
106+
"Support for [Example 145](http://spec.graphql.org/June2018/#example-7ee0e) - [Counter Example 146](http://spec.graphql.org/June2018/#example-3a7c1)"
107+
input ComplexInput {
108+
name: String!
109+
}
110+
111+
# http://spec.graphql.org/June2018/#example-7ee0e - http://spec.graphql.org/June2018/#example-3a7c1
112+
extend type Query {
113+
findDog(complex: ComplexInput!): String
114+
}

samples/validation/ValidationSchema.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ std::future<response::Value> ModifiedResult<validation::CatCommand>::convert(ser
8989
});
9090
}
9191

92+
template <>
93+
validation::ComplexInput ModifiedArgument<validation::ComplexInput>::convert(const response::Value& value)
94+
{
95+
auto valueName = service::ModifiedArgument<response::StringType>::require("name", value);
96+
97+
return {
98+
std::move(valueName)
99+
};
100+
}
101+
92102
} /* namespace service */
93103

94104
namespace validation {
@@ -103,6 +113,7 @@ Query::Query()
103113
{ "pet", [this](service::ResolverParams&& params) { return resolvePet(std::move(params)); } },
104114
{ "catOrDog", [this](service::ResolverParams&& params) { return resolveCatOrDog(std::move(params)); } },
105115
{ "arguments", [this](service::ResolverParams&& params) { return resolveArguments(std::move(params)); } },
116+
{ "findDog", [this](service::ResolverParams&& params) { return resolveFindDog(std::move(params)); } },
106117
{ "__typename", [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } },
107118
{ "__schema", [this](service::ResolverParams&& params) { return resolve_schema(std::move(params)); } },
108119
{ "__type", [this](service::ResolverParams&& params) { return resolve_type(std::move(params)); } }
@@ -183,6 +194,21 @@ std::future<response::Value> Query::resolveArguments(service::ResolverParams&& p
183194
return service::ModifiedResult<Arguments>::convert<service::TypeModifier::Nullable>(std::move(result), std::move(params));
184195
}
185196

197+
service::FieldResult<std::optional<response::StringType>> Query::getFindDog(service::FieldParams&&, ComplexInput&&) const
198+
{
199+
throw std::runtime_error(R"ex(Query::getFindDog is not implemented)ex");
200+
}
201+
202+
std::future<response::Value> Query::resolveFindDog(service::ResolverParams&& params)
203+
{
204+
auto argComplex = service::ModifiedArgument<ComplexInput>::require("complex", params.arguments);
205+
std::unique_lock resolverLock(_resolverMutex);
206+
auto result = getFindDog(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argComplex));
207+
resolverLock.unlock();
208+
209+
return service::ModifiedResult<response::StringType>::convert<service::TypeModifier::Nullable>(std::move(result), std::move(params));
210+
}
211+
186212
std::future<response::Value> Query::resolve_typename(service::ResolverParams&& params)
187213
{
188214
return service::ModifiedResult<response::StringType>::convert(response::StringType{ R"gql(Query)gql" }, std::move(params));
@@ -780,6 +806,8 @@ void AddTypesToSchema(const std::shared_ptr<introspection::Schema>& schema)
780806
schema->AddType("DogCommand", typeDogCommand);
781807
auto typeCatCommand = std::make_shared<introspection::EnumType>("CatCommand", R"md()md");
782808
schema->AddType("CatCommand", typeCatCommand);
809+
auto typeComplexInput = std::make_shared<introspection::InputObjectType>("ComplexInput", R"md(Support for [Example 145](http://spec.graphql.org/June2018/#example-7ee0e) - [Counter Example 146](http://spec.graphql.org/June2018/#example-3a7c1))md");
810+
schema->AddType("ComplexInput", typeComplexInput);
783811
auto typeCatOrDog = std::make_shared<introspection::UnionType>("CatOrDog", R"md()md");
784812
schema->AddType("CatOrDog", typeCatOrDog);
785813
auto typeDogOrHuman = std::make_shared<introspection::UnionType>("DogOrHuman", R"md()md");
@@ -820,6 +848,10 @@ void AddTypesToSchema(const std::shared_ptr<introspection::Schema>& schema)
820848
{ std::string{ service::s_namesCatCommand[static_cast<size_t>(validation::CatCommand::JUMP)] }, R"md()md", std::nullopt }
821849
});
822850

851+
typeComplexInput->AddInputValues({
852+
std::make_shared<introspection::InputValue>("name", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql")
853+
});
854+
823855
typeCatOrDog->AddPossibleTypes({
824856
schema->LookupType("Cat"),
825857
schema->LookupType("Dog")
@@ -845,7 +877,10 @@ void AddTypesToSchema(const std::shared_ptr<introspection::Schema>& schema)
845877
std::make_shared<introspection::Field>("human", R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("Human")),
846878
std::make_shared<introspection::Field>("pet", R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("Pet")),
847879
std::make_shared<introspection::Field>("catOrDog", R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("CatOrDog")),
848-
std::make_shared<introspection::Field>("arguments", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("Arguments"))
880+
std::make_shared<introspection::Field>("arguments", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>(), schema->LookupType("Arguments")),
881+
std::make_shared<introspection::Field>("findDog", R"md()md", std::nullopt, std::vector<std::shared_ptr<introspection::InputValue>>({
882+
std::make_shared<introspection::InputValue>("complex", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ComplexInput")), R"gql()gql")
883+
}), schema->LookupType("String"))
849884
});
850885
typeDog->AddInterfaces({
851886
typePet

samples/validation/ValidationSchema.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ enum class CatCommand
3333
JUMP
3434
};
3535

36+
struct ComplexInput
37+
{
38+
response::StringType name;
39+
};
40+
3641
namespace object {
3742

3843
class Query;
@@ -75,13 +80,15 @@ class Query
7580
virtual service::FieldResult<std::shared_ptr<service::Object>> getPet(service::FieldParams&& params) const;
7681
virtual service::FieldResult<std::shared_ptr<service::Object>> getCatOrDog(service::FieldParams&& params) const;
7782
virtual service::FieldResult<std::shared_ptr<Arguments>> getArguments(service::FieldParams&& params) const;
83+
virtual service::FieldResult<std::optional<response::StringType>> getFindDog(service::FieldParams&& params, ComplexInput&& complexArg) const;
7884

7985
private:
8086
std::future<response::Value> resolveDog(service::ResolverParams&& params);
8187
std::future<response::Value> resolveHuman(service::ResolverParams&& params);
8288
std::future<response::Value> resolvePet(service::ResolverParams&& params);
8389
std::future<response::Value> resolveCatOrDog(service::ResolverParams&& params);
8490
std::future<response::Value> resolveArguments(service::ResolverParams&& params);
91+
std::future<response::Value> resolveFindDog(service::ResolverParams&& params);
8592

8693
std::future<response::Value> resolve_typename(service::ResolverParams&& params);
8794
std::future<response::Value> resolve_schema(service::ResolverParams&& params);

0 commit comments

Comments
 (0)