Skip to content

Commit a38f304

Browse files
committed
Test and fix union types
1 parent faaa2cd commit a38f304

20 files changed

+324
-230
lines changed

include/RequestLoader.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,14 @@ struct ResponseType
2929
ResponseFieldList fields;
3030
};
3131

32-
using ResponseUnionOptions = std::vector<ResponseType>;
33-
using ResponseFieldChildren = std::variant<ResponseFieldList, ResponseUnionOptions>;
34-
3532
struct ResponseField
3633
{
3734
RequestSchemaType type;
3835
TypeModifierStack modifiers;
3936
std::string_view name;
4037
std::string_view cppName;
4138
std::optional<tao::graphqlpeg::position> position;
42-
std::optional<ResponseFieldChildren> children;
39+
ResponseFieldList children;
4340
};
4441

4542
struct RequestVariable

samples/client/MutateClient.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ struct Variables
6565
{
6666
struct CompleteTaskInput
6767
{
68-
response::IdType id;
69-
std::optional<TaskState> testTaskState;
70-
std::optional<response::BooleanType> isComplete;
71-
std::optional<response::StringType> clientMutationId;
68+
response::IdType id {};
69+
std::optional<TaskState> testTaskState {};
70+
std::optional<response::BooleanType> isComplete {};
71+
std::optional<response::StringType> clientMutationId {};
7272
};
7373

7474
CompleteTaskInput input;
@@ -82,17 +82,17 @@ struct Response
8282
{
8383
struct completedTask_Task
8484
{
85-
response::IdType completedTaskId;
86-
std::optional<response::StringType> title;
87-
response::BooleanType isComplete;
85+
response::IdType completedTaskId {};
86+
std::optional<response::StringType> title {};
87+
response::BooleanType isComplete {};
8888
};
8989

90-
std::optional<completedTask_Task> completedTask;
90+
std::optional<completedTask_Task> completedTask {};
9191

92-
std::optional<response::StringType> clientMutationId;
92+
std::optional<response::StringType> clientMutationId {};
9393
};
9494

95-
completedTask_CompleteTaskPayload completedTask;
95+
completedTask_CompleteTaskPayload completedTask {};
9696
};
9797

9898
Response parseResponse(response::Value&& response);

samples/client/QueryClient.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,58 @@ Response::unreadCounts_FolderConnection ModifiedResponse<Response::unreadCounts_
292292
return result;
293293
}
294294

295+
template <>
296+
Response::anyType_UnionType ModifiedResponse<Response::anyType_UnionType>::parse(response::Value&& response)
297+
{
298+
Response::anyType_UnionType result;
299+
300+
if (response.type() == response::Type::Map)
301+
{
302+
auto members = response.release<response::MapType>();
303+
304+
for (auto& member : members)
305+
{
306+
if (member.first == R"js(__typename)js"sv)
307+
{
308+
result._typename = ModifiedResponse<response::StringType>::parse(std::move(member.second));
309+
continue;
310+
}
311+
if (member.first == R"js(id)js"sv)
312+
{
313+
result.id = ModifiedResponse<response::IdType>::parse(std::move(member.second));
314+
continue;
315+
}
316+
if (member.first == R"js(title)js"sv)
317+
{
318+
result.title = ModifiedResponse<response::StringType>::parse<TypeModifier::Nullable>(std::move(member.second));
319+
continue;
320+
}
321+
if (member.first == R"js(isComplete)js"sv)
322+
{
323+
result.isComplete = ModifiedResponse<response::BooleanType>::parse(std::move(member.second));
324+
continue;
325+
}
326+
if (member.first == R"js(subject)js"sv)
327+
{
328+
result.subject = ModifiedResponse<response::StringType>::parse<TypeModifier::Nullable>(std::move(member.second));
329+
continue;
330+
}
331+
if (member.first == R"js(when)js"sv)
332+
{
333+
result.when = ModifiedResponse<response::Value>::parse<TypeModifier::Nullable>(std::move(member.second));
334+
continue;
335+
}
336+
if (member.first == R"js(isNow)js"sv)
337+
{
338+
result.isNow = ModifiedResponse<response::BooleanType>::parse(std::move(member.second));
339+
continue;
340+
}
341+
}
342+
}
343+
344+
return result;
345+
}
346+
295347
namespace query::Query {
296348

297349
const std::string& GetRequestText() noexcept
@@ -335,6 +387,25 @@ const std::string& GetRequestText() noexcept
335387
336388
# Read a field with an enum type
337389
testTaskState
390+
391+
# Try a field with a union type
392+
anyType(ids: ["ZmFrZVRhc2tJZA=="]) {
393+
__typename
394+
...on Node {
395+
id
396+
}
397+
...on Task {
398+
id
399+
title
400+
isComplete
401+
}
402+
...on Appointment {
403+
id
404+
subject
405+
when
406+
isNow
407+
}
408+
}
338409
}
339410
)gql"s;
340411

