Skip to content

Commit 264962a

Browse files
committed
Fix #246
1 parent 31af73f commit 264962a

23 files changed

+1719
-114
lines changed

include/graphqlservice/GraphQLClient.h

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,17 @@ template <typename Type>
7777
return false;
7878
}
7979

80+
// Special-case an innermost nullable INPUT_OBJECT type.
81+
template <TypeModifier... Other>
82+
[[nodiscard]] constexpr bool onlyNoneModifiers() noexcept
83+
{
84+
return (... && (Other == TypeModifier::None));
85+
}
86+
8087
// Serialize variable input values with chained type modifiers which add nullable or list wrappers.
8188
template <typename Type>
8289
struct ModifiedVariable
8390
{
84-
// Special-case an innermost nullable INPUT_OBJECT type.
85-
template <TypeModifier... Other>
86-
[[nodiscard]] static constexpr bool onlyNoneModifiers() noexcept
87-
{
88-
return (... && (Other == TypeModifier::None));
89-
}
90-
9191
// Peel off modifiers until we get to the underlying type.
9292
template <typename U, TypeModifier Modifier = TypeModifier::None, TypeModifier... Other>
9393
struct VariableTraits
@@ -152,6 +152,53 @@ struct ModifiedVariable
152152

153153
return result;
154154
}
155+
156+
// Peel off the none modifier. If it's included, it should always be last in the list.
157+
template <TypeModifier Modifier = TypeModifier::None, TypeModifier... Other>
158+
[[nodiscard]] static
159+
typename std::enable_if_t<TypeModifier::None == Modifier && sizeof...(Other) == 0, Type>
160+
duplicate(const Type& value)
161+
{
162+
// Just copy the value.
163+
return { value };
164+
}
165+
166+
// Peel off nullable modifiers.
167+
template <TypeModifier Modifier, TypeModifier... Other>
168+
[[nodiscard]] static typename std::enable_if_t<TypeModifier::Nullable == Modifier,
169+
typename VariableTraits<Type, Modifier, Other...>::type>
170+
duplicate(const typename VariableTraits<Type, Modifier, Other...>::type& nullableValue)
171+
{
172+
typename VariableTraits<Type, Modifier, Other...>::type result {};
173+
174+
if (nullableValue)
175+
{
176+
if constexpr (isInputType<Type>() && onlyNoneModifiers<Other...>())
177+
{
178+
// Special case duplicating the std::unique_ptr.
179+
result = std::make_unique<Type>(*nullableValue);
180+
}
181+
else
182+
{
183+
result = duplicate<Other...>(*nullableValue);
184+
}
185+
}
186+
187+
return result;
188+
}
189+
190+
// Peel off list modifiers.
191+
template <TypeModifier Modifier, TypeModifier... Other>
192+
[[nodiscard]] static typename std::enable_if_t<TypeModifier::List == Modifier,
193+
typename VariableTraits<Type, Modifier, Other...>::type>
194+
duplicate(const typename VariableTraits<Type, Modifier, Other...>::type& listValue)
195+
{
196+
typename VariableTraits<Type, Modifier, Other...>::type result(listValue.size());
197+
198+
std::transform(listValue.cbegin(), listValue.cend(), result.begin(), duplicate<Other...>);
199+
200+
return result;
201+
}
155202
};
156203

157204
// Convenient type aliases for testing, generated code won't actually use these. These are also

include/graphqlservice/GraphQLService.h

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -599,20 +599,20 @@ template <typename Type>
599599
return false;
600600
}
601601

