Skip to content

Accept either a Base64 encoded binary or an opaque string in response::IdType #232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.1.1
4.2.0
20 changes: 10 additions & 10 deletions include/graphqlservice/GraphQLClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,12 @@ struct ModifiedResponse
};

// Parse a single value of the response document.
static Type parse(response::Value response);
static Type parse(response::Value&& response);

// Peel off the none modifier. If it's included, it should always be last in the list.
template <TypeModifier Modifier = TypeModifier::None, TypeModifier... Other>
static typename std::enable_if_t<TypeModifier::None == Modifier && sizeof...(Other) == 0, Type>
parse(response::Value response)
parse(response::Value&& response)
{
return parse(std::move(response));
}
Expand All @@ -202,7 +202,7 @@ struct ModifiedResponse
template <TypeModifier Modifier, TypeModifier... Other>
static typename std::enable_if_t<TypeModifier::Nullable == Modifier,
std::optional<typename ResponseTraits<Type, Other...>::type>>
parse(response::Value response)
parse(response::Value&& response)
{
if (response.type() == response::Type::Null)
{
Expand All @@ -217,7 +217,7 @@ struct ModifiedResponse
template <TypeModifier Modifier, TypeModifier... Other>
static typename std::enable_if_t<TypeModifier::List == Modifier,
std::vector<typename ResponseTraits<Type, Other...>::type>>
parse(response::Value response)
parse(response::Value&& response)
{
std::vector<typename ResponseTraits<Type, Other...>::type> result;

Expand Down Expand Up @@ -251,19 +251,19 @@ using ScalarResponse = ModifiedResponse<response::Value>;
#ifdef GRAPHQL_DLLEXPORTS
// Export all of the built-in converters
template <>
GRAPHQLCLIENT_EXPORT int ModifiedResponse<int>::parse(response::Value response);
GRAPHQLCLIENT_EXPORT int ModifiedResponse<int>::parse(response::Value&& response);
template <>
GRAPHQLCLIENT_EXPORT double ModifiedResponse<double>::parse(response::Value response);
GRAPHQLCLIENT_EXPORT double ModifiedResponse<double>::parse(response::Value&& response);
template <>
GRAPHQLCLIENT_EXPORT std::string ModifiedResponse<std::string>::parse(response::Value response);
GRAPHQLCLIENT_EXPORT std::string ModifiedResponse<std::string>::parse(response::Value&& response);
template <>
GRAPHQLCLIENT_EXPORT bool ModifiedResponse<bool>::parse(response::Value response);
GRAPHQLCLIENT_EXPORT bool ModifiedResponse<bool>::parse(response::Value&& response);
template <>
GRAPHQLCLIENT_EXPORT response::IdType ModifiedResponse<response::IdType>::parse(
response::Value response);
response::Value&& response);
template <>
GRAPHQLCLIENT_EXPORT response::Value ModifiedResponse<response::Value>::parse(
response::Value response);
response::Value&& response);
#endif // GRAPHQL_DLLEXPORTS

} // namespace graphql::client
Expand Down
100 changes: 80 additions & 20 deletions include/graphqlservice/GraphQLResponse.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include "graphqlservice/internal/Awaitable.h"

