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/transform_io.hpp>
14#include <userver/storages/postgres/io/type_mapping.hpp>
15#include <userver/storages/postgres/io/user_types.hpp>
16#include <userver/utils/trivial_map_fwd.hpp>
18#include <userver/storages/postgres/detail/string_hash.hpp>
20USERVER_NAMESPACE_BEGIN
27template <
typename Enum>
30 std::string_view literal;
32 constexpr Enumerator(Enum en, std::string_view lit) : enumerator{en}, literal{lit} {}
39template <
typename Enum>
41 static_assert(std::is_enum<Enum>(),
"Type must be an enumeration");
48 using EnumType = Enum;
51 using Enumerator = detail::Enumerator<Enum>;
56 using EnumeratorList =
const std::initializer_list<Enumerator>;
75template <
typename Enum,
typename Enable = USERVER_NAMESPACE::
utils::void_t<>>
76struct AreEnumeratorsDefined : std::false_type {};
78template <
typename Enum>
79struct AreEnumeratorsDefined<Enum, USERVER_NAMESPACE::
utils::void_t<
decltype(CppToUserPg<Enum>::enumerators)*>>
82template <
typename Enum>
84 static_assert(std::is_enum<Enum>(),
"Type must be an enumeration");
86 AreEnumeratorsDefined<Enum>(),
87 "CppToUserPg for an enumeration must contain a static "
88 "`enumerators` member of `utils::TrivialBiMap` type or "
89 "`storages::postgres::io::detail::Enumerator[]`"
91 using Type =
decltype(CppToUserPg<Enum>::enumerators);
94template <
typename Enum,
typename =
typename Enumerators<Enum>::Type>
97template <
typename Enum,
typename T>
99 using StringType = std::string_view;
100 using EnumType = Enum;
101 using MappingType = CppToUserPg<EnumType>;
102 using EnumeratorType = Enumerator<EnumType>;
105 std::size_t operator()(EnumType v)
const {
106 using underlying_type = std::underlying_type_t<EnumType>;
107 using hasher = std::hash<underlying_type>;
108 return hasher{}(
static_cast<underlying_type>(v));
112 using EnumToString = std::unordered_map<EnumType, StringType, EnumHash>;
113 using StringToEnum = std::unordered_map<StringType, EnumType, utils::StringViewHash>;
114 using MapsPair = std::pair<EnumToString, StringToEnum>;
116 static MapsPair MapLiterals() {
118 for (
const auto& enumerator : enumerators) {
119 maps.first.insert(std::make_pair(enumerator.enumerator, enumerator.literal));
120 maps.second.insert(std::make_pair(enumerator.literal, enumerator.enumerator));
124 static const MapsPair& GetMaps() {
125 static auto maps_ = MapLiterals();
128 static const EnumToString& EnumeratorMap() {
return GetMaps().first; }
129 static const StringToEnum& LiteralMap() {
return GetMaps().second; }
132 static constexpr const auto& enumerators = MappingType::enumerators;
133 static constexpr std::size_t size = std::size(enumerators);
134 static EnumType GetEnumerator(StringType literal) {
135 static const auto& map = LiteralMap();
136 if (
auto f = map.find(literal); f != map.end()) {
141 static StringType GetLiteral(EnumType enumerator) {
142 static const auto& map = EnumeratorMap();
143 if (
auto f = map.find(enumerator); f != map.end()) {
150template <
typename Enum,
typename Func>
151class EnumerationMap<Enum,
const USERVER_NAMESPACE::
utils::TrivialBiMap<Func>> {
152 using StringType = std::string_view;
153 using EnumType = Enum;
154 using MappingType = CppToUserPg<EnumType>;
157 static constexpr const auto& enumerators = MappingType::enumerators;
158 static constexpr std::size_t size = enumerators.size();
159 static constexpr EnumType GetEnumerator(StringType literal) {
160 auto enumerator = enumerators.TryFind(literal);
161 if (enumerator.has_value())
return *enumerator;
164 static constexpr StringType GetLiteral(EnumType enumerator) {
165 auto literal = enumerators.TryFind(enumerator);
166 if (literal.has_value())
return *literal;
171template <
typename Enum>
172class EnumerationMap<Enum,
const Codegen> {
173 using EnumType = Enum;
174 using MappingType = CppToUserPg<EnumType>;
177 static EnumType GetEnumerator(std::string_view literal) {
return Parse(literal,
formats::
parse::
To<Enum>{}); }
178 static std::string GetLiteral(EnumType enumerator) {
return ToString(enumerator); }
181template <
typename Enum>
182struct EnumParser : BufferParserBase<Enum> {
183 using BaseType = BufferParserBase<Enum>;
184 using EnumMap = EnumerationMap<Enum>;
186 using BaseType::BaseType;
189 std::string_view literal;
191 this->value = EnumMap::GetEnumerator(literal);
195template <
typename Enum>
196struct EnumFormatter : BufferFormatterBase<Enum> {
197 using BaseType = BufferFormatterBase<Enum>;
198 using EnumMap = EnumerationMap<Enum>;
200 using BaseType::BaseType;
202 template <
typename Buffer>
203 void operator()(
const UserTypes& types, Buffer& buffer)
const {
204 auto literal = EnumMap::GetLiteral(
this->value);
205 io::WriteBuffer(types, buffer, literal);
209template <
typename Enum>
210struct EnumConverter {
211 using PostgresType = std::string;
212 using UserType = Enum;
214 Enum operator()(
const PostgresType& db_data)
const {
return Parse(db_data,
formats::
parse::
To<Enum>()); }
216 PostgresType operator()(
const Enum& user_data)
const {
return ToString(user_data); }
220auto HasParseImpl(...) -> std::false_type;
222template <
typename Enum>
223auto HasParseImpl(
int)
224 ->
decltype(Parse(std::declval<std::string_view>(), std::declval<
formats::
parse::
To<Enum>>()), std::true_type{});
226template <
typename Enum>
227struct HasParse :
decltype(storages::
postgres::io::detail::HasParseImpl<Enum>(0)) {};
230auto HasToStringImpl(...) -> std::false_type;
232template <
typename Enum>
233auto HasToStringImpl(
int) ->
decltype(ToString(std::declval<Enum>()), std::true_type{});
235template <
typename Enum>
236struct HasToString :
decltype(storages::
postgres::io::detail::HasToStringImpl<Enum>(0)) {};
243struct Input<T, std::enable_if_t<std::is_enum<T>() && !detail::kCustomParserDefined<T> &&
IsMappedToUserType<T>()>> {
244 using type = io::detail::EnumParser<T>;
254 std::enable_if_t<std::is_enum<T>() && !detail::kCustomFormatterDefined<T> &&
IsMappedToUserType<T>()>> {
255 using type = io::detail::EnumFormatter<T>;
261template <
typename Enum>
265 std::is_enum<Enum>() && !detail::kCustomParserDefined<Enum> && !
IsMappedToUserType<Enum>() &&
266 storages::
postgres::io::detail::HasToString<Enum>::value>> {
273template <
typename Enum>
277 std::is_enum<Enum>() && !detail::kCustomFormatterDefined<Enum> && !
IsMappedToUserType<Enum>() &&
278 storages::
postgres::io::detail::HasParse<Enum>::value>> {