Skip to content

Commit

Permalink
-
Browse files Browse the repository at this point in the history
  • Loading branch information
sabudilovskiy committed Oct 17, 2023
1 parent 97aecbe commit d795a55
Show file tree
Hide file tree
Showing 14 changed files with 500 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/openapi/base/holder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

#include <cstddef>
#include <utils/constexpr_string.hpp>
namespace openapi::traits
{
template <typename T>
struct HolderField
{
T value_{};
size_t counter_changes{};
void operator=(const T& t)
{
value_ = t;
counter_changes++;
}
T& operator()()
{
return value_;
}
const T& operator()() const
{
return value_;
}
};

template <>
struct HolderField<utils::FixedString>
{
utils::FixedString value_{};
size_t counter_changes{};
template <size_t Size>
constexpr void operator=(const utils::ConstexprString<Size>& t)
{
for (size_t index = 0; index < Size; index++)
{
value_[index] = t[index];
}
for (size_t index = Size; index < 256; index++)
{
value_[index] = '\0';
}
counter_changes++;
}
constexpr const utils::FixedString& operator()() const
{
return value_;
}
};
} // namespace openapi::traits
9 changes: 9 additions & 0 deletions src/openapi/base/reflective_uuid_fix.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once
#include <boost/uuid/uuid.hpp>
#include <openapi/base/reflective_checks.hpp>

namespace openapi
{
template <>
constexpr inline bool checks::is_reflective_v<boost::uuids::uuid> = false;
}
68 changes: 68 additions & 0 deletions src/openapi/base/uuid_property.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#pragma once
#include <boost/uuid/uuid.hpp>
#include <compare>
#include <openapi/base/property_base.hpp>

namespace openapi
{
template <typename Traits>
struct PropertyBase<boost::uuids::uuid, Traits>
{
using value_type = boost::uuids::uuid;
using traits = Traits;

template <typename... Args>
PropertyBase(Args&&... args) : value(std::forward<Args>(args)...)
{
}

template <typename Arg>
PropertyBase(std::initializer_list<Arg> init_list)
: value(std::move(init_list))
{
}

std::partial_ordering operator<=>(
const PropertyBase<value_type, Traits>& r) const
{
return *this <=> r();
}
std::partial_ordering operator<=>(const value_type& r) const
{
if (value == r)
{
return std::partial_ordering::equivalent;
}
else
return std::partial_ordering::unordered;
}

bool operator==(const PropertyBase<value_type, Traits>& r) const = default;

template <class Arg>
value_type& operator=(Arg&& arg)
{
value = std::forward<Arg>(arg);
return value;
}
value_type& operator()()
{
return value;
}
const value_type& operator()() const
{
return value;
}
value_type value;
};

template <typename Traits>
struct UuidProperty : PropertyBase<boost::uuids::uuid, Traits>
{
};

template <typename Traits>
struct Property<boost::uuids::uuid, Traits> : UuidProperty<Traits>
{
};
} // namespace openapi
12 changes: 12 additions & 0 deletions src/openapi/base/uuid_traits.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include <openapi/base/named_traits.hpp>

namespace openapi::traits
{
template <typename Traits>
struct UuidHelperTraits : NamedHelperTraits<Traits>
{
};

} // namespace openapi::traits
18 changes: 18 additions & 0 deletions src/openapi/doc/serialize/uuid.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once
#include <openapi/base/uuid_property.hpp>
#include <openapi/base/uuid_traits.hpp>
#include <openapi/doc/serialize/base.hpp>

namespace openapi
{
template <typename Traits>
void Append(DocHelper doc_helper, std::type_identity<UuidProperty<Traits>> = {})
{
constexpr traits::UuidHelperTraits<Traits> traits;
auto& field_node = doc_helper.cur_place;
if (!field_node.IsObject())
field_node = userver::formats::common::Type::kObject;
field_node["type"] = "string";
field_node["format"] = "uuid";
}
} // namespace openapi
25 changes: 25 additions & 0 deletions src/openapi/json/parse/base_property.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <array>
#include <boost/pfr.hpp>
#include <boost/pfr/core.hpp>
#include <exception>
#include <openapi/base/named_traits.hpp>
#include <openapi/base/property_base.hpp>
#include <optional>
#include <stdexcept>
#include <string_view>
#include <unordered_map>
#include <userver/formats/json/value.hpp>
#include <userver/formats/parse/to.hpp>
#include <userver/utils/overloaded.hpp>
#include <utils/constexpr_string.hpp>

namespace userver::formats::parse
{
template <typename T>
requires openapi::IsProperty<T> T Parse(const json::Value& item, To<T>)
{
return T{item.As<typename T::value_type>()};
}
} // namespace userver::formats::parse
21 changes: 21 additions & 0 deletions src/openapi/json/serialize/base_property.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <openapi/base/property_base.hpp>
#include <string_view>
#include <unordered_map>
#include <userver/formats/json/value.hpp>
#include <userver/formats/json/value_builder.hpp>
#include <userver/formats/parse/to.hpp>
#include <userver/utils/overloaded.hpp>
#include <utils/constexpr_string.hpp>

