Skip to content

Add DELIFEQ command #1975

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/commands.def
Original file line number Diff line number Diff line change
Expand Up @@ -10459,6 +10459,31 @@ struct COMMAND_ARG DECRBY_Args[] = {
{MAKE_ARG("decrement",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
};

/********** DELIFEQ ********************/

#ifndef SKIP_CMD_HISTORY_TABLE
/* DELIFEQ history */
#define DELIFEQ_History NULL
#endif

#ifndef SKIP_CMD_TIPS_TABLE
/* DELIFEQ tips */
#define DELIFEQ_Tips NULL
#endif

#ifndef SKIP_CMD_KEY_SPECS_TABLE
/* DELIFEQ key specs */
keySpec DELIFEQ_Keyspecs[1] = {
{NULL,CMD_KEY_RM|CMD_KEY_ACCESS|CMD_KEY_DELETE,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}
};
#endif

/* DELIFEQ argument table */
struct COMMAND_ARG DELIFEQ_Args[] = {
{MAKE_ARG("key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
{MAKE_ARG("value",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
};

/********** GET ********************/

#ifndef SKIP_CMD_HISTORY_TABLE
Expand Down Expand Up @@ -11316,6 +11341,7 @@ struct COMMAND_STRUCT serverCommandTable[] = {
{MAKE_CMD("append","Appends a string to the value of a key. Creates the key if it doesn't exist.","O(1). The amortized time complexity is O(1) assuming the appended value is small and the already present value is of any size, since the dynamic string library used by the server will double the free space available on every reallocation.","2.0.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,APPEND_History,0,APPEND_Tips,0,appendCommand,3,CMD_WRITE|CMD_DENYOOM|CMD_FAST,ACL_CATEGORY_STRING,APPEND_Keyspecs,1,NULL,2),.args=APPEND_Args},
{MAKE_CMD("decr","Decrements the integer value of a key by one. Uses 0 as initial value if the key doesn't exist.","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,DECR_History,0,DECR_Tips,0,decrCommand,2,CMD_WRITE|CMD_DENYOOM|CMD_FAST,ACL_CATEGORY_STRING,DECR_Keyspecs,1,NULL,1),.args=DECR_Args},
{MAKE_CMD("decrby","Decrements a number from the integer value of a key. Uses 0 as initial value if the key doesn't exist.","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,DECRBY_History,0,DECRBY_Tips,0,decrbyCommand,3,CMD_WRITE|CMD_DENYOOM|CMD_FAST,ACL_CATEGORY_STRING,DECRBY_Keyspecs,1,NULL,2),.args=DECRBY_Args},
{MAKE_CMD("delifeq","Delete key if value matches string.","O(1)","9.0.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,DELIFEQ_History,0,DELIFEQ_Tips,0,delifeqCommand,3,CMD_WRITE,ACL_CATEGORY_STRING,DELIFEQ_Keyspecs,1,NULL,2),.args=DELIFEQ_Args},
{MAKE_CMD("get","Returns the string value of a key.","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,GET_History,0,GET_Tips,0,getCommand,2,CMD_READONLY|CMD_FAST,ACL_CATEGORY_STRING,GET_Keyspecs,1,NULL,1),.args=GET_Args},
{MAKE_CMD("getdel","Returns the string value of a key after deleting the key.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,GETDEL_History,0,GETDEL_Tips,0,getdelCommand,2,CMD_WRITE|CMD_FAST,ACL_CATEGORY_STRING,GETDEL_Keyspecs,1,NULL,1),.args=GETDEL_Args},
{MAKE_CMD("getex","Returns the string value of a key after setting its expiration time.","O(1)","6.2.0",CMD_DOC_NONE,NULL,NULL,"string",COMMAND_GROUP_STRING,GETEX_History,0,GETEX_Tips,0,getexCommand,-2,CMD_WRITE|CMD_FAST,ACL_CATEGORY_STRING,GETEX_Keyspecs,1,NULL,2),.args=GETEX_Args},
Expand Down
60 changes: 60 additions & 0 deletions src/commands/delifeq.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"DELIFEQ": {
"summary": "Delete key if value matches string.",
"complexity": "O(1)",
"group": "string",
"since": "9.0.0",
"arity": 3,
"function": "delifeqCommand",
"command_flags": [
"WRITE"
],
"acl_categories": [
"STRING"
],
"key_specs": [
{
"flags": [
"RM",
"ACCESS",
"DELETE"
],
"begin_search": {
"index": {
"pos": 1
}
},
"find_keys": {
"range": {
"lastkey": 0,
"step": 1,
"limit": 0
}
}
}
],
"reply_schema": {
"oneOf": [
{
"description": "The key was not deleted.",
"const": 0
},
{
"description": "The key was deleted.",
"const": 1
}
]
},
"arguments": [
{
"name": "key",
"type": "key",
"key_spec_index": 0
},
{
"name": "value",
"type": "string"
}
]
}
}
1 change: 1 addition & 0 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -3628,6 +3628,7 @@ void setCommand(client *c);
void setnxCommand(client *c);
void setexCommand(client *c);
void psetexCommand(client *c);
void delifeqCommand(client *c);
void getCommand(client *c);
void getexCommand(client *c);
void getdelCommand(client *c);
Expand Down
26 changes: 26 additions & 0 deletions src/t_string.c
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,32 @@ void psetexCommand(client *c) {
setGenericCommand(c, OBJ_PX | OBJ_ARGV3, c->argv[1], c->argv[3], c->argv[2], UNIT_MILLISECONDS, NULL, NULL, NULL);
}

void delifeqCommand(client *c) {
robj *existing_value = lookupKeyWrite(c->db, c->argv[1]);

if (existing_value == NULL) {
addReplyLongLong(c, 0);
return;
}

if (checkType(c, existing_value, OBJ_STRING)) {
/* Error reply already sent */
return;
}

if (compareStringObjects(existing_value, c->argv[2]) != 0) {
addReplyLongLong(c, 0);
return;
}

if (!dbSyncDelete(c->db, c->argv[1])) {
addReplyLongLong(c, 0);
return;
}

addReplyLongLong(c, 1);
}

int getGenericCommand(client *c) {
robj *o;

Expand Down
21 changes: 21 additions & 0 deletions tests/unit/type/string.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,27 @@ if {[string match {*jemalloc*} [s mem_allocator]]} {
lappend res [r get bar]
} {12 12}

test {DELIFEQ non-existing key} {
r del foo
assert_equal 0 [r delifeq foo "test"]
}

test {DELIFEQ existing key, matching value} {
r set foo "test"
assert_equal 1 [r delifeq foo "test"]
}

test {DELIFEQ existing key, non-matching value} {
r set foo "nope"
assert_equal 0 [r delifeq foo "test"]
}

test {DELIFEQ existing key, non-string value} {
r del foo
r sadd foo "test"
assert_error "WRONGTYPE*" {r delifeq foo "test"}
}

if {[string match {*jemalloc*} [s mem_allocator]]} {
test {Memory usage of embedded string value} {
# Check that we can fit 9 bytes of key + value into a 32 byte
Expand Down
Loading