Skip to content

Commit

Permalink
Support of GlideString interface for sinter, sinterstore and sinterca…
Browse files Browse the repository at this point in the history
…rd commands (#1687)

* Support of GlideString interface for sinter, sinterstore and sintercard commands

Add support of GlideString interface for sinter, sinterstore and sintercard commands for both standalone and cluster clients.

---------

Co-authored-by: Yulazari <[email protected]>
  • Loading branch information
yulazariy and Yulazari authored Jun 27, 2024
1 parent 8d468b3 commit 3e2d969
Show file tree
Hide file tree
Showing 5 changed files with 343 additions and 0 deletions.
28 changes: 28 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -1162,11 +1162,23 @@ public CompletableFuture<Long> sinterstore(@NonNull String destination, @NonNull
return commandManager.submitNewCommand(SInterStore, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> sinterstore(
@NonNull GlideString destination, @NonNull GlideString[] keys) {
GlideString[] arguments = ArrayUtils.addFirst(keys, destination);
return commandManager.submitNewCommand(SInterStore, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Set<String>> sinter(@NonNull String[] keys) {
return commandManager.submitNewCommand(SInter, keys, this::handleSetResponse);
}

@Override
public CompletableFuture<Set<GlideString>> sinter(@NonNull GlideString[] keys) {
return commandManager.submitNewCommand(SInter, keys, this::handleSetBinaryResponse);
}

@Override
public CompletableFuture<Long> sunionstore(@NonNull String destination, @NonNull String[] keys) {
String[] arguments = ArrayUtils.addFirst(keys, destination);
Expand Down Expand Up @@ -2545,6 +2557,12 @@ public CompletableFuture<Long> sintercard(@NonNull String[] keys) {
return commandManager.submitNewCommand(SInterCard, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> sintercard(@NonNull GlideString[] keys) {
GlideString[] arguments = ArrayUtils.addFirst(keys, gs(Long.toString(keys.length)));
return commandManager.submitNewCommand(SInterCard, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> sintercard(@NonNull String[] keys, long limit) {
String[] arguments =
Expand All @@ -2555,6 +2573,16 @@ public CompletableFuture<Long> sintercard(@NonNull String[] keys, long limit) {
return commandManager.submitNewCommand(SInterCard, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> sintercard(@NonNull GlideString[] keys, long limit) {
GlideString[] arguments =
concatenateArrays(
new GlideString[] {gs(Long.toString(keys.length))},
keys,
new GlideString[] {gs(SET_LIMIT_REDIS_API), gs(Long.toString(limit))});
return commandManager.submitNewCommand(SInterCard, arguments, this::handleLongResponse);
}

@Override
public CompletableFuture<Object> fcall(
@NonNull String function, @NonNull String[] keys, @NonNull String[] arguments) {
Expand Down
83 changes: 83 additions & 0 deletions java/client/src/main/java/glide/api/commands/SetBaseCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,25 @@ public interface SetBaseCommands {
*/
CompletableFuture<Set<String>> sinter(String[] keys);

/**
* Gets the intersection of all the given sets.
*
* @apiNote When in cluster mode, all <code>keys</code> must map to the same hash slot.
* @see <a href="https://redis.io/commands/sinter/">redis.io</a> for details.
* @param keys The keys of the sets.
* @return A <code>Set</code> of members which are present in all given sets.<br>
* If one or more sets do not exist, an empty set will be returned.
* @example
* <pre>{@code
* Set<GlideString> values = client.sinter(new GlideString[] {gs("set1"), gs("set2")}).get();
* assert values.contains(gs("element")); // Indicates that these sets have a common element
*
* Set<GlideString> values = client.sinter(new GlideString[] {gs("set1"), gs("nonExistingSet")}).get();
* assert values.size() == 0;
* }</pre>
*/
CompletableFuture<Set<GlideString>> sinter(GlideString[] keys);

/**
* Gets the cardinality of the intersection of all the given sets.
*
Expand All @@ -316,6 +335,26 @@ public interface SetBaseCommands {
*/
CompletableFuture<Long> sintercard(String[] keys);

/**
* Gets the cardinality of the intersection of all the given sets.
*
* @since Redis 7.0 and above.
* @apiNote When in cluster mode, all <code>keys</code> must map to the same hash slot.
* @see <a href="https://redis.io/commands/sintercard/">redis.io</a> for details.
* @param keys The keys of the sets.
* @return The cardinality of the intersection result. If one or more sets do not exist, <code>0
* </code> is returned.
* @example
* <pre>{@code
* Long response = client.sintercard(new GlideString[] {gs("set1"), gs("set2")}).get();
* assertEquals(2L, response);
*
* Long emptyResponse = client.sintercard(new GlideString[] {gs("set1"), gs("nonExistingSet")}).get();
* assertEquals(emptyResponse, 0L);
* }</pre>
*/
CompletableFuture<Long> sintercard(GlideString[] keys);

/**
* Gets the cardinality of the intersection of all the given sets.
*
Expand All @@ -342,6 +381,32 @@ public interface SetBaseCommands {
*/
CompletableFuture<Long> sintercard(String[] keys, long limit);

/**
* Gets the cardinality of the intersection of all the given sets.
*
* @since Redis 7.0 and above.
* @apiNote When in cluster mode, all <code>keys</code> must map to the same hash slot.
* @see <a href="https://redis.io/commands/sintercard/">redis.io</a> for details.
* @param keys The keys of the sets.
* @param limit The limit for the intersection cardinality value.
* @return The cardinality of the intersection result. If one or more sets do not exist, <code>0
* </code> is returned. If the intersection cardinality reaches <code>limit</code> partway
* through the computation, returns <code>limit</code> as the cardinality.
* @example
* <pre>{@code
* Long response = client.sintercard(new GlideString[] {gs("set1"), gs("set2")}, 3).get();
* assertEquals(2L, response);
*
* Long emptyResponse = client.sintercard(new GlideString[] {gs("set1"), gs("nonExistingSet")}, 3).get();
* assertEquals(emptyResponse, 0L);
*
* // when intersection cardinality > limit, returns limit as cardinality
* Long response2 = client.sintercard(new GlideString[] {gs("set3"), gs("set4")}, 3).get();
* assertEquals(3L, response2);
* }</pre>
*/
CompletableFuture<Long> sintercard(GlideString[] keys, long limit);

/**
* Stores the members of the intersection of all given sets specified by <code>keys</code> into a
* new set at <code>destination</code>.
Expand All @@ -360,6 +425,24 @@ public interface SetBaseCommands {
*/
CompletableFuture<Long> sinterstore(String destination, String[] keys);

/**
* Stores the members of the intersection of all given sets specified by <code>keys</code> into a
* new set at <code>destination</code>.
*
* @apiNote When in cluster mode, <code>destination</code> and all <code>keys</code> must map to
* the same hash slot.
* @see <a href="https://redis.io/commands/sinterstore/">redis.io</a> for details.
* @param destination The key of the destination set.
* @param keys The keys from which to retrieve the set members.
* @return The number of elements in the resulting set.
* @example
* <pre>{@code
* Long length = client.sinterstore(gs("mySet"), new GlideString[] { gs("set1"), gs("set2") }).get();
* assert length == 5L;
* }</pre>
*/
CompletableFuture<Long> sinterstore(GlideString destination, GlideString[] keys);

/**
* Stores the members of the union of all given sets specified by <code>keys</code> into a new set
* at <code>destination</code>.
Expand Down
100 changes: 100 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3098,6 +3098,29 @@ public void sinter_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void sinter_binary_returns_success() {
// setup
GlideString[] keys = new GlideString[] {gs("key1"), gs("key2")};
Set<GlideString> value = Set.of(gs("1"), gs("2"));

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

// match on protobuf request
when(commandManager.<Set<GlideString>>submitNewCommand(eq(SInter), eq(keys), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Set<GlideString>> response = service.sinter(keys);
Set<GlideString> payload = response.get();

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

@SneakyThrows
@Test
public void sinterstore_returns_success() {
Expand All @@ -3123,6 +3146,31 @@ public void sinterstore_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void sinterstore_binary_returns_success() {
// setup
GlideString destination = gs("key");
GlideString[] keys = new GlideString[] {gs("set1"), gs("set2")};
GlideString[] args = new GlideString[] {gs("key"), gs("set1"), gs("set2")};
Long value = 2L;

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

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

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

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

@SneakyThrows
@Test
public void sunionstore_returns_success() {
Expand Down Expand Up @@ -7976,6 +8024,31 @@ public void sintercard_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void sintercard_binary_returns_success() {
// setup
GlideString key1 = gs("testKey");
GlideString key2 = gs("testKey2");
GlideString[] arguments = new GlideString[] {gs("2"), key1, key2};
Long value = 1L;

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

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

// exercise
CompletableFuture<Long> response = service.sintercard(new GlideString[] {key1, key2});
Long payload = response.get();

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

@SneakyThrows
@Test
public void sintercard_with_limit_returns_success() {
Expand All @@ -8002,6 +8075,33 @@ public void sintercard_with_limit_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void sintercard_with_limit_binary_returns_success() {
// setup
GlideString key1 = gs("testKey");
GlideString key2 = gs("testKey2");
long limit = 1L;
GlideString[] arguments =
new GlideString[] {gs("2"), key1, key2, gs(SET_LIMIT_REDIS_API), gs("1")};
Long value = 1L;

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

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

// exercise
CompletableFuture<Long> response = service.sintercard(new GlideString[] {key1, key2}, limit);
Long payload = response.get();

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

@SneakyThrows
@Test
public void srandmember_returns_success() {
Expand Down
Loading

0 comments on commit 3e2d969

Please sign in to comment.