Skip to content

Commit

Permalink
Add command LSET (#312)
Browse files Browse the repository at this point in the history
* Add command LSET

---------

Co-authored-by: TJ Zhang <tj.zhang@improving.com>
  • Loading branch information
tjzhang-BQ and TJ Zhang authored May 28, 2024
1 parent a52a58e commit 4e3f976
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 1 deletion.
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 @@ -194,6 +194,7 @@ enum RequestType {
ExpireTime = 156;
PExpireTime = 157;
BLMPop = 158;
LSet = 165;
}

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 @@ -164,6 +164,7 @@ pub enum RequestType {
ExpireTime = 156,
PExpireTime = 157,
BLMPop = 158,
LSet = 165,
}

fn get_two_word_command(first: &str, second: &str) -> Cmd {
Expand Down Expand Up @@ -331,6 +332,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::HStrlen => RequestType::HStrlen,
ProtobufRequestType::ExpireTime => RequestType::ExpireTime,
ProtobufRequestType::PExpireTime => RequestType::PExpireTime,
ProtobufRequestType::LSet => RequestType::LSet,
}
}
}
Expand Down Expand Up @@ -494,6 +496,7 @@ impl RequestType {
RequestType::HStrlen => Some(cmd("HSTRLEN")),
RequestType::ExpireTime => Some(cmd("EXPIRETIME")),
RequestType::PExpireTime => Some(cmd("PEXPIRETIME")),
RequestType::LSet => Some(cmd("LSET")),
}
}
}
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 @@ -59,6 +59,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.LPushX;
import static redis_request.RedisRequestOuterClass.RequestType.LRange;
import static redis_request.RedisRequestOuterClass.RequestType.LRem;
import static redis_request.RedisRequestOuterClass.RequestType.LSet;
import static redis_request.RedisRequestOuterClass.RequestType.LTrim;
import static redis_request.RedisRequestOuterClass.RequestType.MGet;
import static redis_request.RedisRequestOuterClass.RequestType.MSet;
Expand Down Expand Up @@ -1543,4 +1544,10 @@ public CompletableFuture<Map<String, String[]>> blmpop(
arguments,
response -> castMapOfArrays(handleMapOrNullResponse(response), String.class));
}

@Override
public CompletableFuture<String> lset(@NonNull String key, long index, @NonNull String element) {
String[] arguments = new String[] {key, Long.toString(index), element};
return commandManager.submitNewCommand(LSet, arguments, this::handleStringResponse);
}
}
19 changes: 19 additions & 0 deletions java/client/src/main/java/glide/api/commands/ListBaseCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -482,4 +482,23 @@ CompletableFuture<Map<String, String[]>> blmpop(
*/
CompletableFuture<Map<String, String[]>> blmpop(
String[] keys, PopDirection direction, double timeout);

/**
* Sets the list element at <code>index</code> to <code>element</code>.<br>
* The index is zero-based, so <code>0</code> means the first element, <code>1</code> the second
* element and so on. Negative indices can be used to designate elements starting at the tail of
* the list. Here, <code>-1</code> means the last element, <code>-2</code> means the penultimate
* and so forth.
*
* @see <a href="https://valkey.io/commands/lset/">valkey.io</a> for details.
* @param key The key of the list.
* @param index The index of the element in the list to be set.
* @return <code>OK</code>.
* @example
* <pre>{@code
* String response = client.lset("testKey", 1, "two").get();
* assertEquals(response, "OK");
* }</pre>
*/
CompletableFuture<String> lset(String key, long index, String element);
}
19 changes: 19 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 @@ -74,6 +74,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.LPushX;
import static redis_request.RedisRequestOuterClass.RequestType.LRange;
import static redis_request.RedisRequestOuterClass.RequestType.LRem;
import static redis_request.RedisRequestOuterClass.RequestType.LSet;
import static redis_request.RedisRequestOuterClass.RequestType.LTrim;
import static redis_request.RedisRequestOuterClass.RequestType.LastSave;
import static redis_request.RedisRequestOuterClass.RequestType.Lolwut;
Expand Down Expand Up @@ -3723,6 +3724,24 @@ public T lmpop(@NonNull String[] keys, @NonNull PopDirection direction) {
return getThis();
}

