Skip to content

Commit 80dba3a

Browse files
authored
Merge pull request #179 from wravery/next
Update to October 2021 release of the GraphQL spec
2 parents 5c7a3a6 + c29bcbf commit 80dba3a

Some content is hidden

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

54 files changed

+1953
-857
lines changed

doc/fieldparams.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ implementation detail by client code. It automatically propagates through the
120120
field resolvers, and if there is a schema exception or one of the `getField`
121121
accessors throws another exception derived from `std::exception`, the
122122
`graphqlservice` library will automatically add the resulting path to the error
123-
report, accoring to the [spec](http://spec.graphql.org/June2018/#sec-Errors).
123+
report, accoring to the [spec](https://spec.graphql.org/October2021/#sec-Errors).
124124

125125
### Launch Policy
126126

doc/responses.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ As the comment in
77
responses are not technically JSON-specific, although that is probably the most
88
common way of representing them. These are the primitive types that may be
99
represented in GraphQL, as of the
10-
[June 2018 spec](http://spec.graphql.org/June2018/#sec-Serialization-Format):
10+
[October 2021 spec](https://spec.graphql.org/October2021/#sec-Serialization-Format):
1111

1212
```c++
1313
enum class Type : uint8_t

include/SchemaGenerator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ class Generator
5757
void outputObjectImplementation(
5858
std::ostream& sourceFile, const ObjectType& objectType, bool isQueryType) const;
5959
void outputObjectIntrospection(std::ostream& sourceFile, const ObjectType& objectType) const;
60+
void outputIntrospectionInterfaces(std::ostream& sourceFile, std::string_view cppType,
61+
const std::vector<std::string_view>& interfaces) const;
6062
void outputIntrospectionFields(
6163
std::ostream& sourceFile, std::string_view cppType, const OutputFieldList& fields) const;
6264
std::string getArgumentDefaultValue(

include/SchemaLoader.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct ScalarType
4848
{
4949
std::string_view type;
5050
std::string_view description;
51+
std::string_view specifiedByURL;
5152
};
5253

5354
using ScalarTypeList = std::vector<ScalarType>;
@@ -113,6 +114,7 @@ using InputTypeList = std::vector<InputType>;
113114
struct Directive
114115
{
115116
std::string_view name;
117+
bool isRepeatable = false;
116118
std::vector<std::string_view> locations;
117119
InputFieldList arguments;
118120
std::string_view description;
@@ -174,6 +176,7 @@ struct InterfaceType
174176
{
175177
std::string_view type;
176178
std::string_view cppType;
179+
std::vector<std::string_view> interfaces;
177180
OutputFieldList fields;
178181
std::string_view description;
179182
};
@@ -219,6 +222,7 @@ class SchemaLoader
219222
explicit SchemaLoader(SchemaOptions&& schemaOptions);
220223

221224
bool isIntrospection() const noexcept;
225+
std::string_view getSchemaDescription() const noexcept;
222226
std::string_view getFilenamePrefix() const noexcept;
223227
std::string_view getSchemaNamespace() const noexcept;
224228

@@ -265,6 +269,7 @@ class SchemaLoader
265269
void visitSchemaDefinition(const peg::ast_node& schemaDefinition);
266270
void visitSchemaExtension(const peg::ast_node& schemaExtension);
267271
void visitScalarTypeDefinition(const peg::ast_node& scalarTypeDefinition);
272+
void visitScalarTypeExtension(const peg::ast_node& scalarTypeExtension);
268273
void visitEnumTypeDefinition(const peg::ast_node& enumTypeDefinition);
269274
void visitEnumTypeExtension(const peg::ast_node& enumTypeExtension);
270275
void visitInputObjectTypeDefinition(const peg::ast_node& inputObjectTypeDefinition);
@@ -277,6 +282,8 @@ class SchemaLoader
277282
void visitObjectTypeExtension(const peg::ast_node& objectTypeExtension);
278283
void visitDirectiveDefinition(const peg::ast_node& directiveDefinition);
279284

285+
static void blockReservedName(
286+
std::string_view name, std::optional<tao::graphqlpeg::position> position = std::nullopt);
280287
static OutputFieldList getOutputFields(const peg::ast_node::children_t& fields);
281288
static InputFieldList getInputFields(const peg::ast_node::children_t& fields);
282289

@@ -286,6 +293,13 @@ class SchemaLoader
286293
const std::optional<std::string_view>& accessor);
287294
void fixupInputFieldList(InputFieldList& fields);
288295
void reorderInputTypeDependencies();
296+
void validateImplementedInterfaces() const;
297+
const InterfaceType& findInterfaceType(
298+
std::string_view typeName, std::string_view interfaceName) const;
299+
void validateInterfaceFields(std::string_view typeName,
300+
std::string_view interfaceName, const OutputFieldList& typeFields) const;
301+
void validateTransitiveInterfaces(
302+
std::string_view typeName, const std::vector<std::string_view>& interfaces) const;
289303

290304
static const std::string_view s_introspectionNamespace;
291305
static const BuiltinTypeMap s_builtinTypes;
@@ -294,6 +308,7 @@ class SchemaLoader
294308

295309
const SchemaOptions _schemaOptions;
296310
const bool _isIntrospection;
311+
std::string_view _schemaDescription;
297312
std::string_view _schemaNamespace;
298313
peg::ast _ast;
299314

include/Validation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ using ValidateDirectiveArguments = internal::string_view_map<ValidateArgument>;
3737

3838
struct ValidateDirective
3939
{
40+
bool isRepeatable = false;
4041
internal::sorted_set<introspection::DirectiveLocation> locations;
4142
ValidateDirectiveArguments arguments;
4243
};
@@ -250,6 +251,7 @@ class ValidateExecutableVisitor
250251
VariableSet _referencedVariables;
251252
FragmentSet _fragmentStack;
252253
size_t _fieldCount = 0;
254+
size_t _introspectionFieldCount = 0;
253255
TypeFields _typeFields;
254256
InputTypeFields _inputTypeFields;
255257
ValidateType _scopedType;

include/graphqlservice/GraphQLResponse.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace graphql::response {
3030

3131
// GraphQL responses are not technically JSON-specific, although that is probably the most common
3232
// way of representing them. These are the primitive types that may be represented in GraphQL, as
33-
// of the [June 2018 spec](http://spec.graphql.org/June2018/#sec-Serialization-Format).
33+
// of the [October 2021 spec](https://spec.graphql.org/October2021/#sec-Serialization-Format).
3434
enum class Type : uint8_t
3535
{
3636
Map, // JSON Object

include/graphqlservice/GraphQLService.h

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,15 @@ class await_async : public coro::suspend_always
229229
}
230230
};
231231

232+
// Directive order matters, and some of them are repeatable. So rather than passing them in a
233+
// response::Value, pass directives in something like the underlying response::MapType which
234+
// preserves the order of the elements without complete uniqueness.
235+
using Directives = std::vector<std::pair<std::string_view, response::Value>>;
236+
237+
// Traversing a fragment spread adds a new set of directives.
238+
using FragmentDefinitionDirectiveStack = std::list<std::reference_wrapper<const Directives>>;
239+
using FragmentSpreadDirectiveStack = std::list<Directives>;
240+
232241
// Pass a common bundle of parameters to all of the generated Object::getField accessors in a
233242
// SelectionSet
234243
struct SelectionSetParams
@@ -239,14 +248,14 @@ struct SelectionSetParams
239248
// The lifetime of each of these borrowed references is guaranteed until the future returned
240249
// by the accessor is resolved or destroyed. They are owned by the OperationData shared pointer.
241250
const std::shared_ptr<RequestState>& state;
242-
const response::Value& operationDirectives;
243-
const response::Value& fragmentDefinitionDirectives;
251+
const Directives& operationDirectives;
252+
const std::shared_ptr<FragmentDefinitionDirectiveStack> fragmentDefinitionDirectives;
244253

245254
// Fragment directives are shared for all fields in that fragment, but they aren't kept alive
246255
// after the call to the last accessor in the fragment. If you need to keep them alive longer,
247-
// you'll need to explicitly copy them into other instances of response::Value.
248-
const response::Value& fragmentSpreadDirectives;
249-
const response::Value& inlineFragmentDirectives;
256+
// you'll need to explicitly copy them into other instances of Directives.
257+
const std::shared_ptr<FragmentSpreadDirectiveStack> fragmentSpreadDirectives;
258+
const std::shared_ptr<FragmentSpreadDirectiveStack> inlineFragmentDirectives;
250259

251260
// Field error path to this selection set.
252261
std::optional<field_path> errorPath;
@@ -259,12 +268,12 @@ struct SelectionSetParams
259268
struct FieldParams : SelectionSetParams
260269
{
261270
GRAPHQLSERVICE_EXPORT explicit FieldParams(
262-
SelectionSetParams&& selectionSetParams, response::Value directives);
271+
SelectionSetParams&& selectionSetParams, Directives directives);
263272

264273
// Each field owns its own field-specific directives. Once the accessor returns it will be
265274
// destroyed, but you can move it into another instance of response::Value to keep it alive
266275
// longer.
267-
response::Value fieldDirectives;
276+
Directives fieldDirectives;
268277
};
269278

270279
// Field accessors may return either a result of T, an awaitable of T, or a std::future<T>, so at
@@ -379,11 +388,11 @@ class Fragment
379388

380389
std::string_view getType() const;
381390
const peg::ast_node& getSelection() const;
382-
const response::Value& getDirectives() const;
391+
const Directives& getDirectives() const;
383392

384393
private:
385394
std::string_view _type;
386-
response::Value _directives;
395+
Directives _directives;
387396

388397
std::reference_wrapper<const peg::ast_node> _selection;
389398
};
@@ -399,16 +408,16 @@ struct ResolverParams : SelectionSetParams
399408
{
400409
GRAPHQLSERVICE_EXPORT explicit ResolverParams(const SelectionSetParams& selectionSetParams,
401410
const peg::ast_node& field, std::string&& fieldName, response::Value arguments,
402-
response::Value fieldDirectives, const peg::ast_node* selection,
403-
const FragmentMap& fragments, const response::Value& variables);
411+
Directives fieldDirectives, const peg::ast_node* selection, const FragmentMap& fragments,
412+
const response::Value& variables);
404413

405414
GRAPHQLSERVICE_EXPORT schema_location getLocation() const;
406415

407416
// These values are different for each resolver.
408417
const peg::ast_node& field;
409418
std::string fieldName;
410419
response::Value arguments { response::Type::Map };
411-
response::Value fieldDirectives { response::Type::Map };
420+
Directives fieldDirectives;
412421
const peg::ast_node* selection;
413422

414423
// These values remain unchanged for the entire operation, but they're passed to each of the
@@ -944,19 +953,20 @@ struct SubscriptionParams
944953
struct OperationData : std::enable_shared_from_this<OperationData>
945954
{
946955
explicit OperationData(std::shared_ptr<RequestState> state, response::Value variables,
947-
response::Value directives, FragmentMap fragments);
956+
Directives directives, FragmentMap fragments);
948957

949958
std::shared_ptr<RequestState> state;
950959
response::Value variables;
951-
response::Value directives;
960+
Directives directives;
952961
FragmentMap fragments;
953962
};
954963

955964
// Subscription callbacks receive the response::Value representing the result of evaluating the
956965
// SelectionSet against the payload.
957966
using SubscriptionCallback = std::function<void(response::Value)>;
958967
using SubscriptionArguments = std::map<std::string_view, response::Value>;
959-
using SubscriptionFilterCallback = std::function<bool(response::MapType::const_reference)>;
968+
using SubscriptionArgumentFilterCallback = std::function<bool(response::MapType::const_reference)>;
969+
using SubscriptionDirectiveFilterCallback = std::function<bool(Directives::const_reference)>;
960970

961971
// Subscriptions are stored in maps using these keys.
962972
using SubscriptionKey = size_t;
@@ -970,15 +980,15 @@ using AwaitableDeliver = internal::Awaitable<void>;
970980
struct SubscriptionData : std::enable_shared_from_this<SubscriptionData>
971981
{
972982
explicit SubscriptionData(std::shared_ptr<OperationData> data, SubscriptionName&& field,
973-
response::Value arguments, response::Value fieldDirectives, peg::ast&& query,
983+
response::Value arguments, Directives fieldDirectives, peg::ast&& query,
974984
std::string&& operationName, SubscriptionCallback&& callback,
975985
const peg::ast_node& selection);
976986

977987
std::shared_ptr<OperationData> data;
978988

979989
SubscriptionName field;
980990
response::Value arguments;
981-
response::Value fieldDirectives;
991+
Directives fieldDirectives;
982992
peg::ast query;
983993
std::string operationName;
984994
SubscriptionCallback callback;
@@ -1023,29 +1033,29 @@ class Request : public std::enable_shared_from_this<Request>
10231033
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name,
10241034
const SubscriptionArguments& arguments, std::shared_ptr<Object> subscriptionObject) const;
10251035
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name,
1026-
const SubscriptionArguments& arguments, const SubscriptionArguments& directives,
1036+
const SubscriptionArguments& arguments, const Directives& directives,
10271037
std::shared_ptr<Object> subscriptionObject) const;
10281038
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name,
1029-
const SubscriptionFilterCallback& applyArguments,
1039+
const SubscriptionArgumentFilterCallback& applyArguments,
10301040
std::shared_ptr<Object> subscriptionObject) const;
10311041
GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name,
1032-
const SubscriptionFilterCallback& applyArguments,
1033-
const SubscriptionFilterCallback& applyDirectives,
1042+
const SubscriptionArgumentFilterCallback& applyArguments,
1043+
const SubscriptionDirectiveFilterCallback& applyDirectives,
10341044
std::shared_ptr<Object> subscriptionObject) const;
10351045

10361046
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
10371047
std::shared_ptr<Object> subscriptionObject) const;
10381048
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
10391049
const SubscriptionArguments& arguments, std::shared_ptr<Object> subscriptionObject) const;
10401050
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
1041-
const SubscriptionArguments& arguments, const SubscriptionArguments& directives,
1051+
const SubscriptionArguments& arguments, const Directives& directives,
10421052
std::shared_ptr<Object> subscriptionObject) const;
10431053
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
1044-
const SubscriptionFilterCallback& applyArguments,
1054+
const SubscriptionArgumentFilterCallback& applyArguments,
10451055
std::shared_ptr<Object> subscriptionObject) const;
10461056
GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(await_async launch, const SubscriptionName& name,
1047-
const SubscriptionFilterCallback& applyArguments,
1048-
const SubscriptionFilterCallback& applyDirectives,
1057+
const SubscriptionArgumentFilterCallback& applyArguments,
1058+
const SubscriptionDirectiveFilterCallback& applyDirectives,
10491059
std::shared_ptr<Object> subscriptionObject) const;
10501060

10511061
private:

0 commit comments

Comments
 (0)