Skip to content

Commit 3ca273a

Browse files
authored
Merge pull request #88 from wravery/master
Implement the Validation section of the spec
2 parents f77f95b + d79d6b6 commit 3ca273a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+8961
-2367
lines changed

include/SchemaGenerator.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
#ifndef SCHEMAGENERATOR_H
77
#define SCHEMAGENERATOR_H
88

9-
#include <graphqlservice/GraphQLService.h>
10-
#include <graphqlservice/GraphQLGrammar.h>
9+
#include "graphqlservice/GraphQLService.h"
10+
#include "graphqlservice/GraphQLGrammar.h"
1111

1212
#include <array>
1313
#include <cstdio>
@@ -291,6 +291,12 @@ class Generator
291291
std::vector<std::string> Build() const noexcept;
292292

293293
private:
294+
std::string getHeaderDir() const noexcept;
295+
std::string getSourceDir() const noexcept;
296+
std::string getHeaderPath() const noexcept;
297+
std::string getObjectHeaderPath() const noexcept;
298+
std::string getSourcePath() const noexcept;
299+
294300
void visitDefinition(const peg::ast_node& definition);
295301

296302
void visitSchemaDefinition(const peg::ast_node& schemaDefinition);

include/Validation.h

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
#pragma once
5+
6+
#ifndef VALIDATION_H
7+
#define VALIDATION_H
8+
9+
#include "graphqlservice/GraphQLService.h"
10+
#include "graphqlservice/IntrospectionSchema.h"
11+
12+
namespace graphql::service {
13+
14+
using ValidateType = response::Value;
15+
16+
struct ValidateArgument
17+
{
18+
bool defaultValue = false;
19+
bool nonNullDefaultValue = false;
20+
ValidateType type;
21+
};
22+
23+
using ValidateTypeFieldArguments = std::map<std::string, ValidateArgument>;
24+
25+
struct ValidateTypeField
26+
{
27+
ValidateType returnType;
28+
ValidateTypeFieldArguments arguments;
29+
};
30+
31+
using ValidateDirectiveArguments = std::map<std::string, ValidateArgument>;
32+
33+
struct ValidateDirective
34+
{
35+
std::set<introspection::DirectiveLocation> locations;
36+
ValidateDirectiveArguments arguments;
37+
};
38+
39+
struct ValidateArgumentVariable
40+
{
41+
bool operator==(const ValidateArgumentVariable& other) const;
42+
43+
std::string name;
44+
};
45+
46+
struct ValidateArgumentEnumValue
47+
{
48+
bool operator==(const ValidateArgumentEnumValue& other) const;
49+
50+
std::string value;
51+
};
52+
53+
struct ValidateArgumentValue;
54+
55+
struct ValidateArgumentValuePtr
56+
{
57+
bool operator==(const ValidateArgumentValuePtr& other) const;
58+
59+
std::unique_ptr<ValidateArgumentValue> value;
60+
schema_location position;
61+
};
62+
63+
struct ValidateArgumentList
64+
{
65+
bool operator==(const ValidateArgumentList& other) const;
66+
67+
std::vector<ValidateArgumentValuePtr> values;
68+
};
69+
70+
struct ValidateArgumentMap
71+
{
72+
bool operator==(const ValidateArgumentMap& other) const;
73+
74+
std::map<std::string, ValidateArgumentValuePtr> values;
75+
};
76+
77+
using ValidateArgumentVariant = std::variant<
78+
ValidateArgumentVariable,
79+
response::IntType,
80+
response::FloatType,
81+
response::StringType,
82+
response::BooleanType,
83+
ValidateArgumentEnumValue,
84+
ValidateArgumentList,
85+
ValidateArgumentMap>;
86+
87+
struct ValidateArgumentValue
88+
{
89+
ValidateArgumentValue(ValidateArgumentVariable&& value);
90+
ValidateArgumentValue(response::IntType value);
91+
ValidateArgumentValue(response::FloatType value);
92+
ValidateArgumentValue(response::StringType&& value);
93+
ValidateArgumentValue(response::BooleanType value);
94+
ValidateArgumentValue(ValidateArgumentEnumValue&& value);
95+
ValidateArgumentValue(ValidateArgumentList&& value);
96+
ValidateArgumentValue(ValidateArgumentMap&& value);
97+
98+
ValidateArgumentVariant data;
99+
};
100+
101+
// ValidateArgumentValueVisitor visits the AST and builds a record of a field return type and map
102+
// of the arguments for comparison to see if 2 fields with the same result name can be merged.
103+
class ValidateArgumentValueVisitor
104+
{
105+
public:
106+
ValidateArgumentValueVisitor(std::vector<schema_error>& errors);
107+
108+
void visit(const peg::ast_node& value);
109+
110+
ValidateArgumentValuePtr getArgumentValue();
111+
112+
private:
113+
void visitVariable(const peg::ast_node& variable);
114+
void visitIntValue(const peg::ast_node& intValue);
115+
void visitFloatValue(const peg::ast_node& floatValue);
116+
void visitStringValue(const peg::ast_node& stringValue);
117+
void visitBooleanValue(const peg::ast_node& booleanValue);
118+
void visitNullValue(const peg::ast_node& nullValue);
119+
void visitEnumValue(const peg::ast_node& enumValue);
120+
void visitListValue(const peg::ast_node& listValue);
121+
void visitObjectValue(const peg::ast_node& objectValue);
122+
123+
ValidateArgumentValuePtr _argumentValue;
124+
std::vector<schema_error>& _errors;
125+
};
126+
127+
using ValidateFieldArguments = std::map<std::string, ValidateArgumentValuePtr>;
128+
129+
struct ValidateField
130+
{
131+
ValidateField(std::string&& returnType, std::optional<std::string>&& objectType, const std::string& fieldName, ValidateFieldArguments&& arguments);
132+
133+
bool operator==(const ValidateField& other) const;
134+
135+
std::string returnType;
136+
std::optional<std::string> objectType;
137+
std::string fieldName;
138+
ValidateFieldArguments arguments;
139+
};
140+
141+
using ValidateTypeKinds = std::map<std::string, introspection::TypeKind>;
142+
143+
// ValidateVariableTypeVisitor visits the AST and builds a ValidateType structure representing
144+
// a variable type in an operation definition as if it came from an Introspection query.
145+
class ValidateVariableTypeVisitor
146+
{
147+
public:
148+
ValidateVariableTypeVisitor(const ValidateTypeKinds& typeKinds);
149+
150+
void visit(const peg::ast_node& typeName);
151+
152+
bool isInputType() const;
153+
ValidateType getType();
154+
155+
private:
156+
void visitNamedType(const peg::ast_node& namedType);
157+
void visitListType(const peg::ast_node& listType);
158+
void visitNonNullType(const peg::ast_node& nonNullType);
159+
160+
const ValidateTypeKinds& _typeKinds;
161+
162+
bool _isInputType = false;
163+
ValidateType _variableType;
164+
};
165+
166+
// ValidateExecutableVisitor visits the AST and validates that it is executable against the service schema.
167+
class ValidateExecutableVisitor
168+
{
169+
public:
170+
ValidateExecutableVisitor(const Request& service);
171+
172+
void visit(const peg::ast_node& root);
173+
174+
std::vector<schema_error> getStructuredErrors();
175+
176+
private:
177+
response::Value executeQuery(std::string_view query) const;
178+
179+
static ValidateTypeFieldArguments getArguments(response::ListType&& argumentsMember);
180+
181+
using FieldTypes = std::map<std::string, ValidateTypeField>;
182+
using TypeFields = std::map<std::string, FieldTypes>;
183+
using InputFieldTypes = ValidateTypeFieldArguments;
184+
using InputTypeFields = std::map<std::string, InputFieldTypes>;
185+
using EnumValues = std::map<std::string, std::set<std::string>>;
186+
187+
std::optional<introspection::TypeKind> getTypeKind(const std::string& name) const;
188+
std::optional<introspection::TypeKind> getScopedTypeKind() const;
189+
constexpr bool isScalarType(introspection::TypeKind kind);
190+
191+
bool matchesScopedType(const std::string& name) const;
192+
193+
TypeFields::const_iterator getScopedTypeFields();
194+
InputTypeFields::const_iterator getInputTypeFields(const std::string& name);
195+
static const ValidateType& getValidateFieldType(const FieldTypes::mapped_type& value);
196+
static const ValidateType& getValidateFieldType(const InputFieldTypes::mapped_type& value);
197+
template <class _FieldTypes>
198+
static std::string getFieldType(const _FieldTypes& fields, const std::string& name);
199+
template <class _FieldTypes>
200+
static std::string getWrappedFieldType(const _FieldTypes& fields, const std::string& name);
201+
static std::string getWrappedFieldType(const ValidateType& returnType);
202+
203+
void visitFragmentDefinition(const peg::ast_node& fragmentDefinition);
204+
void visitOperationDefinition(const peg::ast_node& operationDefinition);
205+
206+
void visitSelection(const peg::ast_node& selection);
207+
208+
void visitField(const peg::ast_node& field);
209+
void visitFragmentSpread(const peg::ast_node& fragmentSpread);
210+
void visitInlineFragment(const peg::ast_node& inlineFragment);
211+
212+
void visitDirectives(introspection::DirectiveLocation location, const peg::ast_node& directives);
213+
214+
bool validateInputValue(bool hasNonNullDefaultValue, const ValidateArgumentValuePtr& argument, const ValidateType& type);
215+
bool validateVariableType(bool isNonNull, const ValidateType& variableType, const schema_location& position, const ValidateType& inputType);
216+
217+
218+
const Request& _service;
219+
std::vector<schema_error> _errors;
220+
221+
using OperationTypes = std::map<std::string_view, std::string>;
222+
using Directives = std::map<std::string, ValidateDirective>;
223+
using ExecutableNodes = std::map<std::string, const peg::ast_node&>;
224+
using FragmentSet = std::unordered_set<std::string>;
225+
using MatchingTypes = std::map<std::string, std::set<std::string>>;
226+
using ScalarTypes = std::set<std::string>;
227+
using VariableDefinitions = std::map<std::string, const peg::ast_node&>;
228+
using VariableTypes = std::map<std::string, ValidateArgument>;
229+
using OperationVariables = std::optional<VariableTypes>;
230+
using VariableSet = std::set<std::string>;
231+
232+
OperationTypes _operationTypes;
233+
ValidateTypeKinds _typeKinds;
234+
MatchingTypes _matchingTypes;
235+
Directives _directives;
236+
EnumValues _enumValues;
237+
ScalarTypes _scalarTypes;
238+
239+
ExecutableNodes _fragmentDefinitions;
240+
ExecutableNodes _operationDefinitions;
241+
242+
OperationVariables _operationVariables;
243+
VariableDefinitions _variableDefinitions;
244+
VariableSet _referencedVariables;
245+
FragmentSet _referencedFragments;
246+
FragmentSet _fragmentStack;
247+
FragmentSet _fragmentCycles;
248+
size_t _fieldCount = 0;
249+
TypeFields _typeFields;
250+
InputTypeFields _inputTypeFields;
251+
std::string _scopedType;
252+
std::map<std::string, ValidateField> _selectionFields;
253+
};
254+
255+
} /* namespace graphql::service */
256+
257+
#endif // VALIDATION_H

