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 Zdiffstore command. (Sorted Set Group) #1244

Merged
merged 6 commits into from
Apr 11, 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
1 change: 1 addition & 0 deletions glide-core/src/protobuf/redis_request.proto
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ enum RequestType {
LPushX = 103;
ZMScore = 104;
ZDiff = 105;
ZDiffStore = 106;
SetRange = 107;
}

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 @@ -114,6 +114,7 @@ pub enum RequestType {
LPushX = 103,
ZMScore = 104,
ZDiff = 105,
ZDiffStore = 106,
SetRange = 107,
}

Expand Down Expand Up @@ -232,6 +233,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::Spop => RequestType::Spop,
ProtobufRequestType::ZMScore => RequestType::ZMScore,
ProtobufRequestType::ZDiff => RequestType::ZDiff,
ProtobufRequestType::ZDiffStore => RequestType::ZDiffStore,
ProtobufRequestType::SetRange => RequestType::SetRange,
}
}
Expand Down Expand Up @@ -346,6 +348,7 @@ impl RequestType {
RequestType::Spop => Some(cmd("SPOP")),
RequestType::ZMScore => Some(cmd("ZMSCORE")),
RequestType::ZDiff => Some(cmd("ZDIFF")),
RequestType::ZDiffStore => Some(cmd("ZDIFFSTORE")),
RequestType::SetRange => Some(cmd("SETRANGE")),
}
}
Expand Down
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 @@ -63,6 +63,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.Unlink;
import static redis_request.RedisRequestOuterClass.RequestType.XAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZDiff;
import static redis_request.RedisRequestOuterClass.RequestType.ZDiffStore;
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
Expand Down Expand Up @@ -748,6 +749,13 @@ public CompletableFuture<Map<String, Double>> zdiffWithScores(@NonNull String[]
return commandManager.submitNewCommand(ZDiff, arguments, this::handleMapResponse);
}

@Override
public CompletableFuture<Long> zdiffstore(@NonNull String destination, @NonNull String[] keys) {
String[] arguments =
ArrayUtils.addAll(new String[] {destination, Long.toString(keys.length)}, keys);
return commandManager.submitNewCommand(ZDiffStore, arguments, this::handleLongResponse);
}

@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 @@ -509,4 +509,21 @@ CompletableFuture<Map<String, Double>> zrangeWithScores(
* }</pre>
*/
CompletableFuture<Map<String, Double>> zdiffWithScores(String[] keys);

/**
* Calculates the difference between the first sorted set and all the successive sorted sets at
* <code>keys</code> and stores the difference as a sorted set to <code>destination</code>,
* overwriting it if it already exists. Non-existent keys are treated as empty sets.
*
* @see <a href="https://redis.io/commands/zdiffstore/">redis.io</a> for more details.
* @param destination The key for the resulting sorted set.
* @param keys The keys of the sorted sets to compare.
* @return The number of members in the resulting sorted set stored at <code>destination</code>.
* @example
* <pre>{@code
* Long payload = client.zdiffstore("mySortedSet", new String[] {"key1", "key2"}).get();
* assert payload > 0; // At least one member differed in "key1" compared to "key2", and this difference was stored in "mySortedSet".
* }</pre>
*/
CompletableFuture<Long> zdiffstore(String destination, String[] keys);
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it make sense to swap keys and destination? I think it's easier to understand. Redis uses this ordering because they have a varargs on the keys, but we don't need to restrict ourselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Don't think so. We have stuck to the Redis ordering up to this point. Does not make sense to change it now.

}
19 changes: 19 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 @@ -75,6 +75,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.Unlink;
import static redis_request.RedisRequestOuterClass.RequestType.XAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZDiff;
import static redis_request.RedisRequestOuterClass.RequestType.ZDiffStore;
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
Expand Down Expand Up @@ -1550,6 +1551,24 @@ public T zdiffWithScores(@NonNull String[] keys) {
return getThis();
}

/**
* Calculates the difference between the first sorted set and all the successive sorted sets at
* <code>keys</code> and stores the difference as a sorted set to <code>destination</code>,
* overwriting it if it already exists. Non-existent keys are treated as empty sets.
*
* @see <a href="https://redis.io/commands/zdiffstore/">redis.io</a> for more details.
* @param destination The key for the resulting sorted set.
* @param keys The keys of the sorted sets to compare.
* @return Command Response - The number of members in the resulting sorted set stored at <code>
* destination</code>.
*/
public T zdiffstore(@NonNull String destination, @NonNull String[] keys) {
ArgsArray commandArgs =
buildArgs(ArrayUtils.addAll(new String[] {destination, Long.toString(keys.length)}, keys));
protobufTransaction.addCommands(buildCommand(ZDiffStore, commandArgs));
return getThis();
}

