Skip to content

Commit 88ec463

Browse files
committed
feat(sharetypes): reuse schema types in proxy client
1 parent e216334 commit 88ec463

19 files changed

+608
-286
lines changed

include/RequestLoader.h

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,30 +84,32 @@ struct [[nodiscard("unnecessary construction")]] RequestOptions
8484
const std::string requestFilename;
8585
const std::optional<std::string> operationName;
8686
const bool noIntrospection = false;
87+
const bool sharedTypes = false;
8788
};
8889

8990
class SchemaLoader;
9091

9192
class [[nodiscard("unnecessary construction")]] RequestLoader
9293
{
9394
public:
94-
explicit RequestLoader(RequestOptions && requestOptions, const SchemaLoader& schemaLoader);
95+
explicit RequestLoader(RequestOptions&& requestOptions, const SchemaLoader& schemaLoader);
9596

9697
[[nodiscard("unnecessary call")]] std::string_view getRequestFilename() const noexcept;
9798
[[nodiscard("unnecessary call")]] const OperationList& getOperations() const noexcept;
9899
[[nodiscard("unnecessary call")]] std::string_view getOperationDisplayName(
99100
const Operation& operation) const noexcept;
100-
[[nodiscard("unnecessary call")]] std::string getOperationNamespace(const Operation& operation)
101-
const noexcept;
102-
[[nodiscard("unnecessary call")]] std::string_view getOperationType(const Operation& operation)
103-
const noexcept;
101+
[[nodiscard("unnecessary call")]] std::string getOperationNamespace(
102+
const Operation& operation) const noexcept;
103+
[[nodiscard("unnecessary call")]] std::string_view getOperationType(
104+
const Operation& operation) const noexcept;
104105
[[nodiscard("unnecessary call")]] std::string_view getRequestText() const noexcept;
105106

106107
[[nodiscard("unnecessary call")]] const ResponseType& getResponseType(
107108
const Operation& operation) const noexcept;
108109
[[nodiscard("unnecessary call")]] const RequestVariableList& getVariables(
109110
const Operation& operation) const noexcept;
110111

112+
[[nodiscard("unnecessary call")]] bool useSharedTypes() const noexcept;
111113
[[nodiscard("unnecessary call")]] const RequestInputTypeList& getReferencedInputTypes(
112114
const Operation& operation) const noexcept;
113115
[[nodiscard("unnecessary call")]] const RequestSchemaTypeList& getReferencedEnums(
@@ -116,32 +118,30 @@ class [[nodiscard("unnecessary construction")]] RequestLoader
116118
[[nodiscard("unnecessary call")]] std::string getInputCppType(
117119
const RequestSchemaType& wrappedInputType) const noexcept;
118120
[[nodiscard("unnecessary call")]] std::string getInputCppType(
119-
const RequestSchemaType& inputType,
120-
const TypeModifierStack& modifiers) const noexcept;
121+
const RequestSchemaType& inputType, const TypeModifierStack& modifiers) const noexcept;
121122
[[nodiscard("unnecessary call")]] static std::string getOutputCppType(
122-
std::string_view outputCppType,
123-
const TypeModifierStack& modifiers) noexcept;
123+
std::string_view outputCppType, const TypeModifierStack& modifiers) noexcept;
124124

125125
[[nodiscard("unnecessary call")]] static std::pair<RequestSchemaType, TypeModifierStack>
126-
unwrapSchemaType(RequestSchemaType && type) noexcept;
126+
unwrapSchemaType(RequestSchemaType&& type) noexcept;
127127

128128
private:
129129
void buildSchema();
130130
void addTypesToSchema();
131-
[[nodiscard("unnecessary call")]] RequestSchemaType getSchemaType(std::string_view type,
132-
const TypeModifierStack& modifiers) const noexcept;
131+
[[nodiscard("unnecessary call")]] RequestSchemaType getSchemaType(
132+
std::string_view type, const TypeModifierStack& modifiers) const noexcept;
133133
void validateRequest() const;
134134

