Repository: redis/redis

Problem statement:
[NEW] Add exclusive (open) range intervals to XPENDING
**The problem/use-case that the feature addresses**

XPENDING can be used for paging through the PEL but requires the user to perform arithmetic gymnastics to achieve proper exclusiveness.

**Description of the feature**

XPENDING should support the exclusive range syntax as implemented in #8072 for XRANGE.


Hints:

Patch:
diff --git a/src/t_stream.c b/src/t_stream.c
index bb38b0fb89f..79fc557ba23 100644
--- a/src/t_stream.c
+++ b/src/t_stream.c
@@ -2218,8 +2218,9 @@ void xpendingCommand(client *c) {
     robj *groupname = c->argv[2];
     robj *consumername = NULL;
     streamID startid, endid;
-    long long count;
+    long long count = 0;
     long long minidle = 0;
+    int startex = 0, endex = 0;
 
     /* Start and stop, and the consumer, can be omitted. Also the IDLE modifier. */
     if (c->argc != 3 && (c->argc < 6 || c->argc > 9)) {
@@ -2243,13 +2244,25 @@ void xpendingCommand(client *c) {
             /* Search for rest of arguments after 'IDLE <idle>' */
             startidx += 2;
         }
+
+        /* count argument. */
         if (getLongLongFromObjectOrReply(c,c->argv[startidx+2],&count,NULL) == C_ERR)
             return;
         if (count < 0) count = 0;
-        if (streamParseIDOrReply(c,c->argv[startidx],&startid,0) == C_ERR)
+
+        /* start and end arguments. */
+        if (streamParseIntervalIDOrReply(c,c->argv[startidx],&startid,&startex,0) != C_OK)
             return;
-        if (streamParseIDOrReply(c,c->argv[startidx+1],&endid,UINT64_MAX) == C_ERR)
+        if (startex && streamIncrID(&startid) != C_OK) {
+            addReplyError(c,"invalid start ID for the interval");
             return;
+        }
+        if (streamParseIntervalIDOrReply(c,c->argv[startidx+1],&endid,&endex,UINT64_MAX) != C_OK)
+            return;
+        if (endex && streamDecrID(&endid) != C_OK) {
+            addReplyError(c,"invalid end ID for the interval");
+            return;
+        }
 
         if (startidx+3 < c->argc) {
             /* 'consumer' was provided */


Test patch:
diff --git a/tests/unit/type/stream-cgroups.tcl b/tests/unit/type/stream-cgroups.tcl
index 41e2ab97973..105cace3120 100644
--- a/tests/unit/type/stream-cgroups.tcl
+++ b/tests/unit/type/stream-cgroups.tcl
@@ -87,6 +87,20 @@ start_server {
         assert {[llength $pending] == 4}
     }
 
+    test {XPENDING with exclusive range intervals works as expected} {
+        set pending [r XPENDING mystream mygroup - + 10]
+        assert {[llength $pending] == 4}
+        set startid [lindex [lindex $pending 0] 0]
+        set endid [lindex [lindex $pending 3] 0]
+        set expending [r XPENDING mystream mygroup ($startid ($endid 10]
+        assert {[llength $expending] == 2}
+        for {set j 0} {$j < 2} {incr j} {
+            set itemid [lindex [lindex $expending $j] 0]
+            assert {$itemid ne $startid}
+            assert {$itemid ne $endid}
+        }
+    }
+
     test {XACK is able to remove items from the client/group PEL} {
         set pending [r XPENDING mystream mygroup - + 10 client-1]
         set id1 [lindex $pending 0 0]