#include <cstdint>
#include <initializer_list>
#include <memory>
#include <string>
#include <string_view>
Expand All @@ -31,7 +33,7 @@ namespace graphql::response {
// GraphQL responses are not technically JSON-specific, although that is probably the most common
// way of representing them. These are the primitive types that may be represented in GraphQL, as
// of the [October 2021 spec](https://spec.graphql.org/October2021/#sec-Serialization-Format).
enum class Type : uint8_t
enum class Type : std::uint8_t
{
Map, // JSON Object
List, // JSON Array
Expand All @@ -41,6 +43,7 @@ enum class Type : uint8_t
Int, // JSON Number
Float, // JSON Number
EnumValue, // JSON String
ID, // JSON String
Scalar, // JSON any type
};

Expand All @@ -53,13 +56,70 @@ using BooleanType = bool;
using IntType = int;
using FloatType = double;
using ScalarType = Value;
using IdType = std::vector<uint8_t>;

struct IdType
{
using ByteData = std::vector<std::uint8_t>;
using OpaqueString = std::string;

GRAPHQLRESPONSE_EXPORT IdType(IdType&& other = IdType { ByteData {} }) noexcept;
GRAPHQLRESPONSE_EXPORT IdType(const IdType& other);
GRAPHQLRESPONSE_EXPORT ~IdType();

// Implicit ByteData constructors
GRAPHQLRESPONSE_EXPORT IdType(size_t count, typename ByteData::value_type value = 0);
GRAPHQLRESPONSE_EXPORT IdType(std::initializer_list<typename ByteData::value_type> values);
GRAPHQLRESPONSE_EXPORT IdType(
typename ByteData::const_iterator begin, typename ByteData::const_iterator end);

// Assignment
GRAPHQLRESPONSE_EXPORT IdType& operator=(IdType&& rhs) noexcept;
IdType& operator=(const IdType& rhs) = delete;

// Conversion
GRAPHQLRESPONSE_EXPORT IdType(ByteData&& data) noexcept;
GRAPHQLRESPONSE_EXPORT IdType& operator=(ByteData&& data) noexcept;

GRAPHQLRESPONSE_EXPORT IdType(OpaqueString&& opaque) noexcept;
GRAPHQLRESPONSE_EXPORT IdType& operator=(OpaqueString&& opaque) noexcept;

template <typename ValueType>
const ValueType& get() const;

template <typename ValueType>
ValueType release();

// Comparison
GRAPHQLRESPONSE_EXPORT bool operator==(const IdType& rhs) const noexcept;
GRAPHQLRESPONSE_EXPORT bool operator==(const ByteData& rhs) const noexcept;
GRAPHQLRESPONSE_EXPORT bool operator==(const OpaqueString& rhs) const noexcept;

GRAPHQLRESPONSE_EXPORT bool operator<(const IdType& rhs) const noexcept;

// Check the Type
GRAPHQLRESPONSE_EXPORT bool isBase64() const noexcept;

private:
std::variant<ByteData, OpaqueString> _data;
};

#ifdef GRAPHQL_DLLEXPORTS
// Export all of the specialized template methods
template <>
GRAPHQLRESPONSE_EXPORT const IdType::ByteData& IdType::get<IdType::ByteData>() const;
template <>
GRAPHQLRESPONSE_EXPORT const IdType::OpaqueString& IdType::get<IdType::OpaqueString>() const;
template <>
GRAPHQLRESPONSE_EXPORT IdType::ByteData IdType::release<IdType::ByteData>();
template <>
GRAPHQLRESPONSE_EXPORT IdType::OpaqueString IdType::release<IdType::OpaqueString>();
#endif // GRAPHQL_DLLEXPORTS

template <typename ValueType>
struct ValueTypeTraits
{
// Set by r-value reference, get by const reference, and release by value. The only types
// that actually support all 3 methods are StringType and ScalarType, everything else
// Set by r-value reference, get by const reference, and release by value. The only types that
// actually support all 3 methods are StringType, IdType, and ScalarType, everything else
// overrides some subset of these types with a template specialization.
using set_type = ValueType&&;
using get_type = const ValueType&;
Expand Down Expand Up @@ -106,15 +166,6 @@ struct ValueTypeTraits<FloatType>
using get_type = FloatType;
};

template <>
struct ValueTypeTraits<IdType>
{
// ID values are represented as a Base64 String, so they require conversion.
using set_type = const IdType&;
using get_type = IdType;
using release_type = IdType;
};

// Represent a discriminated union of GraphQL response value types.
struct Value
{
Expand All @@ -126,7 +177,7 @@ struct Value
GRAPHQLRESPONSE_EXPORT explicit Value(BooleanType value);
GRAPHQLRESPONSE_EXPORT explicit Value(IntType value);
GRAPHQLRESPONSE_EXPORT explicit Value(FloatType value);
GRAPHQLRESPONSE_EXPORT explicit Value(const IdType& value);
GRAPHQLRESPONSE_EXPORT explicit Value(IdType&& value);

GRAPHQLRESPONSE_EXPORT Value(Value&& other) noexcept;
GRAPHQLRESPONSE_EXPORT explicit Value(const Value& other);
Expand All @@ -138,16 +189,22 @@ struct Value

// Comparison
GRAPHQLRESPONSE_EXPORT bool operator==(const Value& rhs) const noexcept;
GRAPHQLRESPONSE_EXPORT bool operator!=(const Value& rhs) const noexcept;

// Check the Type
GRAPHQLRESPONSE_EXPORT Type type() const noexcept;

// JSON doesn't distinguish between Type::String and Type::EnumValue, so if this value comes
// from JSON and it's a string we need to track the fact that it can be interpreted as either.
// JSON doesn't distinguish between Type::String, Type::EnumValue, and Type::ID, so if this
// value comes from JSON and it's a string we need to track the fact that it can be interpreted
// as any of those types.
GRAPHQLRESPONSE_EXPORT Value&& from_json() noexcept;
GRAPHQLRESPONSE_EXPORT bool maybe_enum() const noexcept;

// Input values don't distinguish between Type::String and Type::ID, so if this value comes from
// a string literal input value we need to track that fact that it can be interpreted as either
// of those types.
GRAPHQLRESPONSE_EXPORT Value&& from_input() noexcept;
GRAPHQLRESPONSE_EXPORT bool maybe_id() const noexcept;

// Valid for Type::Map or Type::List
GRAPHQLRESPONSE_EXPORT void reserve(size_t count);
GRAPHQLRESPONSE_EXPORT size_t size() const;
Expand Down Expand Up @@ -196,6 +253,7 @@ struct Value

StringType string;
bool from_json = false;
bool from_input = false;
};

// Type::Null
Expand All @@ -218,10 +276,12 @@ struct Value
using SharedData = std::shared_ptr<const Value>;

using TypeData = std::variant<MapData, ListType, StringData, NullData, BooleanType, IntType,
FloatType, EnumData, ScalarData, SharedData>;
FloatType, EnumData, IdType, ScalarData, SharedData>;

const TypeData& data() const noexcept;

static Type typeOf(const TypeData& data) noexcept;

TypeData _data;
};

