8#include <unordered_map>
10#include <userver/storages/postgres/io/buffer_io.hpp>
11#include <userver/storages/postgres/io/buffer_io_base.hpp>
12#include <userver/storages/postgres/io/pg_types.hpp>
13#include <userver/storages/postgres/io/type_mapping.hpp>
14#include <userver/storages/postgres/io/user_types.hpp>
15#include <userver/utils/trivial_map_fwd.hpp>
17#include <userver/storages/postgres/detail/string_hash.hpp>
19USERVER_NAMESPACE_BEGIN
72template <
typename Enum>
75 std::string_view literal;
77 constexpr Enumerator(Enum en, std::string_view lit)
78 : enumerator{en}, literal{lit} {}
85template <
typename Enum>
87 static_assert(std::is_enum<Enum>(),
"Type must be an enumeration");
93 using EnumType = Enum;
95 using Enumerator = detail::Enumerator<Enum>;
99 using EnumeratorList =
const std::initializer_list<Enumerator>;
104template <
typename Enum,
typename Enable = USERVER_NAMESPACE::utils::void_t<>>
105struct AreEnumeratorsDefined : std::false_type {};
107template <
typename Enum>
108struct AreEnumeratorsDefined<
110 USERVER_NAMESPACE::utils::void_t<
decltype(CppToUserPg<Enum>::enumerators)*>>
113template <
typename Enum>
115 static_assert(std::is_enum<Enum>(),
"Type must be an enumeration");
116 static_assert(AreEnumeratorsDefined<Enum>(),
117 "CppToUserPg for an enumeration must contain a static "
118 "`enumerators` member of `utils::TrivialBiMap` type or "
119 "`storages::postgres::io::detail::Enumerator[]`");
120 using Type =
decltype(CppToUserPg<Enum>::enumerators);
123template <
typename Enum,
typename =
typename Enumerators<Enum>::Type>
126template <
typename Enum,
typename T>
127class EnumerationMap {
128 using StringType = std::string_view;
129 using EnumType = Enum;
130 using MappingType = CppToUserPg<EnumType>;
131 using EnumeratorType = Enumerator<EnumType>;
134 std::size_t operator()(EnumType v)
const {
135 using underlying_type = std::underlying_type_t<EnumType>;
136 using hasher = std::hash<underlying_type>;
137 return hasher{}(
static_cast<underlying_type>(v));
141 using EnumToString = std::unordered_map<EnumType, StringType, EnumHash>;
143 std::unordered_map<StringType, EnumType, utils::StringViewHash>;
144 using MapsPair = std::pair<EnumToString, StringToEnum>;
146 static MapsPair MapLiterals() {
148 for (
const auto& enumerator : enumerators) {
150 std::make_pair(enumerator.enumerator, enumerator.literal));
152 std::make_pair(enumerator.literal, enumerator.enumerator));
156 static const MapsPair& GetMaps() {
157 static auto maps_ = MapLiterals();
160 static const EnumToString& EnumeratorMap() {
return GetMaps().first; }
161 static const StringToEnum& LiteralMap() {
return GetMaps().second; }
164 static constexpr const auto& enumerators = MappingType::enumerators;
165 static constexpr std::size_t size = std::size(enumerators);
166 static EnumType GetEnumerator(StringType literal) {
167 static const auto& map = LiteralMap();
168 if (
auto f = map.find(literal); f != map.end()) {
171 throw InvalidEnumerationLiteral{
172 compiler::GetTypeName<EnumType>(),
173 std::string{literal.data(), literal.size()}};
175 static StringType GetLiteral(EnumType enumerator) {
176 static const auto& map = EnumeratorMap();
177 if (
auto f = map.find(enumerator); f != map.end()) {
184template <
typename Enum,
typename Func>
185class EnumerationMap<Enum,
const USERVER_NAMESPACE::
utils::TrivialBiMap<Func>> {
186 using StringType = std::string_view;
187 using EnumType = Enum;
188 using MappingType = CppToUserPg<EnumType>;
191 static constexpr const auto& enumerators = MappingType::enumerators;
192 static constexpr std::size_t size = enumerators.size();
193 static constexpr EnumType GetEnumerator(StringType literal) {
194 auto enumerator = enumerators.TryFind(literal);
195 if (enumerator.has_value())
return *enumerator;
196 throw InvalidEnumerationLiteral{
197 compiler::GetTypeName<EnumType>(),
198 std::string{literal.data(), literal.size()}};
200 static constexpr StringType GetLiteral(EnumType enumerator) {
201 auto literal = enumerators.TryFind(enumerator);
202 if (literal.has_value())
return *literal;
207template <
typename Enum>
208struct EnumParser : BufferParserBase<Enum> {
209 using BaseType = BufferParserBase<Enum>;
210 using EnumMap = EnumerationMap<Enum>;
212 using BaseType::BaseType;
215 std::string_view literal;
216 io::ReadBuffer(buffer, literal);
217 this->value = EnumMap::GetEnumerator(literal);
221template <
typename Enum>
222struct EnumFormatter : BufferFormatterBase<Enum> {
223 using BaseType = BufferFormatterBase<Enum>;
224 using EnumMap = EnumerationMap<Enum>;
226 using BaseType::BaseType;
228 template <
typename Buffer>
229 void operator()(
const UserTypes& types, Buffer& buffer)
const {
230 auto literal = EnumMap::GetLiteral(
this->value);
231 io::WriteBuffer(types, buffer, literal);