602+
// Special-case an innermost nullable INPUT_OBJECT type.
603+
template <TypeModifier... Other>
604+
[[nodiscard]] constexpr bool onlyNoneModifiers() noexcept
605+
{
606+
return (... && (Other == TypeModifier::None));
607+
}
608+
602609
// Extract individual arguments with chained type modifiers which add nullable or list wrappers.
603610
// If the argument is not optional, use require and let it throw a schema_exception when the
604611
// argument is missing or not the correct type. If it's optional, use find and check the second
605612
// element in the pair to see if it was found or if you just got the default value for that type.
606613
template <typename Type>
607614
struct ModifiedArgument
608615
{
609-
// Special-case an innermost nullable INPUT_OBJECT type.
610-
template <TypeModifier... Other>
611-
[[nodiscard]] static constexpr bool onlyNoneModifiers() noexcept
612-
{
613-
return (... && (Other == TypeModifier::None));
614-
}
615-
616616
// Peel off modifiers until we get to the underlying type.
617617
template <typename U, TypeModifier Modifier = TypeModifier::None, TypeModifier... Other>
618618
struct ArgumentTraits
@@ -747,6 +747,53 @@ struct ModifiedArgument
747747
return { typename ArgumentTraits<Type, Modifier, Other...>::type {}, false };
748748
}
749749
}
750+
751+
// Peel off the none modifier. If it's included, it should always be last in the list.
752+
template <TypeModifier Modifier = TypeModifier::None, TypeModifier... Other>
753+
[[nodiscard]] static
754+
typename std::enable_if_t<TypeModifier::None == Modifier && sizeof...(Other) == 0, Type>
755+
duplicate(const Type& value)
756+
{
757+
// Just copy the value.
758+
return { value };
759+
}
760+
761+
// Peel off nullable modifiers.
762+
template <TypeModifier Modifier, TypeModifier... Other>
763+
[[nodiscard]] static typename std::enable_if_t<TypeModifier::Nullable == Modifier,
764+
typename ArgumentTraits<Type, Modifier, Other...>::type>
765+
duplicate(const typename ArgumentTraits<Type, Modifier, Other...>::type& nullableValue)
766+
{
767+
typename ArgumentTraits<Type, Modifier, Other...>::type result {};
768+
769+
if (nullableValue)
770+
{
771+
if constexpr (isInputType<Type>() && onlyNoneModifiers<Other...>())
772+
{
773+
// Special case duplicating the std::unique_ptr.
774+
result = std::make_unique<Type>(*nullableValue);
775+
}
776+
else
777+
{
778+
result = duplicate<Other...>(*nullableValue);
779+
}
780+
}
781+
782+
return result;
783+
}
784+
785+
// Peel off list modifiers.
786+
template <TypeModifier Modifier, TypeModifier... Other>
787+
[[nodiscard]] static typename std::enable_if_t<TypeModifier::List == Modifier,
788+
typename ArgumentTraits<Type, Modifier, Other...>::type>
789+
duplicate(const typename ArgumentTraits<Type, Modifier, Other...>::type& listValue)
790+
{
791+
typename ArgumentTraits<Type, Modifier, Other...>::type result(listValue.size());
792+
793+
std::transform(listValue.cbegin(), listValue.cend(), result.begin(), duplicate<Other...>);
794+
795+
return result;
796+
}
750797
};
751798

752799
// Convenient type aliases for testing, generated code won't actually use these. These are also

samples/client/benchmark/BenchmarkClient.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sstream>
1111
#include <stdexcept>
1212
#include <string_view>
13+
#include <utility>
1314

1415
using namespace std::literals;
1516

samples/client/multiple/MultipleQueriesClient.cpp

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sstream>
1111
#include <stdexcept>
1212
#include <string_view>
13+
#include <utility>
1314

1415
using namespace std::literals;
1516

@@ -125,6 +126,48 @@ static const std::array<std::string_view, 4> s_namesTaskState = {
125126
"Unassigned"sv,
126127
};
127128

129+
CompleteTaskInput::CompleteTaskInput(response::IdType&& idArg, std::optional<TaskState>&& testTaskStateArg, std::optional<bool>&& isCompleteArg, std::optional<std::string>&& clientMutationIdArg) noexcept
130+
: id { std::move(idArg) }
131+
, testTaskState { std::move(testTaskStateArg) }
132+
, isComplete { std::move(isCompleteArg) }
133+
, clientMutationId { std::move(clientMutationIdArg) }
134+
{
135+
}
136+
137+
CompleteTaskInput::CompleteTaskInput(const CompleteTaskInput& other)
138+
: id { ModifiedVariable<response::IdType>::duplicate(other.id) }
139+
, testTaskState { ModifiedVariable<TaskState>::duplicate<TypeModifier::Nullable>(other.testTaskState) }
140+
, isComplete { ModifiedVariable<bool>::duplicate<TypeModifier::Nullable>(other.isComplete) }
141+
, clientMutationId { ModifiedVariable<std::string>::duplicate<TypeModifier::Nullable>(other.clientMutationId) }
142+
{
143+
}
144+
145+
CompleteTaskInput::CompleteTaskInput(CompleteTaskInput&& other) noexcept
146+
: id { std::move(other.id) }
147+
, testTaskState { std::move(other.testTaskState) }
148+
, isComplete { std::move(other.isComplete) }
149+
, clientMutationId { std::move(other.clientMutationId) }
150+
{
151+
}
152+
153+
CompleteTaskInput& CompleteTaskInput::operator=(const CompleteTaskInput& other)
154+
{
155+
CompleteTaskInput value { other };
156+
157+
std::swap(*this, value);
158+
159+
return *this;
160+
}
161+
162+
CompleteTaskInput& CompleteTaskInput::operator=(CompleteTaskInput&& other) noexcept
163+
{
164+
CompleteTaskInput value { std::move(other) };
165+
166+
std::swap(*this, value);
167+
168+
return *this;
169+
}
170+
128171
} // namespace multiple
129172

130173
using namespace multiple;
@@ -585,12 +628,6 @@ Response parseResponse(response::Value&& response)
585628

586629
} // namespace query::Miscellaneous
587630