Expand All @@ -238,7 +298,7 @@ GRAPHQLRESPONSE_EXPORT void Value::set<FloatType>(FloatType value);
template <>
GRAPHQLRESPONSE_EXPORT void Value::set<ScalarType>(ScalarType&& value);
template <>
GRAPHQLRESPONSE_EXPORT void Value::set<IdType>(const IdType& value);
GRAPHQLRESPONSE_EXPORT void Value::set<IdType>(IdType&& value);
template <>
GRAPHQLRESPONSE_EXPORT const MapType& Value::get<MapType>() const;
template <>
Expand All @@ -254,7 +314,7 @@ GRAPHQLRESPONSE_EXPORT FloatType Value::get<FloatType>() const;
template <>
GRAPHQLRESPONSE_EXPORT const ScalarType& Value::get<ScalarType>() const;
template <>
GRAPHQLRESPONSE_EXPORT IdType Value::get<IdType>() const;
GRAPHQLRESPONSE_EXPORT const IdType& Value::get<IdType>() const;
template <>
GRAPHQLRESPONSE_EXPORT MapType Value::release<MapType>();
template <>
Expand Down
16 changes: 16 additions & 0 deletions include/graphqlservice/internal/Base64.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ class Base64
// Convert a set of bytes to Base64.
GRAPHQLRESPONSE_EXPORT static std::string toBase64(const std::vector<std::uint8_t>& bytes);

enum class Comparison
{
LessThan = -1,
EqualTo = 0,
GreaterThan = 1,

InvalidBase64 = 2,
};

// Compare a set of bytes to a possible Base64 string without performing any heap allocations.
GRAPHQLRESPONSE_EXPORT static Comparison compareBase64(
const std::vector<std::uint8_t>& bytes, std::string_view maybeEncoded) noexcept;

// Validate whether or not a string is valid Base64 without performing any heap allocations.
GRAPHQLRESPONSE_EXPORT static bool validateBase64(std::string_view maybeEncoded) noexcept;

private:
static constexpr char padding = '=';

Expand Down
6 changes: 3 additions & 3 deletions include/graphqlservice/internal/Version.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@

