diff --git a/CHANGELOG.md b/CHANGELOG.md index dd21b1c526..1b4ed06bc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,14 @@ * Python, Node: Added TYPE command ([#945](https://github.com/aws/glide-for-redis/pull/945), [#980](https://github.com/aws/glide-for-redis/pull/980)) * Python, Node: Added HLEN command ([#944](https://github.com/aws/glide-for-redis/pull/944), [#981](https://github.com/aws/glide-for-redis/pull/981)) * Python, Node: Added ZCOUNT command ([#878](https://github.com/aws/glide-for-redis/pull/878)) ([#909](https://github.com/aws/glide-for-redis/pull/909)) -* Python: Added ECHO command ([#953](https://github.com/aws/glide-for-redis/pull/953)) +* Python, Node: Added ECHO command ([#953](https://github.com/aws/glide-for-redis/pull/953), [#1010](https://github.com/aws/glide-for-redis/pull/1010)) * Python, Node: Added ZPOPMIN command ([#975](https://github.com/aws/glide-for-redis/pull/975), [#1008](https://github.com/aws/glide-for-redis/pull/1008)) * Node: Added STRLEN command ([#993](https://github.com/aws/glide-for-redis/pull/993)) * Node: Added LINDEX command ([#999](https://github.com/aws/glide-for-redis/pull/999)) * Python, Node: Added ZPOPMAX command ([#996](https://github.com/aws/glide-for-redis/pull/996), [#1009](https://github.com/aws/glide-for-redis/pull/1009)) * Python: Added ZRANGE command ([#906](https://github.com/aws/glide-for-redis/pull/906)) +* Node: Added HVAL command ([#1022](https://github.com/aws/glide-for-redis/pull/1022)) +* Node: Added PERSIST command ([#1023](https://github.com/aws/glide-for-redis/pull/1023)) #### Features diff --git a/glide-core/src/client/value_conversion.rs b/glide-core/src/client/value_conversion.rs index 73a886e994..5afea2150e 100644 --- a/glide-core/src/client/value_conversion.rs +++ b/glide-core/src/client/value_conversion.rs @@ -202,7 +202,7 @@ pub(crate) fn expected_type_for_cmd(cmd: &Cmd) -> Option { } b"INCRBYFLOAT" | b"HINCRBYFLOAT" => Some(ExpectedReturnType::Double), b"HEXISTS" | b"HSETNX" | b"EXPIRE" | b"EXPIREAT" | b"PEXPIRE" | b"PEXPIREAT" - | b"SISMEMBER" => Some(ExpectedReturnType::Boolean), + | b"SISMEMBER" | b"PERSIST" => Some(ExpectedReturnType::Boolean), b"SMEMBERS" => Some(ExpectedReturnType::Set), b"ZSCORE" => Some(ExpectedReturnType::DoubleOrNull), b"ZPOPMIN" | b"ZPOPMAX" => Some(ExpectedReturnType::MapOfStringToDouble), diff --git a/glide-core/src/protobuf/redis_request.proto b/glide-core/src/protobuf/redis_request.proto index ceaa83c11a..0835cb7c3d 100644 --- a/glide-core/src/protobuf/redis_request.proto +++ b/glide-core/src/protobuf/redis_request.proto @@ -127,6 +127,7 @@ enum RequestType { SIsMember = 83; Hvals = 84; PTTL = 85; + Persist = 86; } message Command { diff --git a/glide-core/src/socket_listener.rs b/glide-core/src/socket_listener.rs index dfea685be6..8a90205dff 100644 --- a/glide-core/src/socket_listener.rs +++ b/glide-core/src/socket_listener.rs @@ -364,6 +364,7 @@ fn get_command(request: &Command) -> Option { RequestType::SIsMember => Some(cmd("SISMEMBER")), RequestType::Hvals => Some(cmd("HVALS")), RequestType::PTTL => Some(cmd("PTTL")), + RequestType::Persist => Some(cmd("PERSIST")), } } diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index b804501790..2b457dc98b 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -47,6 +47,7 @@ import { createMSet, createPExpire, createPExpireAt, + createPersist, createRPop, createRPush, createSAdd, @@ -1183,6 +1184,17 @@ export class BaseClient { return this.createWritePromise(createLindex(key, index)); } + /** Remove the existing timeout on `key`, turning the key from volatile (a key with an expire set) to + * persistent (a key that will never expire as no timeout is associated). + * See https://redis.io/commands/persist/ for more details. + * + * @param key - The key to remove the existing timeout on. + * @returns false if `key` does not exist or does not have an associated timeout. true if the timeout has been removed. + */ + public persist(key: string): Promise { + return this.createWritePromise(createPersist(key)); + } + /** * @internal */ diff --git a/node/src/Commands.ts b/node/src/Commands.ts index a7428736c0..e318b666d0 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -877,3 +877,10 @@ export function createZpopmax(key: string, count?: number): redis_request.Comman export function createEcho(message: string): redis_request.Command { return createCommand(RequestType.Echo, [message]); } + +/** + * @internal + */ +export function createPersist(key: string): redis_request.Command { + return createCommand(RequestType.Persist, [key]); +} diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 6a36f74c91..da6284d0eb 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -48,6 +48,7 @@ import { createMSet, createPExpire, createPExpireAt, + createPersist, createPing, createRPop, createRPush, @@ -924,6 +925,18 @@ export class BaseTransaction> { return this.addAndReturn(createEcho(message)); } + /** Remove the existing timeout on `key`, turning the key from volatile (a key with an expire set) to + * persistent (a key that will never expire as no timeout is associated). + * See https://redis.io/commands/persist/ for more details. + * + * @param key - The key to remove the existing timeout on. + * + * Command Response - false if `key` does not exist or does not have an associated timeout. true if the timeout has been removed. + */ + public persist(key: string): T { + return this.addAndReturn(createPersist(key)); + } + /** Executes a single command, without checking inputs. Every part of the command, including subcommands, * should be added as a separate value in args. * diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index e60b6b5bee..88db406681 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -1651,6 +1651,21 @@ export function runBaseTests(config: { }, config.timeout ); + + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + `persist test_%p`, + async (protocol) => { + await runTest(async (client: BaseClient) => { + const key = uuidv4(); + expect(await client.set(key, "foo")).toEqual("OK"); + expect(await client.persist(key)).toEqual(false); + + expect(await client.expire(key, 10)).toEqual(true); + expect(await client.persist(key)).toEqual(true); + }, protocol); + }, + config.timeout + ); } export function runCommonTests(config: { diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index f468e83921..a77bc685a6 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -70,6 +70,8 @@ export function transactionTest( args.push("string"); baseTransaction.echo(value); args.push(value); + baseTransaction.persist(key1); + args.push(false); baseTransaction.set(key2, "baz", { returnOldValue: true, });