Repository: redis/lettuce
Pull request #3217 (2025-03-15 09:58:51)

json.arrpop forces index=-1 with root path (#3214)
Issue #3214 
<!--
Thank you for proposing a pull request. This template will guide you through the essential steps necessary for a pull request.
-->
Make sure that:

- [x] You have read the [contribution guidelines](https://github.com/lettuce-io/lettuce-core/blob/main/.github/CONTRIBUTING.md).
- [ ] You have created a feature request first to discuss your contribution intent. Please reference the feature request ticket number in the pull request.
- [x] You applied code formatting rules using the `mvn formatter:format` target. Don’t submit any formatting related changes.
- [x] You submit test cases (unit or integration tests) that back your changes.

 <!--
Great! Live long and prosper.
-->



Patch:
diff --git a/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java b/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java
index bd713854c..42e8e40cf 100644
--- a/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java
+++ b/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java
@@ -106,13 +106,14 @@ class RedisJsonCommandBuilder<K, V> extends BaseRedisCommandBuilder<K, V> {
 
         CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key);
 
-        if (jsonPath != null && !jsonPath.isRootPath()) {
-            // OPTIONAL as per API
-            args.add(jsonPath.toString());
-
+        if (jsonPath != null) {
             if (index != -1) {
                 // OPTIONAL as per API
+                args.add(jsonPath.toString());
                 args.add(index);
+            } else if (!jsonPath.isRootPath()) {
+                // OPTIONAL as per API
+                args.add(jsonPath.toString());
             }
         }
 
diff --git a/src/main/java/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.java b/src/main/java/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.java
index ddf33481a..882e4718f 100644
--- a/src/main/java/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.java
+++ b/src/main/java/io/lettuce/core/cluster/ClusterTopologyRefreshOptions.java
@@ -169,7 +169,7 @@ public class ClusterTopologyRefreshOptions {
 
             LettuceAssert.notNull(refreshTrigger, "RefreshTriggers must not be null");
             LettuceAssert.noNullElements(refreshTrigger, "RefreshTriggers must not contain null elements");
-            LettuceAssert.notEmpty(refreshTrigger, "RefreshTriggers must not contain at least one element");
+            LettuceAssert.notEmpty(refreshTrigger, "RefreshTriggers must contain at least one element");
 
             adaptiveRefreshTriggers.addAll(Arrays.asList(refreshTrigger));
             return this;


Test patch:
diff --git a/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java b/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java
index fbb2ae3fb..28df5f01a 100644
--- a/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java
+++ b/src/test/java/io/lettuce/core/RedisJsonCommandBuilderUnitTests.java
@@ -157,7 +157,7 @@ class RedisJsonCommandBuilderUnitTests {
     }
 
     @Test
-    void shouldCorrectlyConstructJsonArrpopRootPath() {
+    void shouldCorrectlyConstructJsonArrpopRootPathNoIndex() {
         Command<String, String, List<JsonValue>> command = builder.jsonArrpop(MY_KEY, JsonPath.ROOT_PATH, -1);
         ByteBuf buf = Unpooled.directBuffer();
         command.encode(buf);
@@ -166,6 +166,16 @@ class RedisJsonCommandBuilderUnitTests {
                 .isEqualTo("*2\r\n" + "$11\r\n" + "JSON.ARRPOP\r\n" + "$15\r\n" + "bikes:inventory\r\n");
     }
 
+    @Test
+    void shouldCorrectlyConstructJsonArrpopRootPath() {
+        Command<String, String, List<JsonValue>> command = builder.jsonArrpop(MY_KEY, JsonPath.ROOT_PATH, 1);
+        ByteBuf buf = Unpooled.directBuffer();
+        command.encode(buf);
+
+        assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*4\r\n" + "$11\r\n" + "JSON.ARRPOP\r\n" + "$15\r\n"
+                + "bikes:inventory\r\n" + "$1\r\n" + "$\r\n" + "$1\r\n" + "1\r\n");
+    }
+
     @Test
     void shouldCorrectlyConstructJsonArrtrim() {
         JsonRangeArgs range = JsonRangeArgs.Builder.start(0).stop(1);
diff --git a/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java b/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java
index 116b12771..225dd749f 100644
--- a/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java
+++ b/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java
@@ -163,8 +163,16 @@ public class RedisJsonIntegrationTests {
         redis.jsonSet("myKey", JsonPath.ROOT_PATH, value);
         List<JsonValue> result = redis.jsonArrpop("myKey");
         assertThat(result.toString()).isEqualTo("[\"one\"]");
-        result = redis.jsonArrpop("myKey", JsonPath.ROOT_PATH, 0);
-        assertThat(result.get(0).isNull()).isTrue();
+        assertThat(redis.jsonGet("myKey").get(0).toString()).isEqualTo("[]");
+    }
+
+    @Test
+    public void jsonArrpopWithRootPathAndIndex() {
+        JsonValue value = redis.getJsonParser().createJsonValue("[\"one\",\"two\",\"three\"]");
+        redis.jsonSet("myKey", JsonPath.ROOT_PATH, value);
+        List<JsonValue> result = redis.jsonArrpop("myKey", JsonPath.ROOT_PATH, 1);
+        assertThat(result.toString()).isEqualTo("[\"two\"]");
+        assertThat(redis.jsonGet("myKey").get(0).toString()).isEqualTo("[\"one\",\"three\"]");
     }
 
     @ParameterizedTest(name = "With {0} as path")