Skip to content

Commit 4114b38

Browse files
committed
Move Base64 conversions from GraphQLService to GraphQLResponse
1 parent 68d0812 commit 4114b38

File tree

14 files changed

+307
-216
lines changed

14 files changed

+307
-216
lines changed

include/graphqlservice/GraphQLResponse.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ struct ValueTypeTraits<FloatType>
107107
template <>
108108
struct ValueTypeTraits<IdType>
109109
{
110-
// ID values are represented as a String, there's no separate handling of this type.
110+
// ID values are represented as a Base64 String, so they require conversion.
111+
using set_type = const IdType&;
112+
using get_type = IdType;
113+
using release_type = IdType;
111114
};
112115

113116
// Represent a discriminated union of GraphQL response value types.
@@ -121,6 +124,7 @@ struct Value
121124
GRAPHQLRESPONSE_EXPORT explicit Value(BooleanType value);
122125
GRAPHQLRESPONSE_EXPORT explicit Value(IntType value);
123126
GRAPHQLRESPONSE_EXPORT explicit Value(FloatType value);
127+
GRAPHQLRESPONSE_EXPORT explicit Value(const IdType& value);
124128

125129
GRAPHQLRESPONSE_EXPORT Value(Value&& other) noexcept;
126130
GRAPHQLRESPONSE_EXPORT explicit Value(const Value& other);
@@ -247,6 +251,8 @@ GRAPHQLRESPONSE_EXPORT void Value::set<FloatType>(FloatType value);
247251
template <>
248252
GRAPHQLRESPONSE_EXPORT void Value::set<ScalarType>(ScalarType&& value);
249253
template <>
254+
GRAPHQLRESPONSE_EXPORT void Value::set<IdType>(const IdType& value);
255+
template <>
250256
GRAPHQLRESPONSE_EXPORT const MapType& Value::get<MapType>() const;
251257
template <>
252258
GRAPHQLRESPONSE_EXPORT const ListType& Value::get<ListType>() const;
@@ -261,13 +267,17 @@ GRAPHQLRESPONSE_EXPORT FloatType Value::get<FloatType>() const;
261267
template <>
262268
GRAPHQLRESPONSE_EXPORT const ScalarType& Value::get<ScalarType>() const;
263269
template <>
270+
GRAPHQLRESPONSE_EXPORT IdType Value::get<IdType>() const;
271+
template <>
264272
GRAPHQLRESPONSE_EXPORT MapType Value::release<MapType>();
265273
template <>
266274
GRAPHQLRESPONSE_EXPORT ListType Value::release<ListType>();
267275
template <>
268276
GRAPHQLRESPONSE_EXPORT StringType Value::release<StringType>();
269277
template <>
270278
GRAPHQLRESPONSE_EXPORT ScalarType Value::release<ScalarType>();
279+
template <>
280+
GRAPHQLRESPONSE_EXPORT IdType Value::release<IdType>();
271281
#endif // GRAPHQL_DLLEXPORTS
272282

273283
} /* namespace graphql::response */

include/graphqlservice/GraphQLService.h

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -281,46 +281,6 @@ struct ResolverResult
281281
using Resolver = std::function<std::future<ResolverResult>(ResolverParams&&)>;
282282
using ResolverMap = internal::string_view_map<Resolver>;
283283

