From 7d97b3c508b4a9bcd1e72b0ea27fe9f24f0282b1 Mon Sep 17 00:00:00 2001 From: Zihua Li Date: Sun, 27 Mar 2022 11:06:19 +0800 Subject: [PATCH 1/2] fix: support TypeScript interface as parameters of hmset and mset Closes #1536 --- bin/overrides.js | 9 ++-- lib/utils/RedisCommander.ts | 32 ++--------- test/functional/transformer.ts | 85 ++++++++++-------------------- test/typing/transformers.test-d.ts | 31 +++++++++++ 4 files changed, 66 insertions(+), 91 deletions(-) create mode 100644 test/typing/transformers.test-d.ts diff --git a/bin/overrides.js b/bin/overrides.js index 42ca1bdf..96a8606f 100644 --- a/bin/overrides.js +++ b/bin/overrides.js @@ -1,8 +1,7 @@ const msetOverrides = { overwrite: false, defs: [ - "$1(object: Record, callback?: Callback<'OK'>): Result<'OK', Context>", - "$1(map: Map, callback?: Callback<'OK'>): Result<'OK', Context>", + "$1(object: object, callback?: Callback<'OK'>): Result<'OK', Context>", ], }; @@ -19,15 +18,13 @@ module.exports = { hset: { overwrite: false, defs: [ - "$1(key: RedisKey, object: Record, callback?: Callback): Result", - "$1(key: RedisKey, map: Map, callback?: Callback): Result", + "$1(key: RedisKey, object: object, callback?: Callback): Result", ], }, hmset: { overwrite: false, defs: [ - "$1(key: RedisKey, object: Record, callback?: Callback<'OK'>): Result<'OK', Context>", - "$1(key: RedisKey, map: Map, callback?: Callback<'OK'>): Result<'OK', Context>", + "$1(key: RedisKey, object: object, callback?: Callback<'OK'>): Result<'OK', Context>", ], }, exec: { diff --git a/lib/utils/RedisCommander.ts b/lib/utils/RedisCommander.ts index 5aabbecc..8d26741c 100644 --- a/lib/utils/RedisCommander.ts +++ b/lib/utils/RedisCommander.ts @@ -4280,12 +4280,7 @@ interface RedisCommander { */ hmset( key: RedisKey, - object: Record, - callback?: Callback<"OK"> - ): Result<"OK", Context>; - hmset( - key: RedisKey, - map: Map, + object: object, callback?: Callback<"OK"> ): Result<"OK", Context>; hmset( @@ -4407,12 +4402,7 @@ interface RedisCommander { */ hset( key: RedisKey, - object: Record, - callback?: Callback - ): Result; - hset( - key: RedisKey, - map: Map, + object: object, callback?: Callback ): Result; hset( @@ -5513,14 +5503,7 @@ interface RedisCommander { * - _complexity_: O(N) where N is the number of keys to set. * - _since_: 1.0.1 */ - mset( - object: Record, - callback?: Callback<"OK"> - ): Result<"OK", Context>; - mset( - map: Map, - callback?: Callback<"OK"> - ): Result<"OK", Context>; + mset(object: object, callback?: Callback<"OK">): Result<"OK", Context>; mset( ...args: [ ...keyValues: (RedisKey | string | Buffer | number)[], @@ -5537,14 +5520,7 @@ interface RedisCommander { * - _complexity_: O(N) where N is the number of keys to set. * - _since_: 1.0.1 */ - msetnx( - object: Record, - callback?: Callback<"OK"> - ): Result<"OK", Context>; - msetnx( - map: Map, - callback?: Callback<"OK"> - ): Result<"OK", Context>; + msetnx(object: object, callback?: Callback<"OK">): Result<"OK", Context>; msetnx( ...args: [ ...keyValues: (RedisKey | string | Buffer | number)[], diff --git a/test/functional/transformer.ts b/test/functional/transformer.ts index 50cb2d36..d54b8da5 100644 --- a/test/functional/transformer.ts +++ b/test/functional/transformer.ts @@ -5,85 +5,56 @@ import { expect } from "chai"; describe("transformer", () => { describe("default transformer", () => { describe("hmset", () => { - it("should support object", (done) => { + it("should support object", async () => { const redis = new Redis(); - redis.hmset("foo", { a: 1, b: "2" }, function (err, result) { - expect(result).to.eql("OK"); - redis.hget("foo", "b", function (err, result) { - expect(result).to.eql("2"); - done(); - }); - }); + expect(await redis.hmset("foo", { a: 1, b: "2" })).to.eql("OK"); + expect(await redis.hget("foo", "b")).to.eql("2"); }); - it("should support Map", (done) => { + + it("should support Map", async () => { const redis = new Redis(); const map = new Map(); map.set("a", 1); map.set("b", "2"); - redis.hmset("foo", map, function (err, result) { - expect(result).to.eql("OK"); - redis.hget("foo", "b", function (err, result) { - expect(result).to.eql("2"); - done(); - }); - }); + expect(await redis.hmset("foo", map)).to.eql("OK"); + expect(await redis.hget("foo", "b")).to.eql("2"); }); - it("should not affect the old way", (done) => { + + it("should not affect the old way", async () => { const redis = new Redis(); - redis.hmset("foo", "a", 1, "b", "2", function (err, result) { - expect(result).to.eql("OK"); - redis.hget("foo", "b", function (err, result) { - expect(result).to.eql("2"); - done(); - }); - }); + expect(await redis.hmset("foo", "a", 1, "b", "2")).to.eql("OK"); + expect(await redis.hget("foo", "b")).to.eql("2"); }); }); describe("mset", () => { - it("should support object", (done) => { + it("should support object", async () => { const redis = new Redis(); - redis.mset({ a: 1, b: "2" }, function (err, result) { - expect(result).to.eql("OK"); - redis.mget("a", "b", function (err, result) { - expect(result).to.eql(["1", "2"]); - done(); - }); - }); + expect(await redis.mset({ a: 1, b: "2" })).to.eql("OK"); + expect(await redis.mget("a", "b")).to.eql(["1", "2"]); }); - it("should support Map", (done) => { + + it("should support Map", async () => { const redis = new Redis(); const map = new Map(); map.set("a", 1); map.set("b", "2"); - redis.mset(map, function (err, result) { - expect(result).to.eql("OK"); - redis.mget("a", "b", function (err, result) { - expect(result).to.eql(["1", "2"]); - done(); - }); - }); + expect(await redis.mset(map)).to.eql("OK"); + expect(await redis.mget("a", "b")).to.eql(["1", "2"]); }); - it("should not affect the old way", (done) => { + + it("should not affect the old way", async () => { const redis = new Redis(); - redis.mset("a", 1, "b", "2", function (err, result) { - expect(result).to.eql("OK"); - redis.mget("a", "b", function (err, result) { - expect(result).to.eql(["1", "2"]); - done(); - }); - }); + expect(await redis.mset("a", 1, "b", "2")).to.eql("OK"); + expect(await redis.mget("a", "b")).to.eql(["1", "2"]); }); - it("should work with keyPrefix option", (done) => { + + it("should work with keyPrefix option", async () => { const redis = new Redis({ keyPrefix: "foo:" }); - redis.mset({ a: 1, b: "2" }, function (err, result) { - expect(result).to.eql("OK"); - const otherRedis = new Redis(); - otherRedis.mget("foo:a", "foo:b", function (err, result) { - expect(result).to.eql(["1", "2"]); - done(); - }); - }); + expect(await redis.mset({ a: 1, b: "2" })).to.eql("OK"); + + const otherRedis = new Redis(); + expect(await otherRedis.mget("foo:a", "foo:b")).to.eql(["1", "2"]); }); }); diff --git a/test/typing/transformers.test-d.ts b/test/typing/transformers.test-d.ts new file mode 100644 index 00000000..ab80580a --- /dev/null +++ b/test/typing/transformers.test-d.ts @@ -0,0 +1,31 @@ +import { expectType } from "tsd"; +import Redis from "../../built"; + +interface User { + name: string; + title: string; +} + +const user: User = { name: "Bob", title: "Engineer" }; +const map = new Map([["key", "value"]]); + +const redis = new Redis(); + +// mset +expectType>(redis.mset(user)); +expectType>(redis.mset(map)); + +// msetnx +expectType>(redis.msetnx(user)); +expectType>(redis.msetnx(map)); + +// hmset +expectType>(redis.hmset("key", user)); +expectType>(redis.hmset("key", map)); + +// hset +expectType>(redis.hset("key", user)); +expectType>(redis.hset("key", map)); + +// hgetall +expectType>>(redis.hgetall("key")); From 65bd61ee75f7fbfa2f15a67726c8b740471a9f5d Mon Sep 17 00:00:00 2001 From: Zihua Li Date: Sun, 27 Mar 2022 19:55:06 +0800 Subject: [PATCH 2/2] Addressed feedbacks --- bin/overrides.js | 3 +++ lib/utils/RedisCommander.ts | 18 ++++++++++++++++++ test/functional/transformer.ts | 9 ++++++++- test/typing/transformers.test-d.ts | 30 +++++++++++++++++++++++++----- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/bin/overrides.js b/bin/overrides.js index 96a8606f..8ef4e6c5 100644 --- a/bin/overrides.js +++ b/bin/overrides.js @@ -2,6 +2,7 @@ const msetOverrides = { overwrite: false, defs: [ "$1(object: object, callback?: Callback<'OK'>): Result<'OK', Context>", + "$1(map: Map, callback?: Callback<'OK'>): Result<'OK', Context>", ], }; @@ -19,12 +20,14 @@ module.exports = { overwrite: false, defs: [ "$1(key: RedisKey, object: object, callback?: Callback): Result", + "$1(key: RedisKey, map: Map, callback?: Callback): Result", ], }, hmset: { overwrite: false, defs: [ "$1(key: RedisKey, object: object, callback?: Callback<'OK'>): Result<'OK', Context>", + "$1(key: RedisKey, map: Map, callback?: Callback<'OK'>): Result<'OK', Context>", ], }, exec: { diff --git a/lib/utils/RedisCommander.ts b/lib/utils/RedisCommander.ts index 8d26741c..0f6cbbad 100644 --- a/lib/utils/RedisCommander.ts +++ b/lib/utils/RedisCommander.ts @@ -4283,6 +4283,11 @@ interface RedisCommander { object: object, callback?: Callback<"OK"> ): Result<"OK", Context>; + hmset( + key: RedisKey, + map: Map, + callback?: Callback<"OK"> + ): Result<"OK", Context>; hmset( ...args: [ key: RedisKey, @@ -4405,6 +4410,11 @@ interface RedisCommander { object: object, callback?: Callback ): Result; + hset( + key: RedisKey, + map: Map, + callback?: Callback + ): Result; hset( ...args: [ key: RedisKey, @@ -5504,6 +5514,10 @@ interface RedisCommander { * - _since_: 1.0.1 */ mset(object: object, callback?: Callback<"OK">): Result<"OK", Context>; + mset( + map: Map, + callback?: Callback<"OK"> + ): Result<"OK", Context>; mset( ...args: [ ...keyValues: (RedisKey | string | Buffer | number)[], @@ -5521,6 +5535,10 @@ interface RedisCommander { * - _since_: 1.0.1 */ msetnx(object: object, callback?: Callback<"OK">): Result<"OK", Context>; + msetnx( + map: Map, + callback?: Callback<"OK"> + ): Result<"OK", Context>; msetnx( ...args: [ ...keyValues: (RedisKey | string | Buffer | number)[], diff --git a/test/functional/transformer.ts b/test/functional/transformer.ts index d54b8da5..5685f75a 100644 --- a/test/functional/transformer.ts +++ b/test/functional/transformer.ts @@ -11,13 +11,20 @@ describe("transformer", () => { expect(await redis.hget("foo", "b")).to.eql("2"); }); - it("should support Map", async () => { + it("should support Map with string keys", async () => { const redis = new Redis(); const map = new Map(); map.set("a", 1); map.set("b", "2"); + map.set(42, true); + map.set(Buffer.from("buffer"), "utf8"); + map.set(Buffer.from([0xff]), "binary"); expect(await redis.hmset("foo", map)).to.eql("OK"); + expect(await redis.hget("foo", "a")).to.eql("1"); expect(await redis.hget("foo", "b")).to.eql("2"); + expect(await redis.hget("foo", "42")).to.eql("true"); + expect(await redis.hget("foo", "buffer")).to.eql("utf8"); + expect(await redis.hget("foo", Buffer.from([0xff]))).to.eql("binary"); }); it("should not affect the old way", async () => { diff --git a/test/typing/transformers.test-d.ts b/test/typing/transformers.test-d.ts index ab80580a..a65b4ac0 100644 --- a/test/typing/transformers.test-d.ts +++ b/test/typing/transformers.test-d.ts @@ -7,25 +7,45 @@ interface User { } const user: User = { name: "Bob", title: "Engineer" }; -const map = new Map([["key", "value"]]); +const stringMap = new Map([["key", "value"]]); +const numberMap = new Map([[42, "value"]]); +const bufferMap = new Map([[Buffer.from([0xff]), "value"]]); +const mixedMap = new Map([ + [Buffer.from([0xff]), "value"], + [42, "value"], + ["field", "value"], +]); const redis = new Redis(); // mset +expectType>(redis.mset("key1", "value1", "key2", "value2")); expectType>(redis.mset(user)); -expectType>(redis.mset(map)); +expectType>(redis.mset(stringMap)); +expectType>(redis.mset(numberMap)); +expectType>(redis.mset(bufferMap)); +expectType>(redis.mset(mixedMap)); // msetnx expectType>(redis.msetnx(user)); -expectType>(redis.msetnx(map)); +expectType>(redis.msetnx(stringMap)); +expectType>(redis.msetnx(numberMap)); +expectType>(redis.msetnx(bufferMap)); +expectType>(redis.msetnx(mixedMap)); // hmset expectType>(redis.hmset("key", user)); -expectType>(redis.hmset("key", map)); +expectType>(redis.hmset("key", stringMap)); +expectType>(redis.hmset("key", numberMap)); +expectType>(redis.hmset("key", bufferMap)); +expectType>(redis.hmset("key", mixedMap)); // hset expectType>(redis.hset("key", user)); -expectType>(redis.hset("key", map)); +expectType>(redis.hset("key", stringMap)); +expectType>(redis.hset("key", numberMap)); +expectType>(redis.hset("key", bufferMap)); +expectType>(redis.hset("key", mixedMap)); // hgetall expectType>>(redis.hgetall("key"));