include/graphqlservice/GraphQLGrammar.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#ifndef GRAPHQLGRAMMAR_H
1010
#define GRAPHQLGRAMMAR_H
1111

12-
#include <graphqlservice/GraphQLTree.h>
12+
#include "graphqlservice/GraphQLTree.h"
1313

1414
#define TAO_PEGTL_NAMESPACE tao::graphqlpeg
1515

include/graphqlservice/GraphQLParse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct ast
1919
{
2020
std::shared_ptr<ast_input> input;
2121
std::shared_ptr<ast_node> root;
22+
bool validated = false;
2223
};
2324

2425
ast parseString(std::string_view input);

include/graphqlservice/GraphQLResponse.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,24 @@ struct ValueTypeTraits
4646
// Set by r-value reference, get by const reference, and release by value. The only types
4747
// that actually support all 3 methods are StringType and ScalarType, everything else
4848
// overrides some subset of these types with a template specialization.
49-
using set_type = ValueType &&;
50-
using get_type = const ValueType &;
49+
using set_type = ValueType&&;
50+
using get_type = const ValueType&;
5151
using release_type = ValueType;
5252
};
5353

5454
template <>
5555
struct ValueTypeTraits<MapType>
5656
{
5757
// Get by const reference and release by value.
58-
using get_type = const MapType &;
58+
using get_type = const MapType&;
5959
using release_type = MapType;
6060
};
6161

6262
template <>
6363
struct ValueTypeTraits<ListType>
6464
{
6565
// Get by const reference and release by value.
66-
using get_type = const ListType &;
66+
using get_type = const ListType&;
6767
using release_type = ListType;
6868
};
6969

0 commit comments

Comments
 (0)