284-
// Binary data and opaque strings like IDs are encoded in Base64.
285-
class Base64
286-
{
287-
public:
288-
// Map a single Base64-encoded character to its 6-bit integer value.
289-
static constexpr uint8_t fromBase64(char ch) noexcept
290-
{
291-
return (ch >= 'A' && ch <= 'Z'
292-
? ch - 'A'
293-
: (ch >= 'a' && ch <= 'z'
294-
? ch - 'a' + 26
295-
: (ch >= '0' && ch <= '9' ? ch - '0' + 52
296-
: (ch == '+' ? 62 : (ch == '/' ? 63 : 0xFF)))));
297-
}
298-
299-
// Convert a Base64-encoded string to a vector of bytes.
300-
GRAPHQLSERVICE_EXPORT static std::vector<uint8_t> fromBase64(const char* encoded, size_t count);
301-
302-
// Map a single 6-bit integer value to its Base64-encoded character.
303-
static constexpr char toBase64(uint8_t i) noexcept
304-
{
305-
return (i < 26 ? static_cast<char>(i + static_cast<uint8_t>('A'))
306-
: (i < 52 ? static_cast<char>(i - 26 + static_cast<uint8_t>('a'))
307-
: (i < 62 ? static_cast<char>(i - 52 + static_cast<uint8_t>('0'))
308-
: (i == 62 ? '+' : (i == 63 ? '/' : padding)))));
309-
}
310-
311-
// Convert a set of bytes to Base64.
312-
GRAPHQLSERVICE_EXPORT static std::string toBase64(const std::vector<uint8_t>& bytes);
313-
314-
private:
315-
static constexpr char padding = '=';
316-
317-
// Throw a schema_exception if the character is out of range.
318-
static uint8_t verifyFromBase64(char ch);
319-
320-
// Throw a logic_error if the integer is out of range.
321-
static char verifyToBase64(uint8_t i);
322-
};
323-
324284
// GraphQL types are nullable by default, but they may be wrapped with non-null or list types.
325285
// Since nullability is a more special case in C++, we invert the default and apply that modifier
326286
// instead when the non-null wrapper is not present in that part of the wrapper chain.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
#pragma once
5+
6+
#ifndef BASE64_H
7+
#define BASE64_H
8+
9+
// clang-format off
10+
#ifdef GRAPHQL_DLLEXPORTS
11+
#ifdef IMPL_GRAPHQLRESPONSE_DLL
12+
#define GRAPHQLRESPONSE_EXPORT __declspec(dllexport)
13+
#else // !IMPL_GRAPHQLRESPONSE_DLL
14+
#define GRAPHQLRESPONSE_EXPORT __declspec(dllimport)
15+
#endif // !IMPL_GRAPHQLRESPONSE_DLL
16+
#else // !GRAPHQL_DLLEXPORTS
17+
#define GRAPHQLRESPONSE_EXPORT
18+
#endif // !GRAPHQL_DLLEXPORTS
19+
// clang-format on
20+
21+
#include <cstdint>
22+
#include <string>
23+
#include <string_view>
24+
#include <vector>
25+
26+
namespace graphql::internal {
27+
28+
// Binary data and opaque strings like IDs are encoded in Base64.
29+
class Base64
30+
{
31+
public:
32+
// Map a single Base64-encoded character to its 6-bit integer value.
33+
static constexpr std::uint8_t fromBase64(char ch) noexcept
34+
{
35+
return (ch >= 'A' && ch <= 'Z'
36+
? ch - 'A'
37+
: (ch >= 'a' && ch <= 'z'
38+
? ch - 'a' + 26
39+
: (ch >= '0' && ch <= '9' ? ch - '0' + 52
40+
: (ch == '+' ? 62 : (ch == '/' ? 63 : 0xFF)))));
41+
}
42+
43+
// Convert a Base64-encoded string to a vector of bytes.
44+
GRAPHQLRESPONSE_EXPORT static std::vector<std::uint8_t> fromBase64(std::string_view encoded);
45+
46+
// Map a single 6-bit integer value to its Base64-encoded character.
47+
static constexpr char toBase64(std::uint8_t i) noexcept
48+
{
49+
return (i < 26
50+
? static_cast<char>(i + static_cast<std::uint8_t>('A'))
51+
: (i < 52 ? static_cast<char>(i - 26 + static_cast<std::uint8_t>('a'))
52+
: (i < 62 ? static_cast<char>(i - 52 + static_cast<std::uint8_t>('0'))
53+
: (i == 62 ? '+' : (i == 63 ? '/' : padding)))));
54+
}
55+
56+
// Convert a set of bytes to Base64.
57+
GRAPHQLRESPONSE_EXPORT static std::string toBase64(const std::vector<std::uint8_t>& bytes);
58+
59+
private:
60+
static constexpr char padding = '=';
61+
62+
// Throw a std::logic_error if the character is out of range.
63+
static std::uint8_t verifyFromBase64(char ch);
64+
65+
// Throw a std::logic_error if the integer is out of range.
66+
static char verifyToBase64(std::uint8_t i);
67+
};
68+
69+
} // namespace graphql::internal
70+
71+
#endif // BASE64_H

samples/client/MutateClient.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
#include "MutateClient.h"
77

8-
#include "graphqlservice/GraphQLService.h"
9-
108
#include <algorithm>
119
#include <array>
1210
#include <sstream>

samples/client/QueryClient.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
#include "QueryClient.h"
77

8-
#include "graphqlservice/GraphQLService.h"
9-
108
#include <algorithm>
119
#include <array>
1210
#include <sstream>

samples/client/SubscribeClient.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
#include "SubscribeClient.h"
77

8-
#include "graphqlservice/GraphQLService.h"
9-
108
#include <algorithm>
119
#include <array>
1210
#include <sstream>

