Skip to content

Commit

Permalink
Add RENAMENX command.
Browse files Browse the repository at this point in the history
Signed-off-by: Yury-Fridlyand <[email protected]>
  • Loading branch information
Yury-Fridlyand committed Apr 23, 2024
1 parent 95b6f2f commit 4b6156c
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 1 deletion.
2 changes: 1 addition & 1 deletion glide-core/src/client/value_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ pub(crate) fn expected_type_for_cmd(cmd: &Cmd) -> Option<ExpectedReturnType> {
}
b"INCRBYFLOAT" | b"HINCRBYFLOAT" => Some(ExpectedReturnType::Double),
b"HEXISTS" | b"HSETNX" | b"EXPIRE" | b"EXPIREAT" | b"PEXPIRE" | b"PEXPIREAT"
| b"SISMEMBER" | b"PERSIST" | b"SMOVE" => Some(ExpectedReturnType::Boolean),
| b"SISMEMBER" | b"PERSIST" | b"SMOVE" | b"RENAMENX" => Some(ExpectedReturnType::Boolean),
b"SMISMEMBER" => Some(ExpectedReturnType::ArrayOfBools),
b"SMEMBERS" | b"SINTER" => Some(ExpectedReturnType::Set),
b"ZSCORE" => Some(ExpectedReturnType::DoubleOrNull),
Expand Down
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 @@ -163,6 +163,7 @@ enum RequestType {
GeoAdd = 121;
GeoHash = 122;
ObjectEncoding = 123;
RenameNx = 130;
}

message Command {
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 @@ -131,6 +131,7 @@ pub enum RequestType {
GeoAdd = 121,
GeoHash = 122,
ObjectEncoding = 123,
RenameNx = 130,
}

fn get_two_word_command(first: &str, second: &str) -> Cmd {
Expand Down Expand Up @@ -265,6 +266,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::GeoAdd => RequestType::GeoAdd,
ProtobufRequestType::GeoHash => RequestType::GeoHash,
ProtobufRequestType::ObjectEncoding => RequestType::ObjectEncoding,
ProtobufRequestType::RenameNx => RequestType::RenameNx,
}
}
}
Expand Down Expand Up @@ -395,6 +397,7 @@ impl RequestType {
RequestType::GeoAdd => Some(cmd("GEOADD")),
RequestType::GeoHash => Some(cmd("GEOHASH")),
RequestType::ObjectEncoding => Some(get_two_word_command("OBJECT", "ENCODING")),
RequestType::RenameNx => Some(cmd("RENAMENX")),
}
}
}
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 @@ -52,6 +52,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.RenameNx;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
import static redis_request.RedisRequestOuterClass.RequestType.SCard;
import static redis_request.RedisRequestOuterClass.RequestType.SDiffStore;
Expand Down Expand Up @@ -341,6 +342,12 @@ public CompletableFuture<String> objectEncoding(@NonNull String key) {
ObjectEncoding, new String[] {key}, this::handleStringOrNullResponse);
}

@Override
public CompletableFuture<Boolean> renamenx(@NonNull String key, @NonNull String newKey) {
return commandManager.submitNewCommand(
RenameNx, new String[] {key, newKey}, this::handleBooleanResponse);
}

@Override
public CompletableFuture<Long> incr(@NonNull String key) {
return commandManager.submitNewCommand(Incr, new String[] {key}, this::handleLongResponse);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,4 +389,23 @@ CompletableFuture<Boolean> pexpireAt(
* }</pre>
*/
CompletableFuture<String> objectEncoding(String key);

/**
* Renames <code>key</code> to <code>newKey</code> if <code>newKey</code> does not yet exist.
*
* @apiNote When in cluster mode, both <code>key</code> and <code>newKey</code> must map to the
* same <code>hash slot
* </code>.
* @see <a href="https://redis.io/commands/renamenx/">redis.io</a> for details.
* @param key The key to rename.
* @param newKey The new key name.
* @return <code>true</code> if <code>key</code> was renamed to <code>newKey</code>, <code>false
* </code> if <code>newKey</code> already exists.
* @example
* <pre>{@code
* Boolean renamed = client.renamenx("old_key", "new_key").get();
* assert renamed;
* }</pre>
*/
CompletableFuture<Boolean> renamenx(String key, String newKey);
}
16 changes: 16 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 @@ -64,6 +64,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.RenameNx;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
import static redis_request.RedisRequestOuterClass.RequestType.SCard;
import static redis_request.RedisRequestOuterClass.RequestType.SDiffStore;
Expand Down Expand Up @@ -1975,6 +1976,21 @@ public T type(@NonNull String key) {
return getThis();
}