namespace openapi
{
template <typename T, typename Traits>
userver::formats::json::Value Serialize(
const PropertyBase<T, Traits>& value,
userver::formats::serialize::To<userver::formats::json::Value> s)
{
return Serialize(value(), s);
}
} // namespace openapi
71 changes: 71 additions & 0 deletions src/openapi/types/uuid_type.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#pragma once
#include <openapi/base/holder.hpp>
#include <openapi/base/named_traits.hpp>
#include <openapi/base/preferences.hpp>
#include <openapi/base/uuid_property.hpp>
#include <string_view>
#include <utils/compilers_macros.hpp>
#include <utils/constexpr_string.hpp>

namespace openapi
{
namespace detail
{
template <utils::ConstexprString Name>
struct UuidTraits : NamedTraits<Name>
{
};

struct UuidTraitsHolder
{
traits::HolderField<utils::FixedString> name;
};

template <utils::ConstexprString value>
void consteval Apply(UuidTraitsHolder& traits, preferences::Name<value>)
{
traits.name = value;
}

template <typename T>
void consteval Apply(UuidTraitsHolder&, const T&)
{
STATIC_ASSERT_FALSE("You are used unknown option");
}

template <typename... Option>
void consteval ApplyAll(UuidTraitsHolder& traits, Option... option)
{
(Apply(traits, option), ...);
}

template <typename... Option>
struct UuidHelper
{
consteval static auto resolve_holder()
{
UuidTraitsHolder helper{};
ApplyAll(helper, Option{}...);
return helper;
}
consteval static auto resolve_traits()
{
constexpr UuidTraitsHolder traits = resolve_holder();
static_assert(traits.name.counter_changes <= 1,
"Don't use more 1 Name in template args");
constexpr auto name = utils::MakeConstexprString<traits.name.value_>();
return UuidTraits<name>{};
}
};

template <typename... Option>
using uuid_traits_helper_t = decltype(UuidHelper<Option...>::resolve_traits());
} // namespace detail

namespace types
{
template <typename... Option>
using Uuid = UuidProperty<detail::uuid_traits_helper_t<Option...>>;

}
} // namespace openapi
12 changes: 12 additions & 0 deletions src/utils/serialize/uuid/string.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "string.hpp"

#include <boost/uuid/uuid_io.hpp>

namespace userver::formats::serialize
{
std::string Serialize(const boost::uuids::uuid& value,
userver::formats::serialize::To<std::string>)
{
return to_string(value);
}
} // namespace userver::formats::serialize
10 changes: 10 additions & 0 deletions src/utils/serialize/uuid/string.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <boost/uuid/uuid.hpp>
#include <string>
#include <userver/formats/serialize/to.hpp>
namespace userver::formats::serialize
{
std::string Serialize(const boost::uuids::uuid& value,
userver::formats::serialize::To<std::string>);
}
71 changes: 71 additions & 0 deletions utests/openapi/http/uuid_request.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include <gtest/gtest.h>

#include <boost/lexical_cast.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <exception>
#include <openapi/all.hpp>
#include <string_view>
#include <userver/formats/parse/boost_uuid.hpp>
#include <userver/formats/parse/common_containers.hpp>
#include <userver/utest/utest.hpp>
#include <utils/parse/uuid/string.hpp>
#include <utils/tests_macros.hpp>

using namespace openapi::http;
using namespace openapi::preferences;
using namespace openapi::types;
using namespace std::literals;

namespace
{
struct SomeBody
{
Uuid<Name<"some_uuid">> some_uuid;
Array<Uuid<>, Name<"some_array">> some_array;
auto operator<=>(const SomeBody&) const = default;
};

struct SomeRequest
{
Header<boost::uuids::uuid, Name<"some_header">> some_header;
Cookie<boost::uuids::uuid, Name<"some_cookie">> some_cookie;
Body<SomeBody> some_body;
auto operator<=>(const SomeRequest&) const = default;
};

boost::uuids::uuid UUID(std::string_view sv)
{
return boost::lexical_cast<boost::uuids::uuid>(sv);
}

} // namespace

UTEST(Openapi_http_request_parse, BasicUuid)
{
TestRequest req;
req.body = R"(
{
"some_uuid" : "2550a976-434f-4e9c-a5da-06fe0ddbfe5d",
"some_array" : ["6ee2dc21-7229-42b9-8fb9-39a49f38d836", "f757748c-03a8-4834-ad2c-e2fe9c03f1e7"]
}
)";

req.headers["some_header"sv] = "6483030f-dcf7-4779-8fbe-e78113bec72e";
req.cookies["some_cookie"] = "314e672f-687c-4001-8df9-3be5d268a0b6";
auto info = MakeInfoFromRequest(req);
auto parsed = Parse(info, userver::formats::parse::To<SomeRequest>{});
// clang-format off
SomeRequest expected{
.some_header = {UUID("6483030f-dcf7-4779-8fbe-e78113bec72e")},
.some_cookie = {UUID("314e672f-687c-4001-8df9-3be5d268a0b6")},
.some_body = {SomeBody{
.some_uuid = {UUID("2550a976-434f-4e9c-a5da-06fe0ddbfe5d")},
.some_array = {}
}}
};
expected.some_body().some_array().emplace_back(Uuid<>{UUID("6ee2dc21-7229-42b9-8fb9-39a49f38d836")});
expected.some_body().some_array().emplace_back(Uuid<>{UUID("f757748c-03a8-4834-ad2c-e2fe9c03f1e7")});
// clang-format on
EXPECT_EQ(parsed, expected);
}
Loading

0 comments on commit d795a55

Please sign in to comment.