samples/today/TodayMock.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,16 +183,15 @@ struct EdgeConstraints
183183
}
184184

185185
std::shared_ptr<_Connection> operator()(const std::optional<int>& first,
186-
const std::optional<response::Value>& after, const std::optional<int>& last,
187-
const std::optional<response::Value>& before) const
186+
std::optional<response::Value>&& after, const std::optional<int>& last,
187+
std::optional<response::Value>&& before) const
188188
{
189189
auto itrFirst = _objects.cbegin();
190190
auto itrLast = _objects.cend();
191191

192192
if (after)
193193
{
194-
const auto& encoded = after->get<response::StringType>();
195-
auto afterId = service::Base64::fromBase64(encoded.c_str(), encoded.size());
194+
auto afterId = after->release<response::IdType>();
196195
auto itrAfter =
197196
std::find_if(itrFirst, itrLast, [&afterId](const std::shared_ptr<_Object>& entry) {
198197
return entry->id() == afterId;
@@ -206,8 +205,7 @@ struct EdgeConstraints
206205

207206
if (before)
208207
{
209-
const auto& encoded = before->get<response::StringType>();
210-
auto beforeId = service::Base64::fromBase64(encoded.c_str(), encoded.size());
208+
auto beforeId = before->release<response::IdType>();
211209
auto itrBefore =
212210
std::find_if(itrFirst, itrLast, [&beforeId](const std::shared_ptr<_Object>& entry) {
213211
return entry->id() == beforeId;
@@ -281,7 +279,7 @@ service::FieldResult<std::shared_ptr<object::AppointmentConnection>> Query::getA
281279
loadAppointments(state);
282280

283281
EdgeConstraints<Appointment, AppointmentConnection> constraints(state, _appointments);
284-
auto connection = constraints(firstWrapped, afterWrapped, lastWrapped, beforeWrapped);
282+
auto connection = constraints(firstWrapped, std::move(afterWrapped), lastWrapped, std::move(beforeWrapped));
285283

286284
return std::static_pointer_cast<object::AppointmentConnection>(connection);
287285
},
@@ -307,7 +305,7 @@ service::FieldResult<std::shared_ptr<object::TaskConnection>> Query::getTasks(
307305
loadTasks(state);
308306

309307
EdgeConstraints<Task, TaskConnection> constraints(state, _tasks);
310-
auto connection = constraints(firstWrapped, afterWrapped, lastWrapped, beforeWrapped);
308+
auto connection = constraints(firstWrapped, std::move(afterWrapped), lastWrapped, std::move(beforeWrapped));
311309

312310
return std::static_pointer_cast<object::TaskConnection>(connection);
313311
},
@@ -333,7 +331,7 @@ service::FieldResult<std::shared_ptr<object::FolderConnection>> Query::getUnread
333331
loadUnreadCounts(state);
334332

335333
EdgeConstraints<Folder, FolderConnection> constraints(state, _unreadCounts);
336-
auto connection = constraints(firstWrapped, afterWrapped, lastWrapped, beforeWrapped);
334+
auto connection = constraints(firstWrapped, std::move(afterWrapped), lastWrapped, std::move(beforeWrapped));
337335

338336
return std::static_pointer_cast<object::FolderConnection>(connection);
339337
},

samples/today/TodayMock.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ class AppointmentEdge : public object::AppointmentEdge
183183

184184
service::FieldResult<response::Value> getCursor(service::FieldParams&& params) const final
185185
{
186-
return response::Value(
187-
service::Base64::toBase64(_appointment->getId(std::move(params)).get()));
186+
return response::Value(_appointment->getId(std::move(params)).get());
188187
}
189188

190189
private:
@@ -277,7 +276,7 @@ class TaskEdge : public object::TaskEdge
277276

278277
service::FieldResult<response::Value> getCursor(service::FieldParams&& params) const final
279278
{
280-
return response::Value(service::Base64::toBase64(_task->getId(std::move(params)).get()));
279+
return response::Value(_task->getId(std::move(params)).get());
281280
}
282281

283282
private:
@@ -370,7 +369,7 @@ class FolderEdge : public object::FolderEdge
370369

371370
service::FieldResult<response::Value> getCursor(service::FieldParams&& params) const final
372371
{
373-
return response::Value(service::Base64::toBase64(_folder->getId(std::move(params)).get()));
372+
return response::Value(_folder->getId(std::move(params)).get());
374373
}
375374

376375
private:

0 commit comments

Comments
 (0)