@@ -385,6 +456,11 @@ Response parseResponse(response::Value&& response)
385456
result.testTaskState = ModifiedResponse<TaskState>::parse<TypeModifier::Nullable>(std::move(member.second));
386457
continue;
387458
}
459+
if (member.first == R"js(anyType)js"sv)
460+
{
461+
result.anyType = ModifiedResponse<Response::anyType_UnionType>::parse<TypeModifier::List, TypeModifier::Nullable>(std::move(member.second));
462+
continue;
463+
}
388464
}
389465
}
390466

samples/client/QueryClient.h

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ static_assert(graphql::internal::MinorVersion == 6, "regenerate with clientgen:
6969
///
7070
/// # Read a field with an enum type
7171
/// testTaskState
72+
///
73+
/// # Try a field with a union type
74+
/// anyType(ids: ["ZmFrZVRhc2tJZA=="]) {
75+
/// __typename
76+
/// ...on Node {
77+
/// id
78+
/// }
79+
/// ...on Task {
80+
/// id
81+
/// title
82+
/// isComplete
83+
/// }
84+
/// ...on Appointment {
85+
/// id
86+
/// subject
87+
/// when
88+
/// isNow
89+
/// }
90+
/// }
7291
/// }
7392
/// </code>
7493
namespace graphql::client::query::Query {
@@ -95,62 +114,74 @@ struct Response
95114
{
96115
struct node_Appointment
97116
{
98-
response::IdType id;
99-
std::optional<response::StringType> subject;
100-
std::optional<response::Value> when;
101-
response::BooleanType isNow;
102-
response::StringType _typename;
117+
response::IdType id {};
118+
std::optional<response::StringType> subject {};
119+
std::optional<response::Value> when {};
120+
response::BooleanType isNow {};
121+
response::StringType _typename {};
103122
};
104123

105-
std::optional<node_Appointment> node;
124+
std::optional<node_Appointment> node {};
106125
};
107126

108-
std::optional<std::vector<std::optional<edges_AppointmentEdge>>> edges;
127+
std::optional<std::vector<std::optional<edges_AppointmentEdge>>> edges {};
109128
};
110129

111-
appointments_AppointmentConnection appointments;
130+
appointments_AppointmentConnection appointments {};
112131

113132
struct tasks_TaskConnection
114133
{
115134
struct edges_TaskEdge
116135
{
117136
struct node_Task
118137
{
119-
response::IdType id;
120-
std::optional<response::StringType> title;
121-
response::BooleanType isComplete;
122-
response::StringType _typename;
138+
response::IdType id {};
139+
std::optional<response::StringType> title {};
140+
response::BooleanType isComplete {};
141+
response::StringType _typename {};
123142
};
124143

125-
std::optional<node_Task> node;
144+
std::optional<node_Task> node {};
126145
};
127146

128-
std::optional<std::vector<std::optional<edges_TaskEdge>>> edges;
147+
std::optional<std::vector<std::optional<edges_TaskEdge>>> edges {};
129148
};
130149

131-
tasks_TaskConnection tasks;
150+
tasks_TaskConnection tasks {};
132151

133152
struct unreadCounts_FolderConnection
134153
{
135154
struct edges_FolderEdge
136155
{
137156
struct node_Folder
138157
{
139-
response::IdType id;
140-
std::optional<response::StringType> name;
141-
response::IntType unreadCount;
142-
response::StringType _typename;
158+
response::IdType id {};
159+
std::optional<response::StringType> name {};
160+
response::IntType unreadCount {};
161+
response::StringType _typename {};
143162
};
144163

145-
std::optional<node_Folder> node;
164+
std::optional<node_Folder> node {};
146165
};
147166

148-
std::optional<std::vector<std::optional<edges_FolderEdge>>> edges;
167+
std::optional<std::vector<std::optional<edges_FolderEdge>>> edges {};
149168
};
150169

151-
unreadCounts_FolderConnection unreadCounts;
170+
unreadCounts_FolderConnection unreadCounts {};
171+
172+
std::optional<TaskState> testTaskState {};
173+
struct anyType_UnionType
174+
{
175+
response::StringType _typename {};
176+
response::IdType id {};
177+
std::optional<response::StringType> title {};
178+
response::BooleanType isComplete {};
179+
std::optional<response::StringType> subject {};
180+
std::optional<response::Value> when {};
181+
response::BooleanType isNow {};
182+
};
152183

153-
std::optional<TaskState> testTaskState;
184+
std::vector<std::optional<anyType_UnionType>> anyType {};
154185
};
155186

156187
Response parseResponse(response::Value&& response);

samples/client/SubscribeClient.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@ struct Response
5555
{
5656
struct nextAppointment_Appointment
5757
{
58-
response::IdType nextAppointmentId;
59-
std::optional<response::Value> when;
60-
std::optional<response::StringType> subject;
61-
response::BooleanType isNow;
58+
response::IdType nextAppointmentId {};
59+
std::optional<response::Value> when {};
60+
std::optional<response::StringType> subject {};
61+
response::BooleanType isNow {};
6262
};
6363

64-
std::optional<nextAppointment_Appointment> nextAppointment;
64+
std::optional<nextAppointment_Appointment> nextAppointment {};
6565
};
6666

