Skip to content

Commit c8b4e37

Browse files
committed
Refactor common schema code into SchemaLoader
1 parent 84d1d7d commit c8b4e37

File tree

7 files changed

+2404
-3823
lines changed

7 files changed

+2404
-3823
lines changed

include/ClientGenerator.h

Lines changed: 7 additions & 320 deletions
Original file line numberDiff line numberDiff line change
@@ -6,228 +6,11 @@
66
#ifndef CLIENTGENERATOR_H
77
#define CLIENTGENERATOR_H
88

9-
#include "graphqlservice/GraphQLGrammar.h"
10-
#include "graphqlservice/GraphQLParse.h"
11-
#include "graphqlservice/GraphQLResponse.h"
12-
#include "graphqlservice/GraphQLSchema.h"
13-
14-
#include <array>
15-
#include <cstdio>
16-
#include <unordered_map>
17-
#include <unordered_set>
18-
19-
namespace graphql::client {
20-
21-
// These are the set of built-in types in GraphQL.
22-
enum class BuiltinType
23-
{
24-
Int,
25-
Float,
26-
String,
27-
Boolean,
28-
ID,
29-
};
30-
31-
using BuiltinTypeMap = std::map<std::string_view, BuiltinType>;
32-
33-
// These are the C++ types we'll use for them.
34-
using CppTypeMap = std::array<std::string_view, static_cast<size_t>(BuiltinType::ID) + 1>;
35-
36-
// Types that we understand and use to generate the skeleton of a service.
37-
enum class SchemaType
38-
{
39-
Scalar,
40-
Enum,
41-
Input,
42-
Union,
43-
Interface,
44-
Object,
45-
Operation,
46-
};
47-
48-
using SchemaTypeMap = std::map<std::string_view, SchemaType>;
49-
50-
// Keep track of the positions of each type declaration in the file.
51-
using PositionMap = std::unordered_map<std::string_view, tao::graphqlpeg::position>;
52-
53-
// For all of the named types we track, we want to keep them in order in a vector but
54-
// be able to lookup their offset quickly by name.
55-
using TypeNameMap = std::unordered_map<std::string_view, size_t>;
56-
57-
// Any type can also have a list and/or non-nullable wrapper, and those can be nested.
58-
// Since it's easier to express nullability than non-nullability in C++, we'll invert
59-
// the presence of NonNull modifiers.
60-
using TypeModifierStack = std::vector<service::TypeModifier>;
61-
62-
// Scalar types are opaque to the generator, it's up to the service implementation
63-
// to handle parsing, validating, and serializing them. We just need to track which
64-
// scalar type names have been declared so we recognize the references.
65-
struct ScalarType
66-
{
67-
std::string_view type;
68-
std::string_view description;
69-
};
70-
71-
using ScalarTypeList = std::vector<ScalarType>;
72-
73-
// Enum types map a type name to a collection of valid string values.
74-
struct EnumValueType
75-
{
76-
std::string_view value;
77-
std::string_view cppValue;
78-
std::string_view description;
79-
std::optional<std::string_view> deprecationReason;
80-
std::optional<tao::graphqlpeg::position> position;
81-
};
82-
83-
struct EnumType
84-
{
85-
std::string_view type;
86-
std::string_view cppType;
87-
std::vector<EnumValueType> values;
88-
std::string_view description;
89-
};
90-
91-
using EnumTypeList = std::vector<EnumType>;
92-
93-
// Input types are complex types that have a set of named fields. Each field may be
94-
// a scalar type (including lists or non-null wrappers) or another nested input type,
95-
// but it cannot include output object types.
96-
enum class InputFieldType
97-
{
98-
Builtin,
99-
Scalar,
100-
Enum,
101-
Input,
102-
};
103-
104-
struct InputField
105-
{
106-
std::string_view type;
107-
std::string_view name;
108-
std::string_view cppName;
109-
std::string_view defaultValueString;
110-
response::Value defaultValue;
111-
InputFieldType fieldType = InputFieldType::Builtin;
112-
TypeModifierStack modifiers;
113-
std::string_view description;
114-
std::optional<tao::graphqlpeg::position> position;
115-
};
116-
117-
using InputFieldList = std::vector<InputField>;
118-
119-
struct InputType
120-
{
121-
std::string_view type;
122-
std::string_view cppType;
123-
InputFieldList fields;
124-
std::string_view description;
125-
};
126-
127-
using InputTypeList = std::vector<InputType>;
128-
129-
// Directives are defined with arguments and a list of valid locations.
130-
struct Directive
131-
{
132-
std::string_view name;
133-
std::vector<std::string_view> locations;
134-
InputFieldList arguments;
135-
std::string_view description;
136-
};
137-
138-
using DirectiveList = std::vector<Directive>;
139-
140-
// Union types map a type name to a set of potential concrete type names.
141-
struct UnionType
142-
{
143-
std::string_view type;
144-
std::string_view cppType;
145-
std::vector<std::string_view> options;
146-
std::string_view description;
147-
};
148-
149-
using UnionTypeList = std::vector<UnionType>;
150-
151-
// Output types are scalar types or complex types that have a set of named fields. Each
152-
// field may be a scalar type (including lists or non-null wrappers) or another nested
153-
// output type, but it cannot include input object types. Each field can also take
154-
// optional arguments which are all input types.
155-
enum class OutputFieldType
156-
{
157-
Builtin,
158-
Scalar,
159-
Enum,
160-
Union,
161-
Interface,
162-
Object,
163-
};
164-
165-
constexpr std::string_view strGet = "get";
166-
constexpr std::string_view strApply = "apply";
167-
168-
struct OutputField
169-
{
170-
std::string_view type;
171-
std::string_view name;
172-
std::string_view cppName;
173-
InputFieldList arguments;
174-
OutputFieldType fieldType = OutputFieldType::Builtin;
175-
TypeModifierStack modifiers;
176-
std::string_view description;
177-
std::optional<std::string_view> deprecationReason;
178-
std::optional<tao::graphqlpeg::position> position;
179-
bool interfaceField = false;
180-
bool inheritedField = false;
181-
std::string_view accessor { strGet };
182-
};
183-
184-
using OutputFieldList = std::vector<OutputField>;
185-
186-
// Interface types are abstract complex output types that have a set of fields. They
187-
// are inherited by concrete object output types which support all of the fields in
188-
// the interface, and the concrete object matches the interface for fragment type
189-
// conditions. The fields can include any output type.
190-
struct InterfaceType
191-
{
192-
std::string_view type;
193-
std::string_view cppType;
194-
OutputFieldList fields;
195-
std::string_view description;
196-
};
197-
198-
using InterfaceTypeList = std::vector<InterfaceType>;
199-
200-
// Object types are concrete complex output types that have a set of fields. They
201-
// may inherit multiple interfaces.
202-
struct ObjectType
203-
{
204-
std::string_view type;
205-
std::string_view cppType;
206-
std::vector<std::string_view> interfaces;
207-
std::vector<std::string_view> unions;
208-
OutputFieldList fields;
209-
std::string_view description;
210-
};
211-
212-
using ObjectTypeList = std::vector<ObjectType>;
213-
214-
// The client maps operation types to named types.
215-
struct OperationType
216-
{
217-
std::string_view type;
218-
std::string_view cppType;
219-
std::string_view operation;
220-
};
9+
#include "SchemaLoader.h"
22110

222-
using OperationTypeList = std::vector<OperationType>;
11+
#include "graphqlservice/GraphQLSchema.h"
22312

224-
struct GeneratorClient
225-
{
226-
const std::string schemaFilename;
227-
const std::string requestFilename;
228-
const std::string filenamePrefix;
229-
const std::string clientNamespace;
230-
};
13+
namespace graphql::generator::client {
23114

23215
struct GeneratorPaths
23316
{
@@ -237,7 +20,7 @@ struct GeneratorPaths
23720

23821
struct GeneratorOptions
23922
{
240-
const GeneratorClient client;
23+
const std::string requestFilename;
24124
const std::optional<GeneratorPaths> paths;
24225
const bool verbose = false;
24326
const bool noIntrospection = false;
@@ -247,7 +30,7 @@ class Generator
24730
{
24831
public:
24932
// Initialize the generator with the introspection client or a custom GraphQL client.
250-
explicit Generator(GeneratorOptions&& options);
33+
explicit Generator(SchemaOptions&& schemaOptions, GeneratorOptions&& options);
25134

25235
// Run the generator and return a list of filenames that were output.
25336
std::vector<std::string> Build() const noexcept;
@@ -258,82 +41,10 @@ class Generator
25841
std::string getHeaderPath() const noexcept;
25942
std::string getSourcePath() const noexcept;
26043

261-
void visitDefinition(const peg::ast_node& definition);
262-
263-
void visitClientDefinition(const peg::ast_node& clientDefinition);
264-
void visitClientExtension(const peg::ast_node& clientExtension);
265-
void visitScalarTypeDefinition(const peg::ast_node& scalarTypeDefinition);
266-
void visitEnumTypeDefinition(const peg::ast_node& enumTypeDefinition);
267-
void visitEnumTypeExtension(const peg::ast_node& enumTypeExtension);
268-
void visitInputObjectTypeDefinition(const peg::ast_node& inputObjectTypeDefinition);
269-
void visitInputObjectTypeExtension(const peg::ast_node& inputObjectTypeExtension);
270-
void visitUnionTypeDefinition(const peg::ast_node& unionTypeDefinition);
271-
void visitUnionTypeExtension(const peg::ast_node& unionTypeExtension);
272-
void visitInterfaceTypeDefinition(const peg::ast_node& interfaceTypeDefinition);
273-
void visitInterfaceTypeExtension(const peg::ast_node& interfaceTypeExtension);
274-
void visitObjectTypeDefinition(const peg::ast_node& objectTypeDefinition);
275-
void visitObjectTypeExtension(const peg::ast_node& objectTypeExtension);
276-
void visitDirectiveDefinition(const peg::ast_node& directiveDefinition);
277-
278-
static std::string_view getSafeCppName(std::string_view type) noexcept;
279-
static OutputFieldList getOutputFields(const peg::ast_node::children_t& fields);
280-
static InputFieldList getInputFields(const peg::ast_node::children_t& fields);
281-
282-
// Recursively visit a Type node until we reach a NamedType and we've
283-
// taken stock of all of the modifier wrappers.
284-
class TypeVisitor
285-
{
286-
public:
287-
std::pair<std::string_view, TypeModifierStack> getType();
288-
289-
void visit(const peg::ast_node& typeName);
290-
291-
private:
292-
void visitNamedType(const peg::ast_node& namedType);
293-
void visitListType(const peg::ast_node& listType);
294-
void visitNonNullType(const peg::ast_node& nonNullType);
295-
296-
std::string_view _type;
297-
TypeModifierStack _modifiers;
298-
bool _nonNull = false;
299-
};
300-
301-
// Recursively visit a Value node representing the default value on an input field
302-
// and build a JSON representation of the hardcoded value.
303-
class DefaultValueVisitor
304-
{
305-
public:
306-
response::Value getValue();
307-
308-
void visit(const peg::ast_node& value);
309-
310-
private:
311-
void visitIntValue(const peg::ast_node& intValue);
312-
void visitFloatValue(const peg::ast_node& floatValue);
313-
void visitStringValue(const peg::ast_node& stringValue);
314-
void visitBooleanValue(const peg::ast_node& booleanValue);
315-
void visitNullValue(const peg::ast_node& nullValue);
316-
void visitEnumValue(const peg::ast_node& enumValue);
317-
void visitListValue(const peg::ast_node& listValue);
318-
void visitObjectValue(const peg::ast_node& objectValue);
319-
320-
response::Value _value;
321-
};
322-
323-
void validateSchema();
324-
void fixupOutputFieldList(OutputFieldList& fields,
325-
const std::optional<std::unordered_set<std::string_view>>& interfaceFields,
326-
const std::optional<std::string_view>& accessor);
327-
void fixupInputFieldList(InputFieldList& fields);
328-
32944
void validateQuery() const;
33045
std::shared_ptr<schema::Schema> buildSchema() const;
33146
void addTypesToSchema(const std::shared_ptr<schema::Schema>& schema) const;
33247

333-
std::string_view getCppType(std::string_view type) const noexcept;
334-
std::string getInputCppType(const InputField& field) const noexcept;
335-
std::string getOutputCppType(const OutputField& field) const noexcept;
336-
33748
bool outputHeader() const noexcept;
33849
void outputObjectDeclaration(
33950
std::ostream& headerFile, const ObjectType& objectType, bool isQueryType) const;
@@ -356,39 +67,15 @@ class Generator
35667
const std::shared_ptr<schema::Schema>& schema, std::string_view type,
35768
TypeModifierStack modifiers, bool nonNull = true) noexcept;
35869

359-
static const BuiltinTypeMap s_builtinTypes;
360-
static const CppTypeMap s_builtinCppTypes;
361-
static const std::string_view s_scalarCppType;
362-
static const std::string s_currentDirectory;
363-
70+
SchemaLoader _loader;
36471
const GeneratorOptions _options;
365-
std::string_view _clientNamespace;
36672
const std::string _headerDir;
36773
const std::string _sourceDir;
36874
const std::string _headerPath;
36975
const std::string _sourcePath;
370-
peg::ast _schema;
37176
peg::ast _request;
372-
373-
SchemaTypeMap _clientTypes;
374-
PositionMap _typePositions;
375-
TypeNameMap _scalarNames;
376-
ScalarTypeList _scalarTypes;
377-
TypeNameMap _enumNames;
378-
EnumTypeList _enumTypes;
379-
TypeNameMap _inputNames;
380-
InputTypeList _inputTypes;
381-
TypeNameMap _unionNames;
382-
UnionTypeList _unionTypes;
383-
TypeNameMap _interfaceNames;
384-
InterfaceTypeList _interfaceTypes;
385-
TypeNameMap _objectNames;
386-
ObjectTypeList _objectTypes;
387-
DirectiveList _directives;
388-
PositionMap _directivePositions;
389-
OperationTypeList _operationTypes;
39077
};
39178

392-
} /* namespace graphql::client */
79+
} /* namespace graphql::generator::client */
39380

39481
#endif // CLIENTGENERATOR_H

0 commit comments

Comments
 (0)