Skip to content

Commit 0652f67

Browse files
addressing comments and adding tests
Signed-off-by: Sarthak Aggarwal <[email protected]>
1 parent 4a36392 commit 0652f67

File tree

4 files changed

+70
-7
lines changed

4 files changed

+70
-7
lines changed

src/commands.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10666,6 +10666,7 @@ struct COMMAND_ARG SET_expiration_Subargs[] = {
1066610666
struct COMMAND_ARG SET_Args[] = {
1066710667
{MAKE_ARG("key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
1066810668
{MAKE_ARG("value",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
10669+
{MAKE_ARG("ifeq",ARG_TYPE_STRING,-1,NULL,"Sets the key's value only if the current value matches the specified comparison value.",NULL,CMD_ARG_OPTIONAL,0,NULL)},
1066910670
{MAKE_ARG("condition",ARG_TYPE_ONEOF,-1,NULL,NULL,"2.6.12",CMD_ARG_OPTIONAL,2,NULL),.subargs=SET_condition_Subargs},
1067010671
{MAKE_ARG("get",ARG_TYPE_PURE_TOKEN,-1,"GET",NULL,"6.2.0",CMD_ARG_OPTIONAL,0,NULL)},
1067110672
{MAKE_ARG("expiration",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,5,NULL),.subargs=SET_expiration_Subargs},
@@ -11139,7 +11140,7 @@ struct COMMAND_STRUCT serverCommandTable[] = {
1113911140
{MAKE_CMD("mset","Atomically creates or modifies the string values of one or more keys.","O(N) where N is the number of keys to set.","1.0.1",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,MSET_History,0,MSET_Tips,2,msetCommand,-3,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_STRING,MSET_Keyspecs,1,NULL,1),.args=MSET_Args},
1114011141
{MAKE_CMD("msetnx","Atomically modifies the string values of one or more keys only when all keys don't exist.","O(N) where N is the number of keys to set.","1.0.1",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,MSETNX_History,0,MSETNX_Tips,0,msetnxCommand,-3,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_STRING,MSETNX_Keyspecs,1,NULL,1),.args=MSETNX_Args},
1114111142
{MAKE_CMD("psetex","Sets both string value and expiration time in milliseconds of a key. The key is created if it doesn't exist.","O(1)","2.6.0",CMD_DOC_DEPRECATED,"`SET` with the `PX` argument","2.6.12","string",COMMAND_GROUP_STRING,PSETEX_History,0,PSETEX_Tips,0,psetexCommand,4,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_STRING,PSETEX_Keyspecs,1,NULL,3),.args=PSETEX_Args},
11142-
{MAKE_CMD("set","Sets the string value of a key, ignoring its type. The key is created if it doesn't exist.","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,SET_History,4,SET_Tips,0,setCommand,-3,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_STRING,SET_Keyspecs,1,setGetKeys,5),.args=SET_Args},
11143+
{MAKE_CMD("set","Sets the string value of a key, ignoring its type. The key is created if it doesn't exist.","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,SET_History,4,SET_Tips,0,setCommand,-3,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_STRING,SET_Keyspecs,1,setGetKeys,6),.args=SET_Args},
1114311144
{MAKE_CMD("setex","Sets the string value and expiration time of a key. Creates the key if it doesn't exist.","O(1)","2.0.0",CMD_DOC_DEPRECATED,"`SET` with the `EX` argument","2.6.12","string",COMMAND_GROUP_STRING,SETEX_History,0,SETEX_Tips,0,setexCommand,4,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_STRING,SETEX_Keyspecs,1,NULL,3),.args=SETEX_Args},
1114411145
{MAKE_CMD("setnx","Set the string value of a key only when the key doesn't exist.","O(1)","1.0.0",CMD_DOC_DEPRECATED,"`SET` with the `NX` argument","2.6.12","string",COMMAND_GROUP_STRING,SETNX_History,0,SETNX_Tips,0,setnxCommand,3,CMD_WRITE|CMD_DENYOOM|CMD_FAST,ACL_CATEGORY_STRING,SETNX_Keyspecs,1,NULL,2),.args=SETNX_Args},
1114511146
{MAKE_CMD("setrange","Overwrites a part of a string value with another by an offset. Creates the key if it doesn't exist.","O(1), not counting the time taken to copy the new string in place. Usually, this string is very small so the amortized complexity is O(1). Otherwise, complexity is O(M) with M being the length of the value argument.","2.2.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,SETRANGE_History,0,SETRANGE_Tips,0,setrangeCommand,4,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_STRING,SETRANGE_Keyspecs,1,NULL,3),.args=SETRANGE_Args},

src/commands/set.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,19 @@
8585
"name": "value",
8686
"type": "string"
8787
},
88+
{
89+
"name": "ifeq",
90+
"type": "string",
91+
"optional": true,
92+
"summary": "Sets the key's value only if the current value matches the specified comparison value.",
93+
"arguments": [
94+
{
95+
"name": "comparison-value",
96+
"type": "string",
97+
"summary": "The value to compare with the current key's value before setting."
98+
}
99+
]
100+
},
88101
{
89102
"name": "condition",
90103
"type": "oneof",

src/t_string.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,21 @@ void setGenericCommand(client *c,
105105
found = (lookupKeyWrite(c->db, key) != NULL);
106106

107107
/* Handle the IFEQ conditional check */
108-
if ((flags & OBJ_SET_IFEQ) && found) {
108+
if (flags & OBJ_SET_IFEQ && found) {
109109
robj *current_value = lookupKeyRead(c->db, key);
110-
if (current_value == NULL || compareStringObjects(current_value, comparison) != 0) {
110+
111+
if (current_value == NULL || current_value->type != OBJ_STRING || checkType(c, comparison, OBJ_STRING) != 0) {
112+
addReplyError(c, "value(s) must be present or string");
113+
return;
114+
}
115+
116+
if (compareStringObjects(current_value, comparison) != 0) {
111117
addReply(c, abort_reply ? abort_reply : shared.null[c->resp]);
112118
return;
113119
}
120+
} else if (flags & OBJ_SET_IFEQ && !found) {
121+
addReply(c, abort_reply ? abort_reply : shared.null[c->resp]);
122+
return;
114123
}
115124

116125
if ((flags & OBJ_SET_NX && found) || (flags & OBJ_SET_XX && !found)) {

tests/unit/type/string.tcl

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -583,18 +583,58 @@ if {[string match {*jemalloc*} [s mem_allocator]]} {
583583
} {*WRONGTYPE*}
584584

585585
test "SET with IFEQ conditional" {
586-
# Setting an initial value for the key
586+
r del foo
587+
587588
r set foo "initial_value"
588589

589-
# Trying to set the key only if the value is exactly "initial_value"
590-
assert_equal OK [r set foo "new_value" ifeq "initial_value"]
590+
assert_equal {OK} [r set foo "new_value" ifeq "initial_value"]
591591
assert_equal "new_value" [r get foo]
592592

593-
# Trying to set the key only if the value is NOT "initial_value"
594593
assert_equal {} [r set foo "should_not_set" ifeq "wrong_value"]
595594
assert_equal "new_value" [r get foo]
596595
}
597596

597+
test "SET with IFEQ conditional - non-string current value" {
598+
r del foo
599+
600+
r sadd foo "some_set_value"
601+
assert_error {ERR value(s) must be present or string} {r set foo "new_value" ifeq "some_set_value"}
602+
}
603+
604+
test "SET with IFEQ conditional - with get" {
605+
r del foo
606+
607+
assert_equal {} [r set foo "new_value" ifeq "initial_value" get]
608+
609+
r set foo "initial_value"
610+
611+
assert_equal "initial_value" [r set foo "new_value" ifeq "initial_value" get]
612+
assert_equal "new_value" [r get foo]
613+
}
614+
615+
616+
test "SET with IFEQ conditional - with xx" {
617+
r del foo
618+
619+
assert_error {} {r set foo "new_value" ifeq "initial_value" xx}
620+
621+
r set foo "initial_value"
622+
623+
assert_equal {OK} [r set foo "new_value" ifeq "initial_value" xx]
624+
assert_equal "new_value" [r get foo]
625+
}
626+
627+
test "SET with IFEQ conditional - with nx" {
628+
r del foo
629+
630+
assert_error {ERR value(s) must be present or string} {r set foo "new_value" ifeq "initial_value" nx}
631+
632+
r set foo "initial_value"
633+
634+
assert_equal {} [r set foo "new_value" ifeq "initial_value" nx]
635+
assert_equal "initial_value" [r get foo]
636+
}
637+
598638
test {Extended SET EX option} {
599639
r del foo
600640
r set foo bar ex 10

0 commit comments

Comments
 (0)