Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: Add Zmscore command. (Sorted Set Command Group) #1234

Merged
merged 6 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion glide-core/src/protobuf/redis_request.proto
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ enum RequestType {
Blpop = 100;
RPushX = 102;
LPushX = 103;
ZMScore = 104;
}

message Command {
Expand All @@ -169,7 +170,7 @@ message Transaction {

message RedisRequest {
uint32 callback_idx = 1;

oneof command {
Command single_command = 2;
Transaction transaction = 3;
Expand Down
3 changes: 3 additions & 0 deletions glide-core/src/request_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub enum RequestType {
Blpop = 100,
RPushX = 102,
LPushX = 103,
ZMScore = 104,
}

fn get_two_word_command(first: &str, second: &str) -> Cmd {
Expand Down Expand Up @@ -225,6 +226,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::LPushX => RequestType::LPushX,
ProtobufRequestType::Blpop => RequestType::Blpop,
ProtobufRequestType::Spop => RequestType::Spop,
ProtobufRequestType::ZMScore => RequestType::ZMScore,
}
}
}
Expand Down Expand Up @@ -335,6 +337,7 @@ impl RequestType {
RequestType::LPushX => Some(cmd("LPUSHX")),
RequestType::Blpop => Some(cmd("BLPOP")),
RequestType::Spop => Some(cmd("SPOP")),
RequestType::ZMScore => Some(cmd("ZMSCORE")),
}
}
}
10 changes: 10 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.Type;
import static redis_request.RedisRequestOuterClass.RequestType.Unlink;
import static redis_request.RedisRequestOuterClass.RequestType.XAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.ZScore;
Expand Down Expand Up @@ -714,6 +715,15 @@ public CompletableFuture<Object[]> zrankWithScore(@NonNull String key, @NonNull
Zrank, new String[] {key, member, WITH_SCORE_REDIS_API}, this::handleArrayOrNullResponse);
}

@Override
public CompletableFuture<Double[]> zmscore(@NonNull String key, @NonNull String[] members) {
String[] arguments = ArrayUtils.addFirst(members, key);
return commandManager.submitNewCommand(
ZMScore,
arguments,
response -> castArray(handleArrayOrNullResponse(response), Double.class));
}

