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)
42template <
typename Enum>
44 static_assert(std::is_enum<Enum>(),
"Type must be an enumeration");
51 using EnumType = Enum;
54 using Enumerator = detail::Enumerator<Enum>;
59 using EnumeratorList =
const std::initializer_list<Enumerator>;
78template <
typename Enum,
typename Enable = USERVER_NAMESPACE::utils::void_t<>>
79struct AreEnumeratorsDefined : std::false_type {};
81template <
typename Enum>
82struct AreEnumeratorsDefined<Enum, USERVER_NAMESPACE::utils::void_t<
decltype(CppToUserPg<Enum>::enumerators)*>>
85template <
typename Enum>
87 static_assert(std::is_enum<Enum>(),
"Type must be an enumeration");
89 AreEnumeratorsDefined<Enum>(),
90 "CppToUserPg for an enumeration must contain a static "
91 "`enumerators` member of `utils::TrivialBiMap` type or "
92 "`storages::postgres::io::detail::Enumerator[]`"
94 using Type =
decltype(CppToUserPg<Enum>::enumerators);
97template <
typename Enum,
typename =
typename Enumerators<Enum>::Type>
100template <
typename Enum,
typename T>
101class EnumerationMap {
102 using StringType = std::string_view;
103 using EnumType = Enum;
104 using MappingType = CppToUserPg<EnumType>;
105 using EnumeratorType = Enumerator<EnumType>;
108 std::size_t operator()(EnumType v)
const {
109 using underlying_type = std::underlying_type_t<EnumType>;
110 using hasher = std::hash<underlying_type>;
111 return hasher{}(
static_cast<underlying_type>(v));
115 using EnumToString = std::unordered_map<EnumType, StringType, EnumHash>;
116 using StringToEnum = std::unordered_map<StringType, EnumType, utils::StringViewHash>;
117 using MapsPair = std::pair<EnumToString, StringToEnum>;
119 static MapsPair MapLiterals() {
121 for (
const auto& enumerator : enumerators) {
122 maps.first.insert(std::make_pair(enumerator.enumerator, enumerator.literal));
123 maps.second.insert(std::make_pair(enumerator.literal, enumerator.enumerator));
127 static const MapsPair& GetMaps() {
128 static auto maps = MapLiterals();
131 static const EnumToString& EnumeratorMap() {
return GetMaps().first; }
132 static const StringToEnum& LiteralMap() {
return GetMaps().second; }
135 static constexpr const auto& enumerators = MappingType::enumerators;
136 static constexpr std::size_t size = std::size(enumerators);
137 static EnumType GetEnumerator(StringType literal) {
138 static const auto& map = LiteralMap();
139 if (
auto f = map.find(literal); f != map.end()) {
144 static StringType GetLiteral(EnumType enumerator) {
145 static const auto& map = EnumeratorMap();
146 if (
auto f = map.find(enumerator); f != map.end()) {
153template <
typename Enum,
typename Func>
154class EnumerationMap<Enum,
const USERVER_NAMESPACE::utils::TrivialBiMap<Func>> {
155 using StringType = std::string_view;
156 using EnumType = Enum;
157 using MappingType = CppToUserPg<EnumType>;
160 static constexpr const auto& enumerators = MappingType::enumerators;
161 static constexpr std::size_t size = enumerators.size();
162 static constexpr EnumType GetEnumerator(StringType literal) {
163 auto enumerator = enumerators.TryFind(literal);
164 if (enumerator.has_value()) {
169 static constexpr StringType GetLiteral(EnumType enumerator) {
170 auto literal = enumerators.TryFind(enumerator);
171 if (literal.has_value()) {
178template <
typename Enum>
179class EnumerationMap<Enum,
const Codegen> {
180 using EnumType = Enum;
181 using MappingType = CppToUserPg<EnumType>;
184 static EnumType GetEnumerator(std::string_view literal) {
return Parse(literal,
formats::
parse::
To<Enum>{}); }
185 static std::string GetLiteral(EnumType enumerator) {
return ToString(enumerator); }
188template <
typename Enum>
189struct EnumParser : BufferParserBase<Enum> {
190 using BaseType = BufferParserBase<Enum>;
191 using EnumMap = EnumerationMap<Enum>;
193 using BaseType::BaseType;
196 std::string_view literal;
198 this->value = EnumMap::GetEnumerator(literal);
202template <
typename Enum>
203struct EnumFormatter : BufferFormatterBase<Enum> {
204 using BaseType = BufferFormatterBase<Enum>;
205 using EnumMap = EnumerationMap<Enum>;
207 using BaseType::BaseType;
209 template <
typename Buffer>
210 void operator()(
const UserTypes& types, Buffer& buffer)
const {
211 auto literal = EnumMap::GetLiteral(
this->value);
212 io::WriteBuffer(types, buffer, literal);
216template <
typename Enum>
217struct EnumConverter {
218 using PostgresType = std::string;
219 using UserType = Enum;
221 Enum operator()(
const PostgresType& db_data)
const {
return Parse(db_data,
formats::
parse::
To<Enum>()); }
223 PostgresType operator()(
const Enum& user_data)
const {
return ToString(user_data); }
227auto HasParseImpl(...) -> std::false_type;
229template <
typename Enum>
231) ->
decltype(Parse(std::declval<std::string_view>(), std::declval<
formats::
parse::
To<Enum>>()), std::true_type{});
233template <
typename Enum>
234struct HasParse :
decltype(storages::
postgres::io::detail::HasParseImpl<Enum>(0)) {};
237auto HasToStringImpl(...) -> std::false_type;
239template <
typename Enum>
240auto HasToStringImpl(
int) ->
decltype(ToString(std::declval<Enum>()), std::true_type{});
242template <
typename Enum>
243struct HasToString :
decltype(storages::
postgres::io::detail::HasToStringImpl<Enum>(0)) {};
250struct Input<T, std::enable_if_t<std::is_enum<T>() && !detail::kCustomParserDefined<T> &&
IsMappedToUserType<T>()>> {
251 using type = io::detail::EnumParser<T>;
261 using type = io::detail::EnumFormatter<T>;
267template <
typename Enum>
271 std::is_enum<Enum>() && !detail::kCustomParserDefined<Enum> && !
IsMappedToUserType<Enum>() &&
272 storages::
postgres::io::detail::HasToString<Enum>::value>> {
279template <
typename Enum>
283 std::is_enum<Enum>() && !detail::kCustomFormatterDefined<Enum> && !
IsMappedToUserType<Enum>() &&
284 storages::
postgres::io::detail::HasParse<Enum>::value>> {