From 527e1ec5b35dd49e31bde91e174e9c9a7befa871 Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving <144171266+SanHalacogluImproving@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:06:01 -0700 Subject: [PATCH] Java: Add `lindex` command. (List Command Group) (#1219) * Java: Add lindex command. (List Command Group) (#158) * Minor documentation update + changed param from int to long + minor IT update. --- .../src/main/java/glide/api/BaseClient.java | 7 +++++ .../glide/api/commands/ListBaseCommands.java | 24 +++++++++++++++++ .../glide/api/models/BaseTransaction.java | 23 ++++++++++++++++ .../test/java/glide/api/RedisClientTest.java | 26 +++++++++++++++++++ .../glide/api/models/TransactionTests.java | 4 +++ .../test/java/glide/SharedCommandTests.java | 21 +++++++++++++++ .../java/glide/TransactionTestUtilities.java | 2 ++ 7 files changed, 107 insertions(+) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 8c0a0c65a6..6422a66a0a 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -36,6 +36,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.LRange; import static redis_request.RedisRequestOuterClass.RequestType.LRem; import static redis_request.RedisRequestOuterClass.RequestType.LTrim; +import static redis_request.RedisRequestOuterClass.RequestType.Lindex; import static redis_request.RedisRequestOuterClass.RequestType.MGet; import static redis_request.RedisRequestOuterClass.RequestType.MSet; import static redis_request.RedisRequestOuterClass.RequestType.PExpire; @@ -445,6 +446,12 @@ public CompletableFuture lrange(@NonNull String key, long start, long response -> castArray(handleArrayOrNullResponse(response), String.class)); } + @Override + public CompletableFuture lindex(@NonNull String key, long index) { + return commandManager.submitNewCommand( + Lindex, new String[] {key, Long.toString(index)}, this::handleStringOrNullResponse); + } + @Override public CompletableFuture ltrim(@NonNull String key, long start, long end) { return commandManager.submitNewCommand( diff --git a/java/client/src/main/java/glide/api/commands/ListBaseCommands.java b/java/client/src/main/java/glide/api/commands/ListBaseCommands.java index 4483133ec5..1dc68d608d 100644 --- a/java/client/src/main/java/glide/api/commands/ListBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/ListBaseCommands.java @@ -103,6 +103,30 @@ public interface ListBaseCommands { */ CompletableFuture lrange(String key, long start, long end); + /** + * Returns the element at index from the list stored at key.
+ * The index is zero-based, so 0 means the first element, 1 the second + * element and so on. Negative indices can be used to designate elements starting at the tail of + * the list. Here, -1 means the last element, -2 means the penultimate + * and so forth. + * + * @see redis.io for details. + * @param key The key of the list. + * @param index The index of the element in the list to retrieve. + * @return The element at index in the list stored at key.
+ * If index is out of range or if key does not exist, null + * is returned. + * @example + *
{@code
+     * String payload1 = client.lindex("myList", 0).get();
+     * assert payload1.equals('value1'); // Returns the first element in the list stored at 'myList'.
+     *
+     * String payload2 = client.lindex("myList", -1).get();
+     * assert payload2.equals('value3'); // Returns the last element in the list stored at 'myList'.
+     * }
+ */ + CompletableFuture lindex(String key, long index); + /** * Trims an existing list so that it will contain only the specified range of elements specified. *
diff --git a/java/client/src/main/java/glide/api/models/BaseTransaction.java b/java/client/src/main/java/glide/api/models/BaseTransaction.java index 7a7a93b1a2..9a59ce1b46 100644 --- a/java/client/src/main/java/glide/api/models/BaseTransaction.java +++ b/java/client/src/main/java/glide/api/models/BaseTransaction.java @@ -45,6 +45,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.LRange; import static redis_request.RedisRequestOuterClass.RequestType.LRem; import static redis_request.RedisRequestOuterClass.RequestType.LTrim; +import static redis_request.RedisRequestOuterClass.RequestType.Lindex; import static redis_request.RedisRequestOuterClass.RequestType.MGet; import static redis_request.RedisRequestOuterClass.RequestType.MSet; import static redis_request.RedisRequestOuterClass.RequestType.PExpire; @@ -677,6 +678,28 @@ public T lrange(@NonNull String key, long start, long end) { return getThis(); } + /** + * Returns the element at index from the list stored at key.
+ * The index is zero-based, so 0 means the first element, 1 the second + * element and so on. Negative indices can be used to designate elements starting at the tail of + * the list. Here, -1 means the last element, -2 means the penultimate + * and so forth. + * + * @see redis.io for details. + * @param key The key of the list. + * @param index The index of the element in the list to retrieve. + * @return Command Response - The element at index in the list stored at key + * .
+ * If index is out of range or if key does not exist, null + * is returned. + */ + public T lindex(@NonNull String key, long index) { + ArgsArray commandArgs = buildArgs(key, Long.toString(index)); + + protobufTransaction.addCommands(buildCommand(Lindex, commandArgs)); + return getThis(); + } + /** * Trims an existing list so that it will contain only the specified range of elements specified.
* The offsets start and end are zero-based indexes, with 0 being the diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index 44414575ec..15deb678cd 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -64,6 +64,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.LRange; import static redis_request.RedisRequestOuterClass.RequestType.LRem; import static redis_request.RedisRequestOuterClass.RequestType.LTrim; +import static redis_request.RedisRequestOuterClass.RequestType.Lindex; import static redis_request.RedisRequestOuterClass.RequestType.MGet; import static redis_request.RedisRequestOuterClass.RequestType.MSet; import static redis_request.RedisRequestOuterClass.RequestType.PExpire; @@ -1348,6 +1349,31 @@ public void lrange_returns_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void lindex_returns_success() { + // setup + String key = "testKey"; + long index = 2; + String[] args = new String[] {key, Long.toString(index)}; + String value = "value"; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(Lindex), eq(args), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.lindex(key, index); + String payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void ltrim_returns_success() { diff --git a/java/client/src/test/java/glide/api/models/TransactionTests.java b/java/client/src/test/java/glide/api/models/TransactionTests.java index a4bc0eb1c9..886a4c56df 100644 --- a/java/client/src/test/java/glide/api/models/TransactionTests.java +++ b/java/client/src/test/java/glide/api/models/TransactionTests.java @@ -43,6 +43,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.LRange; import static redis_request.RedisRequestOuterClass.RequestType.LRem; import static redis_request.RedisRequestOuterClass.RequestType.LTrim; +import static redis_request.RedisRequestOuterClass.RequestType.Lindex; import static redis_request.RedisRequestOuterClass.RequestType.MGet; import static redis_request.RedisRequestOuterClass.RequestType.MSet; import static redis_request.RedisRequestOuterClass.RequestType.PExpire; @@ -232,6 +233,9 @@ public void transaction_builds_protobuf_request(BaseTransaction transaction) results.add( Pair.of(LRange, ArgsArray.newBuilder().addArgs("key").addArgs("1").addArgs("2").build())); + transaction.lindex("key", 1); + results.add(Pair.of(Lindex, ArgsArray.newBuilder().addArgs("key").addArgs("1").build())); + transaction.ltrim("key", 1, 2); results.add( Pair.of(LTrim, ArgsArray.newBuilder().addArgs("key").addArgs("1").addArgs("2").build())); diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java index cb902e7de1..2477549b72 100644 --- a/java/integTest/src/test/java/glide/SharedCommandTests.java +++ b/java/integTest/src/test/java/glide/SharedCommandTests.java @@ -684,6 +684,27 @@ public void lpush_lpop_lrange_type_error(BaseClient client) { assertTrue(lrangeException.getCause() instanceof RequestException); } + @SneakyThrows + @ParameterizedTest + @MethodSource("getClients") + public void lindex(BaseClient client) { + String key1 = UUID.randomUUID().toString(); + String key2 = UUID.randomUUID().toString(); + String[] valueArray = new String[] {"value1", "value2"}; + + assertEquals(2, client.lpush(key1, valueArray).get()); + assertEquals(valueArray[1], client.lindex(key1, 0).get()); + assertEquals(valueArray[0], client.lindex(key1, -1).get()); + assertNull(client.lindex(key1, 3).get()); + assertNull(client.lindex(key2, 3).get()); + + // Key exists, but it is not a List + assertEquals(OK, client.set(key2, "value").get()); + Exception executionException = + assertThrows(ExecutionException.class, () -> client.lindex(key2, 0).get()); + assertTrue(executionException.getCause() instanceof RequestException); + } + @SneakyThrows @ParameterizedTest @MethodSource("getClients") diff --git a/java/integTest/src/test/java/glide/TransactionTestUtilities.java b/java/integTest/src/test/java/glide/TransactionTestUtilities.java index f8b8002cfa..95e1014727 100644 --- a/java/integTest/src/test/java/glide/TransactionTestUtilities.java +++ b/java/integTest/src/test/java/glide/TransactionTestUtilities.java @@ -79,6 +79,7 @@ public static BaseTransaction transactionTest(BaseTransaction baseTransact baseTransaction.lpush(key5, new String[] {value1, value1, value2, value3, value3}); baseTransaction.llen(key5); + baseTransaction.lindex(key5, 0); baseTransaction.lrem(key5, 1, value1); baseTransaction.ltrim(key5, 1, -1); baseTransaction.lrange(key5, 0, -2); @@ -172,6 +173,7 @@ public static Object[] transactionTestResult() { 10.5, 5L, 5L, + value3, // lindex(key5, 0) 1L, OK, new String[] {value3, value2},