Skip to content

Commit

Permalink
Java: Add PFADD command. (valkey-io#1221)
Browse files Browse the repository at this point in the history
* Add `PFADD` command. (#166)

Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
  • Loading branch information
Yury-Fridlyand authored and cyip10 committed Jun 24, 2024
1 parent 5435abc commit d83a89a
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 2 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@

Preview release of **GLIDE for Redis** a Polyglot Redis client.

See the [README](README.md) for additional information.
See the [README](README.md) for additional information.
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 @@ -136,6 +136,7 @@ enum RequestType {
DBSize = 92;
Brpop = 93;
Hkeys = 94;
PfAdd = 96;
}

message Command {
Expand Down
1 change: 1 addition & 0 deletions glide-core/src/socket_listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ fn get_command(request: &Command) -> Option<Cmd> {
RequestType::DBSize => Some(cmd("DBSIZE")),
RequestType::Brpop => Some(cmd("BRPOP")),
RequestType::Hkeys => Some(cmd("HKEYS")),
RequestType::PfAdd => Some(cmd("PFADD")),
}
}

Expand Down
11 changes: 10 additions & 1 deletion java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
import static redis_request.RedisRequestOuterClass.RequestType.Persist;
import static redis_request.RedisRequestOuterClass.RequestType.PfAdd;
import static redis_request.RedisRequestOuterClass.RequestType.RPop;
import static redis_request.RedisRequestOuterClass.RequestType.RPush;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
Expand All @@ -61,6 +62,7 @@

import glide.api.commands.GenericBaseCommands;
import glide.api.commands.HashBaseCommands;
import glide.api.commands.HyperLogLogBaseCommands;
import glide.api.commands.ListBaseCommands;
import glide.api.commands.SetBaseCommands;
import glide.api.commands.SortedSetBaseCommands;
Expand Down Expand Up @@ -105,7 +107,8 @@ public abstract class BaseClient
HashBaseCommands,
ListBaseCommands,
SetBaseCommands,
SortedSetBaseCommands {
SortedSetBaseCommands,
HyperLogLogBaseCommands {

/** Redis simple string response with "OK" */
public static final String OK = ConstantResponse.OK.toString();
Expand Down Expand Up @@ -732,4 +735,10 @@ public CompletableFuture<Map<String, Double>> zrangeWithScores(
@NonNull String key, @NonNull ScoredRangeQuery rangeQuery) {
return this.zrangeWithScores(key, rangeQuery, false);
}

@Override
public CompletableFuture<Long> pfadd(@NonNull String key, @NonNull String[] elements) {
String[] arguments = ArrayUtils.addFirst(elements, key);
return commandManager.submitNewCommand(PfAdd, arguments, this::handleLongResponse);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.api.commands;

import java.util.concurrent.CompletableFuture;

/**
* Supports commands and transactions for the "HyperLogLog Commands" group for standalone and
* cluster clients.
*
* @see <a href="https://redis.io/commands/?group=hyperloglog">HyperLogLog Commands</a>
*/
public interface HyperLogLogBaseCommands {

/**
* Adds all elements to the HyperLogLog data structure stored at the specified <code>key</code>.
* <br>
* Creates a new structure if the <code>key</code> does not exist.
*
* <p>When no <code>elements</code> are provided, and <code>key</code> exists and is a
* HyperLogLog, then no operation is performed. If <code>key</code> does not exist, then the
* HyperLogLog structure is created.
*
* @see <a href="https://redis.io/commands/pfadd/">redis.io</a> for details.
* @param key The <code>key</code> of the HyperLogLog data structure to add elements into.
* @param elements An array of members to add to the HyperLogLog stored at <code>key</code>.
* @return If the HyperLogLog is newly created, or if the HyperLogLog approximated cardinality is
* altered, then returns <code>1</code>. Otherwise, returns <code>0</code>.
* @example
* <pre>{@code
* Long result = client.pfadd("hll_1", new String[] { "a", "b", "c" }).get();
* assert result == 1L; // A data structure was created or modified
*
* result = client.pfadd("hll_2", new String[0]).get();
* assert result == 1L; // A new empty data structure was created
* }</pre>
*/
CompletableFuture<Long> pfadd(String key, String[] elements);
}
23 changes: 23 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 @@ -48,6 +48,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
import static redis_request.RedisRequestOuterClass.RequestType.Persist;
import static redis_request.RedisRequestOuterClass.RequestType.PfAdd;
import static redis_request.RedisRequestOuterClass.RequestType.Ping;
import static redis_request.RedisRequestOuterClass.RequestType.RPop;
import static redis_request.RedisRequestOuterClass.RequestType.RPush;
Expand Down Expand Up @@ -1618,6 +1619,28 @@ public T zrangeWithScores(@NonNull String key, @NonNull ScoredRangeQuery rangeQu
return getThis().zrangeWithScores(key, rangeQuery, false);
}

/**
* Adds all elements to the HyperLogLog data structure stored at the specified <code>key</code>.
* <br>
* Creates a new structure if the <code>key</code> does not exist.
*
* <p>When no <code>elements</code> are provided, and <code>key</code> exists and is a
* HyperLogLog, then no operation is performed. If <code>key</code> does not exist, then the
* HyperLogLog structure is created.
*
* @see <a href="https://redis.io/commands/pfadd/">redis.io</a> for details.
* @param key The <code>key</code> of the HyperLogLog data structure to add elements into.
* @param elements An array of members to add to the HyperLogLog stored at <code>key</code>.
* @return Command Response - If the HyperLogLog is newly created, or if the HyperLogLog
* approximated cardinality is altered, then returns <code>1</code>. Otherwise, returns <code>
* 0</code>.
*/
public T pfadd(@NonNull String key, @NonNull String[] elements) {
ArgsArray commandArgs = buildArgs(ArrayUtils.addFirst(elements, key));
protobufTransaction.addCommands(buildCommand(PfAdd, commandArgs));
return getThis();
}

/** Build protobuf {@link Command} object for given command and arguments. */
protected Command buildCommand(RequestType requestType) {
return buildCommand(requestType, buildArgs());
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 @@ -60,6 +60,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
import static redis_request.RedisRequestOuterClass.RequestType.Persist;
import static redis_request.RedisRequestOuterClass.RequestType.PfAdd;
import static redis_request.RedisRequestOuterClass.RequestType.Ping;
import static redis_request.RedisRequestOuterClass.RequestType.RPop;
import static redis_request.RedisRequestOuterClass.RequestType.RPush;
Expand Down Expand Up @@ -2242,4 +2243,29 @@ public void time_returns_success() {
assertEquals(testResponse, response);
assertEquals(payload, response.get());
}

@SneakyThrows
@Test
public void pfadd_returns_success() {
// setup
String key = "testKey";
String[] elements = new String[] {"a", "b", "c"};
String[] arguments = new String[] {key, "a", "b", "c"};
Long value = 1L;

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

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

// exercise
CompletableFuture<Long> response = service.pfadd(key, elements);
Long payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(payload, response.get());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
import static redis_request.RedisRequestOuterClass.RequestType.Persist;
import static redis_request.RedisRequestOuterClass.RequestType.PfAdd;
import static redis_request.RedisRequestOuterClass.RequestType.Ping;
import static redis_request.RedisRequestOuterClass.RequestType.RPop;
import static redis_request.RedisRequestOuterClass.RequestType.RPush;
Expand Down Expand Up @@ -488,6 +489,12 @@ InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3, false), new Limit(1, 2)),
.addArgs(WITH_SCORES_REDIS_API)
.build()));

transaction.pfadd("hll", new String[] {"a", "b", "c"});
results.add(
Pair.of(
PfAdd,
ArgsArray.newBuilder().addArgs("hll").addArgs("a").addArgs("b").addArgs("c").build()));

var protobufTransaction = transaction.getProtobufTransaction().build();

for (int idx = 0; idx < protobufTransaction.getCommandsCount(); idx++) {
Expand Down
17 changes: 17 additions & 0 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -1434,4 +1434,21 @@ public void zrange_with_different_types_of_keys(BaseClient client) {
assertThrows(ExecutionException.class, () -> client.zrangeWithScores(key, query).get());
assertTrue(executionException.getCause() instanceof RequestException);
}

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
public void pfadd(BaseClient client) {
String key = UUID.randomUUID().toString();
assertEquals(1, client.pfadd(key, new String[0]).get());
assertEquals(1, client.pfadd(key, new String[] {"one", "two"}).get());
assertEquals(0, client.pfadd(key, new String[] {"two"}).get());
assertEquals(0, client.pfadd(key, new String[0]).get());

// Key exists, but it is not a HyperLogLog
assertEquals(OK, client.set("foo", "bar").get());
ExecutionException executionException =
assertThrows(ExecutionException.class, () -> client.pfadd("foo", new String[0]).get());
assertTrue(executionException.getCause() instanceof RequestException);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class TransactionTestUtilities {
private static final String key6 = "{key}" + UUID.randomUUID();
private static final String key7 = "{key}" + UUID.randomUUID();
private static final String key8 = "{key}" + UUID.randomUUID();
private static final String hllKey1 = "{key}:hllKey1-" + UUID.randomUUID();
private static final String value1 = UUID.randomUUID().toString();
private static final String value2 = UUID.randomUUID().toString();
private static final String value3 = UUID.randomUUID().toString();
Expand Down Expand Up @@ -106,6 +107,8 @@ public static BaseTransaction<?> transactionTest(BaseTransaction<?> baseTransact

baseTransaction.echo("GLIDE");

baseTransaction.pfadd(hllKey1, new String[] {"a", "b", "c"});

return baseTransaction;
}

Expand Down Expand Up @@ -170,6 +173,7 @@ public static Object[] transactionTestResult() {
Map.of("timeout", "1000"),
OK,
"GLIDE", // echo
1L, // pfadd(hllKey1, new String[] {"a", "b", "c"})
};
}
}

0 comments on commit d83a89a

Please sign in to comment.