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

Add PPTL() command #146

Merged
merged 4 commits into from
Mar 21, 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
6 changes: 6 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.MSet;
import static redis_request.RedisRequestOuterClass.RequestType.PExpire;
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
import static redis_request.RedisRequestOuterClass.RequestType.RPop;
import static redis_request.RedisRequestOuterClass.RequestType.RPush;
import static redis_request.RedisRequestOuterClass.RequestType.SAdd;
Expand Down Expand Up @@ -586,4 +587,9 @@ public CompletableFuture<Long> zrem(@NonNull String key, @NonNull String[] membe
public CompletableFuture<Long> zcard(@NonNull String key) {
return commandManager.submitNewCommand(Zcard, new String[] {key}, this::handleLongResponse);
}

@Override
public CompletableFuture<Long> pttl(@NonNull String key) {
return commandManager.submitNewCommand(PTTL, new String[] {key}, this::handleLongResponse);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,29 @@ CompletableFuture<Boolean> pexpireAt(
* @example
* <pre>{@code
* Long timeRemaining = client.ttl("my_key").get()
* assert timeRemaining == 3600L //Indicates that "my_key" has a remaining time to live of 3600 seconds.
* assert timeRemaining == 3600L // Indicates that "my_key" has a remaining time to live of 3600 seconds.
*
* Long timeRemaining = client.ttl("nonexistent_key").get();
* assert timeRemaining == -2L; //Returns -2 for a non-existing key.
* assert timeRemaining == -2L; // Returns -2 for a non-existing key.
* }</pre>
*/
CompletableFuture<Long> ttl(String key);

/**
* Returns the remaining time to live of <code>key</code> that has a timeout, in milliseconds.
*
* @see <a href="https://redis.io/commands/pttl/">redis.io</a> for details.
* @param key The key to return its timeout.
* @return TTL in milliseconds. <code>-2</code> if <code>key</code> does not exist, <code>-1
acarbonetto marked this conversation as resolved.
Show resolved Hide resolved
* </code> if <code>key</code> exists but has no associated expire.
* @example
* <pre>{@code
* Long timeRemainingMS = client.pttl("my_key").get()
* assert timeRemainingMS == 5000L // Indicates that "my_key" has a remaining time to live of 5000 milliseconds.
*
* Long timeRemainingMS = client.pttl("nonexistent_key").get();
* assert timeRemainingMS == -2L; // Returns -2 for a non-existing key.
* }</pre>
*/
CompletableFuture<Long> pttl(String key);
}
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 @@ -40,6 +40,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.MSet;
import static redis_request.RedisRequestOuterClass.RequestType.PExpire;
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
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 @@ -1241,6 +1242,21 @@ public T zcard(@NonNull String key) {
return getThis();
}

/**
* Returns the remaining time to live of <code>key</code> that has a timeout, in milliseconds.
*
* @see <a href="https://redis.io/commands/pttl/">redis.io</a> for details.
* @param key The key to return its timeout.
* @return Command Response - TTL in milliseconds. <code>-2</code> if <code>key</code> does not
* exist, <code>-1</code> if <code>key</code> exists but has no associated expire.
*/
public T pttl(@NonNull String key) {
ArgsArray commandArgs = buildArgs(key);

protobufTransaction.addCommands(buildCommand(PTTL, commandArgs));
return getThis();
}

/** Build protobuf {@link Command} object for given command and arguments. */
protected Command buildCommand(RequestType requestType) {
return buildCommand(requestType, buildArgs());
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 @@ -51,6 +51,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.MSet;
import static redis_request.RedisRequestOuterClass.RequestType.PExpire;
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
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 @@ -551,6 +552,28 @@ public void ttl_returns_success() {
assertEquals(ttl, response.get());
}

@SneakyThrows
@Test
public void pttl_returns_success() {
// setup
String key = "testKey";
long pttl = 999000L;

CompletableFuture<Long> testResponse = mock(CompletableFuture.class);
when(testResponse.get()).thenReturn(pttl);

// match on protobuf request
when(commandManager.<Long>submitNewCommand(eq(PTTL), eq(new String[] {key}), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Long> response = service.pttl(key);

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

@SneakyThrows
@Test
public void info_returns_success() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.MSet;
import static redis_request.RedisRequestOuterClass.RequestType.PExpire;
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
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 @@ -286,6 +287,9 @@ public void transaction_builds_protobuf_request(BaseTransaction<?> transaction)
transaction.ttl("key");
results.add(Pair.of(TTL, ArgsArray.newBuilder().addArgs("key").build()));

transaction.pttl("key");
results.add(Pair.of(PTTL, ArgsArray.newBuilder().addArgs("key").build()));

transaction.clientId();
results.add(Pair.of(ClientId, ArgsArray.newBuilder().build()));

Expand Down
16 changes: 14 additions & 2 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -744,11 +744,12 @@ public void exists_multiple_keys(BaseClient client) {
@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
public void expire_pexpire_and_ttl_with_positive_timeout(BaseClient client) {
public void expire_pexpire_and_ttl_pttl_with_positive_timeout(BaseClient client) {
String key = UUID.randomUUID().toString();
assertEquals(OK, client.set(key, "expire_timeout").get());
assertTrue(client.expire(key, 10L).get());
assertTrue(client.ttl(key).get() <= 10L);
assertTrue(client.pttl(key).get() <= 10000L);

// set command clears the timeout.
assertEquals(OK, client.set(key, "pexpire_timeout").get());
Expand All @@ -758,6 +759,7 @@ public void expire_pexpire_and_ttl_with_positive_timeout(BaseClient client) {
assertTrue(client.pexpire(key, 10000L, ExpireOptions.HAS_NO_EXPIRY).get());
}
assertTrue(client.ttl(key).get() <= 10L);
assertTrue(client.pttl(key).get() <= 10000L);

// TTL will be updated to the new value = 15
if (REDIS_VERSION.isLowerThan("7.0.0")) {
Expand All @@ -766,16 +768,18 @@ public void expire_pexpire_and_ttl_with_positive_timeout(BaseClient client) {
assertTrue(client.expire(key, 15L, ExpireOptions.HAS_EXISTING_EXPIRY).get());
}
assertTrue(client.ttl(key).get() <= 15L);
assertTrue(client.pttl(key).get() <= 15000L);
}

@SneakyThrows
@ParameterizedTest
@MethodSource("getClients")
public void expireAt_pexpireAt_and_ttl_with_positive_timeout(BaseClient client) {
public void expireAt_pexpireAt_and_ttl_pttl_with_positive_timeout(BaseClient client) {
String key = UUID.randomUUID().toString();
assertEquals(OK, client.set(key, "expireAt_timeout").get());
assertTrue(client.expireAt(key, Instant.now().getEpochSecond() + 10L).get());
assertTrue(client.ttl(key).get() <= 10L);
assertTrue(client.pttl(key).get() <= 10000L);

// extend TTL
if (REDIS_VERSION.isLowerThan("7.0.0")) {
Expand All @@ -790,6 +794,7 @@ public void expireAt_pexpireAt_and_ttl_with_positive_timeout(BaseClient client)
.get());
}
assertTrue(client.ttl(key).get() <= 50L);
assertTrue(client.pttl(key).get() <= 50000L);

if (REDIS_VERSION.isLowerThan("7.0.0")) {
assertTrue(client.pexpireAt(key, Instant.now().toEpochMilli() + 50000L).get());
Expand All @@ -812,12 +817,15 @@ public void expire_pexpire_with_timestamp_in_the_past_or_negative_timeout(BaseCl

assertEquals(OK, client.set(key, "expire_with_past_timestamp").get());
assertEquals(-1L, client.ttl(key).get());
assertEquals(-1L, client.pttl(key).get());
assertTrue(client.expire(key, -10L).get());
assertEquals(-2L, client.ttl(key).get());
assertEquals(-2L, client.pttl(key).get());

assertEquals(OK, client.set(key, "pexpire_with_past_timestamp").get());
assertTrue(client.pexpire(key, -10000L).get());
assertEquals(-2L, client.ttl(key).get());
assertEquals(-2L, client.pttl(key).get());
}

@SneakyThrows
Expand All @@ -830,11 +838,13 @@ public void expireAt_pexpireAt_with_timestamp_in_the_past_or_negative_timeout(Ba
// set timeout in the past
assertTrue(client.expireAt(key, Instant.now().getEpochSecond() - 50L).get());
assertEquals(-2L, client.ttl(key).get());
assertEquals(-2L, client.pttl(key).get());

assertEquals(OK, client.set(key, "pexpireAt_with_past_timestamp").get());
// set timeout in the past
assertTrue(client.pexpireAt(key, Instant.now().toEpochMilli() - 50000L).get());
assertEquals(-2L, client.ttl(key).get());
assertEquals(-2L, client.pttl(key).get());
}

@SneakyThrows
Expand All @@ -847,6 +857,7 @@ public void expire_pexpire_and_ttl_with_non_existing_key(BaseClient client) {
assertFalse(client.pexpire(key, 10000L).get());

assertEquals(-2L, client.ttl(key).get());
assertEquals(-2L, client.pttl(key).get());
}

@SneakyThrows
Expand All @@ -859,6 +870,7 @@ public void expireAt_pexpireAt_and_ttl_with_non_existing_key(BaseClient client)
assertFalse(client.pexpireAt(key, Instant.now().toEpochMilli() + 10000L).get());

assertEquals(-2L, client.ttl(key).get());
assertEquals(-2L, client.pttl(key).get());
}

@SneakyThrows
Expand Down
Loading