Skip to content

Commit

Permalink
Java: add RENAME command (valkey-io#1481)
Browse files Browse the repository at this point in the history
* implement rename command in new PR

* address comments

* address new comments

* address sharedCommandTest comments

---------

Co-authored-by: Chloe Yip <chloe.yip@Chloes-MacBook-Pro.local>
  • Loading branch information
cyip10 and Chloe Yip committed Jun 24, 2024
1 parent 05bee23 commit 608f85c
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 0 deletions.
7 changes: 7 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.RPop;
import static redis_request.RedisRequestOuterClass.RequestType.RPush;
import static redis_request.RedisRequestOuterClass.RequestType.RPushX;
import static redis_request.RedisRequestOuterClass.RequestType.Rename;
import static redis_request.RedisRequestOuterClass.RequestType.RenameNX;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
import static redis_request.RedisRequestOuterClass.RequestType.SCard;
Expand Down Expand Up @@ -429,6 +430,12 @@ public CompletableFuture<Long> objectRefcount(@NonNull String key) {
ObjectRefCount, new String[] {key}, this::handleLongOrNullResponse);
}

@Override
public CompletableFuture<String> rename(@NonNull String key, @NonNull String newKey) {
return commandManager.submitNewCommand(
Rename, new String[] {key, newKey}, this::handleStringResponse);
}

