Skip to content

Commit 3827f4d

Browse files
committed
feat postgresql: allow using mapped enums in ParameterStore
Tests: протестировано CI commit_hash:c67f1b9e57f0a5e5df54f542f870ea287411f7c9
1 parent 71c6457 commit 3827f4d

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

postgresql/include/userver/storages/postgres/parameter_store.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ class ParameterStore {
3232
ParameterStore& operator=(ParameterStore&&) = default;
3333

3434
/// @brief Adds a parameter to the end of the parameter list.
35-
/// @note Currently only built-in/system types are supported.
35+
/// @note Currently only enums and built-in/system types are supported.
3636
template <typename T>
3737
ParameterStore& PushBack(const T& param) {
3838
static_assert(
39-
io::IsTypeMappedToSystem<T>() || io::IsTypeMappedToSystemArray<T>(),
40-
"Currently only built-in types can be used in ParameterStore"
39+
io::IsTypeMappedToSystem<T>() || io::IsTypeMappedToSystemArray<T>() ||
40+
(std::is_enum_v<T> && io::traits::kIsMappedToPg<T> &&
41+
std::is_same_v<typename io::CppToPg<T>::Mapping, io::CppToUserPg<typename io::CppToPg<T>::Type>>),
42+
"Currently only built-in and enum types can be used in ParameterStore"
4143
);
4244
data_.Write(kNoUserTypes, param);
4345
return *this;

postgresql/src/storages/postgres/tests/enums_pgtest.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ struct storages::postgres::io::CppToUserPg<AnotherRainbow> : storages::postgres:
7979
};
8080
/*! [User enum type cpp2] */
8181

82+
namespace pg_absrnd_mvp::transaction_type {
83+
84+
enum class Enum : std::uint16_t { kPosting = 0, kHold = 1 };
85+
86+
constexpr utils::StringLiteral kPosting{"posting"};
87+
constexpr utils::StringLiteral kHold{"hold"};
88+
89+
} // namespace pg_absrnd_mvp::transaction_type
90+
8291
// Reopen the namespace not to get to the code snippet
8392
namespace storages::postgres::io {
8493

@@ -107,6 +116,17 @@ struct CppToUserPg<AnotherRainbowRO> : EnumMappingBase<AnotherRainbowRO> {
107116
};
108117
};
109118

119+
template <>
120+
struct CppToUserPg<pg_absrnd_mvp::transaction_type::Enum> : EnumMappingBase<pg_absrnd_mvp::transaction_type::Enum> {
121+
static constexpr DBTypeName postgres_name = "__pgtest.transaction_type";
122+
static constexpr USERVER_NAMESPACE::utils::TrivialBiMap enumerators = [](auto selector)
123+
{
124+
return selector()
125+
.Case(pg_absrnd_mvp::transaction_type::kPosting, pg_absrnd_mvp::transaction_type::Enum::kPosting)
126+
.Case(pg_absrnd_mvp::transaction_type::kHold, pg_absrnd_mvp::transaction_type::Enum::kHold);
127+
};
128+
};
129+
110130
namespace traits {
111131

112132
// To ensure it is never written to a buffer
@@ -358,4 +378,38 @@ UTEST_P(PostgreConnection, AutogeneratedEnumToText) {
358378
UEXPECT_NO_THROW(GetConn()->Execute(kDropTestSchema)) << "Drop schema";
359379
}
360380

381+
UTEST_P(PostgreConnection, EnumInParameterStore) {
382+
CheckConnection(GetConn());
383+
ASSERT_FALSE(GetConn()->IsReadOnly()) << "Expect a read-write connection";
384+
385+
UASSERT_NO_THROW(GetConn()->Execute(kDropTestSchema)) << "Drop schema";
386+
UASSERT_NO_THROW(GetConn()->Execute(kCreateTestSchema)) << "Create schema";
387+
388+
// 'hold' and 'posting' order intentionally does not match C++ order/values
389+
const std::string create_enum = "CREATE TYPE __pgtest.transaction_type AS enum ('hold', 'posting')";
390+
UEXPECT_NO_THROW(GetConn()->Execute(create_enum)) << "Successfully created an enumeration type";
391+
UEXPECT_NO_THROW(GetConn()->ReloadUserTypes()) << "Reload user types";
392+
393+
pg::ResultSet res{nullptr};
394+
UEXPECT_NO_THROW(res = GetConn()->Execute("SELECT $1", pg_absrnd_mvp::transaction_type::Enum::kPosting));
395+
EXPECT_EQ(pg_absrnd_mvp::transaction_type::Enum::kPosting, res[0][0].As<pg_absrnd_mvp::transaction_type::Enum>());
396+
397+
UEXPECT_NO_THROW(res = GetConn()->Execute("SELECT 'posting'::__pgtest.transaction_type"));
398+
399+
storages::postgres::ParameterStore parameter_store;
400+
parameter_store.PushBack(pg_absrnd_mvp::transaction_type::Enum::kPosting);
401+
parameter_store.PushBack(pg_absrnd_mvp::transaction_type::Enum::kHold);
402+
UEXPECT_NO_THROW(res = GetConn()->Execute("SELECT $1, $2", parameter_store));
403+
EXPECT_EQ(pg_absrnd_mvp::transaction_type::Enum::kPosting, res[0][0].As<pg_absrnd_mvp::transaction_type::Enum>());
404+
EXPECT_EQ(pg_absrnd_mvp::transaction_type::Enum::kHold, res[0][1].As<pg_absrnd_mvp::transaction_type::Enum>());
405+
406+
const std::string create_table = "CREATE TABLE __pgtest.enum_table (i INTEGER, e __pgtest.transaction_type)";
407+
UEXPECT_NO_THROW(GetConn()->Execute(create_table)) << "Successfully created a table";
408+
UEXPECT_NO_THROW(GetConn()
409+
->Execute("INSERT INTO __pgtest.enum_table(i, e) VALUES (1, $1), (2, $2)", parameter_store));
410+
UEXPECT_NO_THROW(res = GetConn()->Execute("SELECT e FROM __pgtest.enum_table ORDER BY i"));
411+
EXPECT_EQ(pg_absrnd_mvp::transaction_type::Enum::kPosting, res[0][0].As<pg_absrnd_mvp::transaction_type::Enum>());
412+
EXPECT_EQ(pg_absrnd_mvp::transaction_type::Enum::kHold, res[1][0].As<pg_absrnd_mvp::transaction_type::Enum>());
413+
}
414+
361415
USERVER_NAMESPACE_END

0 commit comments

Comments
 (0)