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 RENAME command #1481

Merged
merged 5 commits into from
May 28, 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
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 @@ -70,6 +70,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 @@ -408,6 +409,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 @@ -454,6 +454,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 @@ -88,6 +88,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 @@ -2704,6 +2705,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 @@ -109,6 +109,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 @@ -3894,6 +3895,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 @@ -99,6 +99,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 @@ -695,6 +696,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 @@ -1087,6 +1087,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 @@ -95,6 +95,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 @@ -126,6 +127,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 @@ -650,6 +650,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
Loading