1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-07 13:22:56 +03:00

V5 bringing RESP3, Sentinel and TypeMapping to node-redis

RESP3 Support
   - Some commands responses in RESP3 aren't stable yet and therefore return an "untyped" ReplyUnion.
 
Sentinel

TypeMapping

Correctly types Multi commands

Note: some API changes to be further documented in v4-to-v5.md
This commit is contained in:
Shaya Potter
2024-10-15 17:46:52 +03:00
committed by GitHub
parent 2fc79bdfb3
commit b2d35c5286
1174 changed files with 45931 additions and 36274 deletions

View File

@@ -1,19 +1,19 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments, transformReply } from './ADD';
import ADD from './ADD';
describe('CF ADD', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', 'item'),
['CF.ADD', 'key', 'item']
);
});
describe('CF.ADD', () => {
it('transformArguments', () => {
assert.deepEqual(
ADD.transformArguments('key', 'item'),
['CF.ADD', 'key', 'item']
);
});
testUtils.testWithClient('client.cf.add', async client => {
assert.equal(
await client.cf.add('key', 'item'),
true
);
}, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('client.cf.add', async client => {
assert.equal(
await client.cf.add('key', 'item'),
true
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,7 +1,11 @@
export const FIRST_KEY_INDEX = 1;
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformBooleanReply } from '@redis/client/dist/lib/commands/generic-transformers';
export function transformArguments(key: string, item: string): Array<string> {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, item: RedisArgument) {
return ['CF.ADD', key, item];
}
export { transformBooleanReply as transformReply } from '@redis/client/dist/lib/commands/generic-transformers';
},
transformReply: transformBooleanReply
} as const satisfies Command;

View File

@@ -1,21 +1,19 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './ADDNX';
import ADDNX from './ADDNX';
describe('CF ADDNX', () => {
describe('transformArguments', () => {
it('basic add', () => {
assert.deepEqual(
transformArguments('key', 'item'),
['CF.ADDNX', 'key', 'item']
);
});
});
describe('CF.ADDNX', () => {
it('transformArguments', () => {
assert.deepEqual(
ADDNX.transformArguments('key', 'item'),
['CF.ADDNX', 'key', 'item']
);
});
testUtils.testWithClient('client.cf.add', async client => {
assert.equal(
await client.cf.addNX('key', 'item'),
true
);
}, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('client.cf.add', async client => {
assert.equal(
await client.cf.addNX('key', 'item'),
true
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,7 +1,11 @@
export const FIRST_KEY_INDEX = 1;
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformBooleanReply } from '@redis/client/dist/lib/commands/generic-transformers';
export function transformArguments(key: string, item: string): Array<string> {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, item: RedisArgument) {
return ['CF.ADDNX', key, item];
}
export { transformBooleanReply as transformReply } from '@redis/client/dist/lib/commands/generic-transformers';
},
transformReply: transformBooleanReply
} as const satisfies Command;

View File

@@ -1,19 +1,19 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './COUNT';
import COUNT from './COUNT';
describe('CF COUNT', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', 'item'),
['CF.COUNT', 'key', 'item']
);
});
describe('CF.COUNT', () => {
it('transformArguments', () => {
assert.deepEqual(
COUNT.transformArguments('key', 'item'),
['CF.COUNT', 'key', 'item']
);
});
testUtils.testWithClient('client.cf.count', async client => {
assert.equal(
await client.cf.count('key', 'item'),
0
);
}, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('client.cf.count', async client => {
assert.equal(
await client.cf.count('key', 'item'),
0
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,7 +1,10 @@
export const FIRST_KEY_INDEX = 1;
import { RedisArgument, NumberReply, Command } from '@redis/client/dist/lib/RESP/types';
export function transformArguments(key: string, item: string): Array<string> {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument, item: RedisArgument) {
return ['CF.COUNT', key, item];
}
export declare function transformReply(): number;
},
transformReply: undefined as unknown as () => NumberReply
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './DEL';
import DEL from './DEL';
describe('CF DEL', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', 'item'),
['CF.DEL', 'key', 'item']
);
});
describe('CF.DEL', () => {
it('transformArguments', () => {
assert.deepEqual(
DEL.transformArguments('key', 'item'),
['CF.DEL', 'key', 'item']
);
});
testUtils.testWithClient('client.cf.del', async client => {
await client.cf.reserve('key', 4);
testUtils.testWithClient('client.cf.del', async client => {
const [, reply] = await Promise.all([
client.cf.reserve('key', 4),
client.cf.del('key', 'item')
]);
assert.equal(
await client.cf.del('key', 'item'),
false
);
}, GLOBAL.SERVERS.OPEN);
assert.equal(reply, false);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,7 +1,11 @@
export const FIRST_KEY_INDEX = 1;
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformBooleanReply } from '@redis/client/dist/lib/commands/generic-transformers';
export function transformArguments(key: string, item: string): Array<string> {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, item: RedisArgument) {
return ['CF.DEL', key, item];
}
export { transformBooleanReply as transformReply } from '@redis/client/dist/lib/commands/generic-transformers';
},
transformReply: transformBooleanReply
} as const satisfies Command;

View File

@@ -1,19 +1,19 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './EXISTS';
import EXISTS from './EXISTS';
describe('CF EXISTS', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', 'item'),
['CF.EXISTS', 'key', 'item']
);
});
describe('CF.EXISTS', () => {
it('transformArguments', () => {
assert.deepEqual(
EXISTS.transformArguments('key', 'item'),
['CF.EXISTS', 'key', 'item']
);
});
testUtils.testWithClient('client.cf.exists', async client => {
assert.equal(
await client.cf.exists('key', 'item'),
false
);
}, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('client.cf.exists', async client => {
assert.equal(
await client.cf.exists('key', 'item'),
false
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,9 +1,11 @@
export const FIRST_KEY_INDEX = 1;
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformBooleanReply } from '@redis/client/dist/lib/commands/generic-transformers';
export const IS_READ_ONLY = true;
export function transformArguments(key: string, item: string): Array<string> {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, item: RedisArgument) {
return ['CF.EXISTS', key, item];
}
export { transformBooleanReply as transformReply } from '@redis/client/dist/lib/commands/generic-transformers';
},
transformReply: transformBooleanReply
} as const satisfies Command;

View File

@@ -1,27 +1,29 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './INFO';
import INFO from './INFO';
describe('CF INFO', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('cuckoo'),
['CF.INFO', 'cuckoo']
);
});
describe('CF.INFO', () => {
it('transformArguments', () => {
assert.deepEqual(
INFO.transformArguments('cuckoo'),
['CF.INFO', 'cuckoo']
);
});
testUtils.testWithClient('client.cf.info', async client => {
await client.cf.reserve('key', 4);
testUtils.testWithClient('client.cf.info', async client => {
const [, reply] = await Promise.all([
client.cf.reserve('key', 4),
client.cf.info('key')
]);
const info = await client.cf.info('key');
assert.equal(typeof info, 'object');
assert.equal(typeof info.size, 'number');
assert.equal(typeof info.numberOfBuckets, 'number');
assert.equal(typeof info.numberOfFilters, 'number');
assert.equal(typeof info.numberOfInsertedItems, 'number');
assert.equal(typeof info.numberOfDeletedItems, 'number');
assert.equal(typeof info.bucketSize, 'number');
assert.equal(typeof info.expansionRate, 'number');
assert.equal(typeof info.maxIteration, 'number');
}, GLOBAL.SERVERS.OPEN);
assert.equal(typeof reply, 'object');
assert.equal(typeof reply['Size'], 'number');
assert.equal(typeof reply['Number of buckets'], 'number');
assert.equal(typeof reply['Number of filters'], 'number');
assert.equal(typeof reply['Number of items inserted'], 'number');
assert.equal(typeof reply['Number of items deleted'], 'number');
assert.equal(typeof reply['Bucket size'], 'number');
assert.equal(typeof reply['Expansion rate'], 'number');
assert.equal(typeof reply['Max iterations'], 'number');
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,50 +1,27 @@
export const FIRST_KEY_INDEX = 1;
import { RedisArgument, Command, NumberReply, TuplesToMapReply, UnwrapReply, Resp2Reply, SimpleStringReply, TypeMapping } from '@redis/client/dist/lib/RESP/types';
import { transformInfoV2Reply } from '../bloom';
export const IS_READ_ONLY = true;
export type CfInfoReplyMap = TuplesToMapReply<[
[SimpleStringReply<'Size'>, NumberReply],
[SimpleStringReply<'Number of buckets'>, NumberReply],
[SimpleStringReply<'Number of filters'>, NumberReply],
[SimpleStringReply<'Number of items inserted'>, NumberReply],
[SimpleStringReply<'Number of items deleted'>, NumberReply],
[SimpleStringReply<'Bucket size'>, NumberReply],
[SimpleStringReply<'Expansion rate'>, NumberReply],
[SimpleStringReply<'Max iterations'>, NumberReply]
]>;
export function transformArguments(key: string): Array<string> {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument) {
return ['CF.INFO', key];
}
export type InfoRawReply = [
_: string,
size: number,
_: string,
numberOfBuckets: number,
_: string,
numberOfFilters: number,
_: string,
numberOfInsertedItems: number,
_: string,
numberOfDeletedItems: number,
_: string,
bucketSize: number,
_: string,
expansionRate: number,
_: string,
maxIteration: number
];
export interface InfoReply {
size: number;
numberOfBuckets: number;
numberOfFilters: number;
numberOfInsertedItems: number;
numberOfDeletedItems: number;
bucketSize: number;
expansionRate: number;
maxIteration: number;
}
export function transformReply(reply: InfoRawReply): InfoReply {
return {
size: reply[1],
numberOfBuckets: reply[3],
numberOfFilters: reply[5],
numberOfInsertedItems: reply[7],
numberOfDeletedItems: reply[9],
bucketSize: reply[11],
expansionRate: reply[13],
maxIteration: reply[15]
};
}
},
transformReply: {
2: (reply: UnwrapReply<Resp2Reply<CfInfoReplyMap>>, _, typeMapping?: TypeMapping): CfInfoReplyMap => {
return transformInfoV2Reply<CfInfoReplyMap>(reply, typeMapping);
},
3: undefined as unknown as () => CfInfoReplyMap
}
} as const satisfies Command;

View File

@@ -1,22 +1,22 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './INSERT';
import INSERT from './INSERT';
describe('CF INSERT', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', 'item', {
CAPACITY: 100,
NOCREATE: true
}),
['CF.INSERT', 'key', 'CAPACITY', '100', 'NOCREATE', 'ITEMS', 'item']
);
});
describe('CF.INSERT', () => {
it('transformArguments', () => {
assert.deepEqual(
INSERT.transformArguments('key', 'item', {
CAPACITY: 100,
NOCREATE: true
}),
['CF.INSERT', 'key', 'CAPACITY', '100', 'NOCREATE', 'ITEMS', 'item']
);
});
testUtils.testWithClient('client.cf.insert', async client => {
assert.deepEqual(
await client.cf.insert('key', 'item'),
[true]
);
}, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('client.cf.insert', async client => {
assert.deepEqual(
await client.cf.insert('key', 'item'),
[true]
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,18 +1,34 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { InsertOptions, pushInsertOptions } from ".";
import { Command, RedisArgument } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument, pushVariadicArguments, transformBooleanArrayReply } from '@redis/client/dist/lib/commands/generic-transformers';
export const FIRST_KEY_INDEX = 1;
export function transformArguments(
key: string,
items: string | Array<string>,
options?: InsertOptions
): RedisCommandArguments {
return pushInsertOptions(
['CF.INSERT', key],
items,
options
);
export interface CfInsertOptions {
CAPACITY?: number;
NOCREATE?: boolean;
}
export { transformBooleanArrayReply as transformReply } from '@redis/client/dist/lib/commands/generic-transformers';
export function transofrmCfInsertArguments(
command: RedisArgument,
key: RedisArgument,
items: RedisVariadicArgument,
options?: CfInsertOptions
) {
const args = [command, key];
if (options?.CAPACITY !== undefined) {
args.push('CAPACITY', options.CAPACITY.toString());
}
if (options?.NOCREATE) {
args.push('NOCREATE');
}
args.push('ITEMS');
return pushVariadicArguments(args, items);
}
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments: transofrmCfInsertArguments.bind(undefined, 'CF.INSERT'),
transformReply: transformBooleanArrayReply
} as const satisfies Command;

View File

@@ -1,22 +1,22 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './INSERTNX';
import INSERTNX from './INSERTNX';
describe('CF INSERTNX', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', 'item', {
CAPACITY: 100,
NOCREATE: true
}),
['CF.INSERTNX', 'key', 'CAPACITY', '100', 'NOCREATE', 'ITEMS', 'item']
);
});
describe('CF.INSERTNX', () => {
it('transformArguments', () => {
assert.deepEqual(
INSERTNX.transformArguments('key', 'item', {
CAPACITY: 100,
NOCREATE: true
}),
['CF.INSERTNX', 'key', 'CAPACITY', '100', 'NOCREATE', 'ITEMS', 'item']
);
});
testUtils.testWithClient('client.cf.insertnx', async client => {
assert.deepEqual(
await client.cf.insertNX('key', 'item'),
[true]
);
}, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('client.cf.insertnx', async client => {
assert.deepEqual(
await client.cf.insertNX('key', 'item'),
[true]
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,18 +1,9 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { InsertOptions, pushInsertOptions } from ".";
import { Command } from '@redis/client/dist/lib/RESP/types';
import INSERT, { transofrmCfInsertArguments } from './INSERT';
export const FIRST_KEY_INDEX = 1;
export function transformArguments(
key: string,
items: string | Array<string>,
options?: InsertOptions
): RedisCommandArguments {
return pushInsertOptions(
['CF.INSERTNX', key],
items,
options
);
}
export { transformBooleanArrayReply as transformReply } from '@redis/client/dist/lib/commands/generic-transformers';
export default {
FIRST_KEY_INDEX: INSERT.FIRST_KEY_INDEX,
IS_READ_ONLY: INSERT.IS_READ_ONLY,
transformArguments: transofrmCfInsertArguments.bind(undefined, 'CF.INSERTNX'),
transformReply: INSERT.transformReply
} as const satisfies Command;

View File

@@ -1,31 +1,36 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './LOADCHUNK';
import LOADCHUNK from './LOADCHUNK';
import { RESP_TYPES } from '@redis/client';
describe('CF LOADCHUNK', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('item', 0, ''),
['CF.LOADCHUNK', 'item', '0', '']
);
});
describe('CF.LOADCHUNK', () => {
it('transformArguments', () => {
assert.deepEqual(
LOADCHUNK.transformArguments('item', 0, ''),
['CF.LOADCHUNK', 'item', '0', '']
);
});
testUtils.testWithClient('client.cf.loadChunk', async client => {
const [,, { iterator, chunk }] = await Promise.all([
client.cf.reserve('source', 4),
client.cf.add('source', 'item'),
client.cf.scanDump(
client.commandOptions({ returnBuffers: true }),
'source',
0
)
]);
testUtils.testWithClient('client.cf.loadChunk', async client => {
const [, , { iterator, chunk }] = await Promise.all([
client.cf.reserve('source', 4),
client.cf.add('source', 'item'),
client.cf.scanDump('source', 0)
]);
assert.ok(Buffer.isBuffer(chunk));
assert.equal(
await client.cf.loadChunk('destination', iterator, chunk),
'OK'
);
}, GLOBAL.SERVERS.OPEN);
assert.equal(
await client.cf.loadChunk('destination', iterator, chunk!),
'OK'
);
}, {
...GLOBAL.SERVERS.OPEN,
clientOptions: {
...GLOBAL.SERVERS.OPEN.clientOptions,
commandOptions: {
typeMapping: {
[RESP_TYPES.BLOB_STRING]: Buffer
}
}
}
});
});

View File

@@ -1,13 +1,10 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { SimpleStringReply, Command, RedisArgument } from '@redis/client/dist/lib/RESP/types';
export const FIRST_KEY_INDEX = 1;
export function transformArguments(
key: string,
iterator: number,
chunk: RedisCommandArgument
): RedisCommandArguments {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, iterator: number, chunk: RedisArgument) {
return ['CF.LOADCHUNK', key, iterator.toString(), chunk];
}
export declare function transformReply(): 'OK';
},
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
} as const satisfies Command;

View File

@@ -1,48 +1,48 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './RESERVE';
import RESERVE from './RESERVE';
describe('CF RESERVE', () => {
describe('transformArguments', () => {
it('simple', () => {
assert.deepEqual(
transformArguments('key', 4),
['CF.RESERVE', 'key', '4']
);
});
it('with EXPANSION', () => {
assert.deepEqual(
transformArguments('key', 4, {
EXPANSION: 1
}),
['CF.RESERVE', 'key', '4', 'EXPANSION', '1']
);
});
it('with BUCKETSIZE', () => {
assert.deepEqual(
transformArguments('key', 4, {
BUCKETSIZE: 2
}),
['CF.RESERVE', 'key', '4', 'BUCKETSIZE', '2']
);
});
it('with MAXITERATIONS', () => {
assert.deepEqual(
transformArguments('key', 4, {
MAXITERATIONS: 1
}),
['CF.RESERVE', 'key', '4', 'MAXITERATIONS', '1']
);
});
describe('CF.RESERVE', () => {
describe('transformArguments', () => {
it('simple', () => {
assert.deepEqual(
RESERVE.transformArguments('key', 4),
['CF.RESERVE', 'key', '4']
);
});
testUtils.testWithClient('client.cf.reserve', async client => {
assert.equal(
await client.cf.reserve('key', 4),
'OK'
);
}, GLOBAL.SERVERS.OPEN);
it('with EXPANSION', () => {
assert.deepEqual(
RESERVE.transformArguments('key', 4, {
EXPANSION: 1
}),
['CF.RESERVE', 'key', '4', 'EXPANSION', '1']
);
});
it('with BUCKETSIZE', () => {
assert.deepEqual(
RESERVE.transformArguments('key', 4, {
BUCKETSIZE: 2
}),
['CF.RESERVE', 'key', '4', 'BUCKETSIZE', '2']
);
});
it('with MAXITERATIONS', () => {
assert.deepEqual(
RESERVE.transformArguments('key', 4, {
MAXITERATIONS: 1
}),
['CF.RESERVE', 'key', '4', 'MAXITERATIONS', '1']
);
});
});
testUtils.testWithClient('client.cf.reserve', async client => {
assert.equal(
await client.cf.reserve('key', 4),
'OK'
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,31 +1,34 @@
export const FIRST_KEY_INDEX = 1;
import { RedisArgument, SimpleStringReply, Command } from '@redis/client/dist/lib/RESP/types';
interface ReserveOptions {
BUCKETSIZE?: number;
MAXITERATIONS?: number;
EXPANSION?: number;
export interface CfReserveOptions {
BUCKETSIZE?: number;
MAXITERATIONS?: number;
EXPANSION?: number;
}
export function transformArguments(
key: string,
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(
key: RedisArgument,
capacity: number,
options?: ReserveOptions
): Array<string> {
options?: CfReserveOptions
) {
const args = ['CF.RESERVE', key, capacity.toString()];
if (options?.BUCKETSIZE) {
args.push('BUCKETSIZE', options.BUCKETSIZE.toString());
if (options?.BUCKETSIZE !== undefined) {
args.push('BUCKETSIZE', options.BUCKETSIZE.toString());
}
if (options?.MAXITERATIONS) {
args.push('MAXITERATIONS', options.MAXITERATIONS.toString());
if (options?.MAXITERATIONS !== undefined) {
args.push('MAXITERATIONS', options.MAXITERATIONS.toString());
}
if (options?.EXPANSION) {
args.push('EXPANSION', options.EXPANSION.toString());
if (options?.EXPANSION !== undefined) {
args.push('EXPANSION', options.EXPANSION.toString());
}
return args;
}
export declare function transformReply(): 'OK';
},
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
} as const satisfies Command;

View File

@@ -1,23 +1,24 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './SCANDUMP';
import SCANDUMP from './SCANDUMP';
describe('CF SCANDUMP', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', 0),
['CF.SCANDUMP', 'key', '0']
);
describe('CF.SCANDUMP', () => {
it('transformArguments', () => {
assert.deepEqual(
SCANDUMP.transformArguments('key', 0),
['CF.SCANDUMP', 'key', '0']
);
});
testUtils.testWithClient('client.cf.scanDump', async client => {
const [, reply] = await Promise.all([
client.cf.reserve('key', 4),
client.cf.scanDump('key', 0)
]);
assert.deepEqual(reply, {
iterator: 0,
chunk: null
});
testUtils.testWithClient('client.cf.scanDump', async client => {
await client.cf.reserve('key', 4);
assert.deepEqual(
await client.cf.scanDump('key', 0),
{
iterator: 0,
chunk: null
}
);
}, GLOBAL.SERVERS.OPEN);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,22 +1,15 @@
export const FIRST_KEY_INDEX = 1;
import { RedisArgument, TuplesReply, NumberReply, BlobStringReply, NullReply, UnwrapReply, Command } from '@redis/client/dist/lib/RESP/types';
export function transformArguments(key: string, iterator: number): Array<string> {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument, iterator: number) {
return ['CF.SCANDUMP', key, iterator.toString()];
}
type ScanDumpRawReply = [
iterator: number,
chunk: string | null
];
interface ScanDumpReply {
iterator: number;
chunk: string | null;
}
export function transformReply([iterator, chunk]: ScanDumpRawReply): ScanDumpReply {
},
transformReply(reply: UnwrapReply<TuplesReply<[NumberReply, BlobStringReply | NullReply]>>) {
return {
iterator,
chunk
iterator: reply[0],
chunk: reply[1]
};
}
}
} as const satisfies Command;

View File

@@ -1,48 +0,0 @@
import { strict as assert } from 'assert';
import { pushInsertOptions } from '.';
describe('pushInsertOptions', () => {
describe('single item', () => {
it('single item', () => {
assert.deepEqual(
pushInsertOptions([], 'item'),
['ITEMS', 'item']
);
});
it('multiple items', () => {
assert.deepEqual(
pushInsertOptions([], ['1', '2']),
['ITEMS', '1', '2']
);
});
});
it('with CAPACITY', () => {
assert.deepEqual(
pushInsertOptions([], 'item', {
CAPACITY: 100
}),
['CAPACITY', '100', 'ITEMS', 'item']
);
});
it('with NOCREATE', () => {
assert.deepEqual(
pushInsertOptions([], 'item', {
NOCREATE: true
}),
['NOCREATE', 'ITEMS', 'item']
);
});
it('with CAPACITY and NOCREATE', () => {
assert.deepEqual(
pushInsertOptions([], 'item', {
CAPACITY: 100,
NOCREATE: true
}),
['CAPACITY', '100', 'NOCREATE', 'ITEMS', 'item']
);
});
});

View File

@@ -1,62 +1,37 @@
import * as ADD from './ADD';
import * as ADDNX from './ADDNX';
import * as COUNT from './COUNT';
import * as DEL from './DEL';
import * as EXISTS from './EXISTS';
import * as INFO from './INFO';
import * as INSERT from './INSERT';
import * as INSERTNX from './INSERTNX';
import * as LOADCHUNK from './LOADCHUNK';
import * as RESERVE from './RESERVE';
import * as SCANDUMP from './SCANDUMP';
import { pushVerdictArguments } from '@redis/client/dist/lib/commands/generic-transformers';
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import type { RedisCommands } from '@redis/client/dist/lib/RESP/types';
import ADD from './ADD';
import ADDNX from './ADDNX';
import COUNT from './COUNT';
import DEL from './DEL';
import EXISTS from './EXISTS';
import INFO from './INFO';
import INSERT from './INSERT';
import INSERTNX from './INSERTNX';
import LOADCHUNK from './LOADCHUNK';
import RESERVE from './RESERVE';
import SCANDUMP from './SCANDUMP';
export default {
ADD,
add: ADD,
ADDNX,
addNX: ADDNX,
COUNT,
count: COUNT,
DEL,
del: DEL,
EXISTS,
exists: EXISTS,
INFO,
info: INFO,
INSERT,
insert: INSERT,
INSERTNX,
insertNX: INSERTNX,
LOADCHUNK,
loadChunk: LOADCHUNK,
RESERVE,
reserve: RESERVE,
SCANDUMP,
scanDump: SCANDUMP
};
export interface InsertOptions {
CAPACITY?: number;
NOCREATE?: true;
}
export function pushInsertOptions(
args: RedisCommandArguments,
items: string | Array<string>,
options?: InsertOptions
): RedisCommandArguments {
if (options?.CAPACITY) {
args.push('CAPACITY');
args.push(options.CAPACITY.toString());
}
if (options?.NOCREATE) {
args.push('NOCREATE');
}
args.push('ITEMS');
return pushVerdictArguments(args, items);
}
ADD,
add: ADD,
ADDNX,
addNX: ADDNX,
COUNT,
count: COUNT,
DEL,
del: DEL,
EXISTS,
exists: EXISTS,
INFO,
info: INFO,
INSERT,
insert: INSERT,
INSERTNX,
insertNX: INSERTNX,
LOADCHUNK,
loadChunk: LOADCHUNK,
RESERVE,
reserve: RESERVE,
SCANDUMP,
scanDump: SCANDUMP
} as const satisfies RedisCommands;