@Override
public CompletableFuture<Boolean> renamenx(@NonNull String key, @NonNull String newKey) {
return commandManager.submitNewCommand(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,26 @@ CompletableFuture<Boolean> pexpireAt(
*/
CompletableFuture<Long> objectRefcount(String key);

/**
* Renames <code>key</code> to <code>newKey</code>.<br>
* If <code>newKey</code> already exists it is overwritten.
*
* @apiNote When in cluster mode, both <code>key</code> and <code>newKey</code> must map to the
* same hash slot.
* @see <a href="https://redis.io/commands/rename/">redis.io</a> for details.
* @param key The key to rename.
* @param newKey The new name of the key.
* @return If the <code>key</code> was successfully renamed, return <code>"OK"</code>. If <code>
* key</code> does not exist, an error is thrown.
* @example
* <pre>{@code
* String value = client.set("key", "value").get();
* value = client.rename("key", "newKeyName").get();
* assert value.equals("OK");
* }</pre>
*/
CompletableFuture<String> rename(String key, String newKey);

/**
* Renames <code>key</code> to <code>newKey</code> if <code>newKey</code> does not yet exist.
*
Expand Down
17 changes: 17 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 @@ -95,6 +95,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.RPop;
import static redis_request.RedisRequestOuterClass.RequestType.RPush;
import static redis_request.RedisRequestOuterClass.RequestType.RPushX;
import static redis_request.RedisRequestOuterClass.RequestType.Rename;
import static redis_request.RedisRequestOuterClass.RequestType.RenameNX;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
import static redis_request.RedisRequestOuterClass.RequestType.SCard;
Expand Down Expand Up @@ -2813,6 +2814,22 @@ public T type(@NonNull String key) {
return getThis();
}

/**
* Renames <code>key</code> to <code>newKey</code>.<br>
* If <code>newKey</code> already exists it is overwritten.
*
* @see <a href="https://redis.io/commands/rename/">redis.io</a> for details.
* @param key The <code>key</code> to rename.
* @param newKey The new name of the <code>key</code>.
* @return Command Response - If the <code>key</code> was successfully renamed, return <code>"OK"
* </code>. If <code>key</code> does not exist, the transaction fails with an error.
*/
public T rename(@NonNull String key, @NonNull String newKey) {
ArgsArray commandArgs = buildArgs(key, newKey);
protobufTransaction.addCommands(buildCommand(Rename, commandArgs));
return getThis();
}

/**
* Renames <code>key</code> to <code>newKey</code> if <code>newKey</code> does not yet exist.
*
Expand Down
23 changes: 23 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.RPop;
import static redis_request.RedisRequestOuterClass.RequestType.RPush;
import static redis_request.RedisRequestOuterClass.RequestType.RPushX;
import static redis_request.RedisRequestOuterClass.RequestType.Rename;
import static redis_request.RedisRequestOuterClass.RequestType.RenameNX;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
import static redis_request.RedisRequestOuterClass.RequestType.SCard;
Expand Down Expand Up @@ -4021,6 +4022,28 @@ public void type_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void rename() {
// setup
String key = "key1";
String newKey = "key2";
String[] arguments = new String[] {key, newKey};
CompletableFuture<String> testResponse = new CompletableFuture<>();
testResponse.complete(OK);

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

// exercise
CompletableFuture<String> response = service.rename(key, newKey);

// verify
assertEquals(testResponse, response);
assertEquals(OK, response.get());
}

@SneakyThrows
@Test
public void renamenx_returns_success() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.RPop;
import static redis_request.RedisRequestOuterClass.RequestType.RPush;
import static redis_request.RedisRequestOuterClass.RequestType.RPushX;
import static redis_request.RedisRequestOuterClass.RequestType.Rename;
import static redis_request.RedisRequestOuterClass.RequestType.RenameNX;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
import static redis_request.RedisRequestOuterClass.RequestType.SCard;
Expand Down Expand Up @@ -720,6 +721,9 @@ InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3, false), new Limit(1, 2)),
transaction.type("key");
results.add(Pair.of(Type, buildArgs("key")));

transaction.rename("key", "newKey");
results.add(Pair.of(Rename, buildArgs("key", "newKey")));

transaction.renamenx("key", "newKey");
results.add(Pair.of(RenameNX, buildArgs("key", "newKey")));

Expand Down
18 changes: 18 additions & 0 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,24 @@ public void smove(BaseClient client) {
assertInstanceOf(RequestException.class, executionException.getCause());
}

@SneakyThrows
@ParameterizedTest(autoCloseArguments = false)
@MethodSource("getClients")
public void rename(BaseClient client) {
String key1 = "{key}" + UUID.randomUUID();

assertEquals(OK, client.set(key1, "foo").get());
assertEquals(OK, client.rename(key1, key1 + "_rename").get());
assertEquals(1L, client.exists(new String[] {key1 + "_rename"}).get());

// key doesn't exist
ExecutionException executionException =
assertThrows(
ExecutionException.class,
() ->
client.rename("{same_slot}" + "non_existing_key", "{same_slot}" + "_rename").get());
}

@SneakyThrows
@ParameterizedTest(autoCloseArguments = false)
@MethodSource("getClients")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ private static Object[] genericCommands(BaseTransaction<?> transaction) {
.objectEncoding(genericKey1)
.touch(new String[] {genericKey1})
.set(genericKey2, value2)
.rename(genericKey1, genericKey1)
.renamenx(genericKey1, genericKey2)
.unlink(new String[] {genericKey2})
.get(genericKey2)
Expand Down Expand Up @@ -130,6 +131,7 @@ private static Object[] genericCommands(BaseTransaction<?> transaction) {
"embstr", // objectEncoding(genericKey1)
1L, // touch(new String[] {genericKey1})
OK, // set(genericKey2, value2)
OK, // rename(genericKey1, genericKey1)
false, // renamenx(genericKey1, genericKey2)
1L, // unlink(new String[] {genericKey2})
null, // get(genericKey2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ public void objectFreq() {
public static Stream<Arguments> callCrossSlotCommandsWhichShouldFail() {
return Stream.of(
Arguments.of("smove", null, clusterClient.smove("abc", "zxy", "lkn")),
Arguments.of("rename", null, clusterClient.rename("abc", "xyz")),
Arguments.of("renamenx", null, clusterClient.renamenx("abc", "zxy")),
Arguments.of(
"sinterstore", null, clusterClient.sinterstore("abc", new String[] {"zxy", "lkn"})),
Expand Down

0 comments on commit 608f85c

Please sign in to comment.