Skip to content

Commit 54baee1

Browse files
authored
Merge pull request microsoft#144 from wravery/master
Miscellaneous cleanup getting ready for 3.4.0 release
2 parents e7ba9af + a82649e commit 54baee1

27 files changed

+414
-189
lines changed

README.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ The easiest way to get all of these and to build `cppgraphqlgen` in one step is
4747
[microsoft/vcpkg](https://github.com/microsoft/vcpkg). To install with vcpkg, make sure you've pulled the latest version
4848
and then run `vcpkg install cppgraphqlgen` (or `cppgraphqlgen:x64-windows`, `cppgraphqlgen:x86-windows-static`, etc.
4949
depending on your platform). To install just the dependencies and work in a clone of this repo, you'll need some subset
50-
of `vcpkg install pegtl boost-program-options boost-filesystem rapidjson gtest`. It works for Windows, Linux, and Mac,
50+
of `vcpkg install pegtl boost-program-options rapidjson gtest`. It works for Windows, Linux, and Mac,
5151
but if you want to try building for another platform (e.g. Android or iOS), you'll need to do more of this manually.
5252

5353
Manual installation will work best if you clone the GitHub repos for each of the dependencies and follow the installation
@@ -67,9 +67,9 @@ means you need to include an acknowledgement along with the license text.
6767

6868
### graphqlpeg
6969

70-
- GraphQL parsing: [Parsing Expression Grammar Template Library (PEGTL)](https://github.com/taocpp/PEGTL) release 3.0.0,
70+
- GraphQL parsing: [Parsing Expression Grammar Template Library (PEGTL)](https://github.com/taocpp/PEGTL) release 3.1.1,
7171
which is part of [The Art of C++](https://taocpp.github.io/) library collection. I've added this as a sub-module, so you
72-
do not need to install this separately. If you already have 3.0.0 installed where CMake can find it, it will use that
72+
do not need to install this separately. If you already have 3.1.1 installed where CMake can find it, it will use that
7373
instead of the sub-module and avoid installing another copy of PEGTL.
7474

7575
### graphqlservice
@@ -87,11 +87,6 @@ do that.
8787

8888
I'm using [Boost](https://www.boost.org/doc/libs/1_69_0/more/getting_started/index.html) for `schemagen`:
8989

90-
- C++17 std::filesystem support on Unix:
91-
[Boost.Filesystem](https://www.boost.org/doc/libs/1_69_0/libs/filesystem/doc/index.htm). Most of the default C++
92-
compilers on Linux still have `std::filesystem` from C++17 in an experimental directory and require an extra
93-
library. The standard just adopted the Boost library, so on Unix systems I have an `#ifdef` which redirects back to
94-
it for the time being.
9590
- Command line handling: [Boost.Program_options](https://www.boost.org/doc/libs/1_69_0/doc/html/program_options.html).
9691
Run `schemagen -?` to get a list of options. Many of the files in the [samples](samples/) directory were generated
9792
with `schemagen`, you can look at [samples/CMakeLists.txt](samples/CMakeLists.txt) for a few examples of how to call it:
@@ -108,6 +103,7 @@ Command line options:
108103
--header-dir arg Target path for the <prefix>Schema.h header file
109104
--no-stubs Generate abstract classes without stub implementations
110105
--separate-files Generate separate files for each of the types
106+
--no-introspection Do not generate support for Introspection
111107
```
112108

113109
I've tested this with several versions of Boost going back to 1.65.0. I expect it will work fine with most versions of

cmake/version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.3.0
1+
3.4.0

doc/fieldparams.md

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,36 @@ passes it to every `getField` method as the first parameter.
1111

1212
The `graphql::service::FieldParams` struct is declared in [GraphQLService.h](../include/graphqlservice/GraphQLService.h):
1313
```cpp
14-
// Pass a common bundle of parameters to all of the generated Object::getField accessors in a SelectionSet
14+
// Resolvers may be called in multiple different Operation contexts.
15+
enum class ResolverContext
16+
{
17+
// Resolving a Query operation.
18+
Query,
19+
20+
// Resolving a Mutation operation.
21+
Mutation,
22+
23+
// Adding a Subscription. If you need to prepare to send events for this Subsciption
24+
// (e.g. registering an event sink of your own), this is a chance to do that.
25+
NotifySubscribe,
26+
27+
// Resolving a Subscription event.
28+
Subscription,
29+
30+
// Removing a Subscription. If there are no more Subscriptions registered this is an
31+
// opportunity to release resources which are no longer needed.
32+
NotifyUnsubscribe,
33+
};
34+
35+
// Pass a common bundle of parameters to all of the generated Object::getField accessors in a
36+
// SelectionSet
1537
struct SelectionSetParams
1638
{
39+
// Context for this selection set.
40+
const ResolverContext resolverContext;
41+
1742
// The lifetime of each of these borrowed references is guaranteed until the future returned
18-
// by the accessor is resolved or destroyed. They are owned by the OperationData shared pointer.
43+
// by the accessor is resolved or destroyed. They are owned by the OperationData shared pointer.
1944
const std::shared_ptr<RequestState>& state;
2045
const response::Value& operationDirectives;
2146
const response::Value& fragmentDefinitionDirectives;
@@ -25,19 +50,32 @@ struct SelectionSetParams
2550
// you'll need to explicitly copy them into other instances of response::Value.
2651
const response::Value& fragmentSpreadDirectives;
2752
const response::Value& inlineFragmentDirectives;
53+
54+
// Field error path to this selection set.
55+
std::optional<field_path> errorPath;
56+
57+
// Async launch policy for sub-field resolvers.
58+
const std::launch launch = std::launch::deferred;
2859
};
2960

3061
// Pass a common bundle of parameters to all of the generated Object::getField accessors.
3162
struct FieldParams : SelectionSetParams
3263
{
33-
explicit FieldParams(const SelectionSetParams& selectionSetParams, response::Value&& directives);
64+
GRAPHQLSERVICE_EXPORT explicit FieldParams(
65+
SelectionSetParams&& selectionSetParams, response::Value&& directives);
3466

35-
// Each field owns its own field-specific directives. Once the accessor returns it will be destroyed,
36-
// but you can move it into another instance of response::Value to keep it alive longer.
67+
// Each field owns its own field-specific directives. Once the accessor returns it will be
68+
// destroyed, but you can move it into another instance of response::Value to keep it alive
69+
// longer.
3770
response::Value fieldDirectives;
3871
};
3972
```
4073

74+
### Resolver Context
75+
76+
The `SelectionSetParams::resolverContext` enum member informs the `getField`
77+
accessors about what type of operation is being resolved.
78+
4179
### Request State
4280

4381
The `SelectionSetParams::state` member is a reference to the
@@ -75,7 +113,29 @@ or `fragmentDefinitionDirectives` because those are kept alive until the
75113
passed by `const` reference, the reference should always be valid as long as
76114
there's a pending result from the `getField` call.
77115

116+
### Error Path
117+
118+
The `SelectionSetParams::errorPath` member should be considered an opaque
119+
implementation detail by client code. It automatically propagates through the
120+
field resolvers, and if there is a schema exception or one of the `getField`
121+
accessors throws another exception derived from `std::exception`, the
122+
`graphqlservice` library will automatically add the resulting path to the error
123+
report, accoring to the [spec](http://spec.graphql.org/June2018/#sec-Errors).
124+
125+
### Launch Policy
126+
127+
The `graphqlservice` library uses the `SelectionSetParams::launch` parameter to
128+
determine how it should handle async resolvers in the same selection set or
129+
elements in the same list. It is passed from the top-most `resolve`, `deliver`,
130+
or async `subscribe`/`unsubscribe` call. The `getField` accessors get a copy of
131+
this member in their `FieldParams` argument, and they may change their own
132+
behavior based on that, but they cannot alter the launch policy which
133+
`graphqlservice` uses for the resolvers themselves.
134+
78135
## Related Documents
79136

80137
1. The `getField` methods are discussed in more detail in [resolvers.md](./resolvers.md).
81-
2. Built-in and custom `directives` are discussed in [directives.md](./directives.md).
138+
2. Built-in and custom `directives` are discussed in [directives.md](./directives.md).
139+
3. Subscription resolvers get called up to 3 times depending on which
140+
`subscribe`/`unsubscribe` overrides you call. See [subscriptions.md](./subscriptions.md)
141+
for more details.

doc/json.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ the functions in [JSONResponse.h](../include/JSONResponse.h):
1919
```cpp
2020
namespace graphql::response {
2121

22-
std::string toJSON(Value&& response);
22+
JSONRESPONSE_EXPORT std::string toJSON(Value&& response);
2323

24-
Value parseJSON(const std::string& json);
24+
JSONRESPONSE_EXPORT Value parseJSON(const std::string& json);
2525

2626
} /* namespace graphql::response */
2727
```

doc/parsing.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
As mentioned in the [README](../README.md), `cppgraphqlgen` uses the
66
[Parsing Expression Grammar Template Library (PEGTL)](https://github.com/taocpp/PEGTL)
7-
release 3.0.0, which is part of [The Art of C++](https://taocpp.github.io/)
7+
release 3.1.1, which is part of [The Art of C++](https://taocpp.github.io/)
88
library collection. I've added this as a sub-module, so you do not need to
9-
install this separately. If you already have 3.0.0 installed where CMake can
9+
install this separately. If you already have 3.1.1 installed where CMake can
1010
find it, it will use that instead of the sub-module and avoid installing
11-
another copy of PEGTL. _Note: PEGTL 3.0.0 is currently at pre-release._
11+
another copy of PEGTL.
1212

1313
It uses the [contrib/parse_tree.hpp](../PEGTL/include/tao/pegtl/contrib/parse_tree.hpp)
1414
module to build an AST automatically while parsing the document. The AST and
@@ -40,6 +40,17 @@ queries. If you have persisted queries saved to the file system or you are
4040
using a snapshot/[Approval Testing](https://approvaltests.com/) strategy you
4141
might also use `parseFile` to parse queries saved to text files.
4242

43+
When parsing an executable document with `parseString`, `parseFile`, or the
44+
UDL, the parser will try a subset of the grammar first which does not accept
45+
schema definitions, and if that fails it will try the full grammar as a
46+
fallback so that the validation step can check for documents with an invalid
47+
mix of executable and schema definitions.
48+
49+
There are `parseSchemaString` and `parseSchemaFile` functions which do the
50+
opposite, but unless you are building additional tooling on top of the
51+
`graphqlpeg` library, you will probably not need them. They have only been used
52+
by `schemagen` in this project.
53+
4354
## Encoding
4455

4556
The document must use a UTF-8 encoding. If you need to handle documents in

doc/resolvers.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,19 @@ schema {
3434

3535
Executing a query or mutation starts by calling `Request::resolve` from [GraphQLService.h](../include/graphqlservice/GraphQLService.h):
3636
```cpp
37-
std::future<response::Value> resolve(const std::shared_ptr<RequestState>& state, peg::ast& query, const std::string& operationName, response::Value&& variables) const;
37+
GRAPHQLSERVICE_EXPORT std::future<response::Value> resolve(
38+
const std::shared_ptr<RequestState>& state, peg::ast& query,
39+
const std::string& operationName, response::Value&& variables) const;
3840
```
3941
By default, the `std::future` results are resolved on-demand but synchronously,
4042
using `std::launch::deferred` with the `std::async` function. You can also use
4143
an override of `Request::resolve` which lets you substitute the
4244
`std::launch::async` option to begin executing the query on multiple threads
4345
in parallel:
4446
```cpp
45-
std::future<response::Value> resolve(std::launch launch, const std::shared_ptr<RequestState>& state, peg::ast& query, const std::string& operationName, response::Value&& variables) const;
47+
GRAPHQLSERVICE_EXPORT std::future<response::Value> resolve(std::launch launch,
48+
const std::shared_ptr<RequestState>& state, peg::ast& query,
49+
const std::string& operationName, response::Value&& variables) const;
4650
```
4751

4852
### `graphql::service::Request` and `graphql::<schema>::Operations`
@@ -66,7 +70,7 @@ recursively call the `resolvers` for each of the `fields` in the nested
6670
`graphql::today::object::Appointment` object from the `today` sample in
6771
[AppointmentObject.h](../samples/separate/AppointmentObject.h).
6872
```cpp
69-
std::future<response::Value> resolveId(service::ResolverParams&& params);
73+
std::future<service::ResolverResult> resolveId(service::ResolverParams&& params);
7074
```
7175
In this example, the `resolveId` method invokes `getId`:
7276
```cpp

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](https://facebook.github.io/graphql/June2018/#sec-Serialization-Format):
10+
[June 2018 spec](http://spec.graphql.org/June2018/#sec-Serialization-Format):
1111

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

0 commit comments

Comments
 (0)