From e68005339a403cfb788a44a298179fac50b1dd3e Mon Sep 17 00:00:00 2001 From: Nikolay Pervushin Date: Mon, 23 Dec 2024 18:35:29 +0300 Subject: [PATCH] feat redis: add support for GT and LT flags in ZADD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for `GT` and `LT` flags in `ZADD` and tests. P.S: I didn't find which version it started, so I use 6.2.0. In 6.0 it does not work Tests: протестировано CI Pull Request resolved: https://github.com/userver-framework/userver/pull/777 commit_hash:9acec1b79bb1bb4a476fda9a95ea2fd49250dad7 --- .../storages/redis/command_options.hpp | 38 ++++++++++++++++--- redis/src/storages/redis/client_redistest.cpp | 34 +++++++++++++++++ redis/src/storages/redis/impl/cmd_args.cpp | 5 +++ 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/redis/include/userver/storages/redis/command_options.hpp b/redis/include/userver/storages/redis/command_options.hpp index 985c61ec7d8d..382eec400cf1 100644 --- a/redis/include/userver/storages/redis/command_options.hpp +++ b/redis/include/userver/storages/redis/command_options.hpp @@ -55,23 +55,51 @@ struct GeosearchOptions { struct ZaddOptions { enum class Exist { kAddAlways, kAddIfNotExist, kAddIfExist }; + enum class Compare { kNone, kGreaterThan, kLessThan }; enum class ReturnValue { kAddedCount, kChangedCount }; ZaddOptions() = default; - constexpr ZaddOptions(Exist exist, ReturnValue return_value = ReturnValue::kAddedCount) - : exist(exist), return_value(return_value) {} - constexpr ZaddOptions(ReturnValue return_value, Exist exist = Exist::kAddAlways) - : exist(exist), return_value(return_value) {} + constexpr ZaddOptions( + Exist exist, + ReturnValue return_value = ReturnValue::kAddedCount, + Compare compare = Compare::kNone + ) + : exist(exist), compare(compare), return_value(return_value) {} + constexpr ZaddOptions(Exist exist, Compare compare, ReturnValue return_value = ReturnValue::kAddedCount) + : exist(exist), compare(compare), return_value(return_value) {} + + constexpr ZaddOptions(ReturnValue return_value, Exist exist = Exist::kAddAlways, Compare compare = Compare::kNone) + : exist(exist), compare(compare), return_value(return_value) {} + constexpr ZaddOptions(ReturnValue return_value, Compare compare, Exist exist = Exist::kAddAlways) + : exist(exist), compare(compare), return_value(return_value) {} + + constexpr ZaddOptions( + Compare compare, + Exist exist = Exist::kAddAlways, + ReturnValue return_value = ReturnValue::kAddedCount + ) + : exist(exist), compare(compare), return_value(return_value) {} + constexpr ZaddOptions(Compare compare, ReturnValue return_value, Exist exist = Exist::kAddAlways) + : exist(exist), compare(compare), return_value(return_value) {} Exist exist = Exist::kAddAlways; + Compare compare = Compare::kNone; ReturnValue return_value = ReturnValue::kAddedCount; }; constexpr ZaddOptions operator|(ZaddOptions::Exist exist, ZaddOptions::ReturnValue return_value) { return {exist, return_value}; } +constexpr ZaddOptions operator|(ZaddOptions::Exist exist, ZaddOptions::Compare compare) { return {exist, compare}; } +constexpr ZaddOptions operator|(ZaddOptions::Compare compare, ZaddOptions::Exist exist) { return {compare, exist}; } +constexpr ZaddOptions operator|(ZaddOptions::Compare compare, ZaddOptions::ReturnValue return_value) { + return {compare, return_value}; +} constexpr ZaddOptions operator|(ZaddOptions::ReturnValue return_value, ZaddOptions::Exist exist) { - return {exist, return_value}; + return {return_value, exist}; +} +constexpr ZaddOptions operator|(ZaddOptions::ReturnValue return_value, ZaddOptions::Compare compare) { + return {return_value, compare}; } class ScanOptionsBase { diff --git a/redis/src/storages/redis/client_redistest.cpp b/redis/src/storages/redis/client_redistest.cpp index 1504f918cabf..a86edd215d60 100644 --- a/redis/src/storages/redis/client_redistest.cpp +++ b/redis/src/storages/redis/client_redistest.cpp @@ -697,6 +697,40 @@ UTEST_F(RedisClientTest, Zadd) { EXPECT_FALSE(client->ZaddIncrExisting("zset", 1.1, "five", {}).Get().has_value()); } +UTEST_F(RedisClientTest, ZaddGtLt) { + Version since{6, 2, 0}; + if (!CheckVersion(since)) GTEST_SKIP() << SkipMsgByVersion("Zadd gt/lt", since); + + auto client = GetClient(); + + storages::redis::ZaddOptions options; + options.compare = storages::redis::ZaddOptions::Compare::kGreaterThan; + EXPECT_EQ(client->Zadd("zset_gt_lt", {{1., "one"}, {3., "two"}}, options, {}).Get(), 2); + EXPECT_EQ(client->Zscore("zset_gt_lt", "one", {}).Get(), 1); + EXPECT_EQ(client->Zscore("zset_gt_lt", "two", {}).Get(), 3); + + EXPECT_EQ(client->Zadd("zset_gt_lt", {{3., "one"}, {1., "two"}}, options, {}).Get(), 0); + EXPECT_EQ(client->Zscore("zset_gt_lt", "one", {}).Get(), 3); + EXPECT_EQ(client->Zscore("zset_gt_lt", "two", {}).Get(), 3); + + EXPECT_EQ(client->Zadd("zset_gt_lt", {{4., "one"}, {4., "two"}}, options, {}).Get(), 0); + EXPECT_EQ(client->Zscore("zset_gt_lt", "one", {}).Get(), 4); + EXPECT_EQ(client->Zscore("zset_gt_lt", "two", {}).Get(), 4); + + options.compare = storages::redis::ZaddOptions::Compare::kLessThan; + EXPECT_EQ(client->Zadd("zset_gt_lt", {{3., "one"}, {5., "two"}}, options, {}).Get(), 0); + EXPECT_EQ(client->Zscore("zset_gt_lt", "one", {}).Get(), 3); + EXPECT_EQ(client->Zscore("zset_gt_lt", "two", {}).Get(), 4); + + EXPECT_EQ(client->Zadd("zset_gt_lt", {{5., "one"}, {3., "two"}}, options, {}).Get(), 0); + EXPECT_EQ(client->Zscore("zset_gt_lt", "one", {}).Get(), 3); + EXPECT_EQ(client->Zscore("zset_gt_lt", "two", {}).Get(), 3); + + EXPECT_EQ(client->Zadd("zset_gt_lt", {{1., "one"}, {1., "two"}}, options, {}).Get(), 0); + EXPECT_EQ(client->Zscore("zset_gt_lt", "one", {}).Get(), 1); + EXPECT_EQ(client->Zscore("zset_gt_lt", "two", {}).Get(), 1); +} + UTEST_F(RedisClientTest, Zcard) { auto client = GetClient(); diff --git a/redis/src/storages/redis/impl/cmd_args.cpp b/redis/src/storages/redis/impl/cmd_args.cpp index 085d5327bcbd..1a36115cc915 100644 --- a/redis/src/storages/redis/impl/cmd_args.cpp +++ b/redis/src/storages/redis/impl/cmd_args.cpp @@ -139,6 +139,11 @@ void PutArg(CmdArgs::CmdArgsArray& args_, const ZaddOptions& arg) { else if (arg.exist == ZaddOptions::Exist::kAddIfExist) args_.emplace_back("XX"); + if (arg.compare == ZaddOptions::Compare::kGreaterThan) + args_.emplace_back("GT"); + else if (arg.compare == ZaddOptions::Compare::kLessThan) + args_.emplace_back("LT"); + if (arg.return_value == ZaddOptions::ReturnValue::kChangedCount) args_.emplace_back("CH"); }