namespace graphql::internal {

constexpr std::string_view FullVersion { "4.1.1" };
constexpr std::string_view FullVersion { "4.2.0" };

constexpr size_t MajorVersion = 4;
constexpr size_t MinorVersion = 1;
constexpr size_t PatchVersion = 1;
constexpr size_t MinorVersion = 2;
constexpr size_t PatchVersion = 0;

} // namespace graphql::internal

Expand Down
4 changes: 2 additions & 2 deletions include/graphqlservice/introspection/IntrospectionSchema.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

#include "graphqlservice/internal/Schema.h"

// Check if the library version is compatible with schemagen 4.1.0
// Check if the library version is compatible with schemagen 4.2.0
static_assert(graphql::internal::MajorVersion == 4, "regenerate with schemagen: major version mismatch");
static_assert(graphql::internal::MinorVersion == 1, "regenerate with schemagen: minor version mismatch");
static_assert(graphql::internal::MinorVersion == 2, "regenerate with schemagen: minor version mismatch");

#include <memory>
#include <string>
Expand Down
4 changes: 2 additions & 2 deletions res/ClientGen.rc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include <winver.h>

#define GRAPHQL_RC_VERSION 4,1,1,0
#define GRAPHQL_RC_VERSION_STR "4.1.1"
#define GRAPHQL_RC_VERSION 4,2,0,0
#define GRAPHQL_RC_VERSION_STR "4.2.0"

#ifndef DEBUG
#define VER_DEBUG 0
Expand Down
4 changes: 2 additions & 2 deletions res/SchemaGen.rc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include <winver.h>

#define GRAPHQL_RC_VERSION 4,1,1,0
#define GRAPHQL_RC_VERSION_STR "4.1.1"
#define GRAPHQL_RC_VERSION 4,2,0,0
#define GRAPHQL_RC_VERSION_STR "4.2.0"

#ifndef DEBUG
#define VER_DEBUG 0
Expand Down
4 changes: 2 additions & 2 deletions res/graphqlclient_version.rc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include <winver.h>

#define GRAPHQL_RC_VERSION 4,1,1,0
#define GRAPHQL_RC_VERSION_STR "4.1.1"
#define GRAPHQL_RC_VERSION 4,2,0,0
#define GRAPHQL_RC_VERSION_STR "4.2.0"

#ifndef DEBUG
#define VER_DEBUG 0
Expand Down
4 changes: 2 additions & 2 deletions res/graphqljson_version.rc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include <winver.h>

#define GRAPHQL_RC_VERSION 4,1,1,0
#define GRAPHQL_RC_VERSION_STR "4.1.1"
#define GRAPHQL_RC_VERSION 4,2,0,0
#define GRAPHQL_RC_VERSION_STR "4.2.0"

#ifndef DEBUG
#define VER_DEBUG 0
Expand Down
4 changes: 2 additions & 2 deletions res/graphqlpeg_version.rc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include <winver.h>

#define GRAPHQL_RC_VERSION 4,1,1,0
#define GRAPHQL_RC_VERSION_STR "4.1.1"
#define GRAPHQL_RC_VERSION 4,2,0,0
#define GRAPHQL_RC_VERSION_STR "4.2.0"

#ifndef DEBUG
#define VER_DEBUG 0
Expand Down
4 changes: 2 additions & 2 deletions res/graphqlresponse_version.rc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include <winver.h>

#define GRAPHQL_RC_VERSION 4,1,1,0
#define GRAPHQL_RC_VERSION_STR "4.1.1"
#define GRAPHQL_RC_VERSION 4,2,0,0
#define GRAPHQL_RC_VERSION_STR "4.2.0"

#ifndef DEBUG
#define VER_DEBUG 0
Expand Down
4 changes: 2 additions & 2 deletions res/graphqlservice_version.rc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include <winver.h>

#define GRAPHQL_RC_VERSION 4,1,1,0
#define GRAPHQL_RC_VERSION_STR "4.1.1"
#define GRAPHQL_RC_VERSION 4,2,0,0
#define GRAPHQL_RC_VERSION_STR "4.2.0"

#ifndef DEBUG
#define VER_DEBUG 0
Expand Down
Loading