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>
80 static_assert(std::is_enum<Enum>(),
"Type must be an enumeration");
82 requires { CppToUserPg<Enum>::enumerators; },
83 "CppToUserPg for an enumeration must contain a static `enumerators` member of `utils::TrivialBiMap` type or "
84 "`storages::postgres::io::detail::Enumerator[]`."
86 using Type =
decltype(CppToUserPg<Enum>::enumerators);
89template <
typename Enum,
typename =
typename Enumerators<Enum>::Type>
92template <
typename Enum,
typename T>
94 using StringType = std::string_view;
95 using EnumType = Enum;
96 using MappingType = CppToUserPg<EnumType>;
97 using EnumeratorType = Enumerator<EnumType>;
100 std::size_t operator()(EnumType v)
const {
101 using underlying_type = std::underlying_type_t<EnumType>;
102 using hasher = std::hash<underlying_type>;
103 return hasher{}(
static_cast<underlying_type>(v));
107 using EnumToString = std::unordered_map<EnumType, StringType, EnumHash>;
108 using StringToEnum = std::unordered_map<StringType, EnumType, utils::StringViewHash>;
109 using MapsPair = std::pair<EnumToString, StringToEnum>;
111 static MapsPair MapLiterals() {
113 for (
const auto& enumerator : enumerators) {
114 maps.first.insert(std::make_pair(enumerator.enumerator, enumerator.literal));
115 maps.second.insert(std::make_pair(enumerator.literal, enumerator.enumerator));
119 static const MapsPair& GetMaps() {
120 static auto maps = MapLiterals();
123 static const EnumToString& EnumeratorMap() {
return GetMaps().first; }
124 static const StringToEnum& LiteralMap() {
return GetMaps().second; }
127 static constexpr const auto& enumerators = MappingType::enumerators;
128 static constexpr std::size_t size = std::size(enumerators);
129 static EnumType GetEnumerator(StringType literal) {
130 static const auto& map = LiteralMap();
131 if (
auto f = map.find(literal); f != map.end()) {
136 static StringType GetLiteral(EnumType enumerator) {
137 static const auto& map = EnumeratorMap();
138 if (
auto f = map.find(enumerator); f != map.end()) {
145template <
typename Enum,
typename Func>
146class EnumerationMap<Enum,
const USERVER_NAMESPACE::
utils::TrivialBiMap<Func>> {
147 using StringType = std::string_view;
148 using EnumType = Enum;
149 using MappingType = CppToUserPg<EnumType>;
152 static constexpr const auto& enumerators = MappingType::enumerators;
153 static constexpr std::size_t size = enumerators.size();
154 static constexpr EnumType GetEnumerator(StringType literal) {
155 auto enumerator = enumerators.TryFind(literal);
156 if (enumerator.has_value()) {
161 static constexpr StringType GetLiteral(EnumType enumerator) {
162 auto literal = enumerators.TryFind(enumerator);
163 if (literal.has_value()) {
170template <
typename Enum>
171class EnumerationMap<Enum,
const Codegen> {
172 using EnumType = Enum;
173 using MappingType = CppToUserPg<EnumType>;
176 static EnumType GetEnumerator(std::string_view literal) {
return Parse(literal, formats::
parse::To<Enum>{}); }
177 static std::string GetLiteral(EnumType enumerator) {
return ToString(enumerator); }
180template <
typename Enum>
181struct EnumParser : BufferParserBase<Enum> {
182 using BaseType = BufferParserBase<Enum>;
183 using EnumMap = EnumerationMap<Enum>;
185 using BaseType::BaseType;
188 std::string_view literal;
190 this->value = EnumMap::GetEnumerator(literal);
194template <
typename Enum>
195struct EnumFormatter : BufferFormatterBase<Enum> {
196 using BaseType = BufferFormatterBase<Enum>;
197 using EnumMap = EnumerationMap<Enum>;
199 using BaseType::BaseType;
201 template <
typename Buffer>
202 void operator()(
const UserTypes& types, Buffer& buffer)
const {
203 auto literal = EnumMap::GetLiteral(
this->value);
204 io::WriteBuffer(types, buffer, literal);
208template <
typename Enum>
209struct EnumConverter {
210 using PostgresType = std::string;
211 using UserType = Enum;
213 Enum operator()(
const PostgresType& db_data)
const {
return Parse(db_data, formats::
parse::To<Enum>()); }
215 PostgresType operator()(
const Enum& user_data)
const {
return ToString(user_data); }
218template <
typename Enum>
219concept HasParse =
requires(std::string_view sw) { Parse(sw, formats::
parse::To<Enum>{}); };
221template <
typename Enum>
222concept HasToString =
requires(Enum e) { ToString(e); };
229struct Input<T, std::enable_if_t<std::is_enum_v<T> && !detail::CustomParserDefined<T> && IsMappedToUserType<T>>> {
230 using type =
io::detail::EnumParser<T>;
238struct Output<T, std::enable_if_t<std::is_enum_v<T> && !detail::CustomFormatterDefined<T> && IsMappedToUserType<T>>> {
239 using type =
io::detail::EnumFormatter<T>;
245template <
typename Enum>
249 std::is_enum_v<Enum> && !detail::CustomParserDefined<Enum> && !IsMappedToUserType<Enum> &&
250 storages::
postgres::
io::detail::HasToString<Enum>>> {
257template <
typename Enum>
261 std::is_enum_v<Enum> && !detail::CustomFormatterDefined<Enum> && !IsMappedToUserType<Enum> &&
262 storages::
postgres::
io::detail::HasParse<Enum>>> {