-
Notifications
You must be signed in to change notification settings - Fork 56
Expand file tree
/
Copy pathSchemaLoader.h
More file actions
358 lines (294 loc) · 12.8 KB
/
Copy pathSchemaLoader.h
File metadata and controls
358 lines (294 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#ifndef SCHEMALOADER_H
#define SCHEMALOADER_H
#include "GeneratorLoader.h"
#include "graphqlservice/GraphQLParse.h"
#include "graphqlservice/GraphQLService.h"
#include "graphqlservice/internal/Grammar.h"
#include <array>
#include <unordered_map>
#include <unordered_set>
namespace graphql::generator {
// These are the set of built-in types in GraphQL.
enum class [[nodiscard("unnecessary conversion")]] BuiltinType {
Int,
Float,
String,
Boolean,
ID,
};
using BuiltinTypeMap = std::map<std::string_view, BuiltinType>;
// These are the C++ types we'll use for them.
using CppTypeMap = std::array<std::string_view, static_cast<size_t>(BuiltinType::ID) + 1>;
// Keep track of the positions of each type declaration in the file.
using PositionMap = std::unordered_map<std::string_view, tao::graphqlpeg::position>;
// For all of the named types we track, we want to keep them in order in a vector but
// be able to lookup their offset quickly by name.
using TypeNameMap = std::unordered_map<std::string_view, size_t>;
// Scalar types are opaque to the generator, it's up to the service implementation
// to handle parsing, validating, and serializing them. We just need to track which
// scalar type names have been declared so we recognize the references.
struct [[nodiscard("unnecessary construction")]] ScalarType
{
std::string_view type;
std::string_view description;
std::string_view specifiedByURL {};
};
using ScalarTypeList = std::vector<ScalarType>;
// Enum types map a type name to a collection of valid string values.
struct [[nodiscard("unnecessary construction")]] EnumValueType
{
std::string_view value;
std::string_view cppValue;
std::string_view description;
std::optional<std::string_view> deprecationReason;
std::optional<tao::graphqlpeg::position> position;
};
struct [[nodiscard("unnecessary construction")]] EnumType
{
std::string_view type;
std::string_view cppType;
std::vector<EnumValueType> values;
std::string_view description;
};
using EnumTypeList = std::vector<EnumType>;
// Input types are complex types that have a set of named fields. Each field may be
// a scalar type (including lists or non-null wrappers) or another nested input type,
// but it cannot include output object types.
enum class [[nodiscard("unnecessary conversion")]] InputFieldType {
Builtin,
Scalar,
Enum,
Input,
};
struct [[nodiscard("unnecessary construction")]] InputField
{
std::string_view type;
std::string_view name;
std::string_view cppName;
std::string_view defaultValueString;
response::Value defaultValue;
InputFieldType fieldType = InputFieldType::Builtin;
TypeModifierStack modifiers;
std::string_view description;
std::optional<tao::graphqlpeg::position> position;
};
using InputFieldList = std::vector<InputField>;
struct [[nodiscard("unnecessary construction")]] InputType
{
std::string_view type;
std::string_view cppType;
InputFieldList fields;
std::string_view description;
std::unordered_set<std::string_view> dependencies {};
std::vector<std::string_view> declarations {};
};
using InputTypeList = std::vector<InputType>;
// Directives are defined with arguments and a list of valid locations.
struct [[nodiscard("unnecessary construction")]] Directive
{
std::string_view name;
bool isRepeatable = false;
std::vector<std::string_view> locations;
InputFieldList arguments;
std::string_view description;
};
using DirectiveList = std::vector<Directive>;
// Union types map a type name to a set of potential concrete type names.
struct [[nodiscard("unnecessary construction")]] UnionType
{
std::string_view type;
std::string_view cppType;
std::vector<std::string_view> options;
std::string_view description;
};
using UnionTypeList = std::vector<UnionType>;
// Output types are scalar types or complex types that have a set of named fields. Each
// field may be a scalar type (including lists or non-null wrappers) or another nested
// output type, but it cannot include input object types. Each field can also take
// optional arguments which are all input types.
enum class [[nodiscard("unnecessary conversion")]] OutputFieldType {
Builtin,
Scalar,
Enum,
Union,
Interface,
Object,
};
constexpr std::string_view strGet = "get";
constexpr std::string_view strApply = "apply";
struct [[nodiscard("unnecessary construction")]] OutputField
{
std::string_view type;
std::string_view name;
InputFieldList arguments;
OutputFieldType fieldType = OutputFieldType::Builtin;
TypeModifierStack modifiers;
std::string_view description;
std::optional<std::string_view> deprecationReason;
std::optional<tao::graphqlpeg::position> position;
bool interfaceField = false;
bool inheritedField = false;
std::string_view accessor { strGet };
};
using OutputFieldList = std::vector<OutputField>;
// Interface types are abstract complex output types that have a set of fields. They
// are inherited by concrete object output types which support all of the fields in
// the interface, and the concrete object matches the interface for fragment type
// conditions. The fields can include any output type.
struct [[nodiscard("unnecessary construction")]] InterfaceType
{
std::string_view type;
std::string_view cppType;
std::vector<std::string_view> interfaces;
OutputFieldList fields;
std::string_view description;
};
using InterfaceTypeList = std::vector<InterfaceType>;
// Object types are concrete complex output types that have a set of fields. They
// may inherit multiple interfaces.
struct [[nodiscard("unnecessary construction")]] ObjectType
{
std::string_view type;
std::string_view cppType;
std::vector<std::string_view> interfaces;
std::vector<std::string_view> unions;
OutputFieldList fields;
std::string_view description;
};
using ObjectTypeList = std::vector<ObjectType>;
// The schema maps operation types to named types.
struct [[nodiscard("unnecessary construction")]] OperationType
{
std::string_view type;
std::string_view cppType;
std::string_view operation;
};
using OperationTypeList = std::vector<OperationType>;
struct [[nodiscard("unnecessary construction")]] SchemaOptions
{
const std::string schemaFilename;
const std::string filenamePrefix;
const std::string schemaNamespace;
const bool isIntrospection = false;
};
class [[nodiscard("unnecessary construction")]] SchemaLoader
{
public:
// Initialize the loader with the introspection schema or a custom GraphQL schema.
explicit SchemaLoader(SchemaOptions && schemaOptions);
[[nodiscard("unnecessary call")]] bool isIntrospection() const noexcept;
[[nodiscard("unnecessary call")]] std::string_view getSchemaDescription() const noexcept;
[[nodiscard("unnecessary call")]] std::string_view getFilenamePrefix() const noexcept;
[[nodiscard("unnecessary call")]] std::string_view getSchemaNamespace() const noexcept;
[[nodiscard("unnecessary call")]] static std::string_view getIntrospectionNamespace() noexcept;
[[nodiscard("unnecessary call")]] static const BuiltinTypeMap& getBuiltinTypes() noexcept;
[[nodiscard("unnecessary call")]] static const CppTypeMap& getBuiltinCppTypes() noexcept;
[[nodiscard("unnecessary call")]] static std::string_view getScalarCppType() noexcept;
[[nodiscard("unnecessary call")]] SchemaType getSchemaType(std::string_view type) const;
[[nodiscard("unnecessary call")]] const tao::graphqlpeg::position& getTypePosition(
std::string_view type) const;
[[nodiscard("unnecessary call")]] size_t getScalarIndex(std::string_view type) const;
[[nodiscard("unnecessary call")]] const ScalarTypeList& getScalarTypes() const noexcept;
[[nodiscard("unnecessary call")]] size_t getEnumIndex(std::string_view type) const;
[[nodiscard("unnecessary call")]] const EnumTypeList& getEnumTypes() const noexcept;
[[nodiscard("unnecessary call")]] size_t getInputIndex(std::string_view type) const;
[[nodiscard("unnecessary call")]] const InputTypeList& getInputTypes() const noexcept;
[[nodiscard("unnecessary call")]] size_t getUnionIndex(std::string_view type) const;
[[nodiscard("unnecessary call")]] const UnionTypeList& getUnionTypes() const noexcept;
[[nodiscard("unnecessary call")]] size_t getInterfaceIndex(std::string_view type) const;
[[nodiscard("unnecessary call")]] const InterfaceTypeList& getInterfaceTypes() const noexcept;
[[nodiscard("unnecessary call")]] size_t getObjectIndex(std::string_view type) const;
[[nodiscard("unnecessary call")]] const ObjectTypeList& getObjectTypes() const noexcept;
[[nodiscard("unnecessary call")]] const DirectiveList& getDirectives() const noexcept;
[[nodiscard("unnecessary call")]] const tao::graphqlpeg::position& getDirectivePosition(
std::string_view type) const;
[[nodiscard("unnecessary call")]] const OperationTypeList& getOperationTypes() const noexcept;
[[nodiscard("unnecessary call")]] static std::string_view getSafeCppName(
std::string_view type) noexcept;
[[nodiscard("unnecessary call")]] std::string_view getCppType(std::string_view type)
const noexcept;
[[nodiscard("unnecessary memory copy")]] std::string getInputCppType(const InputField& field)
const noexcept;
[[nodiscard("unnecessary memory copy")]] std::string getOutputCppType(const OutputField& field)
const noexcept;
[[nodiscard("unnecessary memory copy")]] static std::string getOutputCppAccessor(
const OutputField& field) noexcept;
[[nodiscard("unnecessary memory copy")]] static std::string getOutputCppResolver(
const OutputField& field) noexcept;
[[nodiscard("unnecessary call")]] static bool shouldMoveInputField(
const InputField& field) noexcept;
private:
[[nodiscard("unnecessary call")]] static bool isExtension(
const peg::ast_node& definition) noexcept;
void visitDefinition(const peg::ast_node& definition);
void visitSchemaDefinition(const peg::ast_node& schemaDefinition);
void visitSchemaExtension(const peg::ast_node& schemaExtension);
void visitScalarTypeDefinition(const peg::ast_node& scalarTypeDefinition);
void visitScalarTypeExtension(const peg::ast_node& scalarTypeExtension);
void visitEnumTypeDefinition(const peg::ast_node& enumTypeDefinition);
void visitEnumTypeExtension(const peg::ast_node& enumTypeExtension);
void visitInputObjectTypeDefinition(const peg::ast_node& inputObjectTypeDefinition);
void visitInputObjectTypeExtension(const peg::ast_node& inputObjectTypeExtension);
void visitUnionTypeDefinition(const peg::ast_node& unionTypeDefinition);
void visitUnionTypeExtension(const peg::ast_node& unionTypeExtension);
void visitInterfaceTypeDefinition(const peg::ast_node& interfaceTypeDefinition);
void visitInterfaceTypeExtension(const peg::ast_node& interfaceTypeExtension);
void visitObjectTypeDefinition(const peg::ast_node& objectTypeDefinition);
void visitObjectTypeExtension(const peg::ast_node& objectTypeExtension);
void visitDirectiveDefinition(const peg::ast_node& directiveDefinition);
static void blockReservedName(std::string_view name,
std::optional<tao::graphqlpeg::position> position = std::nullopt);
[[nodiscard("unnecessary memory copy")]] static OutputFieldList getOutputFields(
const peg::ast_node::children_t& fields);
[[nodiscard("unnecessary memory copy")]] static InputFieldList getInputFields(
const peg::ast_node::children_t& fields);
void validateSchema();
void fixupOutputFieldList(OutputFieldList & fields,
const std::optional<std::unordered_set<std::string_view>>& interfaceFields,
const std::optional<std::string_view>& accessor);
void fixupInputFieldList(InputFieldList & fields);
void reorderInputTypeDependencies();
void validateImplementedInterfaces() const;
[[nodiscard("unnecessary call")]] const InterfaceType& findInterfaceType(
std::string_view typeName,
std::string_view interfaceName) const;
void validateInterfaceFields(std::string_view typeName,
std::string_view interfaceName,
const OutputFieldList& typeFields) const;
void validateTransitiveInterfaces(std::string_view typeName,
const std::vector<std::string_view>& interfaces) const;
[[nodiscard("unnecessary memory copy")]] static std::string getJoinedCppName(
std::string_view prefix,
std::string_view fieldName) noexcept;
static const std::string_view s_introspectionNamespace;
static const BuiltinTypeMap s_builtinTypes;
static const CppTypeMap s_builtinCppTypes;
static const std::string_view s_scalarCppType;
const SchemaOptions _schemaOptions;
const bool _isIntrospection;
std::string_view _schemaDescription;
std::string_view _schemaNamespace;
peg::ast _ast;
SchemaTypeMap _schemaTypes;
PositionMap _typePositions;
TypeNameMap _scalarNames;
ScalarTypeList _scalarTypes;
TypeNameMap _enumNames;
EnumTypeList _enumTypes;
TypeNameMap _inputNames;
InputTypeList _inputTypes;
TypeNameMap _unionNames;
UnionTypeList _unionTypes;
TypeNameMap _interfaceNames;
InterfaceTypeList _interfaceTypes;
TypeNameMap _objectNames;
ObjectTypeList _objectTypes;
DirectiveList _directives;
PositionMap _directivePositions;
OperationTypeList _operationTypes;
};
} // namespace graphql::generator
#endif // SCHEMALOADER_H