diff --git a/command.ts b/command.ts index ac2d04a5..9512576c 100644 --- a/command.ts +++ b/command.ts @@ -118,6 +118,12 @@ export interface SetOpts { ex?: number; px?: number; keepttl?: boolean; + /** + * Enables `GET` option. + * + * `GET` option was added in Redis v6.2. + */ + get?: boolean; } export interface SetWithModeOpts extends SetOpts { @@ -327,12 +333,12 @@ export interface RedisCommands { set( key: string, value: RedisValue, - opts?: SetOpts, + opts?: Omit & { get?: false | null }, ): Promise; set( key: string, value: RedisValue, - opts?: SetWithModeOpts, + opts?: (Omit & { get: true }) | SetWithModeOpts, ): Promise; setbit(key: string, offset: number, value: RedisValue): Promise; setex(key: string, seconds: number, value: RedisValue): Promise; diff --git a/deps/std/testing.ts b/deps/std/testing.ts index c7a3a1f8..b7cea7aa 100644 --- a/deps/std/testing.ts +++ b/deps/std/testing.ts @@ -1 +1,3 @@ export * from "jsr:@std/testing@^1.0.0/bdd"; +export type * from "jsr:@std/testing@^1.0.0/types"; +export { assertType } from "jsr:@std/testing@^1.0.0/types"; diff --git a/redis.ts b/redis.ts index 0a79b401..dfc1f51d 100644 --- a/redis.ts +++ b/redis.ts @@ -1347,17 +1347,21 @@ class RedisImpl implements Redis { set( key: string, value: RedisValue, - opts?: SetOpts, + opts?: Omit & { get?: false | null }, ): Promise; set( key: string, value: RedisValue, - opts?: SetWithModeOpts, + opts?: (Omit & { get: true }) | SetWithModeOpts, ): Promise; set( key: string, value: RedisValue, - opts?: SetOpts | SetWithModeOpts, + opts?: + | (Omit & { + get?: true | false | null; + }) + | SetWithModeOpts, ) { const args: RedisValue[] = [key, value]; if (opts?.ex !== undefined) { @@ -1368,11 +1372,17 @@ class RedisImpl implements Redis { if (opts?.keepttl) { args.push("KEEPTTL"); } + let isAbleToReturnNil = false; if ((opts as SetWithModeOpts)?.mode) { args.push((opts as SetWithModeOpts).mode); - return this.execStatusOrNilReply("SET", ...args); + isAbleToReturnNil = true; } - return this.execStatusReply("SET", ...args); + if (opts?.get) { + args.push("GET"); + } + return isAbleToReturnNil + ? this.execStatusOrNilReply("SET", ...args) + : this.execStatusReply("SET", ...args); } setbit(key: string, offset: number, value: RedisValue) { diff --git a/tests/commands/string.ts b/tests/commands/string.ts index b2e7b1c7..18840807 100644 --- a/tests/commands/string.ts +++ b/tests/commands/string.ts @@ -1,5 +1,13 @@ import { assertEquals } from "../../deps/std/assert.ts"; -import { afterAll, beforeAll, beforeEach, it } from "../../deps/std/testing.ts"; +import type { IsExact, IsNullable } from "../../deps/std/testing.ts"; +import { + afterAll, + assertType, + beforeAll, + beforeEach, + describe, + it, +} from "../../deps/std/testing.ts"; import type { Connector, TestServer } from "../test_util.ts"; import type { Redis } from "../../mod.ts"; @@ -165,18 +173,38 @@ export function stringTests( assertEquals(await client.get("key1"), "test"); }); - it("set", async () => { - const s = await client.set("key", "fuga你好こんにちは"); - assertEquals(s, "OK"); - const fuga = await client.get("key"); - assertEquals(fuga, "fuga你好こんにちは"); - }); + describe("set", () => { + it("can set a key", async () => { + const s = await client.set("key", "fuga你好こんにちは"); + assertEquals(s, "OK"); + assertType>(true); + const fuga = await client.get("key"); + assertEquals(fuga, "fuga你好こんにちは"); + }); - it("set Number", async () => { - const s = await client.set("key", 123); - assertEquals(s, "OK"); - const v = await client.get("key"); - assertEquals(v, "123"); + it("supports `Number`", async () => { + const s = await client.set("key", 123); + assertEquals(s, "OK"); + const v = await client.get("key"); + assertEquals(v, "123"); + }); + + it("supports `GET` option", async () => { + const prev = "foobar"; + await client.set("setWithGetOpt", prev); + const result = await client.set("setWithGetOpt", "baz", { get: true }); + assertEquals(result, prev); + assertType>(true); + }); + + it("supports `NX` option", async () => { + const prev = "foo"; + const v1 = await client.set("setWithNX", prev, { mode: "NX" }); + assertEquals(v1, "OK"); + const v2 = await client.set("setWithNX", "bar", { mode: "NX" }); + assertEquals(v2, null); + assertType>(true); + }); }); it("setbit", async () => {