Skip to content

Commit 681c08d

Browse files
authored
Merge pull request #247 from wravery/input-copy-constructors
Generate input type copy constructors
2 parents 31af73f + b07ad02 commit 681c08d

25 files changed

+1895
-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 Type { 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>(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/GraphQLResponse.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ template <>
146146
GRAPHQLRESPONSE_EXPORT IdType::IdType(
147147
typename ByteData::const_pointer begin, typename ByteData::const_pointer end);
148148
template <>
149+
GRAPHQLRESPONSE_EXPORT IdType::IdType(
150+
typename ByteData::pointer begin, typename ByteData::pointer end);
151+
template <>
149152
GRAPHQLRESPONSE_EXPORT const IdType::ByteData& IdType::get<IdType::ByteData>() const;
150153
template <>
151154
GRAPHQLRESPONSE_EXPORT const IdType::OpaqueString& IdType::get<IdType::OpaqueString>() const;

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 Type { 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>(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: 48 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,53 @@ static const std::array<std::string_view, 4> s_namesTaskState = {
125126
"Unassigned"sv,
126127
};
127128

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

130178
using namespace multiple;
@@ -585,12 +633,6 @@ Response parseResponse(response::Value&& response)
585633

586634
} // namespace query::Miscellaneous
587635

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

samples/client/multiple/MultipleQueriesClient.h

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

128128
struct [[nodiscard]] CompleteTaskInput
129129
{
130+
explicit CompleteTaskInput(
131+
response::IdType idArg = response::IdType {},
132+
std::optional<TaskState> testTaskStateArg = std::optional<TaskState> {},
133+
std::optional<bool> isCompleteArg = std::optional<bool> {},
134+
std::optional<std::string> clientMutationIdArg = std::optional<std::string> {}) noexcept;
135+
CompleteTaskInput(const CompleteTaskInput& other);
136+
CompleteTaskInput(CompleteTaskInput&& other) noexcept;
137+
138+
CompleteTaskInput& operator=(const CompleteTaskInput& other);
139+
CompleteTaskInput& operator=(CompleteTaskInput&& other) noexcept;
140+
130141
response::IdType id {};
131142
std::optional<TaskState> testTaskState {};
132143
std::optional<bool> isComplete {};
@@ -135,6 +146,12 @@ struct [[nodiscard]] CompleteTaskInput
135146

136147
} // namespace multiple
137148

149+
template <>
150+
constexpr bool isInputType<multiple::CompleteTaskInput>() noexcept
151+
{
152+
return true;
153+
}
154+
138155
namespace query::Appointments {
139156

140157
using multiple::GetRequestText;

samples/client/mutate/MutateClient.cpp

Lines changed: 47 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,57 @@ static const std::array<std::string_view, 4> s_namesTaskState = {
5859
"Unassigned"sv,
5960
};
6061

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

63-
using namespace mutate;
74+
CompleteTaskInput::CompleteTaskInput(const CompleteTaskInput& other)
75+
: id { ModifiedVariable<response::IdType>::duplicate(other.id) }
76+
, testTaskState { ModifiedVariable<TaskState>::duplicate<TypeModifier::Nullable>(other.testTaskState) }
77+
, isComplete { ModifiedVariable<bool>::duplicate<TypeModifier::Nullable>(other.isComplete) }
78+
, clientMutationId { ModifiedVariable<std::string>::duplicate<TypeModifier::Nullable>(other.clientMutationId) }
79+
{
80+
}
6481

65-
template <>
66-
constexpr bool isInputType<CompleteTaskInput>() noexcept
82+
CompleteTaskInput::CompleteTaskInput(CompleteTaskInput&& other) noexcept
83+
: id { std::move(other.id) }
84+
, testTaskState { std::move(other.testTaskState) }
85+
, isComplete { std::move(other.isComplete) }
86+
, clientMutationId { std::move(other.clientMutationId) }
87+
{
88+
}
89+
90+
CompleteTaskInput& CompleteTaskInput::operator=(const CompleteTaskInput& other)
6791
{
68-
return true;
92+
CompleteTaskInput value { other };
93+
94+
std::swap(*this, value);
95+
96+
return *this;
97+
}
98+
99+
CompleteTaskInput& CompleteTaskInput::operator=(CompleteTaskInput&& other) noexcept
100+
{
101+
id = std::move(other.id);
102+
testTaskState = std::move(other.testTaskState);
103+
isComplete = std::move(other.isComplete);
104+
clientMutationId = std::move(other.clientMutationId);
105+
106+
return *this;
69107
}
70108

109+
} // namespace mutate
110+
111+
using namespace mutate;
112+
71113
template <>
72114
response::Value ModifiedVariable<TaskState>::serialize(TaskState&& value)
73115
{

samples/client/mutate/MutateClient.h

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

6161
struct [[nodiscard]] CompleteTaskInput
6262
{
63+
explicit CompleteTaskInput(
64+
response::IdType idArg = response::IdType {},
65+
std::optional<TaskState> testTaskStateArg = std::optional<TaskState> {},
66+
std::optional<bool> isCompleteArg = std::optional<bool> {},
67+
std::optional<std::string> clientMutationIdArg = std::optional<std::string> {}) noexcept;
68+
CompleteTaskInput(const CompleteTaskInput& other);
69+
CompleteTaskInput(CompleteTaskInput&& other) noexcept;
70+
71+
CompleteTaskInput& operator=(const CompleteTaskInput& other);
72+
CompleteTaskInput& operator=(CompleteTaskInput&& other) noexcept;
73+
6374
response::IdType id {};
6475
std::optional<TaskState> testTaskState {};
6576
std::optional<bool> isComplete {};
@@ -68,6 +79,12 @@ struct [[nodiscard]] CompleteTaskInput
6879

6980
} // namespace mutate
7081

82+
template <>
83+
constexpr bool isInputType<mutate::CompleteTaskInput>() noexcept
84+
{
85+
return true;
86+
}
87+
7188
namespace mutation::CompleteTaskMutation {
7289

7390
using mutate::GetRequestText;

0 commit comments

Comments
 (0)