135135
[[nodiscard("unnecessary call")]] static std::string_view trimWhitespace(
136136
std::string_view content) noexcept;
137137

138138
void findOperation();
139139
void collectFragments() noexcept;
140-
void collectVariables(Operation & operation) noexcept;
141-
void collectInputTypes(Operation & operation, const RequestSchemaType& variableType) noexcept;
142-
void reorderInputTypeDependencies(Operation & operation);
143-
void collectEnums(Operation & operation, const RequestSchemaType& variableType) noexcept;
144-
void collectEnums(Operation & operation, const ResponseField& responseField) noexcept;
140+
void collectVariables(Operation& operation) noexcept;
141+
void collectInputTypes(Operation& operation, const RequestSchemaType& variableType) noexcept;
142+
void reorderInputTypeDependencies(Operation& operation);
143+
void collectEnums(Operation& operation, const RequestSchemaType& variableType) noexcept;
144+
void collectEnums(Operation& operation, const ResponseField& responseField) noexcept;
145145

146146
using FragmentDefinitionMap = std::map<std::string_view, const peg::ast_node*>;
147147

@@ -150,8 +150,7 @@ class [[nodiscard("unnecessary construction")]] RequestLoader
150150
{
151151
public:
152152
explicit SelectionVisitor(const SchemaLoader& schemaLoader,
153-
const FragmentDefinitionMap& fragments,
154-
const std::shared_ptr<schema::Schema>& schema,
153+
const FragmentDefinitionMap& fragments, const std::shared_ptr<schema::Schema>& schema,
155154
const RequestSchemaType& type);
156155

157156
void visit(const peg::ast_node& selection);
@@ -163,7 +162,7 @@ class [[nodiscard("unnecessary construction")]] RequestLoader
163162
void visitFragmentSpread(const peg::ast_node& fragmentSpread);
164163
void visitInlineFragment(const peg::ast_node& inlineFragment);
165164

166-
void mergeFragmentFields(ResponseFieldList && fragmentFields) noexcept;
165+
void mergeFragmentFields(ResponseFieldList&& fragmentFields) noexcept;
167166

168167
const SchemaLoader& _schemaLoader;
169168
const FragmentDefinitionMap& _fragments;

samples/proxy/client.cpp

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#include "schema/ProxySchema.h"
77
#include "schema/QueryObject.h"
8-
#include "schema/ResultsObject.h"
8+
#include "schema/QueryResultsObject.h"
99

1010
#include "graphqlservice/JSONResponse.h"
1111

@@ -151,9 +151,8 @@ class Query
151151
explicit Query(std::string_view host, std::string_view port, std::string_view target,
152152
int version) noexcept;
153153

154-
std::future<std::shared_ptr<proxy::object::Results>> getRelay(std::string&& queryArg,
155-
std::optional<std::string>&& operationNameArg,
156-
std::optional<std::string>&& variablesArg) const;
154+
std::future<std::shared_ptr<proxy::object::QueryResults>> getRelay(
155+
proxy::QueryInput&& inputArg) const;
157156

158157
private:
159158
const std::string m_host;
@@ -173,21 +172,22 @@ Query::Query(
173172

174173
// Based on:
175174
// https://www.boost.org/doc/libs/1_82_0/libs/beast/example/http/client/awaitable/http_client_awaitable.cpp
176-
std::future<std::shared_ptr<proxy::object::Results>> Query::getRelay(std::string&& queryArg,
177-
std::optional<std::string>&& operationNameArg, std::optional<std::string>&& variablesArg) const
175+
std::future<std::shared_ptr<proxy::object::QueryResults>> Query::getRelay(
176+
proxy::QueryInput&& inputArg) const
178177
{
179178
response::Value payload { response::Type::Map };
180179

181-
payload.emplace_back("query"s, response::Value { std::move(queryArg) });
180+
payload.emplace_back("query"s, response::Value { std::move(inputArg.query) });
182181

183-
if (operationNameArg)
182+
if (inputArg.operationName)
184183
{
185-
payload.emplace_back("operationName"s, response::Value { std::move(*operationNameArg) });
184+
payload.emplace_back("operationName"s,
185+
response::Value { std::move(*inputArg.operationName) });
186186
}
187187

188-
if (variablesArg)
188+
if (inputArg.variables)
189189
{
190-
payload.emplace_back("variables"s, response::Value { std::move(*variablesArg) });
190+
payload.emplace_back("variables"s, response::Value { std::move(*inputArg.variables) });
191191
}
192192

193193
std::string requestBody = response::toJSON(std::move(payload));
@@ -199,7 +199,8 @@ std::future<std::shared_ptr<proxy::object::Results>> Query::getRelay(std::string
199199
const char* port,
200200
const char* target,
201201
int version,
202-
std::string requestBody) -> net::awaitable<std::shared_ptr<proxy::object::Results>> {
202+
std::string requestBody)
203+
-> net::awaitable<std::shared_ptr<proxy::object::QueryResults>> {
203204
// These objects perform our I/O. They use an executor with a default completion token
204205
// of use_awaitable. This makes our code easy, but will use exceptions as the default
205206
// error handling, i.e. if the connection drops, we might see an exception.
@@ -252,7 +253,7 @@ std::future<std::shared_ptr<proxy::object::Results>> Query::getRelay(std::string
252253

253254
auto [data, errors] = client::parseServiceResponse(response::parseJSON(res.body()));
254255

255-
co_return std::make_shared<proxy::object::Results>(
256+
co_return std::make_shared<proxy::object::QueryResults>(
256257
std::make_shared<Results>(std::move(data), std::move(errors)));
257258
}(m_host.c_str(), m_port.c_str(), m_target.c_str(), m_version, std::move(requestBody)),
258259
net::use_future);
@@ -279,15 +280,16 @@ int main(int argc, char** argv)
279280
using namespace proxy::client::query::relayQuery;
280281

281282
auto query = GetRequestObject();
282-
auto variables = serializeVariables(
283-
{ input, ((argc > 1) ? std::make_optional(argv[1]) : std::nullopt) });
283+
auto variables = serializeVariables({ QueryInput { OperationType::QUERY,
284+
input,
285+
((argc > 1) ? std::make_optional(argv[1]) : std::nullopt),
286+
std::nullopt } });
284287
auto launch = service::await_async { std::make_shared<service::await_worker_queue>() };
285288
auto state = std::make_shared<AsyncIoWorker>();
286289
auto serviceResponse = client::parseServiceResponse(
287290
service->resolve({ query, GetOperationName(), std::move(variables), launch, state })
288291
.get());
289-
auto result =
290-
proxy::client::query::relayQuery::parseResponse(std::move(serviceResponse.data));
292+
auto result = parseResponse(std::move(serviceResponse.data));
291293
auto errors = std::move(serviceResponse.errors);
292294

293295
if (result.relay.data)

samples/proxy/query/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ cmake_minimum_required(VERSION 3.28)
77
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/cppgraphqlgen-functions.cmake)
88

99
if(GRAPHQL_UPDATE_SAMPLES AND GRAPHQL_BUILD_CLIENTGEN)
10-
update_graphql_client_files(proxy ../schema/schema.graphql query.graphql Proxy proxy)
10+
update_graphql_client_files(proxy ../schema/schema.graphql query.graphql Proxy proxy --shared-types)
1111
endif()
1212

1313
add_graphql_client_target(proxy)
14+
target_link_libraries(proxy_client PRIVATE proxy_schema)

samples/proxy/query/ProxyClient.cpp

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ const std::string& GetRequestText() noexcept
2626
# Copyright (c) Microsoft Corporation. All rights reserved.
2727
# Licensed under the MIT License.
2828
29-
query relayQuery($query: String!, $operationName: String, $variables: String) {
30-
relay(query: $query, operationName: $operationName, variables: $variables) {
29+
query relayQuery($input: QueryInput!) {
30+
relay(input: $input) {
3131
data
3232
errors
3333
}
@@ -53,14 +53,70 @@ const peg::ast& GetRequestObject() noexcept
5353

5454
} // namespace client
5555
} // namespace proxy
56+
5657
namespace client {
5758

5859
using namespace proxy;
5960

6061
template <>
61-
graphql::proxy::client::query::relayQuery::Response::relay_Results Response<graphql::proxy::client::query::relayQuery::Response::relay_Results>::parse(response::Value&& response)
62+
response::Value Variable<OperationType>::serialize(OperationType&& value)
63+
{
64+
static const std::array<std::string_view, 3> s_names = {
65+
R"gql(QUERY)gql"sv,
66+
R"gql(MUTATION)gql"sv,
67+
R"gql(SUBSCRIPTION)gql"sv
68+
};
69+
70+
response::Value result { response::Type::EnumValue };
71+
72+
result.set<std::string>(std::string { s_names[static_cast<std::size_t>(value)] });
73+
74+
return result;
75+
}
76+
77+
template <>
78+
response::Value Variable<QueryInput>::serialize(QueryInput&& inputValue)
79+
{
80+
response::Value result { response::Type::Map };
81+
82+
result.emplace_back(R"js(type)js"s, ModifiedVariable<OperationType>::serialize(std::move(inputValue.type)));
83+
result.emplace_back(R"js(query)js"s, ModifiedVariable<std::string>::serialize(std::move(inputValue.query)));
84+
result.emplace_back(R"js(operationName)js"s, ModifiedVariable<std::string>::serialize<TypeModifier::Nullable>(std::move(inputValue.operationName)));
85+
result.emplace_back(R"js(variables)js"s, ModifiedVariable<std::string>::serialize<TypeModifier::Nullable>(std::move(inputValue.variables)));
86+
87+
return result;
88+
}
89+
90+
template <>
91+
OperationType Response<OperationType>::parse(response::Value&& value)
92+
{
93+
if (!value.maybe_enum())
94+
{
95+
throw std::logic_error { R"ex(not a valid OperationType value)ex" };
96+
}
97+
98+
static const std::array<std::pair<std::string_view, OperationType>, 3> s_values = {
99+
std::make_pair(R"gql(QUERY)gql"sv, OperationType::QUERY),
100+
std::make_pair(R"gql(MUTATION)gql"sv, OperationType::MUTATION),
101+
std::make_pair(R"gql(SUBSCRIPTION)gql"sv, OperationType::SUBSCRIPTION)
102+
};
103+
104+
const auto result = internal::sorted_map_lookup<internal::shorter_or_less>(
105+
s_values,
106+
std::string_view { value.get<std::string>() });
107+
108+
if (!result)
109+
{
110+
throw std::logic_error { R"ex(not a valid OperationType value)ex" };
111+
}
112+
113+
return *result;
114+
}
115+
116+
template <>
117+
graphql::proxy::client::query::relayQuery::Response::relay_QueryResults Response<graphql::proxy::client::query::relayQuery::Response::relay_QueryResults>::parse(response::Value&& response)
62118
{
63-
graphql::proxy::client::query::relayQuery::Response::relay_Results result;
119+
graphql::proxy::client::query::relayQuery::Response::relay_QueryResults result;
64120

65121
if (response.type() == response::Type::Map)
66122
{
@@ -101,9 +157,7 @@ response::Value serializeVariables(Variables&& variables)
101157

102158
response::Value result { response::Type::Map };
103159

104-
result.emplace_back(R"js(query)js"s, ModifiedVariable<std::string>::serialize(std::move(variables.query)));
105-
result.emplace_back(R"js(operationName)js"s, ModifiedVariable<std::string>::serialize<TypeModifier::Nullable>(std::move(variables.operationName)));
106-
result.emplace_back(R"js(variables)js"s, ModifiedVariable<std::string>::serialize<TypeModifier::Nullable>(std::move(variables.variables)));
160+
result.emplace_back(R"js(input)js"s, ModifiedVariable<QueryInput>::serialize(std::move(variables.input)));
107161

108162
return result;
109163
}
@@ -122,7 +176,7 @@ Response parseResponse(response::Value&& response)
122176
{
123177
if (member.first == R"js(relay)js"sv)
124178
{
125-
result.relay = ModifiedResponse<query::relayQuery::Response::relay_Results>::parse(std::move(member.second));
179+
result.relay = ModifiedResponse<query::relayQuery::Response::relay_QueryResults>::parse(std::move(member.second));
126180
continue;
127181
}
128182
}

samples/proxy/query/ProxyClient.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#include "graphqlservice/internal/Version.h"
1616

17+
#include "ProxySchema.h"
18+
1719
#include <optional>
1820
#include <string>
1921
#include <vector>
@@ -29,8 +31,8 @@ namespace graphql::proxy {
2931
/// # Copyright (c) Microsoft Corporation. All rights reserved.
3032
/// # Licensed under the MIT License.
3133
///
32-
/// query relayQuery($query: String!, $operationName: String, $variables: String) {
33-
/// relay(query: $query, operationName: $operationName, variables: $variables) {
34+
/// query relayQuery($input: QueryInput!) {
35+
/// relay(input: $input) {
3436
/// data
3537
/// errors
3638
/// }
@@ -52,24 +54,26 @@ using graphql::proxy::client::GetRequestObject;
5254
// Return the name of this operation in the shared request document.
5355
[[nodiscard("unnecessary call")]] const std::string& GetOperationName() noexcept;
5456

57+
using graphql::proxy::OperationType;
58+
59+
using graphql::proxy::QueryInput;
60+
5561
struct [[nodiscard("unnecessary construction")]] Variables
5662
{
57-
std::string query {};
58-
std::optional<std::string> operationName {};
59-
std::optional<std::string> variables {};
63+
QueryInput input {};
6064
};
6165

6266
[[nodiscard("unnecessary conversion")]] response::Value serializeVariables(Variables&& variables);
6367

6468
struct [[nodiscard("unnecessary construction")]] Response
6569
{
66-
struct [[nodiscard("unnecessary construction")]] relay_Results
70+
struct [[nodiscard("unnecessary construction")]] relay_QueryResults
6771
{
6872
std::optional<std::string> data {};
6973
std::optional<std::vector<std::optional<std::string>>> errors {};
7074
};
7175

72-
relay_Results relay {};
76+
relay_QueryResults relay {};
7377
};
7478

7579
[[nodiscard("unnecessary conversion")]] Response parseResponse(response::Value&& response);

samples/proxy/query/ProxyClient.ixx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,24 @@ namespace client {
1616
using client::GetRequestText;
1717
using client::GetRequestObject;
1818

19+
} // namespace client
20+
21+
using proxy::OperationType;
22+
23+
using proxy::QueryInput;
24+
25+
namespace client {
26+
1927
namespace query::relayQuery {
2028

2129
using graphql::proxy::client::GetRequestText;
2230
using graphql::proxy::client::GetRequestObject;
2331
using relayQuery::GetOperationName;
2432

33+
using graphql::proxy::OperationType;
34+
35+
using graphql::proxy::QueryInput;
36+
2537
using relayQuery::Variables;
2638
using relayQuery::serializeVariables;
2739

samples/proxy/query/query.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-
query relayQuery($query: String!, $operationName: String, $variables: String) {
5-
relay(query: $query, operationName: $operationName, variables: $variables) {
4+
query relayQuery($input: QueryInput!) {
5+
relay(input: $input) {
66
data
77
errors
88
}

0 commit comments

Comments
 (0)