/**
* Adds an entry to the specified stream stored at <code>key</code>.<br>
* If the <code>key</code> doesn't exist, the stream is created.
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 @@ -96,6 +96,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.Unlink;
import static redis_request.RedisRequestOuterClass.RequestType.XAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZDiff;
import static redis_request.RedisRequestOuterClass.RequestType.ZDiffStore;
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
Expand Down Expand Up @@ -2350,6 +2351,31 @@ public void zmscore_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void zdiffstore_returns_success() {
// setup
String destKey = "testDestKey";
String[] keys = new String[] {"testKey1", "testKey2"};
String[] arguments = new String[] {destKey, Long.toString(keys.length), "testKey1", "testKey2"};
Long value = 3L;

CompletableFuture<Long> testResponse = new CompletableFuture<>();
testResponse.complete(value);

// match on protobuf request
when(commandManager.<Long>submitNewCommand(eq(ZDiffStore), eq(arguments), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Long> response = service.zdiffstore(destKey, keys);
Long payload = response.get();

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

@SneakyThrows
@Test
public void zdiff_returns_success() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.Unlink;
import static redis_request.RedisRequestOuterClass.RequestType.XAdd;
import static redis_request.RedisRequestOuterClass.RequestType.ZDiff;
import static redis_request.RedisRequestOuterClass.RequestType.ZDiffStore;
import static redis_request.RedisRequestOuterClass.RequestType.ZMScore;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMax;
import static redis_request.RedisRequestOuterClass.RequestType.ZPopMin;
Expand Down Expand Up @@ -368,6 +369,9 @@ public void transaction_builds_protobuf_request(BaseTransaction<?> transaction)
.addArgs(WITH_SCORES_REDIS_API)
.build()));

transaction.zdiffstore("destKey", new String[] {"key1", "key2"});
results.add(Pair.of(ZDiffStore, buildArgs("destKey", "2", "key1", "key2")));

transaction.xadd("key", Map.of("field1", "foo1"));
results.add(Pair.of(XAdd, buildArgs("key", "*", "field1", "foo1")));

Expand Down
42 changes: 42 additions & 0 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,48 @@ public void zmscore(BaseClient client) {
assertTrue(executionException.getCause() instanceof RequestException);
}

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
public void zdiffstore(BaseClient client) {
String key1 = "{testKey}:1-" + UUID.randomUUID();
String key2 = "{testKey}:2-" + UUID.randomUUID();
String key3 = "{testKey}:3-" + UUID.randomUUID();
String key4 = "{testKey}:4-" + UUID.randomUUID();
String key5 = "{testKey}:5-" + UUID.randomUUID();

Map<String, Double> membersScores1 = Map.of("one", 1.0, "two", 2.0, "three", 3.0);
Map<String, Double> membersScores2 = Map.of("two", 2.0);
Map<String, Double> membersScores3 = Map.of("one", 0.5, "two", 2.0, "three", 3.0, "four", 4.0);

assertEquals(3, client.zadd(key1, membersScores1).get());
assertEquals(1, client.zadd(key2, membersScores2).get());
assertEquals(4, client.zadd(key3, membersScores3).get());

assertEquals(2, client.zdiffstore(key4, new String[] {key1, key2}).get());
assertEquals(
Map.of("one", 1.0, "three", 3.0),
client.zrangeWithScores(key4, new RangeByIndex(0, -1)).get());

assertEquals(1, client.zdiffstore(key4, new String[] {key3, key2, key1}).get());
assertEquals(Map.of("four", 4.0), client.zrangeWithScores(key4, new RangeByIndex(0, -1)).get());

assertEquals(0, client.zdiffstore(key4, new String[] {key1, key3}).get());
assertTrue(client.zrangeWithScores(key4, new RangeByIndex(0, -1)).get().isEmpty());

// Non-Existing key
assertEquals(0, client.zdiffstore(key4, new String[] {key5, key1}).get());
assertTrue(client.zrangeWithScores(key4, new RangeByIndex(0, -1)).get().isEmpty());

// Key exists, but it is not a set
SanHalacogluImproving marked this conversation as resolved.
Show resolved Hide resolved
assertEquals(OK, client.set(key5, "bar").get());
ExecutionException executionException =
assertThrows(
ExecutionException.class,
() -> client.zdiffstore(key4, new String[] {key5, key1}).get());
assertTrue(executionException.getCause() instanceof RequestException);
}

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public static BaseTransaction<?> transactionTest(BaseTransaction<?> baseTransact
baseTransaction.zscore(key8, "two");
baseTransaction.zpopmin(key8);
baseTransaction.zpopmax(key8);
baseTransaction.zdiffstore(key8, new String[] {key8, key8});

baseTransaction.zadd(zSetKey2, Map.of("one", 1.0, "two", 2.0));
baseTransaction.zdiff(new String[] {zSetKey2, key8});
Expand Down Expand Up @@ -206,6 +207,7 @@ public static Object[] transactionTestResult() {
2.0, // zscore(key8, "two")
Map.of("two", 2.0), // zpopmin(key8)
Map.of("three", 3.0), // zpopmax(key8)
0L, // zdiffstore(key8, new String[] {key8, key8})
2L, // zadd(zSetKey2, Map.of("one", 1.0, "two", 2.0))
new String[] {"one", "two"}, // zdiff(new String[] {zSetKey2, key8})
Map.of("one", 1.0, "two", 2.0), // zdiffWithScores(new String[] {zSetKey2, key8})
Expand Down
Loading