Skip to content

Commit efce1b0

Browse files
committed
Finish RequestLoader
1 parent 4fa3e7b commit efce1b0

File tree

13 files changed

+665
-262
lines changed

13 files changed

+665
-262
lines changed

include/ClientGenerator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef CLIENTGENERATOR_H
77
#define CLIENTGENERATOR_H
88

9+
#include "SchemaLoader.h"
910
#include "RequestLoader.h"
1011

1112
namespace graphql::generator::client {

include/GeneratorLoader.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
#pragma once
5+
6+
#ifndef GENERATORLOADER_H
7+
#define GENERATORLOADER_H
8+
9+
#include "graphqlservice/GraphQLService.h"
10+
11+
namespace graphql::generator {
12+
13+
// Types that we understand and use to generate the skeleton of a service.
14+
enum class SchemaType
15+
{
16+
Scalar,
17+
Enum,
18+
Input,
19+
Union,
20+
Interface,
21+
Object,
22+
Operation,
23+
};
24+
25+
using SchemaTypeMap = std::map<std::string_view, SchemaType>;
26+
27+
// Any type can also have a list and/or non-nullable wrapper, and those can be nested.
28+
// Since it's easier to express nullability than non-nullability in C++, we'll invert
29+
// the presence of NonNull modifiers.
30+
using TypeModifierStack = std::vector<service::TypeModifier>;
31+
32+
// Recursively visit a Type node until we reach a NamedType and we've
33+
// taken stock of all of the modifier wrappers.
34+
class TypeVisitor
35+
{
36+
public:
37+
std::pair<std::string_view, TypeModifierStack> getType();
38+
39+
void visit(const peg::ast_node& typeName);
40+
41+
private:
42+
void visitNamedType(const peg::ast_node& namedType);
43+
void visitListType(const peg::ast_node& listType);
44+
void visitNonNullType(const peg::ast_node& nonNullType);
45+
46+
std::string_view _type;
47+
TypeModifierStack _modifiers;
48+
bool _nonNull = false;
49+
};
50+
51+
// Recursively visit a Value node representing the default value on an input field
52+
// and build a JSON representation of the hardcoded value.
53+
class DefaultValueVisitor
54+
{
55+
public:
56+
response::Value getValue();
57+
58+
void visit(const peg::ast_node& value);
59+
60+
private:
61+
void visitIntValue(const peg::ast_node& intValue);
62+
void visitFloatValue(const peg::ast_node& floatValue);
63+
void visitStringValue(const peg::ast_node& stringValue);
64+
void visitBooleanValue(const peg::ast_node& booleanValue);
65+
void visitNullValue(const peg::ast_node& nullValue);
66+
void visitEnumValue(const peg::ast_node& enumValue);
67+
void visitListValue(const peg::ast_node& listValue);
68+
void visitObjectValue(const peg::ast_node& objectValue);
69+
70+
response::Value _value;
71+
};
72+
73+
} /* namespace graphql::generator */
74+
75+
#endif // GENERATORLOADER_H

include/RequestLoader.h

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,49 @@
66
#ifndef REQUESTLOADER_H
77
#define REQUESTLOADER_H
88

9-
#include "SchemaLoader.h"
9+
#include "GeneratorLoader.h"
1010

11+
#include "graphqlservice/GraphQLGrammar.h"
12+
#include "graphqlservice/GraphQLParse.h"
1113
#include "graphqlservice/GraphQLSchema.h"
14+
#include "graphqlservice/GraphQLService.h"
1215

1316
namespace graphql::generator {
1417

15-
using ResponseField = InputField;
16-
using ResponseFieldList = InputFieldList;
18+
struct ResponseField;
19+
20+
using ResponseFieldList = std::vector<ResponseField>;
1721

1822
struct ResponseType
1923
{
20-
std::string_view type;
24+
std::shared_ptr<const schema::BaseType> type;
2125
std::string_view cppType;
2226
ResponseFieldList fields;
2327
};
2428

29+
using ResponseUnionOptions = std::vector<ResponseType>;
30+
using ResponseFieldChildren = std::variant<ResponseFieldList, ResponseUnionOptions>;
31+
32+
struct ResponseField
33+
{
34+
std::shared_ptr<const schema::BaseType> type;
35+
std::string_view name;
36+
std::string_view cppName;
37+
std::string_view defaultValueString;
38+
response::Value defaultValue;
39+
std::optional<tao::graphqlpeg::position> position;
40+
std::optional<ResponseFieldChildren> children;
41+
};
42+
2543
struct RequestOptions
2644
{
2745
const std::string requestFilename;
2846
const std::string operationName;
2947
const bool noIntrospection = false;
3048
};
3149

50+
class SchemaLoader;
51+
3252
class RequestLoader
3353
{
3454
public:
@@ -39,7 +59,7 @@ class RequestLoader
3959
std::string_view getOperationType() const noexcept;
4060
std::string_view getRequestText() const noexcept;
4161

42-
const ResponseType& getVariablesType() const noexcept;
62+
const ResponseFieldList& getVariables() const noexcept;
4363
const ResponseType& getResponseType() const noexcept;
4464

4565
private:
@@ -52,6 +72,36 @@ class RequestLoader
5272
static std::string_view trimWhitespace(std::string_view content) noexcept;
5373

5474
void findOperation();
75+
void collectVariables() noexcept;
76+
void collectFragments() noexcept;
77+
78+
using FragmentDefinitionMap = std::map<std::string_view, const peg::ast_node*>;
79+
80+
// SelectionVisitor visits the AST and fills in the ResponseType for the request.
81+
class SelectionVisitor
82+
{
83+
public:
84+
explicit SelectionVisitor(const FragmentDefinitionMap& fragments,
85+
const std::shared_ptr<schema::Schema>& schema,
86+
const std::shared_ptr<const schema::BaseType>& type);
87+
88+
void visit(const peg::ast_node& selection);
89+
90+
ResponseFieldList getFields();
91+
92+
private:
93+
void visitField(const peg::ast_node& field);
94+
void visitFragmentSpread(const peg::ast_node& fragmentSpread);
95+
void visitInlineFragment(const peg::ast_node& inlineFragment);
96+
97+
const std::optional<std::reference_wrapper<const service::field_path>> _path;
98+
const FragmentDefinitionMap& _fragments;
99+
const std::shared_ptr<schema::Schema>& _schema;
100+
const std::shared_ptr<const schema::BaseType>& _type;
101+
102+
internal::string_view_set _names;
103+
ResponseFieldList _fields;
104+
};
55105

56106
const RequestOptions _requestOptions;
57107
const SchemaLoader& _schemaLoader;
@@ -62,8 +112,10 @@ class RequestLoader
62112
const peg::ast_node* _operation = nullptr;
63113
std::string_view _operationName;
64114
std::string_view _operationType;
65-
ResponseType _variablesType;
115+
ResponseFieldList _variables;
66116
ResponseType _responseType;
117+
118+
FragmentDefinitionMap _fragments;
67119
};
68120

69121
} /* namespace graphql::generator */

include/SchemaLoader.h

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

9+
#include "GeneratorLoader.h"
10+
911
#include "graphqlservice/GraphQLGrammar.h"
1012
#include "graphqlservice/GraphQLParse.h"
1113
#include "graphqlservice/GraphQLService.h"
@@ -31,32 +33,13 @@ using BuiltinTypeMap = std::map<std::string_view, BuiltinType>;
3133
// These are the C++ types we'll use for them.
3234
using CppTypeMap = std::array<std::string_view, static_cast<size_t>(BuiltinType::ID) + 1>;
3335

34-
// Types that we understand and use to generate the skeleton of a service.
35-
enum class SchemaType
36-
{
37-
Scalar,
38-
Enum,
39-
Input,
40-
Union,
41-
Interface,
42-
Object,
43-
Operation,
44-
};
45-
46-
using SchemaTypeMap = std::map<std::string_view, SchemaType>;
47-
4836
// Keep track of the positions of each type declaration in the file.
4937
using PositionMap = std::unordered_map<std::string_view, tao::graphqlpeg::position>;
5038

5139
// For all of the named types we track, we want to keep them in order in a vector but
5240
// be able to lookup their offset quickly by name.
5341
using TypeNameMap = std::unordered_map<std::string_view, size_t>;
5442

55-
// Any type can also have a list and/or non-nullable wrapper, and those can be nested.
56-
// Since it's easier to express nullability than non-nullability in C++, we'll invert
57-
// the presence of NonNull modifiers.
58-
using TypeModifierStack = std::vector<service::TypeModifier>;
59-
6043
// Scalar types are opaque to the generator, it's up to the service implementation
6144
// to handle parsing, validating, and serializing them. We just need to track which
6245
// scalar type names have been declared so we recognize the references.
@@ -241,7 +224,7 @@ class SchemaLoader
241224
static const CppTypeMap& getBuiltinCppTypes() noexcept;
242225
static std::string_view getScalarCppType() noexcept;
243226

244-
const SchemaType& getSchemaType(std::string_view type) const;
227+
SchemaType getSchemaType(std::string_view type) const;
245228
const tao::graphqlpeg::position& getTypePosition(std::string_view type) const;
246229

247230
size_t getScalarIndex(std::string_view type) const;
@@ -291,47 +274,6 @@ class SchemaLoader
291274
void visitObjectTypeExtension(const peg::ast_node& objectTypeExtension);
292275
void visitDirectiveDefinition(const peg::ast_node& directiveDefinition);
293276

294-
// Recursively visit a Type node until we reach a NamedType and we've
295-
// taken stock of all of the modifier wrappers.
296-
class TypeVisitor
297-
{
298-
public:
299-
std::pair<std::string_view, TypeModifierStack> getType();
300-
301-
void visit(const peg::ast_node& typeName);
302-
303-
private:
304-
void visitNamedType(const peg::ast_node& namedType);
305-
void visitListType(const peg::ast_node& listType);
306-
void visitNonNullType(const peg::ast_node& nonNullType);
307-
308-
std::string_view _type;
309-
TypeModifierStack _modifiers;
310-
bool _nonNull = false;
311-
};
312-
313-
// Recursively visit a Value node representing the default value on an input field
314-
// and build a JSON representation of the hardcoded value.
315-
class DefaultValueVisitor
316-
{
317-
public:
318-
response::Value getValue();
319-
320-
void visit(const peg::ast_node& value);
321-
322-
private:
323-
void visitIntValue(const peg::ast_node& intValue);
324-
void visitFloatValue(const peg::ast_node& floatValue);
325-
void visitStringValue(const peg::ast_node& stringValue);
326-
void visitBooleanValue(const peg::ast_node& booleanValue);
327-
void visitNullValue(const peg::ast_node& nullValue);
328-
void visitEnumValue(const peg::ast_node& enumValue);
329-
void visitListValue(const peg::ast_node& listValue);
330-
void visitObjectValue(const peg::ast_node& objectValue);
331-
332-
response::Value _value;
333-
};
334-
335277
static OutputFieldList getOutputFields(const peg::ast_node::children_t& fields);
336278
static InputFieldList getInputFields(const peg::ast_node::children_t& fields);
337279

samples/client/MutateClient.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ static_assert(graphql::internal::MinorVersion == 6, "regenerate with clientgen:
1919
#include <string>
2020
#include <vector>
2121

22-
/** Operation: mutation (default)
22+
/** Operation: mutation CompleteTaskMutation
2323
2424
# Copyright (c) Microsoft Corporation. All rights reserved.
2525
# Licensed under the MIT License.
2626
27-
mutation {
28-
completedTask: completeTask(input: {id: "ZmFrZVRhc2tJZA==", isComplete: true, clientMutationId: "Hi There!"}) {
27+
mutation CompleteTaskMutation($input: CompleteTaskInput! = {id: "ZmFrZVRhc2tJZA==", isComplete: true, clientMutationId: "Hi There!"}) {
28+
completedTask: completeTask(input: $input) {
2929
completedTask: task {
3030
completedTaskId: id
3131
title

samples/client/QueryClient.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ static_assert(graphql::internal::MinorVersion == 6, "regenerate with clientgen:
1919
#include <string>
2020
#include <vector>
2121

22-
/** Operation: query Everything
22+
/** Operation: query (default)
2323
2424
# Copyright (c) Microsoft Corporation. All rights reserved.
2525
# Licensed under the MIT License.
2626
27-
query Everything {
27+
query {
2828
appointments {
2929
edges {
3030
node {

samples/mutate.today.graphql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33

4-
mutation {
5-
completedTask: completeTask(input: {id: "ZmFrZVRhc2tJZA==", isComplete: true, clientMutationId: "Hi There!"}) {
4+
mutation CompleteTaskMutation($input: CompleteTaskInput! = {id: "ZmFrZVRhc2tJZA==", isComplete: true, clientMutationId: "Hi There!"}) {
5+
completedTask: completeTask(input: $input) {
66
completedTask: task {
77
completedTaskId: id
88
title

samples/query.today.graphql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33

4-
query Everything {
4+
query {
55
appointments {
66
edges {
77
node {

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ endif()
107107
if(GRAPHQL_BUILD_SCHEMAGEN OR GRAPHQL_BUILD_CLIENTGEN)
108108
add_library(generator_util STATIC
109109
SchemaLoader.cpp
110+
GeneratorLoader.cpp
110111
GeneratorUtil.cpp)
111112
target_link_libraries(generator_util PUBLIC
112113
graphqlpeg

0 commit comments

Comments
 (0)