From bf272742e4c5ae59fc8cac1dd2393e18254a38ea Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 19 Jan 2023 19:13:27 +0200 Subject: [PATCH] ref #2370 add support for CommandIterator in ScanIterator Co-authored-by: Leibale Eidelman --- packages/client/lib/client/index.spec.ts | 58 +++++++++++++++++------- packages/client/lib/client/index.ts | 37 +++++++++++++-- packages/test-utils/lib/dockers.ts | 2 +- 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/packages/client/lib/client/index.spec.ts b/packages/client/lib/client/index.spec.ts index 63200bf82d..fbe5558fa8 100644 --- a/packages/client/lib/client/index.spec.ts +++ b/packages/client/lib/client/index.spec.ts @@ -215,7 +215,7 @@ describe('Client', () => { testUtils.testWithClient('client.hGetAll should return object', async client => { await client.v4.hSet('key', 'field', 'value'); - + assert.deepEqual( await promisify(client.hGetAll).call(client, 'key'), Object.create(null, { @@ -317,7 +317,7 @@ describe('Client', () => { } }); - testUtils.testWithClient('client.multi.hGetAll should return object', async client => { + testUtils.testWithClient('client.multi.hGetAll should return object', async client => { assert.deepEqual( await multiExecAsync( client.multi() @@ -607,24 +607,48 @@ describe('Client', () => { return client.executeIsolated(isolated => killClient(isolated, client)); }, GLOBAL.SERVERS.OPEN); - testUtils.testWithClient('scanIterator', async client => { - const promises = [], - keys = new Set(); - for (let i = 0; i < 100; i++) { - const key = i.toString(); - keys.add(key); - promises.push(client.set(key, '')); - } + describe('scanIterator', () => { + testUtils.testWithClient('strings', async client => { + const args: Array = [], + keys = new Set(); + for (let i = 0; i < 100; i++) { + const key = i.toString(); + args.push(key, ''); + keys.add(key); + } - await Promise.all(promises); + await client.mSet(args); - const results = new Set(); - for await (const key of client.scanIterator()) { - results.add(key); - } + const results = new Set(); + for await (const key of client.scanIterator()) { + results.add(key); + } - assert.deepEqual(keys, results); - }, GLOBAL.SERVERS.OPEN); + assert.deepEqual(keys, results); + }, GLOBAL.SERVERS.OPEN); + + testUtils.testWithClient('buffers', async client => { + const args: Array = [], + keys = new Set(); + for (let i = 0; i < 100; i++) { + const key = Buffer.from([i]); + args.push(key, ''); + keys.add(key); + } + + await client.mSet(args); + + const results = new Set(), + iteartor = client.scanIterator( + client.commandOptions({ returnBuffers: true }) + ); + for await (const key of iteartor) { + results.add(key); + } + + assert.deepEqual(keys, results); + }, GLOBAL.SERVERS.OPEN); + }); testUtils.testWithClient('hScanIterator', async client => { const hash: Record = {}; diff --git a/packages/client/lib/client/index.ts b/packages/client/lib/client/index.ts index 8c5a23db44..1599621988 100644 --- a/packages/client/lib/client/index.ts +++ b/packages/client/lib/client/index.ts @@ -415,7 +415,7 @@ export default class RedisClient< ); } else if (!this.#socket.isReady && this.#options?.disableOfflineQueue) { return Promise.reject(new ClientOfflineError()); - } + } const promise = this.#queue.addCommand(args, options); this.#tick(); @@ -656,10 +656,29 @@ export default class RedisClient< return results; } - async* scanIterator(options?: ScanCommandOptions): AsyncIterable { + scanIterator>( + commandOptions: T, + options?: ScanCommandOptions + ): AsyncIterable; + scanIterator( + options?: ScanCommandOptions + ): AsyncIterable; + async* scanIterator>( + commandOptions?: T | ScanCommandOptions, + options?: ScanCommandOptions + ): AsyncIterable { + if (!isCommandOptions(commandOptions)) { + options = commandOptions; + commandOptions = undefined; + } + + const scan = commandOptions ? + (...args: Array) => (this as any).scan(commandOptions, ...args) : + (...args: Array) => (this as any).scan(...args); + let cursor = 0; do { - const reply = await (this as any).scan(cursor, options); + const reply = await scan(cursor, options); cursor = reply.cursor; for (const key of reply.keys) { yield key; @@ -726,3 +745,15 @@ attachCommands({ executor: RedisClient.prototype.commandsExecutor }); (RedisClient.prototype as any).Multi = RedisClientMultiCommand; + +const client = RedisClient.create(); + +const a = client.scanIterator( + client.commandOptions({returnBuffers: true}) +) + +const b = client.scanIterator( + client.commandOptions({returnBuffers: false}) +) + +const c = client.scanIterator() \ No newline at end of file diff --git a/packages/test-utils/lib/dockers.ts b/packages/test-utils/lib/dockers.ts index 8f0be95b09..8af13002fc 100644 --- a/packages/test-utils/lib/dockers.ts +++ b/packages/test-utils/lib/dockers.ts @@ -52,7 +52,7 @@ const DOCKER_FODLER_PATH = path.join(__dirname, '../docker'); async function spawnRedisServerDocker({ image, version }: RedisServerDockerConfig, serverArguments: Array): Promise { const port = (await portIterator.next()).value, { stdout, stderr } = await execAsync( - 'docker run -d --network host $(' + + `docker run -d -p ${port}:${port} $(` + `docker build ${DOCKER_FODLER_PATH} -q ` + `--build-arg IMAGE=${image}:${version} ` + `--build-arg REDIS_ARGUMENTS="--save '' --port ${port.toString()} ${serverArguments.join(' ')}"` +