From 99646aa86035ef09eac47007a34aed4eb4abdbfe Mon Sep 17 00:00:00 2001 From: uki00a Date: Mon, 21 Oct 2024 23:21:57 +0900 Subject: [PATCH] feat: support `EXAT` and `PXAT` options of the SET command --- command.ts | 12 ++++++++++++ redis.ts | 10 ++++++++-- tests/commands/string.ts | 22 ++++++++++++++++++++-- tests/test_util.ts | 4 ++++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/command.ts b/command.ts index 9512576c..1ab81d67 100644 --- a/command.ts +++ b/command.ts @@ -117,6 +117,18 @@ export type StralgoTarget = "KEYS" | "STRINGS"; export interface SetOpts { ex?: number; px?: number; + /** + * Sets `EXAT` option. + * + * `EXAT` option was added in Redis v6.2. + */ + exat?: number; + /** + * Sets `PXAT` option. + * + * `PXAT` option was added in Redis v6.2. + */ + pxat?: number; keepttl?: boolean; /** * Enables `GET` option. diff --git a/redis.ts b/redis.ts index dfc1f51d..16397104 100644 --- a/redis.ts +++ b/redis.ts @@ -1364,14 +1364,20 @@ class RedisImpl implements Redis { | SetWithModeOpts, ) { const args: RedisValue[] = [key, value]; - if (opts?.ex !== undefined) { + if (opts?.ex != null) { args.push("EX", opts.ex); - } else if (opts?.px !== undefined) { + } else if (opts?.px != null) { args.push("PX", opts.px); + } else if (opts?.exat != null) { + args.push("EXAT", opts.exat); + } else if (opts?.pxat != null) { + args.push("PXAT", opts.pxat); } + // TODO: Isn't `KEEPTTL` option exclusive with `EX`, `PX`, etc.? if (opts?.keepttl) { args.push("KEEPTTL"); } + let isAbleToReturnNil = false; if ((opts as SetWithModeOpts)?.mode) { args.push((opts as SetWithModeOpts).mode); diff --git a/tests/commands/string.ts b/tests/commands/string.ts index 18840807..57256453 100644 --- a/tests/commands/string.ts +++ b/tests/commands/string.ts @@ -8,7 +8,11 @@ import { describe, it, } from "../../deps/std/testing.ts"; -import type { Connector, TestServer } from "../test_util.ts"; +import { + type Connector, + type TestServer, + usesRedisVersion, +} from "../test_util.ts"; import type { Redis } from "../../mod.ts"; export function stringTests( @@ -205,6 +209,20 @@ export function stringTests( assertEquals(v2, null); assertType>(true); }); + + it("supports `EXAT` option", async () => { + const t = Math.floor(new Date().valueOf() / 1000); + await client.set("setWithEXAT", "foo", { exat: t }); + const ttl = await client.ttl("setWithEXAT"); + assertEquals(t, ttl); + }); + + it("supports `PXAT` option", async () => { + const t = new Date().valueOf(); + await client.set("setWithPXAT", "bar", { pxat: t }); + const ttl = await client.ttl("setWithPXAT"); + assertEquals(t, ttl); + }); }); it("setbit", async () => { @@ -244,7 +262,7 @@ export function stringTests( it("stralgo", { // NOTE(#454): STRALGO has been dropped - ignore: !Deno.env.get("REDIS_VERSION")?.startsWith("6."), + ignore: !usesRedisVersion("6"), }, async () => { await client.set("a", "Hello"); await client.set("b", "Deno!"); diff --git a/tests/test_util.ts b/tests/test_util.ts index ae084cbe..b55109e6 100644 --- a/tests/test_util.ts +++ b/tests/test_util.ts @@ -117,3 +117,7 @@ function tempPath(fileName: string): string { const url = new URL(`./tmp/${fileName}`, import.meta.url); return url.pathname; } + +export function usesRedisVersion(version: "6" | "7"): boolean { + return !!Deno.env.get("REDIS_VERSION")?.startsWith(`${version}.`); +}