6767
Response parseResponse(response::Value&& response);

samples/query.today.graphql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,23 @@ query {
3636

3737
# Read a field with an enum type
3838
testTaskState
39+
40+
# Try a field with a union type
41+
anyType(ids: ["ZmFrZVRhc2tJZA=="]) {
42+
__typename
43+
...on Node {
44+
id
45+
}
46+
...on Task {
47+
id
48+
title
49+
isComplete
50+
}
51+
...on Appointment {
52+
id
53+
subject
54+
when
55+
isNow
56+
}
57+
}
3958
}

samples/schema.today.graphql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ type Query {
3434
expensive: [Expensive!]!
3535

3636
testTaskState: TaskState
37+
38+
anyType(ids: [ID!]!): [UnionType]!
3739
}
3840

3941
"Node interface for Relay support"

samples/separate/QueryObject.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Query::Query()
2626
{ R"gql(tasks)gql"sv, [this](service::ResolverParams&& params) { return resolveTasks(std::move(params)); } },
2727
{ R"gql(__type)gql"sv, [this](service::ResolverParams&& params) { return resolve_type(std::move(params)); } },
2828
{ R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } },
29+
{ R"gql(anyType)gql"sv, [this](service::ResolverParams&& params) { return resolveAnyType(std::move(params)); } },
2930
{ R"gql(__schema)gql"sv, [this](service::ResolverParams&& params) { return resolve_schema(std::move(params)); } },
3031
{ R"gql(expensive)gql"sv, [this](service::ResolverParams&& params) { return resolveExpensive(std::move(params)); } },
3132
{ R"gql(tasksById)gql"sv, [this](service::ResolverParams&& params) { return resolveTasksById(std::move(params)); } },
@@ -244,6 +245,22 @@ std::future<service::ResolverResult> Query::resolveTestTaskState(service::Resolv
244245
return service::ModifiedResult<TaskState>::convert<service::TypeModifier::Nullable>(std::move(result), std::move(params));
245246
}
246247

248+
service::FieldResult<std::vector<std::shared_ptr<service::Object>>> Query::getAnyType(service::FieldParams&&, std::vector<response::IdType>&&) const
249+
{
250+
throw std::runtime_error(R"ex(Query::getAnyType is not implemented)ex");
251+
}
252+
253+
std::future<service::ResolverResult> Query::resolveAnyType(service::ResolverParams&& params)
254+
{
255+
auto argIds = service::ModifiedArgument<response::IdType>::require<service::TypeModifier::List>("ids", params.arguments);
256+
std::unique_lock resolverLock(_resolverMutex);
257+
auto directives = std::move(params.fieldDirectives);
258+
auto result = getAnyType(service::FieldParams(std::move(params), std::move(directives)), std::move(argIds));
259+
resolverLock.unlock();
260+
261+
return service::ModifiedResult<service::Object>::convert<service::TypeModifier::List, service::TypeModifier::Nullable>(std::move(result), std::move(params));
262+
}
263+
247264
std::future<service::ResolverResult> Query::resolve_typename(service::ResolverParams&& params)
248265
{
249266
return service::ModifiedResult<response::StringType>::convert(response::StringType{ R"gql(Query)gql" }, std::move(params));
@@ -301,7 +318,10 @@ void AddQueryDetails(std::shared_ptr<schema::ObjectType> typeQuery, const std::s
301318
schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))),
302319
schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))),
303320
schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))),
304-
schema::Field::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("TaskState"))
321+
schema::Field::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("TaskState")),
322+
schema::Field::Make(R"gql(anyType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("UnionType"))), {
323+
schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv)
324+
})
305325
});
306326
}
307327

samples/separate/QueryObject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Query
3030
virtual service::FieldResult<response::StringType> getUnimplemented(service::FieldParams&& params) const;
3131
virtual service::FieldResult<std::vector<std::shared_ptr<Expensive>>> getExpensive(service::FieldParams&& params) const;
3232
virtual service::FieldResult<std::optional<TaskState>> getTestTaskState(service::FieldParams&& params) const;
33+
virtual service::FieldResult<std::vector<std::shared_ptr<service::Object>>> getAnyType(service::FieldParams&& params, std::vector<response::IdType>&& idsArg) const;
3334

3435
private:
3536
std::future<service::ResolverResult> resolveNode(service::ResolverParams&& params);
@@ -43,6 +44,7 @@ class Query
4344
std::future<service::ResolverResult> resolveUnimplemented(service::ResolverParams&& params);
4445
std::future<service::ResolverResult> resolveExpensive(service::ResolverParams&& params);
4546
std::future<service::ResolverResult> resolveTestTaskState(service::ResolverParams&& params);
47+
std::future<service::ResolverResult> resolveAnyType(service::ResolverParams&& params);
4648

4749
std::future<service::ResolverResult> resolve_typename(service::ResolverParams&& params);
4850
std::future<service::ResolverResult> resolve_schema(service::ResolverParams&& params);

0 commit comments

Comments
 (0)