From 7164805960f21c941f3d0156a18371777ad0e1f1 Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving <144171266+SanHalacogluImproving@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:52:12 -0700 Subject: [PATCH] Java: Add hlen command. (Hash Command Group) (#159) --- .../src/main/java/glide/api/BaseClient.java | 6 +++++ .../glide/api/commands/HashBaseCommands.java | 18 ++++++++++++++ .../glide/api/models/BaseTransaction.java | 17 +++++++++++++ .../test/java/glide/api/RedisClientTest.java | 24 +++++++++++++++++++ .../glide/api/models/TransactionTests.java | 4 ++++ .../test/java/glide/SharedCommandTests.java | 23 ++++++++++++++++++ .../java/glide/TransactionTestUtilities.java | 2 ++ 7 files changed, 94 insertions(+) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 48bf3a50b4..0a960c9c13 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -13,6 +13,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.Expire; import static redis_request.RedisRequestOuterClass.RequestType.ExpireAt; import static redis_request.RedisRequestOuterClass.RequestType.GetString; +import static redis_request.RedisRequestOuterClass.RequestType.HLen; import static redis_request.RedisRequestOuterClass.RequestType.HashDel; import static redis_request.RedisRequestOuterClass.RequestType.HashExists; import static redis_request.RedisRequestOuterClass.RequestType.HashGet; @@ -323,6 +324,11 @@ public CompletableFuture hdel(@NonNull String key, @NonNull String[] field return commandManager.submitNewCommand(HashDel, args, this::handleLongResponse); } + @Override + public CompletableFuture hlen(@NonNull String key) { + return commandManager.submitNewCommand(HLen, new String[] {key}, this::handleLongResponse); + } + @Override public CompletableFuture hmget(@NonNull String key, @NonNull String[] fields) { String[] arguments = ArrayUtils.addFirst(fields, key); diff --git a/java/client/src/main/java/glide/api/commands/HashBaseCommands.java b/java/client/src/main/java/glide/api/commands/HashBaseCommands.java index 8007106a16..3d1d8333eb 100644 --- a/java/client/src/main/java/glide/api/commands/HashBaseCommands.java +++ b/java/client/src/main/java/glide/api/commands/HashBaseCommands.java @@ -65,6 +65,24 @@ public interface HashBaseCommands { */ CompletableFuture hdel(String key, String[] fields); + /** + * Returns the number of fields contained in the hash stored at key. + * + * @see redis.io for details. + * @param key The key of the hash. + * @return The number of fields in the hash, or 0 when the key does not exist.
+ * If key holds a value that is not a hash, an error is returned. + * @example + *
{@code
+     * Long num1 = client.hlen("myHash").get();
+     * assert num1 == 3L;
+     *
+     * Long num2 = client.hlen("nonExistingKey").get();
+     * assert num2 == 0L;
+     * }
+ */ + CompletableFuture hlen(String key); + /** * Returns the values associated with the specified fields in the hash stored at key. * 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 d0c1d4814c..cc9bb807da 100644 --- a/java/client/src/main/java/glide/api/models/BaseTransaction.java +++ b/java/client/src/main/java/glide/api/models/BaseTransaction.java @@ -18,6 +18,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.Expire; import static redis_request.RedisRequestOuterClass.RequestType.ExpireAt; import static redis_request.RedisRequestOuterClass.RequestType.GetString; +import static redis_request.RedisRequestOuterClass.RequestType.HLen; import static redis_request.RedisRequestOuterClass.RequestType.HashDel; import static redis_request.RedisRequestOuterClass.RequestType.HashExists; import static redis_request.RedisRequestOuterClass.RequestType.HashGet; @@ -394,6 +395,22 @@ public T hdel(@NonNull String key, @NonNull String[] fields) { return getThis(); } + /** + * Returns the number of fields contained in the hash stored at key. + * + * @see redis.io for details. + * @param key The key of the hash. + * @return Command Response - The number of fields in the hash, or 0 when the key + * does not exist.
+ * If key holds a value that is not a hash, an error is returned. + */ + public T hlen(@NonNull String key) { + ArgsArray commandArgs = buildArgs(key); + + protobufTransaction.addCommands(buildCommand(HLen, commandArgs)); + return getThis(); + } + /** * Returns the values associated with the specified fields in the hash stored at key. * diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index 2aee44867d..a371d48a66 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -29,6 +29,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.Expire; import static redis_request.RedisRequestOuterClass.RequestType.ExpireAt; import static redis_request.RedisRequestOuterClass.RequestType.GetString; +import static redis_request.RedisRequestOuterClass.RequestType.HLen; import static redis_request.RedisRequestOuterClass.RequestType.HashDel; import static redis_request.RedisRequestOuterClass.RequestType.HashExists; import static redis_request.RedisRequestOuterClass.RequestType.HashGet; @@ -855,6 +856,29 @@ public void hdel_success() { assertEquals(value, payload); } + @SneakyThrows + @Test + public void hlen_success() { + // setup + String key = "testKey"; + String[] args = {key}; + Long value = 2L; + + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(value); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(HLen), eq(args), any())).thenReturn(testResponse); + + // exercise + CompletableFuture response = service.hlen(key); + Long payload = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(value, payload); + } + @SneakyThrows @Test public void hmget_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 7d1f98430f..dd8d2af71c 100644 --- a/java/client/src/test/java/glide/api/models/TransactionTests.java +++ b/java/client/src/test/java/glide/api/models/TransactionTests.java @@ -16,6 +16,7 @@ import static redis_request.RedisRequestOuterClass.RequestType.Expire; import static redis_request.RedisRequestOuterClass.RequestType.ExpireAt; import static redis_request.RedisRequestOuterClass.RequestType.GetString; +import static redis_request.RedisRequestOuterClass.RequestType.HLen; import static redis_request.RedisRequestOuterClass.RequestType.HashDel; import static redis_request.RedisRequestOuterClass.RequestType.HashExists; import static redis_request.RedisRequestOuterClass.RequestType.HashGet; @@ -146,6 +147,9 @@ public void transaction_builds_protobuf_request(BaseTransaction transaction) transaction.hdel("key", new String[] {"field"}); results.add(Pair.of(HashDel, ArgsArray.newBuilder().addArgs("key").addArgs("field").build())); + transaction.hlen("key"); + results.add(Pair.of(HLen, ArgsArray.newBuilder().addArgs("key").build())); + transaction.hmget("key", new String[] {"field"}); results.add(Pair.of(HashMGet, ArgsArray.newBuilder().addArgs("key").addArgs("field").build())); diff --git a/java/integTest/src/test/java/glide/SharedCommandTests.java b/java/integTest/src/test/java/glide/SharedCommandTests.java index ab565d1f1e..d0d7e38be3 100644 --- a/java/integTest/src/test/java/glide/SharedCommandTests.java +++ b/java/integTest/src/test/java/glide/SharedCommandTests.java @@ -442,6 +442,29 @@ public void hdel_multiple_existing_fields_non_existing_field_non_existing_key(Ba assertEquals(0, client.hdel("non_existing_key", new String[] {field3}).get()); } + @SneakyThrows + @ParameterizedTest + @MethodSource("getClients") + public void hlen(BaseClient client) { + String key1 = UUID.randomUUID().toString(); + String key2 = UUID.randomUUID().toString(); + String field1 = UUID.randomUUID().toString(); + String field2 = UUID.randomUUID().toString(); + String value = UUID.randomUUID().toString(); + Map fieldValueMap = Map.of(field1, value, field2, value); + + assertEquals(2, client.hset(key1, fieldValueMap).get()); + assertEquals(2, client.hlen(key1).get()); + assertEquals(1, client.hdel(key1, new String[] {field1}).get()); + assertEquals(1, client.hlen(key1).get()); + assertEquals(0, client.hlen("nonExistingHash").get()); + + assertEquals(OK, client.set(key2, "value").get()); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> client.hlen(key2).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 4c74b4b24d..3ea9091b60 100644 --- a/java/integTest/src/test/java/glide/TransactionTestUtilities.java +++ b/java/integTest/src/test/java/glide/TransactionTestUtilities.java @@ -56,6 +56,7 @@ public static BaseTransaction transactionTest(BaseTransaction baseTransact baseTransaction.hset(key4, Map.of(field1, value1, field2, value2)); baseTransaction.hget(key4, field1); + baseTransaction.hlen(key4); baseTransaction.hexists(key4, field2); baseTransaction.hmget(key4, new String[] {field1, "non_existing_field", field2}); baseTransaction.hgetall(key4); @@ -115,6 +116,7 @@ public static Object[] transactionTestResult() { 1L, 2L, value1, + 2L, // hlen(key4) true, new String[] {value1, null, value2}, Map.of(field1, value1, field2, value2),