/**
* Sets the list element at <code>index</code> to <code>element</code>.<br>
* The index is zero-based, so <code>0</code> means the first element, <code>1</code> the second
* element and so on. Negative indices can be used to designate elements starting at the tail of
* the list. Here, <code>-1</code> means the last element, <code>-2</code> means the penultimate
* and so forth.
*
* @see <a href="https://valkey.io/commands/lset/">valkey.io</a> for details.
* @param key The key of the list.
* @param index The index of the element in the list to be set.
* @return Command Response - <code>OK</code>.
*/
public T lset(@NonNull String key, long index, @NonNull String element) {
ArgsArray commandArgs = buildArgs(key, Long.toString(index), element);
protobufTransaction.addCommands(buildCommand(LSet, 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 @@ -95,6 +95,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.LPushX;
import static redis_request.RedisRequestOuterClass.RequestType.LRange;
import static redis_request.RedisRequestOuterClass.RequestType.LRem;
import static redis_request.RedisRequestOuterClass.RequestType.LSet;
import static redis_request.RedisRequestOuterClass.RequestType.LTrim;
import static redis_request.RedisRequestOuterClass.RequestType.LastSave;
import static redis_request.RedisRequestOuterClass.RequestType.Lolwut;
Expand Down Expand Up @@ -5101,4 +5102,29 @@ public void lmpop_with_count_returns_success() {
assertEquals(testResponse, response);
assertEquals(value, payload);
}

@SneakyThrows
@Test
public void lset_returns_success() {
// setup
String key = "testKey";
long index = 0;
String element = "two";
String[] arguments = new String[] {key, "0", element};

CompletableFuture<String> testResponse = new CompletableFuture<>();
testResponse.complete(OK);

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

// exercise
CompletableFuture<String> response = service.lset(key, index, element);
String payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(OK, payload);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.LPushX;
import static redis_request.RedisRequestOuterClass.RequestType.LRange;
import static redis_request.RedisRequestOuterClass.RequestType.LRem;
import static redis_request.RedisRequestOuterClass.RequestType.LSet;
import static redis_request.RedisRequestOuterClass.RequestType.LTrim;
import static redis_request.RedisRequestOuterClass.RequestType.LastSave;
import static redis_request.RedisRequestOuterClass.RequestType.Lolwut;
Expand Down Expand Up @@ -853,6 +854,9 @@ InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3, false), new Limit(1, 2)),
transaction.blmpop(new String[] {"key"}, PopDirection.LEFT, 1L, 0.1);
results.add(Pair.of(BLMPop, buildArgs("0.1", "1", "key", "LEFT", "COUNT", "1")));

transaction.lset("key", 0, "zero");
results.add(Pair.of(LSet, buildArgs("key", "0", "zero")));

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

for (int idx = 0; idx < protobufTransaction.getCommandsCount(); idx++) {
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 @@ -4207,4 +4207,46 @@ public void blmpop_timeout_check(BaseClient client) {
testClient.blmpop(new String[] {key}, PopDirection.LEFT, 0).get(3, TimeUnit.SECONDS));
}
}

@SneakyThrows
@ParameterizedTest(autoCloseArguments = false)
@MethodSource("getClients")
public void lset(BaseClient client) {
// setup
String key = "testKey";
String nonExistingKey = "nonExisting";
long index = 0;
long oobIndex = 10;
long negativeIndex = -1;
String element = "zero";
String[] lpushArgs = {"four", "three", "two", "one"};
String[] expectedList = {"zero", "two", "three", "four"};
String[] expectedList2 = {"zero", "two", "three", "zero"};

// key does not exist
ExecutionException noSuchKeyException =
assertThrows(
ExecutionException.class, () -> client.lset(nonExistingKey, index, element).get());
assertInstanceOf(RequestException.class, noSuchKeyException.getCause());

// pushing elements to list
client.lpush(key, lpushArgs).get();

// index out of range
ExecutionException indexOutOfBoundException =
assertThrows(ExecutionException.class, () -> client.lset(key, oobIndex, element).get());
assertInstanceOf(RequestException.class, indexOutOfBoundException.getCause());

// assert lset result
String response = client.lset(key, index, element).get();
assertEquals(OK, response);
String[] updatedList = client.lrange(key, 0, -1).get();
assertArrayEquals(updatedList, expectedList);

// assert lset with a negative index for the last element in the list
String response2 = client.lset(key, negativeIndex, element).get();
assertEquals(OK, response2);
String[] updatedList2 = client.lrange(key, 0, -1).get();
assertArrayEquals(updatedList2, expectedList2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ private static Object[] listCommands(BaseTransaction<?> transaction) {
String listKey2 = "{ListKey}-2-" + UUID.randomUUID();
String listKey3 = "{ListKey}-3-" + UUID.randomUUID();
String listKey4 = "{ListKey}-4-" + UUID.randomUUID();
String listKey5 = "{ListKey}-5-" + UUID.randomUUID();

transaction
.lpush(listKey1, new String[] {value1, value1, value2, value3, value3})
Expand All @@ -268,7 +269,10 @@ private static Object[] listCommands(BaseTransaction<?> transaction) {
.lpush(listKey3, new String[] {value1, value2, value3})
.linsert(listKey3, AFTER, value2, value2)
.blpop(new String[] {listKey3}, 0.01)
.brpop(new String[] {listKey3}, 0.01);
.brpop(new String[] {listKey3}, 0.01)
.lpush(listKey5, new String[] {value2, value3})
.lset(listKey5, 0, value1)
.lrange(listKey5, 0, -1);

if (REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0")) {
transaction
Expand Down Expand Up @@ -298,6 +302,9 @@ private static Object[] listCommands(BaseTransaction<?> transaction) {
4L, // linsert(listKey3, AFTER, value2, value2)
new String[] {listKey3, value3}, // blpop(new String[] { listKey3 }, 0.01)
new String[] {listKey3, value1}, // brpop(new String[] { listKey3 }, 0.01)
2L, // lpush(listKey5, new String[] {value2, value3})
OK, // lset(listKey5, 0, value1)
new String[] {value1, value2} // lrange(listKey5, 0, -1)
};

if (REDIS_VERSION.isGreaterThanOrEqualTo("7.0.0")) {
Expand Down

0 comments on commit 4e3f976

Please sign in to comment.