588-
template <>
589-
constexpr bool isInputType<CompleteTaskInput>() noexcept
590-
{
591-
return true;
592-
}
593-
594631
template <>
595632
response::Value ModifiedVariable<TaskState>::serialize(TaskState&& value)
596633
{

samples/client/multiple/MultipleQueriesClient.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ enum class [[nodiscard]] TaskState
127127

128128
struct [[nodiscard]] CompleteTaskInput
129129
{
130+
explicit CompleteTaskInput(response::IdType&& idArg = response::IdType {}, std::optional<TaskState>&& testTaskStateArg = std::optional<TaskState> {}, std::optional<bool>&& isCompleteArg = std::optional<bool> {}, std::optional<std::string>&& clientMutationIdArg = std::optional<std::string> {}) noexcept;
131+
CompleteTaskInput(const CompleteTaskInput& other);
132+
CompleteTaskInput(CompleteTaskInput&& other) noexcept;
133+
134+
CompleteTaskInput& operator=(const CompleteTaskInput& other);
135+
CompleteTaskInput& operator=(CompleteTaskInput&& other) noexcept;
136+
130137
response::IdType id {};
131138
std::optional<TaskState> testTaskState {};
132139
std::optional<bool> isComplete {};
@@ -135,6 +142,12 @@ struct [[nodiscard]] CompleteTaskInput
135142

136143
} // namespace multiple
137144

145+
template <>
146+
constexpr bool isInputType<multiple::CompleteTaskInput>() noexcept
147+
{
148+
return true;
149+
}
150+
138151
namespace query::Appointments {
139152

140153
using multiple::GetRequestText;

samples/client/mutate/MutateClient.cpp

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sstream>
1111
#include <stdexcept>
1212
#include <string_view>
13+
#include <utility>
1314

1415
using namespace std::literals;
1516

@@ -58,16 +59,52 @@ static const std::array<std::string_view, 4> s_namesTaskState = {
5859
"Unassigned"sv,
5960
};
6061

61-
} // namespace mutate
62+
CompleteTaskInput::CompleteTaskInput(response::IdType&& idArg, std::optional<TaskState>&& testTaskStateArg, std::optional<bool>&& isCompleteArg, std::optional<std::string>&& clientMutationIdArg) noexcept
63+
: id { std::move(idArg) }
64+
, testTaskState { std::move(testTaskStateArg) }
65+
, isComplete { std::move(isCompleteArg) }
66+
, clientMutationId { std::move(clientMutationIdArg) }
67+
{
68+
}
6269

63-
using namespace mutate;
70+
CompleteTaskInput::CompleteTaskInput(const CompleteTaskInput& other)
71+
: id { ModifiedVariable<response::IdType>::duplicate(other.id) }
72+
, testTaskState { ModifiedVariable<TaskState>::duplicate<TypeModifier::Nullable>(other.testTaskState) }
73+
, isComplete { ModifiedVariable<bool>::duplicate<TypeModifier::Nullable>(other.isComplete) }
74+
, clientMutationId { ModifiedVariable<std::string>::duplicate<TypeModifier::Nullable>(other.clientMutationId) }
75+
{
76+
}
6477

65-
template <>
66-
constexpr bool isInputType<CompleteTaskInput>() noexcept
78+
CompleteTaskInput::CompleteTaskInput(CompleteTaskInput&& other) noexcept
79+
: id { std::move(other.id) }
80+
, testTaskState { std::move(other.testTaskState) }
81+
, isComplete { std::move(other.isComplete) }
82+
, clientMutationId { std::move(other.clientMutationId) }
6783
{
68-
return true;
6984
}
7085

86+
CompleteTaskInput& CompleteTaskInput::operator=(const CompleteTaskInput& other)
87+
{
88+
CompleteTaskInput value { other };
89+
90+
std::swap(*this, value);
91+
92+
return *this;
93+
}
94+
95+
CompleteTaskInput& CompleteTaskInput::operator=(CompleteTaskInput&& other) noexcept
96+
{
97+
CompleteTaskInput value { std::move(other) };
98+
99+
std::swap(*this, value);
100+
101+
return *this;
102+
}
103+
104+
} // namespace mutate
105+
106+
using namespace mutate;
107+
71108
template <>
72109
response::Value ModifiedVariable<TaskState>::serialize(TaskState&& value)
73110
{

samples/client/mutate/MutateClient.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ enum class [[nodiscard]] TaskState
6060

6161
struct [[nodiscard]] CompleteTaskInput
6262
{
63+
explicit CompleteTaskInput(response::IdType&& idArg = response::IdType {}, std::optional<TaskState>&& testTaskStateArg = std::optional<TaskState> {}, std::optional<bool>&& isCompleteArg = std::optional<bool> {}, std::optional<std::string>&& clientMutationIdArg = std::optional<std::string> {}) noexcept;
64+
CompleteTaskInput(const CompleteTaskInput& other);
65+
CompleteTaskInput(CompleteTaskInput&& other) noexcept;
66+
67+
CompleteTaskInput& operator=(const CompleteTaskInput& other);
68+
CompleteTaskInput& operator=(CompleteTaskInput&& other) noexcept;
69+
6370
response::IdType id {};
6471
std::optional<TaskState> testTaskState {};
6572
std::optional<bool> isComplete {};
@@ -68,6 +75,12 @@ struct [[nodiscard]] CompleteTaskInput
6875

6976
} // namespace mutate
7077

78+
template <>
79+
constexpr bool isInputType<mutate::CompleteTaskInput>() noexcept
80+
{
81+
return true;
82+
}
83+
7184
namespace mutation::CompleteTaskMutation {
7285

7386
using mutate::GetRequestText;

0 commit comments

Comments
 (0)