diff --git a/packages/client/lib/client/index.spec.ts b/packages/client/lib/client/index.spec.ts index d520f970b0..de2d8a9e3b 100644 --- a/packages/client/lib/client/index.spec.ts +++ b/packages/client/lib/client/index.spec.ts @@ -406,6 +406,17 @@ describe('Client', () => { assert.equal(await client.sendCommand(['PING']), 'PONG'); }, GLOBAL.SERVERS.OPEN); + testUtils.testWithClient('should respect type mapping proxy', async client => { + await client.set('key', 'value'); + + const reply = await client.withTypeMapping({ + [RESP_TYPES.BLOB_STRING]: Buffer + }).sendCommand(['GET', 'key']); + + assert.ok(reply instanceof Buffer); + assert.equal(reply.toString(), 'value'); + }, GLOBAL.SERVERS.OPEN); + testUtils.testWithClient('Unactivated AbortController should not abort', async client => { await client.sendCommand(['PING'], { abortSignal: new AbortController().signal diff --git a/packages/client/lib/client/index.ts b/packages/client/lib/client/index.ts index c20c75830e..e20b3cd348 100644 --- a/packages/client/lib/client/index.ts +++ b/packages/client/lib/client/index.ts @@ -255,7 +255,10 @@ export type RedisClientType< RedisClientExtensions ); -type ProxyClient = RedisClient; +type ProxyClient = RedisClient; +type ProxyClientConstructor = new ( + options?: RedisClientOptions +) => ProxyClient; type NamespaceProxyClient = { _self: ProxyClient }; @@ -320,7 +323,10 @@ export default class RedisClient< } } - static #SingleEntryCache = new SingleEntryCache() + static #SingleEntryCache = new SingleEntryCache< + CommanderConfig | undefined, + ProxyClientConstructor + >() static factory< M extends RedisModules = {}, @@ -340,18 +346,20 @@ export default class RedisClient< createFunctionCommand: RedisClient.#createFunctionCommand, createScriptCommand: RedisClient.#createScriptCommand, config - }); + }) as ProxyClientConstructor; Client.prototype.Multi = RedisClientMultiCommand.extend(config); RedisClient.#SingleEntryCache.set(config, Client); } + const ClientConstructor = Client; + return ( options?: Omit, keyof Exclude> ) => { // returning a "proxy" to prevent the namespaces._self to leak between "proxies" - return Object.create(new Client(options)) as RedisClientType; + return Object.create(new ClientConstructor(options)) as RedisClientType; }; } @@ -598,11 +606,11 @@ export default class RedisClient< const cscConfig = this.#options.clientSideCache; this.#clientSideCache = new BasicClientSideCache(cscConfig); } - this.#queue.addPushHandler((push: Array): boolean => { - if (push[0].toString() !== 'invalidate') return false; + this.#queue.addPushHandler((push: Array): boolean => { + if (String(push[0]) !== 'invalidate') return false; if (push[1] !== null) { - for (const key of push[1]) { + for (const key of push[1] as Iterable) { this.#clientSideCache?.invalidate(key) } } else { @@ -612,11 +620,11 @@ export default class RedisClient< return true }); } else if (options?.emitInvalidate) { - this.#queue.addPushHandler((push: Array): boolean => { - if (push[0].toString() !== 'invalidate') return false; + this.#queue.addPushHandler((push: Array): boolean => { + if (String(push[0]) !== 'invalidate') return false; if (push[1] !== null) { - for (const key of push[1]) { + for (const key of push[1] as Iterable) { this.emit('invalidate', key); } } else { @@ -1057,7 +1065,7 @@ export default class RedisClient< */ _ejectSocket(): RedisSocket { const socket = this._self.#socket; - // @ts-ignore + // @ts-expect-error allow temporarily clearing the socket during internal socket replacement this._self.#socket = null; socket.removeAllListeners(); return socket; @@ -1183,7 +1191,7 @@ export default class RedisClient< // Merge global options with provided options const opts = { - ...this._self._commandOptions, + ...this._commandOptions, ...options, }; @@ -1524,7 +1532,7 @@ export default class RedisClient< MULTI() { type Multi = new (...args: ConstructorParameters) => RedisClientMultiCommandType; - return new ((this as any).Multi as Multi)( + return new ((this as unknown as { Multi: Multi }).Multi)( this._executeMulti.bind(this), this._executePipeline.bind(this), this._commandOptions?.typeMapping