@Override
public CompletableFuture<String> xadd(@NonNull String key, @NonNull Map<String, String> values) {
return xadd(key, values, StreamAddOptions.builder().build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,4 +456,22 @@ CompletableFuture<Map<String, Double>> zrangeWithScores(
* }</pre>
*/
CompletableFuture<Object[]> zrankWithScore(String key, String member);

/**
* Returns the scores associated with the specified <code>members</code> in the sorted set stored
* at <code>key</code>.
*
* @see <a href="https://redis.io/commands/zmscore/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param members An array of members in the sorted set.
* @return An <code>Array</code> of scores of the <code>members</code>.<br>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if the key doesn't exist? what if the key doesn't hold a sorted set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the key doesn't exist, the same thing happens, returns null for all corresponding members. If the key is not a set that is an error condition and we do not document error conditions. This is the same as PY and Node.

* If a <code>member</code> does not exist, the corresponding value in the <code>Array</code>
* will be <code>null</code>.
* @example
* <pre>{@code
* Double[] payload = client.zmscore(key1, new String[] {"one", "nonExistentMember", "three"}).get();
* assert payload.equals(new Double[] {1.0, null, 3.0});
* }</pre>
*/
CompletableFuture<Double[]> zmscore(String key, String[] members);
}
18 changes: 18 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 @@ -71,6 +71,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.Type;
import static redis_request.RedisRequestOuterClass.RequestType.Unlink;
import static redis_request.RedisRequestOuterClass.RequestType.XAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.ZScore;
Expand Down Expand Up @@ -1514,6 +1515,23 @@ public T zrankWithScore(@NonNull String key, @NonNull String member) {
return getThis();
}

/**
* Returns the scores associated with the specified <code>members</code> in the sorted set stored
SanHalacogluImproving marked this conversation as resolved.
Show resolved Hide resolved
* at <code>key</code>.
*
* @see <a href="https://redis.io/commands/zmscore/">redis.io</a> for more details.
* @param key The key of the sorted set.
* @param members An array of members in the sorted set.
* @return Command Response - An <code>Array</code> of scores of the <code>members</code>.<br>
* If a <code>member</code> does not exist, the corresponding value in the <code>Array</code>
* will be <code>null</code>.
*/
public T zmscore(@NonNull String key, @NonNull String[] members) {
ArgsArray commandArgs = buildArgs(ArrayUtils.addFirst(members, key));
protobufTransaction.addCommands(buildCommand(ZMScore, commandArgs));
return getThis();
}

/**
* Adds an entry to the specified stream.
*
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 @@ -91,6 +91,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.Type;
import static redis_request.RedisRequestOuterClass.RequestType.Unlink;
import static redis_request.RedisRequestOuterClass.RequestType.XAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.ZScore;
Expand Down Expand Up @@ -2270,6 +2271,31 @@ public void zrankWithScore_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void zmscore_returns_success() {
// setup
String key = "testKey";
String[] members = new String[] {"member1", "member2"};
String[] arguments = new String[] {key, "member1", "member2"};
Double[] value = new Double[] {2.5, 8.2};

CompletableFuture<Double[]> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<Double[]>submitNewCommand(eq(ZMScore), eq(arguments), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Double[]> response = service.zmscore(key, members);
Double[] payload = response.get();

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

@SneakyThrows
@Test
public void xadd_returns_success() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.Type;
import static redis_request.RedisRequestOuterClass.RequestType.Unlink;
import static redis_request.RedisRequestOuterClass.RequestType.XAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
import static redis_request.RedisRequestOuterClass.RequestType.ZScore;
Expand Down Expand Up @@ -459,6 +460,12 @@ public void transaction_builds_protobuf_request(BaseTransaction<?> transaction)
.addArgs(WITH_SCORE_REDIS_API)
.build()));

transaction.zmscore("key", new String[] {"member1", "member2"});
results.add(
Pair.of(
ZMScore,
ArgsArray.newBuilder().addArgs("key").addArgs("member1").addArgs("member2").build()));

transaction.xadd("key", Map.of("field1", "foo1"));
results.add(
Pair.of(
Expand Down
27 changes: 27 additions & 0 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,33 @@ public void zrank(BaseClient client) {
assertTrue(executionException.getCause() instanceof RequestException);
}

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
public void zmscore(BaseClient client) {
String key1 = UUID.randomUUID().toString();
String key2 = UUID.randomUUID().toString();
Map<String, Double> membersScores = Map.of("one", 1.0, "two", 2.0, "three", 3.0);
assertEquals(3, client.zadd(key1, membersScores).get());
assertArrayEquals(
new Double[] {1.0, 2.0, 3.0},
client.zmscore(key1, new String[] {"one", "two", "three"}).get());
assertArrayEquals(
new Double[] {1.0, null, null, 3.0},
client
.zmscore(key1, new String[] {"one", "nonExistentMember", "nonExistentMember", "three"})
.get());
assertArrayEquals(
new Double[] {null}, client.zmscore("nonExistentKey", new String[] {"one"}).get());

// Key exists, but it is not a set
assertEquals(OK, client.set(key2, "bar").get());
ExecutionException executionException =
assertThrows(
ExecutionException.class, () -> client.zmscore(key2, new String[] {"one"}).get());
assertTrue(executionException.getCause() instanceof RequestException);
}

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public static BaseTransaction<?> transactionTest(BaseTransaction<?> baseTransact
baseTransaction.zaddIncr(key8, "one", 3);
baseTransaction.zrem(key8, new String[] {"one"});
baseTransaction.zcard(key8);
baseTransaction.zmscore(key8, new String[] {"two", "three"});
baseTransaction.zrange(key8, new RangeByIndex(0, 1));
baseTransaction.zrangeWithScores(key8, new RangeByIndex(0, 1));
baseTransaction.zscore(key8, "two");
Expand Down Expand Up @@ -192,6 +193,7 @@ public static Object[] transactionTestResult() {
4.0,
1L,
2L,
new Double[] {2.0, 3.0}, // zmscore(key8, new String[] {"two", "three"})
new String[] {"two", "three"}, // zrange
Map.of("two", 2.0, "three", 3.0), // zrangeWithScores
2.0, // zscore(key8, "two")
Expand Down
Loading