1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-06 02:15:48 +03:00

ref #2370 add support for CommandIterator in ScanIterator

Co-authored-by: Leibale Eidelman <me@leibale.com>
This commit is contained in:
shacharPash
2023-01-19 19:13:27 +02:00
parent abf2b4bc82
commit bf272742e4
3 changed files with 76 additions and 21 deletions

View File

@@ -215,7 +215,7 @@ describe('Client', () => {
testUtils.testWithClient('client.hGetAll should return object', async client => { testUtils.testWithClient('client.hGetAll should return object', async client => {
await client.v4.hSet('key', 'field', 'value'); await client.v4.hSet('key', 'field', 'value');
assert.deepEqual( assert.deepEqual(
await promisify(client.hGetAll).call(client, 'key'), await promisify(client.hGetAll).call(client, 'key'),
Object.create(null, { 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( assert.deepEqual(
await multiExecAsync( await multiExecAsync(
client.multi() client.multi()
@@ -607,24 +607,48 @@ describe('Client', () => {
return client.executeIsolated(isolated => killClient(isolated, client)); return client.executeIsolated(isolated => killClient(isolated, client));
}, GLOBAL.SERVERS.OPEN); }, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('scanIterator', async client => { describe('scanIterator', () => {
const promises = [], testUtils.testWithClient('strings', async client => {
keys = new Set(); const args: Array<string> = [],
for (let i = 0; i < 100; i++) { keys = new Set<string>();
const key = i.toString(); for (let i = 0; i < 100; i++) {
keys.add(key); const key = i.toString();
promises.push(client.set(key, '')); args.push(key, '');
} keys.add(key);
}
await Promise.all(promises); await client.mSet(args);
const results = new Set(); const results = new Set<string>();
for await (const key of client.scanIterator()) { for await (const key of client.scanIterator()) {
results.add(key); results.add(key);
} }
assert.deepEqual(keys, results); assert.deepEqual(keys, results);
}, GLOBAL.SERVERS.OPEN); }, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('buffers', async client => {
const args: Array<string | Buffer> = [],
keys = new Set<Buffer>();
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<Buffer>(),
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 => { testUtils.testWithClient('hScanIterator', async client => {
const hash: Record<string, string> = {}; const hash: Record<string, string> = {};

View File

@@ -415,7 +415,7 @@ export default class RedisClient<
); );
} else if (!this.#socket.isReady && this.#options?.disableOfflineQueue) { } else if (!this.#socket.isReady && this.#options?.disableOfflineQueue) {
return Promise.reject(new ClientOfflineError()); return Promise.reject(new ClientOfflineError());
} }
const promise = this.#queue.addCommand<T>(args, options); const promise = this.#queue.addCommand<T>(args, options);
this.#tick(); this.#tick();
@@ -656,10 +656,29 @@ export default class RedisClient<
return results; return results;
} }
async* scanIterator(options?: ScanCommandOptions): AsyncIterable<string> { scanIterator<T extends CommandOptions<ClientCommandOptions>>(
commandOptions: T,
options?: ScanCommandOptions
): AsyncIterable<T['returnBuffers'] extends true ? Buffer : string>;
scanIterator(
options?: ScanCommandOptions
): AsyncIterable<string>;
async* scanIterator<T extends CommandOptions<ClientCommandOptions>>(
commandOptions?: T | ScanCommandOptions,
options?: ScanCommandOptions
): AsyncIterable<T['returnBuffers'] extends true ? Buffer : string> {
if (!isCommandOptions(commandOptions)) {
options = commandOptions;
commandOptions = undefined;
}
const scan = commandOptions ?
(...args: Array<unknown>) => (this as any).scan(commandOptions, ...args) :
(...args: Array<unknown>) => (this as any).scan(...args);
let cursor = 0; let cursor = 0;
do { do {
const reply = await (this as any).scan(cursor, options); const reply = await scan(cursor, options);
cursor = reply.cursor; cursor = reply.cursor;
for (const key of reply.keys) { for (const key of reply.keys) {
yield key; yield key;
@@ -726,3 +745,15 @@ attachCommands({
executor: RedisClient.prototype.commandsExecutor executor: RedisClient.prototype.commandsExecutor
}); });
(RedisClient.prototype as any).Multi = RedisClientMultiCommand; (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()

View File

@@ -52,7 +52,7 @@ const DOCKER_FODLER_PATH = path.join(__dirname, '../docker');
async function spawnRedisServerDocker({ image, version }: RedisServerDockerConfig, serverArguments: Array<string>): Promise<RedisServerDocker> { async function spawnRedisServerDocker({ image, version }: RedisServerDockerConfig, serverArguments: Array<string>): Promise<RedisServerDocker> {
const port = (await portIterator.next()).value, const port = (await portIterator.next()).value,
{ stdout, stderr } = await execAsync( { stdout, stderr } = await execAsync(
'docker run -d --network host $(' + `docker run -d -p ${port}:${port} $(` +
`docker build ${DOCKER_FODLER_PATH} -q ` + `docker build ${DOCKER_FODLER_PATH} -q ` +
`--build-arg IMAGE=${image}:${version} ` + `--build-arg IMAGE=${image}:${version} ` +
`--build-arg REDIS_ARGUMENTS="--save '' --port ${port.toString()} ${serverArguments.join(' ')}"` + `--build-arg REDIS_ARGUMENTS="--save '' --port ${port.toString()} ${serverArguments.join(' ')}"` +