Skip to content

Commit 180d978

Browse files
authored
Set with get option (#662)
* support set_with_get_option (#658) * test set_with_get_option
1 parent fc67c2e commit 180d978

File tree

11 files changed

+271
-1
lines changed

11 files changed

+271
-1
lines changed

src/sw/redis++/async_redis.h

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ class AsyncRedis {
407407
Future<void> mset(std::initializer_list<T> il) {
408408
return mset(il.begin(), il.end());
409409
}
410-
410+
411411
template <typename Input, typename Callback>
412412
auto mset(Input first, Input last, Callback &&cb)
413413
-> typename std::enable_if<IsInvocable<typename std::decay<Callback>::type, Future<void> &&>::value, void>::type {
@@ -507,6 +507,71 @@ class AsyncRedis {
507507
fmt::set_keepttl, key, val, keepttl, type);
508508
}
509509

510+
Future<OptionalString> set_with_get_option(const StringView &key,
511+
const StringView &val,
512+
const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0),
513+
UpdateType type = UpdateType::ALWAYS) {
514+
return _command<OptionalString>(fmt::set_with_get_option, key, val, ttl, type);
515+
}
516+
517+
template <typename Callback>
518+
auto set_with_get_option(const StringView &key,
519+
const StringView &val,
520+
Callback &&cb)
521+
-> typename std::enable_if<IsInvocable<typename std::decay<Callback>::type, Future<OptionalString> &&>::value, void>::type {
522+
_callback_fmt_command<OptionalString>(std::forward<Callback>(cb),
523+
fmt::set_with_get_option, key, val, std::chrono::milliseconds(0), UpdateType::ALWAYS);
524+
}
525+
526+
template <typename Callback>
527+
auto set_with_get_option(const StringView &key,
528+
const StringView &val,
529+
const std::chrono::milliseconds &ttl,
530+
Callback &&cb)
531+
-> typename std::enable_if<IsInvocable<typename std::decay<Callback>::type, Future<OptionalString> &&>::value, void>::type {
532+
_callback_fmt_command<OptionalString>(std::forward<Callback>(cb),
533+
fmt::set_with_get_option, key, val, ttl, UpdateType::ALWAYS);
534+
}
535+
536+
template <typename Callback>
537+
auto set_with_get_option(const StringView &key,
538+
const StringView &val,
539+
const std::chrono::milliseconds &ttl,
540+
UpdateType type,
541+
Callback &&cb)
542+
-> typename std::enable_if<IsInvocable<typename std::decay<Callback>::type, Future<OptionalString> &&>::value, void>::type {
543+
_callback_fmt_command<OptionalString>(std::forward<Callback>(cb),
544+
fmt::set_with_get_option, key, val, ttl, type);
545+
}
546+
547+
Future<OptionalString> set_with_get_option(const StringView &key,
548+
const StringView &val,
549+
bool keepttl,
550+
UpdateType type = UpdateType::ALWAYS) {
551+
return _command<OptionalString>(fmt::set_with_get_keepttl_option, key, val, keepttl, type);
552+
}
553+
554+
template <typename Callback>
555+
auto set_with_get_option(const StringView &key,
556+
const StringView &val,
557+
bool keepttl,
558+
Callback &&cb)
559+
-> typename std::enable_if<IsInvocable<typename std::decay<Callback>::type, Future<OptionalString> &&>::value, void>::type {
560+
_callback_fmt_command<OptionalString>(std::forward<Callback>(cb),
561+
fmt::set_with_get_keepttl_option, key, val, keepttl, UpdateType::ALWAYS);
562+
}
563+
564+
template <typename Callback>
565+
auto set_with_get_option(const StringView &key,
566+
const StringView &val,
567+
bool keepttl,
568+
UpdateType type,
569+
Callback &&cb)
570+
-> typename std::enable_if<IsInvocable<typename std::decay<Callback>::type, Future<OptionalString> &&>::value, void>::type {
571+
_callback_fmt_command<OptionalString>(std::forward<Callback>(cb),
572+
fmt::set_with_get_keepttl_option, key, val, keepttl, type);
573+
}
574+
510575
Future<long long> strlen(const StringView &key) {
511576
return _command<long long>(fmt::strlen, key);
512577
}

src/sw/redis++/cmd_formatter.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,38 @@ inline FormattedCommand set_keepttl(const StringView &key,
277277
return format_cmd(args);
278278
}
279279

280+
inline FormattedCommand set_with_get_option(const StringView &key,
281+
const StringView &val,
282+
const std::chrono::milliseconds &ttl,
283+
UpdateType type) {
284+
CmdArgs args;
285+
args << "SET" << key << val << "GET";
286+
287+
if (ttl > std::chrono::milliseconds(0)) {
288+
args << "PX" << ttl.count();
289+
}
290+
291+
cmd::detail::set_update_type(args, type);
292+
293+
return format_cmd(args);
294+
}
295+
296+
inline FormattedCommand set_with_get_keepttl_option(const StringView &key,
297+
const StringView &val,
298+
bool keepttl,
299+
UpdateType type) {
300+
CmdArgs args;
301+
args << "SET" << key << val << "GET";
302+
303+
if (keepttl) {
304+
args << "KEEPTTL";
305+
}
306+
307+
cmd::detail::set_update_type(args, type);
308+
309+
return format_cmd(args);
310+
}
311+
280312
inline FormattedCommand strlen(const StringView &key) {
281313
return format_cmd("STRLEN %b", key.data(), key.size());
282314
}

src/sw/redis++/command.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,40 @@ void set_keepttl(Connection &connection,
8989
connection.send(args);
9090
}
9191

92+
void set_with_get_option(Connection &connection,
93+
const StringView &key,
94+
const StringView &val,
95+
long long ttl,
96+
UpdateType type) {
97+
CmdArgs args;
98+
args << "SET" << key << val << "GET";
99+
100+
if (ttl > 0) {
101+
args << "PX" << ttl;
102+
}
103+
104+
detail::set_update_type(args, type);
105+
106+
connection.send(args);
107+
}
108+
109+
void set_with_get_keepttl_option(Connection &connection,
110+
const StringView &key,
111+
const StringView &val,
112+
bool keepttl,
113+
UpdateType type) {
114+
CmdArgs args;
115+
args << "SET" << key << val << "GET";
116+
117+
if (keepttl) {
118+
args << "KEEPTTL";
119+
}
120+
121+
detail::set_update_type(args, type);
122+
123+
connection.send(args);
124+
}
125+
92126
// LIST commands.
93127

94128
void linsert(Connection &connection,

src/sw/redis++/command.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,18 @@ void set_keepttl(Connection &connection,
430430
bool keepttl,
431431
UpdateType type);
432432

433+
void set_with_get_option(Connection &connection,
434+
const StringView &key,
435+
const StringView &val,
436+
long long ttl,
437+
UpdateType type);
438+
439+
void set_with_get_keepttl_option(Connection &connection,
440+
const StringView &key,
441+
const StringView &val,
442+
bool keepttl,
443+
UpdateType type);
444+
433445
inline void setex(Connection &connection,
434446
const StringView &key,
435447
long long ttl,

src/sw/redis++/queued_redis.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,24 @@ class QueuedRedis {
472472
return command(cmd::set_keepttl, key, val, keepttl, type);
473473
}
474474

475+
QueuedRedis& set_with_get_option(const StringView &key,
476+
const StringView &val,
477+
const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0),
478+
UpdateType type = UpdateType::ALWAYS) {
479+
_set_cmd_indexes.insert(_cmd_num);
480+
481+
return command(cmd::set_with_get_option, key, val, ttl.count(), type);
482+
}
483+
484+
QueuedRedis& set_with_get_option(const StringView &key,
485+
const StringView &val,
486+
bool keepttl,
487+
UpdateType type = UpdateType::ALWAYS) {
488+
_set_cmd_indexes.insert(_cmd_num);
489+
490+
return command(cmd::set_with_get_keepttl_option, key, val, keepttl, type);
491+
}
492+
475493
QueuedRedis& setex(const StringView &key,
476494
long long ttl,
477495
const StringView &val) {

src/sw/redis++/redis.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,24 @@ bool Redis::set(const StringView &key,
378378
return reply::parse_set_reply(*reply);
379379
}
380380

381+
OptionalString Redis::set_with_get_option(const StringView &key,
382+
const StringView &val,
383+
const std::chrono::milliseconds &ttl,
384+
UpdateType type) {
385+
auto reply = command(cmd::set_with_get_option, key, val, ttl.count(), type);
386+
387+
return reply::parse<OptionalString>(*reply);
388+
}
389+
390+
OptionalString Redis::set_with_get_option(const StringView &key,
391+
const StringView &val,
392+
bool keepttl,
393+
UpdateType type) {
394+
auto reply = command(cmd::set_with_get_keepttl_option, key, val, keepttl, type);
395+
396+
return reply::parse<OptionalString>(*reply);
397+
}
398+
381399
void Redis::setex(const StringView &key,
382400
long long ttl,
383401
const StringView &val) {

src/sw/redis++/redis.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,37 @@ class Redis {
923923
bool keepttl,
924924
UpdateType type = UpdateType::ALWAYS);
925925

926+
/// @brief Atomically set the string stored at `key` to `val`, and return the old value.
927+
///
928+
/// Example:
929+
/// @code{.cpp}
930+
/// // Set a key-value pair, and expire it after 10 seconds and get the previous value.
931+
/// auto val = redis.set_with_get_option("key", "value", std::chrono::seconds(10));
932+
/// if (val)
933+
/// std::cout << *val << std::endl;
934+
/// else
935+
/// std::cout << "key not exist" << std::endl;
936+
/// @endcode
937+
/// @param key Key.
938+
/// @param val Value.
939+
/// @param ttl Timeout on the key. If `ttl` is 0ms, do not set timeout.
940+
/// @param type Options for set command:
941+
/// - UpdateType::EXIST: Set the key only if it already exists.
942+
/// - UpdateType::NOT_EXIST: Set the key only if it does not exist.
943+
/// - UpdateType::ALWAYS: Always set the key no matter whether it exists.
944+
/// @return The old value stored at key.
945+
/// @note If key does not exist, `getset` returns `OptionalString{}` (`std::nullopt`).
946+
/// @see https://redis.io/commands/set
947+
OptionalString set_with_get_option(const StringView &key,
948+
const StringView &val,
949+
const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0),
950+
UpdateType type = UpdateType::ALWAYS);
951+
952+
OptionalString set_with_get_option(const StringView &key,
953+
const StringView &val,
954+
bool keepttl,
955+
UpdateType type = UpdateType::ALWAYS);
956+
926957
// TODO: add SETBIT command.
927958

928959
/// @brief Set key-value pair with the given timeout in seconds.

src/sw/redis++/redis_cluster.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,24 @@ bool RedisCluster::set(const StringView &key,
289289
return reply::parse_set_reply(*reply);
290290
}
291291

292+
OptionalString RedisCluster::set_with_get_option(const StringView &key,
293+
const StringView &val,
294+
const std::chrono::milliseconds &ttl,
295+
UpdateType type) {
296+
auto reply = command(cmd::set_with_get_option, key, val, ttl.count(), type);
297+
298+
return reply::parse<OptionalString>(*reply);
299+
}
300+
301+
OptionalString RedisCluster::set_with_get_option(const StringView &key,
302+
const StringView &val,
303+
bool keepttl,
304+
UpdateType type) {
305+
auto reply = command(cmd::set_with_get_keepttl_option, key, val, keepttl, type);
306+
307+
return reply::parse<OptionalString>(*reply);
308+
}
309+
292310
void RedisCluster::setex(const StringView &key,
293311
long long ttl,
294312
const StringView &val) {

src/sw/redis++/redis_cluster.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,16 @@ class RedisCluster {
283283
bool keepttl,
284284
UpdateType type = UpdateType::ALWAYS);
285285

286+
OptionalString set_with_get_option(const StringView &key,
287+
const StringView &val,
288+
const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0),
289+
UpdateType type = UpdateType::ALWAYS);
290+
291+
OptionalString set_with_get_option(const StringView &key,
292+
const StringView &val,
293+
bool keepttl,
294+
UpdateType type = UpdateType::ALWAYS);
295+
286296
void setex(const StringView &key,
287297
long long ttl,
288298
const StringView &val);

test/src/sw/redis++/string_cmds_test.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class StringCmdTest {
4141

4242
void _test_getset();
4343

44+
void _test_set_with_get_option();
45+
4446
void _test_mgetset();
4547

4648
RedisInstance &_redis;

0 commit comments

Comments
 (0)