From 0b0273730aca100bb9fec9d42a3caad34bdddaec Mon Sep 17 00:00:00 2001 From: Leibale Date: Mon, 12 Jun 2023 11:28:13 -0400 Subject: [PATCH] legacy mode --- .../client/lib/client/legacy-mode.spec.ts | 111 ++++++++++++++++++ packages/client/lib/client/legacy-mode.ts | 20 ++-- 2 files changed, 122 insertions(+), 9 deletions(-) create mode 100644 packages/client/lib/client/legacy-mode.spec.ts diff --git a/packages/client/lib/client/legacy-mode.spec.ts b/packages/client/lib/client/legacy-mode.spec.ts new file mode 100644 index 0000000000..189ed07243 --- /dev/null +++ b/packages/client/lib/client/legacy-mode.spec.ts @@ -0,0 +1,111 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import { promisify } from 'util'; +import { RedisLegacyClientType } from './legacy-mode'; +import { ErrorReply } from '../errors'; +import { RedisClientType } from '.'; +import { once } from 'events'; + +function testWithLegacyClient(title: string, fn: (legacy: RedisLegacyClientType, client: RedisClientType) => Promise) { + testUtils.testWithClient(title, client => fn(client.legacy(), client), GLOBAL.SERVERS.OPEN); +} + +describe.only('Legacy Mode', () => { + describe('client.sendCommand', () => { + testWithLegacyClient('resolve', async client => { + assert.equal( + await promisify(client.sendCommand).call(client, 'PING'), + 'PONG' + ); + }); + + testWithLegacyClient('reject', async client => { + await assert.rejects( + promisify(client.sendCommand).call(client, 'ERROR'), + ErrorReply + ); + }); + + testWithLegacyClient('reject without a callback', async (legacy, client) => { + legacy.sendCommand('ERROR'); + const [err] = await once(client, 'error'); + assert.ok(err instanceof ErrorReply); + }); + }); + + describe('hGetAll (TRANSFORM_LEGACY_REPLY)', () => { + testWithLegacyClient('resolve', async client => { + await promisify(client.hSet).call(client, 'key', 'field', 'value'); + assert.deepEqual( + await promisify(client.hGetAll).call(client, 'key'), + Object.create(null, { + field: { + value: 'value', + configurable: true, + enumerable: true + } + }) + ); + }); + + testWithLegacyClient('reject', async client => { + await assert.rejects( + promisify(client.hGetAll).call(client), + ErrorReply + ); + }); + }); + + describe('client.set', () => { + testWithLegacyClient('vardict', async client => { + assert.equal( + await promisify(client.set).call(client, 'a', 'b'), + 'OK' + ); + }); + + testWithLegacyClient('array', async client => { + assert.equal( + await promisify(client.set).call(client, ['a', 'b']), + 'OK' + ); + }); + + testWithLegacyClient('vardict & arrays', async client => { + assert.equal( + await promisify(client.set).call(client, ['a'], 'b', ['EX', 1]), + 'OK' + ); + }); + + testWithLegacyClient('reject without a callback', async (legacy, client) => { + legacy.set('ERROR'); + const [err] = await once(client, 'error'); + assert.ok(err instanceof ErrorReply); + }); + }); + + describe('client.multi', () => { + testWithLegacyClient('resolve', async client => { + const multi = client.multi().ping().sendCommand('PING'); + assert.deepEqual( + await promisify(multi.exec).call(multi), + ['PONG', 'PONG'] + ); + }); + + testWithLegacyClient('reject', async client => { + const multi = client.multi().sendCommand('ERROR'); + await assert.rejects( + promisify(multi.exec).call(multi), + ErrorReply + ); + }); + + testWithLegacyClient('reject without a callback', async (legacy, client) => { + legacy.multi().sendCommand('ERROR').exec(); + const [err] = await once(client, 'error'); + assert.ok(err instanceof ErrorReply); + }); + }); +}); diff --git a/packages/client/lib/client/legacy-mode.ts b/packages/client/lib/client/legacy-mode.ts index 78793c5f80..576d73be96 100644 --- a/packages/client/lib/client/legacy-mode.ts +++ b/packages/client/lib/client/legacy-mode.ts @@ -91,7 +91,7 @@ export class RedisLegacyClient { this._Multi = LegacyMultiCommand.factory(RESP); } - sendCommand(...args: LegacyArguments) { + sendCommand(...args: LegacyCommandArguments) { const redisArgs: CommandArguments = [], callback = RedisLegacyClient._transformArguments(redisArgs, args), promise = this._client.sendCommand(redisArgs); @@ -115,15 +115,16 @@ type MultiWithCommands = { [P in keyof typeof COMMANDS]: (...args: LegacyCommandArguments) => RedisLegacyMultiType; }; -export type RedisLegacyMultiType = Omit & MultiWithCommands; +export type RedisLegacyMultiType = LegacyMultiCommand & MultiWithCommands; -class LegacyMultiCommand extends RedisMultiCommand { +class LegacyMultiCommand { private static _createCommand(name: string, command: Command, resp: RespVersions) { const transformReply = RedisLegacyClient.getTransformReply(command, resp); return function (this: LegacyMultiCommand, ...args: LegacyArguments) { const redisArgs = [name]; RedisLegacyClient.pushArguments(redisArgs, args); - return this.addCommand(redisArgs, transformReply); + this._multi.addCommand(redisArgs, transformReply); + return this; }; } @@ -144,21 +145,22 @@ class LegacyMultiCommand extends RedisMultiCommand { }; } - private _client: RedisClientType; + private readonly _multi = new RedisMultiCommand(); + private readonly _client: RedisClientType; constructor(client: RedisClientType) { - super(); this._client = client; } sendCommand(...args: LegacyArguments) { const redisArgs: CommandArguments = []; RedisLegacyClient.pushArguments(redisArgs, args); - return this.addCommand(redisArgs); + this._multi.addCommand(redisArgs); + return this; } exec(cb?: (err: ErrorReply | null, replies?: Array) => unknown) { - const promise = this._client.executeMulti(this.queue); + const promise = this._client.executeMulti(this._multi.queue); if (!cb) { promise.catch(err => this._client.emit('error', err)); @@ -166,7 +168,7 @@ class LegacyMultiCommand extends RedisMultiCommand { } promise - .then(results => cb(null, this.transformReplies(results))) + .then(results => cb(null, this._multi.transformReplies(results))) .catch(err => cb?.(err)); } }