diff --git a/src/commands.def b/src/commands.def index 3bafaee3d..b096da430 100644 --- a/src/commands.def +++ b/src/commands.def @@ -10005,6 +10005,7 @@ struct COMMAND_ARG ZRANGE_Args[] = { {MAKE_ARG("rev",ARG_TYPE_PURE_TOKEN,-1,"REV",NULL,"6.2.0",CMD_ARG_OPTIONAL,0,NULL)}, {MAKE_ARG("limit",ARG_TYPE_BLOCK,-1,"LIMIT",NULL,"6.2.0",CMD_ARG_OPTIONAL,2,NULL),.subargs=ZRANGE_limit_Subargs}, {MAKE_ARG("withscores",ARG_TYPE_PURE_TOKEN,-1,"WITHSCORES",NULL,NULL,CMD_ARG_OPTIONAL,0,NULL)}, +{MAKE_ARG("withstatus",ARG_TYPE_PURE_TOKEN,-1,"WITHSTATUS",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)}, }; /********** ZRANGEBYLEX ********************/ @@ -10073,6 +10074,7 @@ struct COMMAND_ARG ZRANGEBYSCORE_Args[] = { {MAKE_ARG("min",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)}, {MAKE_ARG("max",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)}, {MAKE_ARG("withscores",ARG_TYPE_PURE_TOKEN,-1,"WITHSCORES",NULL,"2.0.0",CMD_ARG_OPTIONAL,0,NULL)}, +{MAKE_ARG("withstatus",ARG_TYPE_PURE_TOKEN,-1,"WITHSTATUS",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)}, {MAKE_ARG("limit",ARG_TYPE_BLOCK,-1,"LIMIT",NULL,NULL,CMD_ARG_OPTIONAL,2,NULL),.subargs=ZRANGEBYSCORE_limit_Subargs}, }; @@ -10276,6 +10278,7 @@ struct COMMAND_ARG ZREVRANGE_Args[] = { {MAKE_ARG("start",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)}, {MAKE_ARG("stop",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)}, {MAKE_ARG("withscores",ARG_TYPE_PURE_TOKEN,-1,"WITHSCORES",NULL,NULL,CMD_ARG_OPTIONAL,0,NULL)}, +{MAKE_ARG("withstatus",ARG_TYPE_PURE_TOKEN,-1,"WITHSTATUS",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)}, }; /********** ZREVRANGEBYLEX ********************/ @@ -10344,6 +10347,7 @@ struct COMMAND_ARG ZREVRANGEBYSCORE_Args[] = { {MAKE_ARG("max",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)}, {MAKE_ARG("min",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)}, {MAKE_ARG("withscores",ARG_TYPE_PURE_TOKEN,-1,"WITHSCORES",NULL,NULL,CMD_ARG_OPTIONAL,0,NULL)}, +{MAKE_ARG("withstatus",ARG_TYPE_PURE_TOKEN,-1,"WITHSTATUS",NULL,"9.0.0",CMD_ARG_OPTIONAL,0,NULL)}, {MAKE_ARG("limit",ARG_TYPE_BLOCK,-1,"LIMIT",NULL,NULL,CMD_ARG_OPTIONAL,2,NULL),.subargs=ZREVRANGEBYSCORE_limit_Subargs}, }; @@ -12578,18 +12582,18 @@ struct COMMAND_STRUCT redisCommandTable[] = { {MAKE_CMD("zpopmax","Returns the highest-scoring members from a sorted set after removing them. Deletes the sorted set if the last member was popped.","O(log(N)*M) with N being the number of elements in the sorted set, and M being the number of elements popped.","5.0.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZPOPMAX_History,0,ZPOPMAX_Tips,0,zpopmaxCommand,-2,CMD_WRITE|CMD_FAST,ACL_CATEGORY_SORTEDSET,ZPOPMAX_Keyspecs,1,NULL,2),.args=ZPOPMAX_Args}, {MAKE_CMD("zpopmin","Returns the lowest-scoring members from a sorted set after removing them. Deletes the sorted set if the last member was popped.","O(log(N)*M) with N being the number of elements in the sorted set, and M being the number of elements popped.","5.0.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZPOPMIN_History,0,ZPOPMIN_Tips,0,zpopminCommand,-2,CMD_WRITE|CMD_FAST,ACL_CATEGORY_SORTEDSET,ZPOPMIN_Keyspecs,1,NULL,2),.args=ZPOPMIN_Args}, {MAKE_CMD("zrandmember","Returns one or more random members from a sorted set.","O(N) where N is the number of members returned","6.2.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZRANDMEMBER_History,0,ZRANDMEMBER_Tips,1,zrandmemberCommand,-2,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZRANDMEMBER_Keyspecs,1,NULL,2),.args=ZRANDMEMBER_Args}, -{MAKE_CMD("zrange","Returns members in a sorted set within a range of indexes.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.","1.2.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZRANGE_History,1,ZRANGE_Tips,0,zrangeCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZRANGE_Keyspecs,1,NULL,7),.args=ZRANGE_Args}, +{MAKE_CMD("zrange","Returns members in a sorted set within a range of indexes.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.","1.2.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZRANGE_History,1,ZRANGE_Tips,0,zrangeCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZRANGE_Keyspecs,1,NULL,8),.args=ZRANGE_Args}, {MAKE_CMD("zrangebylex","Returns members in a sorted set within a lexicographical range.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","2.8.9",CMD_DOC_DEPRECATED,"`ZRANGE` with the `BYLEX` argument","6.2.0","sorted_set",COMMAND_GROUP_SORTED_SET,ZRANGEBYLEX_History,0,ZRANGEBYLEX_Tips,0,zrangebylexCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZRANGEBYLEX_Keyspecs,1,NULL,4),.args=ZRANGEBYLEX_Args}, -{MAKE_CMD("zrangebyscore","Returns members in a sorted set within a range of scores.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","1.0.5",CMD_DOC_DEPRECATED,"`ZRANGE` with the `BYSCORE` argument","6.2.0","sorted_set",COMMAND_GROUP_SORTED_SET,ZRANGEBYSCORE_History,1,ZRANGEBYSCORE_Tips,0,zrangebyscoreCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZRANGEBYSCORE_Keyspecs,1,NULL,5),.args=ZRANGEBYSCORE_Args}, +{MAKE_CMD("zrangebyscore","Returns members in a sorted set within a range of scores.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","1.0.5",CMD_DOC_DEPRECATED,"`ZRANGE` with the `BYSCORE` argument","6.2.0","sorted_set",COMMAND_GROUP_SORTED_SET,ZRANGEBYSCORE_History,1,ZRANGEBYSCORE_Tips,0,zrangebyscoreCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZRANGEBYSCORE_Keyspecs,1,NULL,6),.args=ZRANGEBYSCORE_Args}, {MAKE_CMD("zrangestore","Stores a range of members from sorted set in a key.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements stored into the destination key.","6.2.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZRANGESTORE_History,0,ZRANGESTORE_Tips,0,zrangestoreCommand,-5,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_SORTEDSET,ZRANGESTORE_Keyspecs,2,NULL,7),.args=ZRANGESTORE_Args}, {MAKE_CMD("zrank","Returns the index of a member in a sorted set ordered by ascending scores.","O(log(N))","2.0.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZRANK_History,1,ZRANK_Tips,0,zrankCommand,-3,CMD_READONLY|CMD_FAST,ACL_CATEGORY_SORTEDSET,ZRANK_Keyspecs,1,NULL,3),.args=ZRANK_Args}, {MAKE_CMD("zrem","Removes one or more members from a sorted set. Deletes the sorted set if all members were removed.","O(M*log(N)) with N being the number of elements in the sorted set and M the number of elements to be removed.","1.2.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZREM_History,1,ZREM_Tips,0,zremCommand,-3,CMD_WRITE|CMD_FAST,ACL_CATEGORY_SORTEDSET,ZREM_Keyspecs,1,NULL,2),.args=ZREM_Args}, {MAKE_CMD("zremrangebylex","Removes members in a sorted set within a lexicographical range. Deletes the sorted set if all members were removed.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.","2.8.9",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZREMRANGEBYLEX_History,0,ZREMRANGEBYLEX_Tips,0,zremrangebylexCommand,4,CMD_WRITE,ACL_CATEGORY_SORTEDSET,ZREMRANGEBYLEX_Keyspecs,1,NULL,3),.args=ZREMRANGEBYLEX_Args}, {MAKE_CMD("zremrangebyrank","Removes members in a sorted set within a range of indexes. Deletes the sorted set if all members were removed.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.","2.0.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZREMRANGEBYRANK_History,0,ZREMRANGEBYRANK_Tips,0,zremrangebyrankCommand,4,CMD_WRITE,ACL_CATEGORY_SORTEDSET,ZREMRANGEBYRANK_Keyspecs,1,NULL,3),.args=ZREMRANGEBYRANK_Args}, {MAKE_CMD("zremrangebyscore","Removes members in a sorted set within a range of scores. Deletes the sorted set if all members were removed.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.","1.2.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZREMRANGEBYSCORE_History,0,ZREMRANGEBYSCORE_Tips,0,zremrangebyscoreCommand,4,CMD_WRITE,ACL_CATEGORY_SORTEDSET,ZREMRANGEBYSCORE_Keyspecs,1,NULL,3),.args=ZREMRANGEBYSCORE_Args}, -{MAKE_CMD("zrevrange","Returns members in a sorted set within a range of indexes in reverse order.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.","1.2.0",CMD_DOC_DEPRECATED,"`ZRANGE` with the `REV` argument","6.2.0","sorted_set",COMMAND_GROUP_SORTED_SET,ZREVRANGE_History,0,ZREVRANGE_Tips,0,zrevrangeCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZREVRANGE_Keyspecs,1,NULL,4),.args=ZREVRANGE_Args}, +{MAKE_CMD("zrevrange","Returns members in a sorted set within a range of indexes in reverse order.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.","1.2.0",CMD_DOC_DEPRECATED,"`ZRANGE` with the `REV` argument","6.2.0","sorted_set",COMMAND_GROUP_SORTED_SET,ZREVRANGE_History,0,ZREVRANGE_Tips,0,zrevrangeCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZREVRANGE_Keyspecs,1,NULL,5),.args=ZREVRANGE_Args}, {MAKE_CMD("zrevrangebylex","Returns members in a sorted set within a lexicographical range in reverse order.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","2.8.9",CMD_DOC_DEPRECATED,"`ZRANGE` with the `REV` and `BYLEX` arguments","6.2.0","sorted_set",COMMAND_GROUP_SORTED_SET,ZREVRANGEBYLEX_History,0,ZREVRANGEBYLEX_Tips,0,zrevrangebylexCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZREVRANGEBYLEX_Keyspecs,1,NULL,4),.args=ZREVRANGEBYLEX_Args}, -{MAKE_CMD("zrevrangebyscore","Returns members in a sorted set within a range of scores in reverse order.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","2.2.0",CMD_DOC_DEPRECATED,"`ZRANGE` with the `REV` and `BYSCORE` arguments","6.2.0","sorted_set",COMMAND_GROUP_SORTED_SET,ZREVRANGEBYSCORE_History,1,ZREVRANGEBYSCORE_Tips,0,zrevrangebyscoreCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZREVRANGEBYSCORE_Keyspecs,1,NULL,5),.args=ZREVRANGEBYSCORE_Args}, +{MAKE_CMD("zrevrangebyscore","Returns members in a sorted set within a range of scores in reverse order.","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","2.2.0",CMD_DOC_DEPRECATED,"`ZRANGE` with the `REV` and `BYSCORE` arguments","6.2.0","sorted_set",COMMAND_GROUP_SORTED_SET,ZREVRANGEBYSCORE_History,1,ZREVRANGEBYSCORE_Tips,0,zrevrangebyscoreCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZREVRANGEBYSCORE_Keyspecs,1,NULL,6),.args=ZREVRANGEBYSCORE_Args}, {MAKE_CMD("zrevrank","Returns the index of a member in a sorted set ordered by descending scores.","O(log(N))","2.0.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZREVRANK_History,1,ZREVRANK_Tips,0,zrevrankCommand,-3,CMD_READONLY|CMD_FAST,ACL_CATEGORY_SORTEDSET,ZREVRANK_Keyspecs,1,NULL,3),.args=ZREVRANK_Args}, {MAKE_CMD("zscan","Iterates over members and scores of a sorted set.","O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.","2.8.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZSCAN_History,0,ZSCAN_Tips,1,zscanCommand,-3,CMD_READONLY,ACL_CATEGORY_SORTEDSET,ZSCAN_Keyspecs,1,NULL,4),.args=ZSCAN_Args}, {MAKE_CMD("zscore","Returns the score of a member in a sorted set.","O(1)","1.2.0",CMD_DOC_NONE,NULL,NULL,"sorted_set",COMMAND_GROUP_SORTED_SET,ZSCORE_History,0,ZSCORE_Tips,0,zscoreCommand,3,CMD_READONLY|CMD_FAST,ACL_CATEGORY_SORTEDSET,ZSCORE_Keyspecs,1,NULL,2),.args=ZSCORE_Args}, diff --git a/src/commands/zrange.json b/src/commands/zrange.json index dc7af8dc1..55e8c1017 100644 --- a/src/commands/zrange.json +++ b/src/commands/zrange.json @@ -131,6 +131,13 @@ "token": "WITHSCORES", "type": "pure-token", "optional": true + }, + { + "name": "withstatus", + "token": "WITHSTATUS", + "type": "pure-token", + "optional": true, + "since": "9.0.0" } ] } diff --git a/src/commands/zrangebyscore.json b/src/commands/zrangebyscore.json index 557ef1dc6..35c1075e0 100644 --- a/src/commands/zrangebyscore.json +++ b/src/commands/zrangebyscore.json @@ -98,6 +98,13 @@ "optional": true, "since": "2.0.0" }, + { + "name": "withstatus", + "token": "WITHSTATUS", + "type": "pure-token", + "optional": true, + "since": "9.0.0" + }, { "token": "LIMIT", "name": "limit", diff --git a/src/commands/zrevrange.json b/src/commands/zrevrange.json index 116fe82b2..9df82b42c 100644 --- a/src/commands/zrevrange.json +++ b/src/commands/zrevrange.json @@ -88,6 +88,13 @@ "token": "WITHSCORES", "type": "pure-token", "optional": true + }, + { + "name": "withstatus", + "token": "WITHSTATUS", + "type": "pure-token", + "optional": true, + "since": "9.0.0" } ] } diff --git a/src/commands/zrevrangebyscore.json b/src/commands/zrevrangebyscore.json index ab040527e..9faeea0a1 100644 --- a/src/commands/zrevrangebyscore.json +++ b/src/commands/zrevrangebyscore.json @@ -97,6 +97,13 @@ "type": "pure-token", "optional": true }, + { + "name": "withstatus", + "token": "WITHSTATUS", + "type": "pure-token", + "optional": true, + "since": "9.0.0" + }, { "token": "LIMIT", "name": "limit", diff --git a/src/t_zset.c b/src/t_zset.c index ff61afdd3..45dbb5b4a 100644 --- a/src/t_zset.c +++ b/src/t_zset.c @@ -3510,14 +3510,14 @@ void zrangestoreCommand (client *c) { zrangeGenericCommand(&handler, 2, 1, ZRANGE_AUTO, ZRANGE_DIRECTION_AUTO); } -/* ZRANGE [BYSCORE | BYLEX] [REV] [WITHSCORES] [LIMIT offset count] */ +/* ZRANGE [BYSCORE | BYLEX] [REV] [WITHSCORES] [WITHSTATUS] [LIMIT offset count] */ void zrangeCommand(client *c) { zrange_result_handler handler; zrangeResultHandlerInit(&handler, c, ZRANGE_CONSUMER_TYPE_CLIENT); zrangeGenericCommand(&handler, 1, 0, ZRANGE_AUTO, ZRANGE_DIRECTION_AUTO); } -/* ZREVRANGE [WITHSCORES] */ +/* ZREVRANGE [WITHSCORES] [WITHSTATUS] */ void zrevrangeCommand(client *c) { zrange_result_handler handler; zrangeResultHandlerInit(&handler, c, ZRANGE_CONSUMER_TYPE_CLIENT); @@ -3629,14 +3629,14 @@ void genericZrangebyscoreCommand(zrange_result_handler *handler, handler->finalizeResultEmission(handler, rangelen); } -/* ZRANGEBYSCORE [WITHSCORES] [LIMIT offset count] */ +/* ZRANGEBYSCORE [WITHSCORES] [WITHSTATUS] [LIMIT offset count] */ void zrangebyscoreCommand(client *c) { zrange_result_handler handler; zrangeResultHandlerInit(&handler, c, ZRANGE_CONSUMER_TYPE_CLIENT); zrangeGenericCommand(&handler, 1, 0, ZRANGE_SCORE, ZRANGE_DIRECTION_FORWARD); } -/* ZREVRANGEBYSCORE [WITHSCORES] [LIMIT offset count] */ +/* ZREVRANGEBYSCORE [WITHSCORES] [WITHSTATUS] [LIMIT offset count] */ void zrevrangebyscoreCommand(client *c) { zrange_result_handler handler; zrangeResultHandlerInit(&handler, c, ZRANGE_CONSUMER_TYPE_CLIENT); @@ -3903,14 +3903,14 @@ void genericZrangebylexCommand(zrange_result_handler *handler, handler->finalizeResultEmission(handler, rangelen); } -/* ZRANGEBYLEX [LIMIT offset count] */ +/* ZRANGEBYLEX [LIMIT offset count] [WITHSTATUS] */ void zrangebylexCommand(client *c) { zrange_result_handler handler; zrangeResultHandlerInit(&handler, c, ZRANGE_CONSUMER_TYPE_CLIENT); zrangeGenericCommand(&handler, 1, 0, ZRANGE_LEX, ZRANGE_DIRECTION_FORWARD); } -/* ZREVRANGEBYLEX [LIMIT offset count] */ +/* ZREVRANGEBYLEX [LIMIT offset count] [WITHSTATUS] */ void zrevrangebylexCommand(client *c) { zrange_result_handler handler; zrangeResultHandlerInit(&handler, c, ZRANGE_CONSUMER_TYPE_CLIENT); @@ -3925,7 +3925,7 @@ void zrevrangebylexCommand(client *c) { * other command pass explicit value. * * The argc_start points to the src key argument, so following syntax is like: - * [BYSCORE | BYLEX] [REV] [WITHSCORES] [LIMIT offset count] + * [BYSCORE | BYLEX] [REV] [WITHSCORES] [WITHSTATUS] [LIMIT offset count] */ void zrangeGenericCommand(zrange_result_handler *handler, int argc_start, int store, zrange_type rangetype, zrange_direction direction) @@ -3942,6 +3942,7 @@ void zrangeGenericCommand(zrange_result_handler *handler, int argc_start, int st long opt_start = 0; long opt_end = 0; int opt_withscores = 0; + int opt_withstatus = 0; long opt_offset = 0; long opt_limit = -1; @@ -3950,6 +3951,8 @@ void zrangeGenericCommand(zrange_result_handler *handler, int argc_start, int st int leftargs = c->argc-j-1; if (!store && !strcasecmp(c->argv[j]->ptr,"withscores")) { opt_withscores = 1; + } else if (!store && !strcasecmp(c->argv[j]->ptr,"withstatus")) { + opt_withstatus = 1; } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) { if ((getLongFromObjectOrReply(c, c->argv[j+1], &opt_offset, NULL) != C_OK) || (getLongFromObjectOrReply(c, c->argv[j+2], &opt_limit, NULL) != C_OK)) @@ -4039,8 +4042,10 @@ void zrangeGenericCommand(zrange_result_handler *handler, int argc_start, int st if (store) { handler->beginResultEmission(handler, -1); handler->finalizeResultEmission(handler, 0); + } else if (opt_withstatus) { + addReply(c, shared.nullarray[c->resp]); } else { - addReply(c, shared.emptyarray); + addReply(c,shared.emptyarray); } goto cleanup; } diff --git a/tests/assets/test_cli_hint_suite.txt b/tests/assets/test_cli_hint_suite.txt index 20abea008..4d8d57cd3 100644 --- a/tests/assets/test_cli_hint_suite.txt +++ b/tests/assets/test_cli_hint_suite.txt @@ -58,14 +58,14 @@ # One-of choices: BLMOVE source destination LEFT|RIGHT LEFT|RIGHT timeout "BLMOVE src dst LEFT " "LEFT|RIGHT timeout" -# Optional args can be in any order: ZRANGE key min max [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES] -"ZRANGE k 1 2 " "[BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]" -"ZRANGE k 1 2 bylex " "[REV] [LIMIT offset count] [WITHSCORES]" -"ZRANGE k 1 2 bylex rev " "[LIMIT offset count] [WITHSCORES]" -"ZRANGE k 1 2 limit 2 4 " "[BYSCORE|BYLEX] [REV] [WITHSCORES]" -"ZRANGE k 1 2 bylex rev limit 2 4 WITHSCORES " "" -"ZRANGE k 1 2 rev " "[BYSCORE|BYLEX] [LIMIT offset count] [WITHSCORES]" -"ZRANGE k 1 2 WITHSCORES " "[BYSCORE|BYLEX] [REV] [LIMIT offset count]" +# Optional args can be in any order: ZRANGE key min max [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES] [WITHSTATUS] +"ZRANGE k 1 2 " "[BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES] [WITHSTATUS]" +"ZRANGE k 1 2 bylex " "[REV] [LIMIT offset count] [WITHSCORES] [WITHSTATUS]" +"ZRANGE k 1 2 bylex rev " "[LIMIT offset count] [WITHSCORES] [WITHSTATUS]" +"ZRANGE k 1 2 limit 2 4 " "[BYSCORE|BYLEX] [REV] [WITHSCORES] [WITHSTATUS]" +"ZRANGE k 1 2 bylex rev limit 2 4 WITHSCORES WITHSTATUS " "" +"ZRANGE k 1 2 rev " "[BYSCORE|BYLEX] [LIMIT offset count] [WITHSCORES] [WITHSTATUS]" +"ZRANGE k 1 2 WITHSCORES " "[BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSTATUS]" # Optional one-of args with parameters: SET key value [NX|XX|IFEQ ifeq-value|IFNE ifne-value|IFDEQ ifdeq-digest|IFDNE ifdne-digest] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL] "SET key value " "[NX|XX|IFEQ ifeq-value|IFNE ifne-value|IFDEQ ifdeq-digest|IFDNE ifdne-digest] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]" diff --git a/tests/unit/type/zset.tcl b/tests/unit/type/zset.tcl index e840b2a16..af06d9525 100644 --- a/tests/unit/type/zset.tcl +++ b/tests/unit/type/zset.tcl @@ -454,6 +454,62 @@ start_server {tags {"zset"}} { assert_equal {d 4 c 3 b 2 a 1} [r zrevrange ztmp 0 -1 withscores] } + test "ZREVRANGE with/without WITHSTATUS - $encoding" { + r del ztmp + r zadd ztmp 1 a 2 b 3 c 4 d + + # Test WITHSTATUS when key exists and has elements + assert_equal {d c b a} [r zrevrange ztmp 0 -1 WITHSTATUS] + + # Test WITHSTATUS when key exists but is empty (no elements in range) + assert_equal {} [r zrevrange ztmp 10 20 WITHSTATUS] + + # Test WITHSTATUS with WITHSCORES + assert_equal {d 4 c 3 b 2 a 1} [r zrevrange ztmp 0 -1 WITHSCORES WITHSTATUS] + + # Test WITHSTATUS with ZREVRANGE and LIMIT + assert_equal {d c} [r zrevrange ztmp 0 1 WITHSTATUS] + + # Test key does not exist - should return nullarray + assert_equal {} [r zrevrange non_existent_key 0 -1 WITHSTATUS] + + # Test key exists but has no matching elements in range + assert_equal {} [r zrevrange ztmp 10 20 WITHSTATUS] + + # Test nullarray vs emptyarray distinction in RESP3 + r hello 3 + r readraw 1 + + # Test nullarray (key does not exist) in RESP3 + set null_res [r zrevrange non_existent_key 0 -1 WITHSTATUS] + assert_equal {_} $null_res + + # Test emptyarray (key exists but no matching elements) in RESP3 + set empty_res [r zrevrange ztmp 10 20 WITHSTATUS] + assert_equal {*0} $empty_res + + r readraw 0 + r hello 2 + + r readraw 1 + + # Test nullarray (key does not exist) in RESP2 + set null_res [r zrevrange non_existent_key 0 -1 WITHSTATUS] + assert_equal {*-1} $null_res + + # Test emptyarray (key exists but no matching elements) in RESP2 + set empty_res [r zrevrange ztmp 10 20 WITHSTATUS] + assert_equal {*0} $empty_res + + r readraw 0 + + # Test WITHSTATUS with LIMIT (using BYSCORE) + assert_equal {d c} [r zrevrangebyscore ztmp +inf -inf LIMIT 0 2 WITHSTATUS] + + # Test WITHSTATUS with multiple modifiers + assert_equal {d 4 c 3} [r zrevrangebyscore ztmp +inf -inf LIMIT 0 2 WITHSCORES WITHSTATUS] + } + test "ZRANK/ZREVRANK basics - $encoding" { set nullres {$-1} if {$::force_resp3} { @@ -628,6 +684,64 @@ start_server {tags {"zset"}} { assert_equal {} [r zrangebyscore zset 2 5 LIMIT 12 13 WITHSCORES] } + test "ZRANGEBYSCORE with/without WITHSTATUS - $encoding" { + create_default_zset + + # Test WITHSTATUS when key exists and has elements + assert_equal {b c d} [r zrangebyscore zset 0 3 WITHSTATUS] + + # Test WITHSTATUS when key exists but is empty (no elements in range) + assert_equal {} [r zrangebyscore zset 10 20 WITHSTATUS] + + # Test WITHSTATUS with WITHSCORES + assert_equal {b 1 c 2 d 3} [r zrangebyscore zset 0 3 WITHSCORES WITHSTATUS] + + # Test WITHSTATUS with LIMIT + assert_equal {b c} [r zrangebyscore zset 0 3 LIMIT 0 2 WITHSTATUS] + + # Test key does not exist - should return nullarray + assert_equal {} [r zrangebyscore non_existent_key 0 10 WITHSTATUS] + + # Test nullarray vs emptyarray distinction in RESP3 + r hello 3 + r readraw 1 + + # Test nullarray (key does not exist) in RESP3 + set null_res [r zrangebyscore non_existent_key 0 10 WITHSTATUS] + assert_equal {_} $null_res + + # Test emptyarray (key exists but no matching elements) in RESP3 + set empty_res [r zrangebyscore zset 10 20 WITHSTATUS] + assert_equal {*0} $empty_res + + r readraw 0 + r hello 2 + + r readraw 1 + + # Test nullarray (key does not exist) in RESP2 + set null_res [r zrangebyscore non_existent_key 0 10 WITHSTATUS] + assert_equal {*-1} $null_res + + # Test emptyarray (key exists but no matching elements) in RESP2 + set empty_res [r zrangebyscore zset 10 20 WITHSTATUS] + assert_equal {*0} $empty_res + + r readraw 0 + + # Test WITHSTATUS with ZREVRANGEBYSCORE + assert_equal {d c b} [r zrevrangebyscore zset 3 0 WITHSTATUS] + + # Test WITHSTATUS with ZREVRANGEBYSCORE and WITHSCORES + assert_equal {d 3 c 2 b 1} [r zrevrangebyscore zset 3 0 WITHSCORES WITHSTATUS] + + # Test WITHSTATUS with ZREVRANGEBYSCORE and LIMIT + assert_equal {d c} [r zrevrangebyscore zset 3 0 LIMIT 0 2 WITHSTATUS] + + # Test WITHSTATUS with ZREVRANGEBYSCORE and LIMIT + assert_equal {d c} [r zrevrangebyscore zset 3 0 LIMIT 0 2 WITHSTATUS] + } + test "ZRANGEBYSCORE with non-value min or max - $encoding" { assert_error "*not*float*" {r zrangebyscore fooz str 1} assert_error "*not*float*" {r zrangebyscore fooz 1 str} @@ -726,6 +840,58 @@ start_server {tags {"zset"}} { assert_equal {} [r zrevrangebylex zset + \[o LIMIT -1 5] } + test "ZRANGEBYLEX with/without WITHSTATUS - $encoding" { + create_default_lex_zset + + # Test WITHSTATUS when key exists and has elements + assert_equal {alpha bar cool} [r zrangebylex zset - \[cool WITHSTATUS] + + # Test WITHSTATUS when key exists but is empty (no elements in range) + assert_equal {} [r zrangebylex zset \[zzz + WITHSTATUS] + + # Test WITHSTATUS with LIMIT + assert_equal {alpha bar} [r zrangebylex zset - \[cool LIMIT 0 2 WITHSTATUS] + + # Test key does not exist - should return nullarray + assert_equal {} [r zrangebylex non_existent_key - + WITHSTATUS] + + # Test nullarray vs emptyarray distinction in RESP3 + r hello 3 + r readraw 1 + + # Test nullarray (key does not exist) in RESP3 + set null_res [r zrangebylex non_existent_key - + WITHSTATUS] + assert_equal {_} $null_res + + # Test emptyarray (key exists but no matching elements) in RESP3 + set empty_res [r zrangebylex zset \[zzz + WITHSTATUS] + assert_equal {*0} $empty_res + + r readraw 0 + r hello 2 + + r readraw 1 + + # Test nullarray (key does not exist) in RESP2 + set null_res [r zrangebylex non_existent_key - + WITHSTATUS] + assert_equal {*-1} $null_res + + # Test emptyarray (key exists but no matching elements) in RESP2 + set empty_res [r zrangebylex zset \[zzz + WITHSTATUS] + assert_equal {*0} $empty_res + + r readraw 0 + + # Test WITHSTATUS with ZREVRANGEBYLEX + assert_equal {omega hill great} [r zrevrangebylex zset + \[g WITHSTATUS] + + # Test WITHSTATUS with ZREVRANGEBYLEX and LIMIT + assert_equal {omega hill} [r zrevrangebylex zset + \[g LIMIT 0 2 WITHSTATUS] + + # Test WITHSTATUS with ZREVRANGEBYLEX and LIMIT + assert_equal {omega hill} [r zrevrangebylex zset + \[g LIMIT 0 2 WITHSTATUS] + } + test "ZRANGEBYLEX with invalid lex range specifiers - $encoding" { assert_error "*not*string*" {r zrangebylex fooz foo bar} assert_error "*not*string*" {r zrangebylex fooz \[foo bar} @@ -2507,6 +2673,78 @@ start_server {tags {"zset"}} { r config set zset-max-listpack-entries $original_max } + test {ZRANGE with/without WITHSTATUS} { + # Test basic functionality with WITHSTATUS parameter + r zadd zset_withstatus 1 a 2 b 3 c + + # Test WITHSTATUS when key exists and has elements + assert_equal {a b c} [r zrange zset_withstatus 0 -1 WITHSTATUS] + + # Test WITHSTATUS when key exists but is empty (no elements in range) + r zadd zset_empty 1 a 2 b 3 c + assert_equal {} [r zrange zset_empty 10 20 WITHSTATUS] + + # Test WITHSTATUS with WITHSCORES + assert_equal {a 1 b 2 c 3} [r zrange zset_withstatus 0 -1 WITHSCORES WITHSTATUS] + + # Test WITHSTATUS with BYSCORE + assert_equal {a b c} [r zrange zset_withstatus 0 5 BYSCORE WITHSTATUS] + + # Test WITHSTATUS with BYLEX + r zadd zset_lex 0 alpha 0 bar 0 cool + assert_equal {alpha bar} [r zrange zset_lex - \[bar BYLEX WITHSTATUS] + + # Test WITHSTATUS with REV + assert_equal {c b a} [r zrange zset_withstatus 0 -1 REV WITHSTATUS] + + # Test WITHSTATUS with LIMIT (only works with BYSCORE or BYLEX) + assert_equal {a b} [r zrange zset_withstatus 0 5 BYSCORE LIMIT 0 2 WITHSTATUS] + + # Test WITHSTATUS with multiple modifiers + assert_equal {a 1 b 2} [r zrange zset_withstatus 0 5 BYSCORE LIMIT 0 2 WITHSCORES WITHSTATUS] + + # Test key does not exist - should return nullarray + assert_equal {} [r zrange non_existent_key 0 -1 WITHSTATUS] + # Note: In RESP2, nullarray is represented as an empty array in the test framework + # but the actual protocol response would be different + + # Test key exists but has no matching elements in range + assert_equal {} [r zrange zset_withstatus 10 20 WITHSTATUS] + + # Test nullarray vs emptyarray distinction in RESP3 + r hello 3 + r readraw 1 + + # Test nullarray (key does not exist) in RESP3 + set null_res [r zrange non_existent_key 0 -1 WITHSTATUS] + assert_equal {_} $null_res + + # Test emptyarray (key exists but no matching elements) in RESP3 + set empty_res [r zrange zset_withstatus 10 20 WITHSTATUS] + assert_equal {*0} $empty_res + + r readraw 0 + r hello 2 + + r readraw 1 + + # Test nullarray (key does not exist) in RESP2 + set null_res [r zrange non_existent_key 0 -1 WITHSTATUS] + assert_equal {*-1} $null_res + + # Test emptyarray (key exists but no matching elements) in RESP2 + set empty_res [r zrange zset_withstatus 10 20 WITHSTATUS] + assert_equal {*0} $empty_res + + r readraw 0 + + # Test WITHSTATUS without other parameters (should work like normal ZRANGE) + assert_equal {a b c} [r zrange zset_withstatus 0 -1 WITHSTATUS] + + # Test WITHSTATUS with WITHSCORES (should work together) + assert_equal {a 1 b 2 c 3} [r zrange zset_withstatus 0 -1 WITHSCORES WITHSTATUS] + } + test {ZRANGE invalid syntax} { catch {r zrange z1{t} 0 -1 limit 1 2} err assert_match "*syntax*" $err