/**
* Renames <code>key</code> to <code>newKey</code> if <code>newKey</code> does not yet exist.
*
* @see <a href="https://redis.io/commands/renamenx/">redis.io</a> for details.
* @param key The key to rename.
* @param newKey The new key name.
* @return Command Response - <code>true</code> if <code>key</code> was renamed to <code>newKey
* </code>, <code>false</code> if <code>newKey</code> already exists.
*/
public T renamenx(@NonNull String key, @NonNull String newKey) {
ArgsArray commandArgs = buildArgs(key, newKey);
protobufTransaction.addCommands(buildCommand(RenameNx, commandArgs));
return getThis();
}

/**
* Inserts <code>element</code> in the list at <code>key</code> either before or after the <code>
* pivot</code>.
Expand Down
24 changes: 24 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,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.RenameNx;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
import static redis_request.RedisRequestOuterClass.RequestType.SCard;
import static redis_request.RedisRequestOuterClass.RequestType.SDiffStore;
Expand Down Expand Up @@ -3024,6 +3025,29 @@ public void type_returns_success() {
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void renamenx_returns_success() {
// setup
String key = "key1";
String newKey = "key2";
String[] arguments = new String[] {key, newKey};

CompletableFuture<Boolean> testResponse = new CompletableFuture<>();
testResponse.complete(true);

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

// exercise
CompletableFuture<Boolean> response = service.renamenx(key, newKey);

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

@SneakyThrows
@Test
public void time_returns_success() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,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.RenameNx;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
import static redis_request.RedisRequestOuterClass.RequestType.SCard;
import static redis_request.RedisRequestOuterClass.RequestType.SDiffStore;
Expand Down Expand Up @@ -462,6 +463,9 @@ InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3, false), new Limit(1, 2)),
transaction.type("key");
results.add(Pair.of(Type, buildArgs("key")));

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

transaction.linsert("key", AFTER, "pivot", "elem");
results.add(Pair.of(LInsert, buildArgs("key", "AFTER", "pivot", "elem")));

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 @@ -975,6 +975,48 @@ public void smove(BaseClient client) {
}
}

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

assertEquals(OK, client.set(key3, "key3").get());

// rename missing key
var executionException =
assertThrows(ExecutionException.class, () -> client.renamenx(key1, key2).get());
assertInstanceOf(RequestException.class, executionException.getCause());
assertTrue(executionException.getMessage().toLowerCase().contains("no such key"));

// rename a string
assertEquals(OK, client.set(key1, "key1").get());
assertTrue(client.renamenx(key1, key2).get());
assertFalse(client.renamenx(key2, key3).get());
assertEquals("key1", client.get(key2).get());
assertEquals(1, client.del(new String[] {key1, key2}).get());

// rename a set
assertEquals(3, client.sadd(key1, new String[] {"a", "b", "c"}).get());
assertTrue(client.renamenx(key1, key2).get());
assertFalse(client.renamenx(key2, key3).get());
assertEquals(Set.of("a", "b", "c"), client.smembers(key2).get());
assertEquals("none", client.type(key1).get());

// this one remains unchanged
assertEquals("key3", client.get(key3).get());

// same-slot requirement
if (client instanceof RedisClusterClient) {
executionException =
assertThrows(ExecutionException.class, () -> client.renamenx("abc", "zxy").get());
assertInstanceOf(RequestException.class, executionException.getCause());
assertTrue(executionException.getMessage().toLowerCase().contains("crossslot"));
}
}

@SneakyThrows
@ParameterizedTest(autoCloseArguments = false)
@MethodSource("getClients")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public static BaseTransaction<?> transactionTest(BaseTransaction<?> baseTransact
baseTransaction.set(key2, value2, SetOptions.builder().returnOldValue(true).build());
baseTransaction.strlen(key2);
baseTransaction.customCommand(new String[] {"MGET", key1, key2});
baseTransaction.renamenx(key1, key2);

baseTransaction.exists(new String[] {key1});
baseTransaction.persist(key1);
Expand Down Expand Up @@ -177,6 +178,7 @@ public static Object[] transactionTestResult() {
null,
(long) value1.length(), // strlen(key2)
new String[] {value1, value2},
false, // renamenx(key1, key2)
1L,
Boolean.FALSE, // persist(key1)
1L,
Expand Down

0 comments on commit 4b6156c

Please sign in to comment.