Skip to content

Commit

Permalink
Java: Added Hmget command for BaseClient and BaseTransaction (Hash Co…
Browse files Browse the repository at this point in the history
…mmands) (valkey-io#1015)

* Java: Added Hmget command for BaseClient and BaseTransaction (Hash Commands)

* Fixed documentation styling.

* Minor updates based on PR comments.
  • Loading branch information
SanHalacogluImproving authored Feb 22, 2024
1 parent b556002 commit e264963
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 0 deletions.
8 changes: 8 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.GetString;
import static redis_request.RedisRequestOuterClass.RequestType.HashDel;
import static redis_request.RedisRequestOuterClass.RequestType.HashGet;
import static redis_request.RedisRequestOuterClass.RequestType.HashMGet;
import static redis_request.RedisRequestOuterClass.RequestType.HashSet;
import static redis_request.RedisRequestOuterClass.RequestType.Incr;
import static redis_request.RedisRequestOuterClass.RequestType.IncrBy;
Expand Down Expand Up @@ -297,6 +298,13 @@ public CompletableFuture<Long> hdel(@NonNull String key, @NonNull String[] field
return commandManager.submitNewCommand(HashDel, args, this::handleLongResponse);
}

@Override
public CompletableFuture<String[]> hmget(@NonNull String key, @NonNull String[] fields) {
String[] arguments = ArrayUtils.addFirst(fields, key);
return commandManager.submitNewCommand(
HashMGet, arguments, response -> castArray(handleArrayResponse(response), String.class));
}

@Override
public CompletableFuture<Long> sadd(String key, String[] members) {
String[] arguments = ArrayUtils.addFirst(members, key);
Expand Down
19 changes: 19 additions & 0 deletions java/client/src/main/java/glide/api/commands/HashCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,23 @@ public interface HashCommands {
* If <code>key</code> does not exist, it is treated as an empty hash and it returns 0.<br>
*/
CompletableFuture<Long> hdel(String key, String[] fields);

/**
* Returns the values associated with the specified fields in the hash stored at <code>key</code>.
*
* @see <a href="https://redis.io/commands/hmget/">redis.io</a> for details.
* @param key The key of the hash.
* @param fields The fields in the hash stored at <code>key</code> to retrieve from the database.
* @return An array of values associated with the given fields, in the same order as they are
* requested.<br>
* For every field that does not exist in the hash, a null value is returned.<br>
* If <code>key</code> does not exist, it is treated as an empty hash, and it returns an array
* of null values.<br>
* @example
* <pre>
* String[] values = client.hmget("my_hash", new String[] {"field1", "field2"}).get()
* assert values == new String[] {"value1", "value2"}
* </pre>
*/
CompletableFuture<String[]> hmget(String key, String[] fields);
}
20 changes: 20 additions & 0 deletions java/client/src/main/java/glide/api/models/BaseTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.GetString;
import static redis_request.RedisRequestOuterClass.RequestType.HashDel;
import static redis_request.RedisRequestOuterClass.RequestType.HashGet;
import static redis_request.RedisRequestOuterClass.RequestType.HashMGet;
import static redis_request.RedisRequestOuterClass.RequestType.HashSet;
import static redis_request.RedisRequestOuterClass.RequestType.Incr;
import static redis_request.RedisRequestOuterClass.RequestType.IncrBy;
Expand Down Expand Up @@ -362,6 +363,25 @@ public T hdel(@NonNull String key, @NonNull String[] fields) {
return getThis();
}

/**
* Returns the values associated with the specified fields in the hash stored at <code>key</code>.
*
* @see <a href="https://redis.io/commands/hmget/">redis.io</a> for details.
* @param key The key of the hash.
* @param fields The fields in the hash stored at <code>key</code> to retrieve from the database.
* @return Command Response - An array of values associated with the given fields, in the same
* order as they are requested.<br>
* For every field that does not exist in the hash, a null value is returned.<br>
* If <code>key</code> does not exist, it is treated as an empty hash, and it returns an array
* of null values.<br>
*/
public T hmget(@NonNull String key, @NonNull String[] fields) {
ArgsArray commandArgs = buildArgs(ArrayUtils.addFirst(fields, key));

protobufTransaction.addCommands(buildCommand(HashMGet, commandArgs));
return getThis();
}

/**
* Add specified members to the set stored at <code>key</code>. Specified members that are already
* a member of this set are ignored.
Expand Down
26 changes: 26 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.GetString;
import static redis_request.RedisRequestOuterClass.RequestType.HashDel;
import static redis_request.RedisRequestOuterClass.RequestType.HashGet;
import static redis_request.RedisRequestOuterClass.RequestType.HashMGet;
import static redis_request.RedisRequestOuterClass.RequestType.HashSet;
import static redis_request.RedisRequestOuterClass.RequestType.Incr;
import static redis_request.RedisRequestOuterClass.RequestType.IncrBy;
Expand Down Expand Up @@ -568,6 +569,31 @@ public void hdel_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void hmget_success() {
// setup
String key = "testKey";
String[] fields = {"testField1", "testField2"};
String[] args = {"testKey", "testField1", "testField2"};
String[] value = {"testValue1", "testValue2"};

CompletableFuture<String[]> testResponse = mock(CompletableFuture.class);
when(testResponse.get()).thenReturn(value);

// match on protobuf request
when(commandManager.<String[]>submitNewCommand(eq(HashMGet), eq(args), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<String[]> response = service.hmget(key, fields);
String[] payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void sadd_returns_success() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.GetString;
import static redis_request.RedisRequestOuterClass.RequestType.HashDel;
import static redis_request.RedisRequestOuterClass.RequestType.HashGet;
import static redis_request.RedisRequestOuterClass.RequestType.HashMGet;
import static redis_request.RedisRequestOuterClass.RequestType.HashSet;
import static redis_request.RedisRequestOuterClass.RequestType.Incr;
import static redis_request.RedisRequestOuterClass.RequestType.IncrBy;
Expand Down Expand Up @@ -91,6 +92,9 @@ public void transaction_builds_protobuf_request(BaseTransaction<?> transaction)
transaction.mget(new String[] {"key"});
results.add(Pair.of(MGet, ArgsArray.newBuilder().addArgs("key").build()));

transaction.hmget("key", new String[] {"field"});
results.add(Pair.of(HashMGet, ArgsArray.newBuilder().addArgs("key").addArgs("field").build()));

transaction.incr("key");
results.add(Pair.of(Incr, ArgsArray.newBuilder().addArgs("key").build()));

Expand Down
20 changes: 20 additions & 0 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,26 @@ 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 hmget_multiple_existing_fields_non_existing_field_non_existing_key(
BaseClient client) {
String key = UUID.randomUUID().toString();
String field1 = UUID.randomUUID().toString();
String field2 = UUID.randomUUID().toString();
String value = UUID.randomUUID().toString();
Map<String, String> fieldValueMap = Map.of(field1, value, field2, value);

assertEquals(2, client.hset(key, fieldValueMap).get());
assertArrayEquals(
new String[] {value, null, value},
client.hmget(key, new String[] {field1, "non_existing_field", field2}).get());
assertArrayEquals(
new String[] {null, null},
client.hmget("non_existing_key", new String[] {field1, field2}).get());
}

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public static BaseTransaction<?> transactionTest(BaseTransaction<?> baseTransact

baseTransaction.hset(key4, Map.of(field1, value1, field2, value2));
baseTransaction.hget(key4, field1);
baseTransaction.hmget(key4, new String[] {field1, "non_existing_field", field2});
baseTransaction.hdel(key4, new String[] {field1});

baseTransaction.sadd(key5, new String[] {"baz", "foo"});
Expand Down Expand Up @@ -72,6 +73,7 @@ public static Object[] transactionTestResult() {
0.5,
2L,
value1,
new String[] {value1, null, value2},
1L,
2L,
1L,
Expand Down

0 comments on commit e264963

Please sign in to comment.