1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-04 15:02:09 +03:00
This commit is contained in:
Leibale
2023-06-07 11:41:23 -04:00
parent eb47bb03fc
commit 05f9f0ee0d
31 changed files with 390 additions and 386 deletions

View File

@@ -90,5 +90,5 @@ await client.connect();
// Add your example code here... // Add your example code here...
await client.quit(); client.destroy();
``` ```

View File

@@ -27,4 +27,4 @@ console.log('blpopPromise resolved');
// {"key":"keyName","element":"value"} // {"key":"keyName","element":"value"}
console.log(`listItem is '${JSON.stringify(listItem)}'`); console.log(`listItem is '${JSON.stringify(listItem)}'`);
await client.quit(); client.destroy();

View File

@@ -77,4 +77,4 @@ const info = await client.bf.info('mybloom');
// } // }
console.log(info); console.log(info);
await client.quit(); client.destroy();

View File

@@ -25,4 +25,4 @@ console.log('Afer connectPromise has resolved...');
// isReady will return True here, client is ready to use. // isReady will return True here, client is ready to use.
console.log(`client.isOpen: ${client.isOpen}, client.isReady: ${client.isReady}`); console.log(`client.isOpen: ${client.isOpen}, client.isReady: ${client.isReady}`);
await client.quit(); client.destroy();

View File

@@ -1,25 +1,31 @@
// Define a custom script that shows example of SET command // Define a custom script that shows example of SET command
// with several modifiers. // with several modifiers.
import { createClient } from 'redis'; import { createClient } from '../packages/client';
const client = createClient(); const client = createClient();
await client.connect(); await client.connect();
await client.del('mykey'); await client.del('mykey');
let result = await client.set('mykey', 'myvalue', { console.log(
EX: 60, await client.set('mykey', 'myvalue', {
GET: true expiration: {
}); type: 'EX',
value: 60
},
GET: true
})
); // null
console.log(result); //null console.log(
await client.set('mykey', 'newvalue', {
expiration: {
type: 'EX',
value: 60
},
GET: true
})
); // 'myvalue'
result = await client.set('mykey', 'newvalue', { await client.close();
EX: 60,
GET: true
});
console.log(result); //myvalue
await client.quit();

View File

@@ -23,4 +23,4 @@ try {
console.log(`GET command failed: ${e.message}`); console.log(`GET command failed: ${e.message}`);
} }
await client.quit(); client.destroy();

View File

@@ -77,4 +77,4 @@ console.log('Count-Min Sketch info:');
// } // }
console.log(info); console.log(info);
await client.quit(); client.destroy();

View File

@@ -76,4 +76,4 @@ const info = await client.cf.info('mycuckoo');
// } // }
console.log(info); console.log(info);
await client.quit(); client.destroy();

View File

@@ -9,4 +9,4 @@ const serverTime = await client.time();
// 2022-02-25T12:57:40.000Z { microseconds: 351346 } // 2022-02-25T12:57:40.000Z { microseconds: 351346 }
console.log(serverTime); console.log(serverTime);
await client.quit(); client.destroy();

View File

@@ -48,4 +48,4 @@ try {
console.error(e); console.error(e);
} }
await client.quit(); client.destroy();

View File

@@ -24,4 +24,4 @@ await client.connect();
await client.set('mykey', '5'); await client.set('mykey', '5');
console.log(await client.mincr('mykey', 'myotherkey', 10)); // [ 15, 10 ] console.log(await client.mincr('mykey', 'myotherkey', 10)); // [ 15, 10 ]
await client.quit(); client.destroy();

View File

@@ -73,4 +73,4 @@ const numPets = await client.json.arrLen('noderedis:jsondata', '$.pets');
// We now have 4 pets. // We now have 4 pets.
console.log(`We now have ${numPets} pets.`); console.log(`We now have ${numPets} pets.`);
await client.quit(); client.destroy();

View File

@@ -85,4 +85,4 @@ for (const doc of results.documents) {
console.log(`${doc.id}: ${doc.value.name}, ${doc.value.age} years old.`); console.log(`${doc.id}: ${doc.value.name}, ${doc.value.age} years old.`);
} }
await client.quit(); client.destroy();

View File

@@ -145,4 +145,4 @@ console.log(
// ] // ]
// } // }
await client.quit(); client.destroy();

View File

@@ -88,4 +88,4 @@ console.log(JSON.stringify(results, null, 2));
// } // }
// ] // ]
// } // }
await client.quit(); client.destroy();

View File

@@ -12,4 +12,4 @@ for await (const member of client.sScanIterator(setName)) {
console.log(member); console.log(member);
} }
await client.quit(); client.destroy();

View File

@@ -28,4 +28,4 @@ for await (const memberWithScore of client.zScanIterator('mysortedset')) {
console.log(memberWithScore); console.log(memberWithScore);
} }
await client.quit(); client.destroy();

View File

@@ -47,4 +47,4 @@ console.log(`Length of mystream: ${await client.xLen('mystream')}.`);
// Should be approximately 1000: // Should be approximately 1000:
console.log(`Length of mytrimmedstream: ${await client.xLen('mytrimmedstream')}.`); console.log(`Length of mytrimmedstream: ${await client.xLen('mytrimmedstream')}.`);
await client.quit(); client.destroy();

View File

@@ -119,4 +119,4 @@ try {
console.error(e); console.error(e);
} }
await client.quit(); client.destroy();

View File

@@ -110,4 +110,4 @@ const [ simonCount, lanceCount ] = await client.topK.count('mytopk', [
console.log(`Count estimate for simon: ${simonCount}.`); console.log(`Count estimate for simon: ${simonCount}.`);
console.log(`Count estimate for lance: ${lanceCount}.`); console.log(`Count estimate for lance: ${lanceCount}.`);
await client.quit(); client.destroy();

View File

@@ -37,4 +37,4 @@ console.log(responses);
// Clean up fixtures. // Clean up fixtures.
await client.del(['hash1', 'hash2', 'hash3']); await client.del(['hash1', 'hash2', 'hash3']);
await client.quit(); client.destroy();

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import { VerbatimString } from './verbatim-string'; import { VerbatimString } from './verbatim-string';
import { SimpleError, BlobError, ErrorReply } from '../errors'; import { SimpleError, BlobError, ErrorReply } from '../errors';
import { Flags } from './types'; import { TypeMapping } from './types';
// https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md // https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md
export const RESP_TYPES = { export const RESP_TYPES = {
@@ -34,7 +34,7 @@ const ASCII = {
'e': 101 'e': 101
} as const; } as const;
export const PUSH_FLAGS = { export const PUSH_TYPE_MAPPING = {
[RESP_TYPES.BLOB_STRING]: Buffer [RESP_TYPES.BLOB_STRING]: Buffer
}; };
@@ -45,7 +45,7 @@ interface DecoderOptions {
onReply(reply: any): unknown; onReply(reply: any): unknown;
onErrorReply(err: ErrorReply): unknown; onErrorReply(err: ErrorReply): unknown;
onPush(push: Array<any>): unknown; onPush(push: Array<any>): unknown;
getFlags(): Flags; getTypeMapping(): TypeMapping;
} }
export class Decoder { export class Decoder {
@@ -118,7 +118,7 @@ export class Decoder {
return this._handleDecodedValue( return this._handleDecodedValue(
this._config.onReply, this._config.onReply,
this._decodeBigNumber( this._decodeBigNumber(
this._config.getFlags()[RESP_TYPES.BIG_NUMBER], this._config.getTypeMapping()[RESP_TYPES.BIG_NUMBER],
chunk chunk
) )
); );
@@ -127,7 +127,7 @@ export class Decoder {
return this._handleDecodedValue( return this._handleDecodedValue(
this._config.onReply, this._config.onReply,
this._decodeDouble( this._decodeDouble(
this._config.getFlags()[RESP_TYPES.DOUBLE], this._config.getTypeMapping()[RESP_TYPES.DOUBLE],
chunk chunk
) )
); );
@@ -136,7 +136,7 @@ export class Decoder {
return this._handleDecodedValue( return this._handleDecodedValue(
this._config.onReply, this._config.onReply,
this._decodeSimpleString( this._decodeSimpleString(
this._config.getFlags()[RESP_TYPES.SIMPLE_STRING], this._config.getTypeMapping()[RESP_TYPES.SIMPLE_STRING],
chunk chunk
) )
); );
@@ -145,7 +145,7 @@ export class Decoder {
return this._handleDecodedValue( return this._handleDecodedValue(
this._config.onReply, this._config.onReply,
this._decodeBlobString( this._decodeBlobString(
this._config.getFlags()[RESP_TYPES.BLOB_STRING], this._config.getTypeMapping()[RESP_TYPES.BLOB_STRING],
chunk chunk
) )
); );
@@ -154,7 +154,7 @@ export class Decoder {
return this._handleDecodedValue( return this._handleDecodedValue(
this._config.onReply, this._config.onReply,
this._decodeVerbatimString( this._decodeVerbatimString(
this._config.getFlags()[RESP_TYPES.VERBATIM_STRING], this._config.getTypeMapping()[RESP_TYPES.VERBATIM_STRING],
chunk chunk
) )
); );
@@ -174,26 +174,29 @@ export class Decoder {
case RESP_TYPES.ARRAY: case RESP_TYPES.ARRAY:
return this._handleDecodedValue( return this._handleDecodedValue(
this._config.onReply, this._config.onReply,
this._decodeArray(this._config.getFlags(), chunk) this._decodeArray(this._config.getTypeMapping(), chunk)
); );
case RESP_TYPES.SET: case RESP_TYPES.SET:
return this._handleDecodedValue( return this._handleDecodedValue(
this._config.onReply, this._config.onReply,
this._decodeSet(this._config.getFlags(), chunk) this._decodeSet(this._config.getTypeMapping(), chunk)
); );
case RESP_TYPES.MAP: case RESP_TYPES.MAP:
return this._handleDecodedValue( return this._handleDecodedValue(
this._config.onReply, this._config.onReply,
this._decodeMap(this._config.getFlags(), chunk) this._decodeMap(this._config.getTypeMapping(), chunk)
); );
case RESP_TYPES.PUSH: case RESP_TYPES.PUSH:
return this._handleDecodedValue( return this._handleDecodedValue(
this._config.onPush, this._config.onPush,
this._decodeArray(PUSH_FLAGS, chunk) this._decodeArray(PUSH_TYPE_MAPPING, chunk)
); );
default:
throw new Error(`Unknown RESP type ${type} "${String.fromCharCode(type)}"`);
} }
} }
@@ -269,8 +272,8 @@ export class Decoder {
return this._decodeUnsingedNumber.bind(this, number); return this._decodeUnsingedNumber.bind(this, number);
} }
private _decodeBigNumber(flag, chunk) { private _decodeBigNumber(type, chunk) {
if (flag === String) { if (type === String) {
return this._decodeSimpleString(String, chunk); return this._decodeSimpleString(String, chunk);
} }
@@ -319,8 +322,8 @@ export class Decoder {
return this._decodeUnsingedBigNumber.bind(this, bigNumber); return this._decodeUnsingedBigNumber.bind(this, bigNumber);
} }
private _decodeDouble(flag, chunk) { private _decodeDouble(type, chunk) {
if (flag === String) { if (type === String) {
return this._decodeSimpleString(String, chunk); return this._decodeSimpleString(String, chunk);
} }
@@ -464,38 +467,38 @@ export class Decoder {
return cursor; return cursor;
} }
private _decodeSimpleString(flag, chunk) { private _decodeSimpleString(type, chunk) {
const start = this._cursor, const start = this._cursor,
crlfIndex = this._findCRLF(chunk, start); crlfIndex = this._findCRLF(chunk, start);
if (crlfIndex === -1) { if (crlfIndex === -1) {
return this._continueDecodeSimpleString.bind( return this._continueDecodeSimpleString.bind(
this, this,
[chunk.subarray(start)], [chunk.subarray(start)],
flag type
); );
} }
const slice = chunk.subarray(start, crlfIndex); const slice = chunk.subarray(start, crlfIndex);
return flag === Buffer ? return type === Buffer ?
slice : slice :
slice.toString(); slice.toString();
} }
private _continueDecodeSimpleString(chunks, flag, chunk) { private _continueDecodeSimpleString(chunks, type, chunk) {
const start = this._cursor, const start = this._cursor,
crlfIndex = this._findCRLF(chunk, start); crlfIndex = this._findCRLF(chunk, start);
if (crlfIndex === -1) { if (crlfIndex === -1) {
chunks.push(chunk.subarray(start)); chunks.push(chunk.subarray(start));
return this._continueDecodeSimpleString.bind(this, chunks, flag); return this._continueDecodeSimpleString.bind(this, chunks, type);
} }
chunks.push(chunk.subarray(start, crlfIndex)); chunks.push(chunk.subarray(start, crlfIndex));
return flag === Buffer ? return type === Buffer ?
Buffer.concat(chunks) : Buffer.concat(chunks) :
chunks.join(''); chunks.join('');
} }
private _decodeBlobString(flag, chunk) { private _decodeBlobString(type, chunk) {
// RESP 2 bulk string null // RESP 2 bulk string null
// https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md#resp-bulk-strings // https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md#resp-bulk-strings
if (chunk[this._cursor] === ASCII['-']) { if (chunk[this._cursor] === ASCII['-']) {
@@ -505,26 +508,26 @@ export class Decoder {
const length = this._decodeUnsingedNumber(0, chunk); const length = this._decodeUnsingedNumber(0, chunk);
if (typeof length === 'function') { if (typeof length === 'function') {
return this._continueDecodeBlobStringLength.bind(this, length, flag); return this._continueDecodeBlobStringLength.bind(this, length, type);
} else if (this._cursor >= chunk.length) { } else if (this._cursor >= chunk.length) {
return this._decodeBlobStringWithLength.bind(this, length, flag); return this._decodeBlobStringWithLength.bind(this, length, type);
} }
return this._decodeBlobStringWithLength(length, flag, chunk); return this._decodeBlobStringWithLength(length, type, chunk);
} }
private _continueDecodeBlobStringLength(lengthCb, flag, chunk) { private _continueDecodeBlobStringLength(lengthCb, type, chunk) {
const length = lengthCb(chunk); const length = lengthCb(chunk);
if (typeof length === 'function') { if (typeof length === 'function') {
return this._continueDecodeBlobStringLength.bind(this, length, flag); return this._continueDecodeBlobStringLength.bind(this, length, type);
} else if (this._cursor >= chunk.length) { } else if (this._cursor >= chunk.length) {
return this._decodeBlobStringWithLength.bind(this, length, flag); return this._decodeBlobStringWithLength.bind(this, length, type);
} }
return this._decodeBlobStringWithLength(length, flag, chunk); return this._decodeBlobStringWithLength(length, type, chunk);
} }
private _decodeStringWithLength(length, skip, flag, chunk) { private _decodeStringWithLength(length, skip, type, chunk) {
const end = this._cursor + length; const end = this._cursor + length;
if (end >= chunk.length) { if (end >= chunk.length) {
const slice = chunk.subarray(this._cursor); const slice = chunk.subarray(this._cursor);
@@ -534,18 +537,18 @@ export class Decoder {
length - slice.length, length - slice.length,
[slice], [slice],
skip, skip,
flag type
); );
} }
const slice = chunk.subarray(this._cursor, end); const slice = chunk.subarray(this._cursor, end);
this._cursor = end + skip; this._cursor = end + skip;
return flag === Buffer ? return type === Buffer ?
slice : slice :
slice.toString(); slice.toString();
} }
private _continueDecodeStringWithLength(length, chunks, skip, flag, chunk) { private _continueDecodeStringWithLength(length, chunks, skip, type, chunk) {
const end = this._cursor + length; const end = this._cursor + length;
if (end >= chunk.length) { if (end >= chunk.length) {
const slice = chunk.subarray(this._cursor); const slice = chunk.subarray(this._cursor);
@@ -556,46 +559,46 @@ export class Decoder {
length - slice.length, length - slice.length,
chunks, chunks,
skip, skip,
flag type
); );
} }
chunks.push(chunk.subarray(this._cursor, end)); chunks.push(chunk.subarray(this._cursor, end));
this._cursor = end + skip; this._cursor = end + skip;
return flag === Buffer ? return type === Buffer ?
Buffer.concat(chunks) : Buffer.concat(chunks) :
chunks.join(''); chunks.join('');
} }
private _decodeBlobStringWithLength(length, flag, chunk) { private _decodeBlobStringWithLength(length, type, chunk) {
return this._decodeStringWithLength(length, 2, flag, chunk); return this._decodeStringWithLength(length, 2, type, chunk);
} }
private _decodeVerbatimString(flag, chunk) { private _decodeVerbatimString(type, chunk) {
return this._continueDecodeVerbatimStringLength( return this._continueDecodeVerbatimStringLength(
this._decodeUnsingedNumber.bind(this, 0), this._decodeUnsingedNumber.bind(this, 0),
flag, type,
chunk chunk
); );
} }
private _continueDecodeVerbatimStringLength(lengthCb, flag, chunk) { private _continueDecodeVerbatimStringLength(lengthCb, type, chunk) {
const length = lengthCb(chunk); const length = lengthCb(chunk);
return typeof length === 'function'? return typeof length === 'function'?
this._continueDecodeVerbatimStringLength.bind(this, length, flag) : this._continueDecodeVerbatimStringLength.bind(this, length, type) :
this._decodeVerbatimStringWithLength(length, flag, chunk); this._decodeVerbatimStringWithLength(length, type, chunk);
} }
private _decodeVerbatimStringWithLength(length, flag, chunk) { private _decodeVerbatimStringWithLength(length, type, chunk) {
const stringLength = length - 4; // skip <format>: const stringLength = length - 4; // skip <format>:
if (flag === VerbatimString) { if (type === VerbatimString) {
return this._decodeVerbatimStringFormat(stringLength, chunk); return this._decodeVerbatimStringFormat(stringLength, chunk);
} }
this._cursor += 4; // skip <format>: this._cursor += 4; // skip <format>:
return this._cursor >= chunk.length ? return this._cursor >= chunk.length ?
this._decodeBlobStringWithLength.bind(this, stringLength, flag) : this._decodeBlobStringWithLength.bind(this, stringLength, type) :
this._decodeBlobStringWithLength(stringLength, flag, chunk); this._decodeBlobStringWithLength(stringLength, type, chunk);
} }
private _decodeVerbatimStringFormat(stringLength, chunk) { private _decodeVerbatimStringFormat(stringLength, chunk) {
@@ -656,14 +659,14 @@ export class Decoder {
new BlobError(string); new BlobError(string);
} }
private _decodeNestedType(flags, chunk) { private _decodeNestedType(typeMapping, chunk) {
const type = chunk[this._cursor]; const type = chunk[this._cursor];
return ++this._cursor === chunk.length ? return ++this._cursor === chunk.length ?
this._decodeNestedTypeValue.bind(this, type, flags) : this._decodeNestedTypeValue.bind(this, type, typeMapping) :
this._decodeNestedTypeValue(type, flags, chunk); this._decodeNestedTypeValue(type, typeMapping, chunk);
} }
private _decodeNestedTypeValue(type, flags, chunk) { private _decodeNestedTypeValue(type, typeMapping, chunk) {
switch (type) { switch (type) {
case RESP_TYPES.NULL: case RESP_TYPES.NULL:
return this._decodeNull(); return this._decodeNull();
@@ -675,19 +678,19 @@ export class Decoder {
return this._decodeNumber(chunk); return this._decodeNumber(chunk);
case RESP_TYPES.BIG_NUMBER: case RESP_TYPES.BIG_NUMBER:
return this._decodeBigNumber(flags[RESP_TYPES.BIG_NUMBER], chunk); return this._decodeBigNumber(typeMapping[RESP_TYPES.BIG_NUMBER], chunk);
case RESP_TYPES.DOUBLE: case RESP_TYPES.DOUBLE:
return this._decodeDouble(flags[RESP_TYPES.DOUBLE], chunk); return this._decodeDouble(typeMapping[RESP_TYPES.DOUBLE], chunk);
case RESP_TYPES.SIMPLE_STRING: case RESP_TYPES.SIMPLE_STRING:
return this._decodeSimpleString(flags[RESP_TYPES.SIMPLE_STRING], chunk); return this._decodeSimpleString(typeMapping[RESP_TYPES.SIMPLE_STRING], chunk);
case RESP_TYPES.BLOB_STRING: case RESP_TYPES.BLOB_STRING:
return this._decodeBlobString(flags[RESP_TYPES.BLOB_STRING], chunk); return this._decodeBlobString(typeMapping[RESP_TYPES.BLOB_STRING], chunk);
case RESP_TYPES.VERBATIM_STRING: case RESP_TYPES.VERBATIM_STRING:
return this._decodeVerbatimString(flags[RESP_TYPES.VERBATIM_STRING], chunk); return this._decodeVerbatimString(typeMapping[RESP_TYPES.VERBATIM_STRING], chunk);
case RESP_TYPES.SIMPLE_ERROR: case RESP_TYPES.SIMPLE_ERROR:
return this._decodeSimpleError(chunk); return this._decodeSimpleError(chunk);
@@ -696,17 +699,20 @@ export class Decoder {
return this._decodeBlobError(chunk); return this._decodeBlobError(chunk);
case RESP_TYPES.ARRAY: case RESP_TYPES.ARRAY:
return this._decodeArray(flags, chunk); return this._decodeArray(typeMapping, chunk);
case RESP_TYPES.SET: case RESP_TYPES.SET:
return this._decodeSet(flags, chunk); return this._decodeSet(typeMapping, chunk);
case RESP_TYPES.MAP: case RESP_TYPES.MAP:
return this._decodeMap(flags, chunk); return this._decodeMap(typeMapping, chunk);
default:
throw new Error(`Unknown RESP type ${type} "${String.fromCharCode(type)}"`);
} }
} }
private _decodeArray(flags, chunk) { private _decodeArray(typeMapping, chunk) {
// RESP 2 null // RESP 2 null
// https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md#resp-arrays // https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md#resp-arrays
if (chunk[this._cursor] === ASCII['-']) { if (chunk[this._cursor] === ASCII['-']) {
@@ -716,49 +722,49 @@ export class Decoder {
return this._decodeArrayWithLength( return this._decodeArrayWithLength(
this._decodeUnsingedNumber(0, chunk), this._decodeUnsingedNumber(0, chunk),
flags, typeMapping,
chunk chunk
); );
} }
private _decodeArrayWithLength(length, flags, chunk) { private _decodeArrayWithLength(length, typeMapping, chunk) {
return typeof length === 'function' ? return typeof length === 'function' ?
this._continueDecodeArrayLength.bind(this, length, flags) : this._continueDecodeArrayLength.bind(this, length, typeMapping) :
this._decodeArrayItems( this._decodeArrayItems(
new Array(length), new Array(length),
0, 0,
flags, typeMapping,
chunk chunk
); );
} }
private _continueDecodeArrayLength(lengthCb, flags, chunk) { private _continueDecodeArrayLength(lengthCb, typeMapping, chunk) {
return this._decodeArrayWithLength( return this._decodeArrayWithLength(
lengthCb(chunk), lengthCb(chunk),
flags, typeMapping,
chunk chunk
); );
} }
private _decodeArrayItems(array, filled, flags, chunk) { private _decodeArrayItems(array, filled, typeMapping, chunk) {
for (let i = filled; i < array.length; i++) { for (let i = filled; i < array.length; i++) {
if (this._cursor >= chunk.length) { if (this._cursor >= chunk.length) {
return this._decodeArrayItems.bind( return this._decodeArrayItems.bind(
this, this,
array, array,
i, i,
flags typeMapping
); );
} }
const item = this._decodeNestedType(flags, chunk); const item = this._decodeNestedType(typeMapping, chunk);
if (typeof item === 'function') { if (typeof item === 'function') {
return this._continueDecodeArrayItems.bind( return this._continueDecodeArrayItems.bind(
this, this,
array, array,
i, i,
item, item,
flags typeMapping
); );
} }
@@ -768,7 +774,7 @@ export class Decoder {
return array; return array;
} }
private _continueDecodeArrayItems(array, filled, itemCb, flags, chunk) { private _continueDecodeArrayItems(array, filled, itemCb, typeMapping, chunk) {
const item = itemCb(chunk); const item = itemCb(chunk);
if (typeof item === 'function') { if (typeof item === 'function') {
return this._continueDecodeArrayItems.bind( return this._continueDecodeArrayItems.bind(
@@ -776,52 +782,52 @@ export class Decoder {
array, array,
filled, filled,
item, item,
flags typeMapping
); );
} }
array[filled++] = item; array[filled++] = item;
return this._decodeArrayItems(array, filled, flags, chunk); return this._decodeArrayItems(array, filled, typeMapping, chunk);
} }
private _decodeSet(flags, chunk) { private _decodeSet(typeMapping, chunk) {
const length = this._decodeUnsingedNumber(0, chunk); const length = this._decodeUnsingedNumber(0, chunk);
if (typeof length === 'function') { if (typeof length === 'function') {
return this._continueDecodeSetLength.bind(this, length, flags); return this._continueDecodeSetLength.bind(this, length, typeMapping);
} }
return this._decodeSetItems( return this._decodeSetItems(
length, length,
flags, typeMapping,
chunk chunk
); );
} }
private _continueDecodeSetLength(lengthCb, flags, chunk) { private _continueDecodeSetLength(lengthCb, typeMapping, chunk) {
const length = lengthCb(chunk); const length = lengthCb(chunk);
return typeof length === 'function' ? return typeof length === 'function' ?
this._continueDecodeSetLength.bind(this, length, flags) : this._continueDecodeSetLength.bind(this, length, typeMapping) :
this._decodeSetItems(length, flags, chunk); this._decodeSetItems(length, typeMapping, chunk);
} }
private _decodeSetItems(length, flags, chunk) { private _decodeSetItems(length, typeMapping, chunk) {
return flags[RESP_TYPES.SET] === Set ? return typeMapping[RESP_TYPES.SET] === Set ?
this._decodeSetAsSet( this._decodeSetAsSet(
new Set(), new Set(),
length, length,
flags, typeMapping,
chunk chunk
) : ) :
this._decodeArrayItems( this._decodeArrayItems(
new Array(length), new Array(length),
0, 0,
flags, typeMapping,
chunk chunk
); );
} }
private _decodeSetAsSet(set, remaining, flags, chunk) { private _decodeSetAsSet(set, remaining, typeMapping, chunk) {
// using `remaining` instead of `length` & `set.size` to make it work even if the set contains duplicates // using `remaining` instead of `length` & `set.size` to make it work even if the set contains duplicates
while (remaining > 0) { while (remaining > 0) {
if (this._cursor >= chunk.length) { if (this._cursor >= chunk.length) {
@@ -829,18 +835,18 @@ export class Decoder {
this, this,
set, set,
remaining, remaining,
flags typeMapping
); );
} }
const item = this._decodeNestedType(flags, chunk); const item = this._decodeNestedType(typeMapping, chunk);
if (typeof item === 'function') { if (typeof item === 'function') {
return this._continueDecodeSetAsSet.bind( return this._continueDecodeSetAsSet.bind(
this, this,
set, set,
remaining, remaining,
item, item,
flags typeMapping
); );
} }
@@ -851,7 +857,7 @@ export class Decoder {
return set; return set;
} }
private _continueDecodeSetAsSet(set, remaining, itemCb, flags, chunk) { private _continueDecodeSetAsSet(set, remaining, itemCb, typeMapping, chunk) {
const item = itemCb(chunk); const item = itemCb(chunk);
if (typeof item === 'function') { if (typeof item === 'function') {
return this._continueDecodeSetAsSet.bind( return this._continueDecodeSetAsSet.bind(
@@ -859,42 +865,42 @@ export class Decoder {
set, set,
remaining, remaining,
item, item,
flags typeMapping
); );
} }
set.add(item); set.add(item);
return this._decodeSetAsSet(set, remaining - 1, flags, chunk); return this._decodeSetAsSet(set, remaining - 1, typeMapping, chunk);
} }
private _decodeMap(flags, chunk) { private _decodeMap(typeMapping, chunk) {
const length = this._decodeUnsingedNumber(0, chunk); const length = this._decodeUnsingedNumber(0, chunk);
if (typeof length === 'function') { if (typeof length === 'function') {
return this._continueDecodeMapLength.bind(this, length, flags); return this._continueDecodeMapLength.bind(this, length, typeMapping);
} }
return this._decodeMapItems( return this._decodeMapItems(
length, length,
flags, typeMapping,
chunk chunk
); );
} }
private _continueDecodeMapLength(lengthCb, flags, chunk) { private _continueDecodeMapLength(lengthCb, typeMapping, chunk) {
const length = lengthCb(chunk); const length = lengthCb(chunk);
return typeof length === 'function' ? return typeof length === 'function' ?
this._continueDecodeMapLength.bind(this, length, flags) : this._continueDecodeMapLength.bind(this, length, typeMapping) :
this._decodeMapItems(length, flags, chunk); this._decodeMapItems(length, typeMapping, chunk);
} }
private _decodeMapItems(length, flags, chunk) { private _decodeMapItems(length, typeMapping, chunk) {
switch (flags[RESP_TYPES.MAP]) { switch (typeMapping[RESP_TYPES.MAP]) {
case Map: case Map:
return this._decodeMapAsMap( return this._decodeMapAsMap(
new Map(), new Map(),
length, length,
flags, typeMapping,
chunk chunk
); );
@@ -902,7 +908,7 @@ export class Decoder {
return this._decodeArrayItems( return this._decodeArrayItems(
new Array(length * 2), new Array(length * 2),
0, 0,
flags, typeMapping,
chunk chunk
); );
@@ -910,13 +916,13 @@ export class Decoder {
return this._decodeMapAsObject( return this._decodeMapAsObject(
Object.create(null), Object.create(null),
length, length,
flags, typeMapping,
chunk chunk
); );
} }
} }
private _decodeMapAsMap(map, remaining, flags, chunk) { private _decodeMapAsMap(map, remaining, typeMapping, chunk) {
// using `remaining` instead of `length` & `map.size` to make it work even if the map contains duplicate keys // using `remaining` instead of `length` & `map.size` to make it work even if the map contains duplicate keys
while (remaining > 0) { while (remaining > 0) {
if (this._cursor >= chunk.length) { if (this._cursor >= chunk.length) {
@@ -924,18 +930,18 @@ export class Decoder {
this, this,
map, map,
remaining, remaining,
flags typeMapping
); );
} }
const key = this._decodeMapKey(flags, chunk); const key = this._decodeMapKey(typeMapping, chunk);
if (typeof key === 'function') { if (typeof key === 'function') {
return this._continueDecodeMapKey.bind( return this._continueDecodeMapKey.bind(
this, this,
map, map,
remaining, remaining,
key, key,
flags typeMapping
); );
} }
@@ -945,12 +951,12 @@ export class Decoder {
map, map,
remaining, remaining,
key, key,
this._decodeNestedType.bind(this, flags), this._decodeNestedType.bind(this, typeMapping),
flags typeMapping
); );
} }
const value = this._decodeNestedType(flags, chunk); const value = this._decodeNestedType(typeMapping, chunk);
if (typeof value === 'function') { if (typeof value === 'function') {
return this._continueDecodeMapValue.bind( return this._continueDecodeMapValue.bind(
this, this,
@@ -958,7 +964,7 @@ export class Decoder {
remaining, remaining,
key, key,
value, value,
flags typeMapping
); );
} }
@@ -969,14 +975,14 @@ export class Decoder {
return map; return map;
} }
private _decodeMapKey(flags, chunk) { private _decodeMapKey(typeMapping, chunk) {
const type = chunk[this._cursor]; const type = chunk[this._cursor];
return ++this._cursor === chunk.length ? return ++this._cursor === chunk.length ?
this._decodeMapKeyValue.bind(this, type, flags) : this._decodeMapKeyValue.bind(this, type, typeMapping) :
this._decodeMapKeyValue(type, flags, chunk); this._decodeMapKeyValue(type, typeMapping, chunk);
} }
private _decodeMapKeyValue(type, flags, chunk) { private _decodeMapKeyValue(type, typeMapping, chunk) {
switch (type) { switch (type) {
// decode simple string map key as string (and not as buffer) // decode simple string map key as string (and not as buffer)
case RESP_TYPES.SIMPLE_STRING: case RESP_TYPES.SIMPLE_STRING:
@@ -987,11 +993,11 @@ export class Decoder {
return this._decodeBlobString(String, chunk); return this._decodeBlobString(String, chunk);
default: default:
return this._decodeNestedTypeValue(type, flags, chunk); return this._decodeNestedTypeValue(type, typeMapping, chunk);
} }
} }
private _continueDecodeMapKey(map, remaining, keyCb, flags, chunk) { private _continueDecodeMapKey(map, remaining, keyCb, typeMapping, chunk) {
const key = keyCb(chunk); const key = keyCb(chunk);
if (typeof key === 'function') { if (typeof key === 'function') {
return this._continueDecodeMapKey.bind( return this._continueDecodeMapKey.bind(
@@ -999,7 +1005,7 @@ export class Decoder {
map, map,
remaining, remaining,
key, key,
flags typeMapping
); );
} }
@@ -1009,12 +1015,12 @@ export class Decoder {
map, map,
remaining, remaining,
key, key,
this._decodeNestedType.bind(this, flags), this._decodeNestedType.bind(this, typeMapping),
flags typeMapping
); );
} }
const value = this._decodeNestedType(flags, chunk); const value = this._decodeNestedType(typeMapping, chunk);
if (typeof value === 'function') { if (typeof value === 'function') {
return this._continueDecodeMapValue.bind( return this._continueDecodeMapValue.bind(
this, this,
@@ -1022,15 +1028,15 @@ export class Decoder {
remaining, remaining,
key, key,
value, value,
flags typeMapping
); );
} }
map.set(key, value); map.set(key, value);
return this._decodeMapAsMap(map, remaining - 1, flags, chunk); return this._decodeMapAsMap(map, remaining - 1, typeMapping, chunk);
} }
private _continueDecodeMapValue(map, remaining, key, valueCb, flags, chunk) { private _continueDecodeMapValue(map, remaining, key, valueCb, typeMapping, chunk) {
const value = valueCb(chunk); const value = valueCb(chunk);
if (typeof value === 'function') { if (typeof value === 'function') {
return this._continueDecodeMapValue.bind( return this._continueDecodeMapValue.bind(
@@ -1039,34 +1045,34 @@ export class Decoder {
remaining, remaining,
key, key,
value, value,
flags typeMapping
); );
} }
map.set(key, value); map.set(key, value);
return this._decodeMapAsMap(map, remaining - 1, flags, chunk); return this._decodeMapAsMap(map, remaining - 1, typeMapping, chunk);
} }
private _decodeMapAsObject(object, remaining, flags, chunk) { private _decodeMapAsObject(object, remaining, typeMapping, chunk) {
while (remaining > 0) { while (remaining > 0) {
if (this._cursor >= chunk.length) { if (this._cursor >= chunk.length) {
return this._decodeMapAsObject.bind( return this._decodeMapAsObject.bind(
this, this,
object, object,
remaining, remaining,
flags typeMapping
); );
} }
const key = this._decodeMapKey(flags, chunk); const key = this._decodeMapKey(typeMapping, chunk);
if (typeof key === 'function') { if (typeof key === 'function') {
return this._continueDecodeMapAsObjectKey.bind( return this._continueDecodeMapAsObjectKey.bind(
this, this,
object, object,
remaining, remaining,
key, key,
flags typeMapping
); );
} }
@@ -1076,12 +1082,12 @@ export class Decoder {
object, object,
remaining, remaining,
key, key,
this._decodeNestedType.bind(this, flags), this._decodeNestedType.bind(this, typeMapping),
flags typeMapping
); );
} }
const value = this._decodeNestedType(flags, chunk); const value = this._decodeNestedType(typeMapping, chunk);
if (typeof value === 'function') { if (typeof value === 'function') {
return this._continueDecodeMapAsObjectValue.bind( return this._continueDecodeMapAsObjectValue.bind(
this, this,
@@ -1089,7 +1095,7 @@ export class Decoder {
remaining, remaining,
key, key,
value, value,
flags typeMapping
); );
} }
@@ -1100,7 +1106,7 @@ export class Decoder {
return object; return object;
} }
private _continueDecodeMapAsObjectKey(object, remaining, keyCb, flags, chunk) { private _continueDecodeMapAsObjectKey(object, remaining, keyCb, typeMapping, chunk) {
const key = keyCb(chunk); const key = keyCb(chunk);
if (typeof key === 'function') { if (typeof key === 'function') {
return this._continueDecodeMapAsObjectKey.bind( return this._continueDecodeMapAsObjectKey.bind(
@@ -1108,7 +1114,7 @@ export class Decoder {
object, object,
remaining, remaining,
key, key,
flags typeMapping
); );
} }
@@ -1118,12 +1124,12 @@ export class Decoder {
object, object,
remaining, remaining,
key, key,
this._decodeNestedType.bind(this, flags), this._decodeNestedType.bind(this, typeMapping),
flags typeMapping
); );
} }
const value = this._decodeNestedType(flags, chunk); const value = this._decodeNestedType(typeMapping, chunk);
if (typeof value === 'function') { if (typeof value === 'function') {
return this._continueDecodeMapAsObjectValue.bind( return this._continueDecodeMapAsObjectValue.bind(
this, this,
@@ -1131,16 +1137,16 @@ export class Decoder {
remaining, remaining,
key, key,
value, value,
flags typeMapping
); );
} }
object[key] = value; object[key] = value;
return this._decodeMapAsObject(object, remaining - 1, flags, chunk); return this._decodeMapAsObject(object, remaining - 1, typeMapping, chunk);
} }
private _continueDecodeMapAsObjectValue(object, remaining, key, valueCb, flags, chunk) { private _continueDecodeMapAsObjectValue(object, remaining, key, valueCb, typeMapping, chunk) {
const value = valueCb(chunk); const value = valueCb(chunk);
if (typeof value === 'function') { if (typeof value === 'function') {
return this._continueDecodeMapAsObjectValue.bind( return this._continueDecodeMapAsObjectValue.bind(
@@ -1149,12 +1155,12 @@ export class Decoder {
remaining, remaining,
key, key,
value, value,
flags typeMapping
); );
} }
object[key] = value; object[key] = value;
return this._decodeMapAsObject(object, remaining - 1, flags, chunk); return this._decodeMapAsObject(object, remaining - 1, typeMapping, chunk);
} }
} }

View File

@@ -148,45 +148,45 @@ export type ReplyUnion = NullReply | BooleanReply | NumberReply | BigNumberReply
Map<ReplyUnion, ReplyUnion> | Array<ReplyUnion | ReplyUnion> Map<ReplyUnion, ReplyUnion> | Array<ReplyUnion | ReplyUnion>
>; >;
export type Reply = ReplyWithFlags<ReplyUnion, {}>; export type Reply = ReplyWithTypeMapping<ReplyUnion, {}>;
export type Flag<T> = ((...args: any) => T) | (new (...args: any) => T); export type Flag<T> = ((...args: any) => T) | (new (...args: any) => T);
type RespTypeUnion<T> = T extends RespType<RespTypes, unknown, unknown, infer FLAG_TYPES> ? FLAG_TYPES : never; type RespTypeUnion<T> = T extends RespType<RespTypes, unknown, unknown, infer FLAG_TYPES> ? FLAG_TYPES : never;
export type Flags = { export type TypeMapping = {
[P in RespTypes]?: Flag<RespTypeUnion<Extract<ReplyUnion, RespType<P, any, any, any>>>>; [P in RespTypes]?: Flag<RespTypeUnion<Extract<ReplyUnion, RespType<P, any, any, any>>>>;
}; };
type MapKey< type MapKey<
T, T,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = ReplyWithFlags<T, FLAGS & { > = ReplyWithTypeMapping<T, TYPE_MAPPING & {
// simple and blob strings as map keys decoded as strings // simple and blob strings as map keys decoded as strings
[RESP_TYPES.SIMPLE_STRING]: StringConstructor; [RESP_TYPES.SIMPLE_STRING]: StringConstructor;
[RESP_TYPES.BLOB_STRING]: StringConstructor; [RESP_TYPES.BLOB_STRING]: StringConstructor;
}>; }>;
export type ReplyWithFlags< export type ReplyWithTypeMapping<
REPLY, REPLY,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = ( > = (
// if REPLY is a type, extract the coresponding type from FLAGS or use the default type // if REPLY is a type, extract the coresponding type from TYPE_MAPPING or use the default type
REPLY extends RespType<infer RESP_TYPE, infer DEFAULT, infer TYPES, unknown> ? REPLY extends RespType<infer RESP_TYPE, infer DEFAULT, infer TYPES, unknown> ?
FLAGS[RESP_TYPE] extends Flag<infer T> ? TYPE_MAPPING[RESP_TYPE] extends Flag<infer T> ?
ReplyWithFlags<Extract<DEFAULT | TYPES, T>, FLAGS> : ReplyWithTypeMapping<Extract<DEFAULT | TYPES, T>, TYPE_MAPPING> :
ReplyWithFlags<DEFAULT, FLAGS> ReplyWithTypeMapping<DEFAULT, TYPE_MAPPING>
: ( : (
// if REPLY is a known generic type, convert its generic arguments // if REPLY is a known generic type, convert its generic arguments
// TODO: tuples? // TODO: tuples?
REPLY extends Array<infer T> ? Array<ReplyWithFlags<T, FLAGS>> : REPLY extends Array<infer T> ? Array<ReplyWithTypeMapping<T, TYPE_MAPPING>> :
REPLY extends Set<infer T> ? Set<ReplyWithFlags<T, FLAGS>> : REPLY extends Set<infer T> ? Set<ReplyWithTypeMapping<T, TYPE_MAPPING>> :
REPLY extends Map<infer K, infer V> ? Map<MapKey<K, FLAGS>, ReplyWithFlags<V, FLAGS>> : REPLY extends Map<infer K, infer V> ? Map<MapKey<K, TYPE_MAPPING>, ReplyWithTypeMapping<V, TYPE_MAPPING>> :
// `Date` & `Buffer` are supersets of `Record`, so they need to be checked first // `Date` & `Buffer` are supersets of `Record`, so they need to be checked first
REPLY extends Date ? REPLY : REPLY extends Date ? REPLY :
REPLY extends Buffer ? REPLY : REPLY extends Buffer ? REPLY :
REPLY extends Record<PropertyKey, any> ? { REPLY extends Record<PropertyKey, any> ? {
[P in keyof REPLY]: ReplyWithFlags<REPLY[P], FLAGS>; [P in keyof REPLY]: ReplyWithTypeMapping<REPLY[P], TYPE_MAPPING>;
} : } :
// otherwise, just return the REPLY as is // otherwise, just return the REPLY as is
REPLY REPLY
@@ -333,17 +333,17 @@ export type CommandReply<
export type CommandSignature< export type CommandSignature<
COMMAND extends Command, COMMAND extends Command,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = (...args: Parameters<COMMAND['transformArguments']>) => Promise<ReplyWithFlags<CommandReply<COMMAND, RESP>, FLAGS>>; > = (...args: Parameters<COMMAND['transformArguments']>) => Promise<ReplyWithTypeMapping<CommandReply<COMMAND, RESP>, TYPE_MAPPING>>;
export type CommandWithPoliciesSignature< export type CommandWithPoliciesSignature<
COMMAND extends Command, COMMAND extends Command,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags, TYPE_MAPPING extends TypeMapping,
POLICIES extends CommandPolicies POLICIES extends CommandPolicies
> = (...args: Parameters<COMMAND['transformArguments']>) => Promise< > = (...args: Parameters<COMMAND['transformArguments']>) => Promise<
ReplyWithPolicy< ReplyWithPolicy<
ReplyWithFlags<CommandReply<COMMAND, RESP>, FLAGS>, ReplyWithTypeMapping<CommandReply<COMMAND, RESP>, TYPE_MAPPING>,
MergePolicies<COMMAND, POLICIES> MergePolicies<COMMAND, POLICIES>
> >
>; >;

View File

@@ -1,7 +1,7 @@
import { SinglyLinkedList, DoublyLinkedNode, DoublyLinkedList } from './linked-list'; import { SinglyLinkedList, DoublyLinkedNode, DoublyLinkedList } from './linked-list';
import encodeCommand from '../RESP/encoder'; import encodeCommand from '../RESP/encoder';
import { Decoder, PUSH_FLAGS, RESP_TYPES } from '../RESP/decoder'; import { Decoder, PUSH_TYPE_MAPPING, RESP_TYPES } from '../RESP/decoder';
import { CommandArguments, Flags, ReplyUnion, RespVersions } from '../RESP/types'; import { CommandArguments, TypeMapping, ReplyUnion, RespVersions } from '../RESP/types';
import { ChannelListeners, PubSub, PubSubCommand, PubSubListener, PubSubType, PubSubTypeListeners } from './pub-sub'; import { ChannelListeners, PubSub, PubSubCommand, PubSubListener, PubSubType, PubSubTypeListeners } from './pub-sub';
import { AbortError, ErrorReply } from '../errors'; import { AbortError, ErrorReply } from '../errors';
import { EventEmitter } from 'stream'; import { EventEmitter } from 'stream';
@@ -10,7 +10,7 @@ export interface QueueCommandOptions {
chainId?: symbol; chainId?: symbol;
asap?: boolean; asap?: boolean;
abortSignal?: AbortSignal; abortSignal?: AbortSignal;
flags?: Flags; typeMapping?: TypeMapping;
} }
export interface CommandWaitingToBeSent extends CommandWaitingForReply { export interface CommandWaitingToBeSent extends CommandWaitingForReply {
@@ -26,15 +26,15 @@ interface CommandWaitingForReply {
resolve(reply?: unknown): void; resolve(reply?: unknown): void;
reject(err: unknown): void; reject(err: unknown): void;
channelsCounter?: number; channelsCounter?: number;
flags?: Flags; typeMapping?: TypeMapping;
} }
export type OnShardedChannelMoved = (channel: string, listeners: ChannelListeners) => void; export type OnShardedChannelMoved = (channel: string, listeners: ChannelListeners) => void;
const PONG = Buffer.from('pong'); const PONG = Buffer.from('pong');
const RESP2_PUSH_FLAGS = { const RESP2_PUSH_TYPE_MAPPING = {
...PUSH_FLAGS, ...PUSH_TYPE_MAPPING,
[RESP_TYPES.SIMPLE_STRING]: Buffer [RESP_TYPES.SIMPLE_STRING]: Buffer
}; };
@@ -102,8 +102,8 @@ export default class RedisCommandsQueue {
} }
} }
private _getFlags() { private _getTypeMapping() {
return this._waitingForReply.head!.value.flags ?? {}; return this._waitingForReply.head!.value.typeMapping ?? {};
} }
private _initiateResp3Decoder() { private _initiateResp3Decoder() {
@@ -115,7 +115,7 @@ export default class RedisCommandsQueue {
} }
}, },
getFlags: () => this._getFlags() getTypeMapping: () => this._getTypeMapping()
}); });
} }
@@ -126,9 +126,9 @@ export default class RedisCommandsQueue {
if (this._onPush(reply)) return; if (this._onPush(reply)) return;
if (PONG.equals(reply[0] as Buffer)) { if (PONG.equals(reply[0] as Buffer)) {
const { resolve, flags } = this._waitingForReply.shift()!, const { resolve, typeMapping } = this._waitingForReply.shift()!,
buffer = ((reply[1] as Buffer).length === 0 ? reply[0] : reply[1]) as Buffer; buffer = ((reply[1] as Buffer).length === 0 ? reply[0] : reply[1]) as Buffer;
resolve(flags?.[RESP_TYPES.SIMPLE_STRING] === Buffer ? buffer : buffer.toString()); resolve(typeMapping?.[RESP_TYPES.SIMPLE_STRING] === Buffer ? buffer : buffer.toString());
return; return;
} }
} }
@@ -140,11 +140,11 @@ export default class RedisCommandsQueue {
// PubSub is handled in onReply // PubSub is handled in onReply
// @ts-expect-error // @ts-expect-error
onPush: undefined, onPush: undefined,
getFlags: () => { getTypeMapping: () => {
// PubSub push is an Array in RESP2 // PubSub push is an Array in RESP2
return this._pubSub.isActive ? return this._pubSub.isActive ?
RESP2_PUSH_FLAGS : RESP2_PUSH_TYPE_MAPPING :
this._getFlags(); this._getTypeMapping();
} }
}); });
} }
@@ -161,7 +161,7 @@ export default class RedisCommandsQueue {
const value: CommandWaitingToBeSent = { const value: CommandWaitingToBeSent = {
args, args,
chainId: options?.chainId, chainId: options?.chainId,
flags: options?.flags, typeMapping: options?.typeMapping,
resolve, resolve,
reject, reject,
abort: undefined abort: undefined
@@ -243,7 +243,7 @@ export default class RedisCommandsQueue {
this._waitingToBeSent.push({ this._waitingToBeSent.push({
args: command.args, args: command.args,
channelsCounter: command.channelsCounter, channelsCounter: command.channelsCounter,
flags: PUSH_FLAGS, typeMapping: PUSH_TYPE_MAPPING,
resolve: () => { resolve: () => {
command.resolve(); command.resolve();
resolve(); resolve();
@@ -282,7 +282,7 @@ export default class RedisCommandsQueue {
return encoded; return encoded;
} }
#flushWaitingForReply(err: Error): void { private _flushWaitingForReply(err: Error): void {
while (this._waitingForReply.head) { while (this._waitingForReply.head) {
this._waitingForReply.shift()!.reject(err); this._waitingForReply.shift()!.reject(err);
} }
@@ -304,7 +304,7 @@ export default class RedisCommandsQueue {
this.decoder.reset(); this.decoder.reset();
this._pubSub.reset(); this._pubSub.reset();
this.#flushWaitingForReply(err); this._flushWaitingForReply(err);
if (!this._chainInExecution) return; if (!this._chainInExecution) return;
@@ -321,7 +321,7 @@ export default class RedisCommandsQueue {
flushAll(err: Error): void { flushAll(err: Error): void {
this.decoder.reset(); this.decoder.reset();
this._pubSub.reset(); this._pubSub.reset();
this.#flushWaitingForReply(err); this._flushWaitingForReply(err);
while (this._waitingToBeSent.head) { while (this._waitingToBeSent.head) {
RedisCommandsQueue._flushWaitingToBeSent( RedisCommandsQueue._flushWaitingToBeSent(
this._waitingToBeSent.shift()!, this._waitingToBeSent.shift()!,

View File

@@ -7,14 +7,14 @@ import { ClientClosedError, ClientOfflineError, DisconnectsClientError, WatchErr
import { URL } from 'url'; import { URL } from 'url';
import { TcpSocketConnectOpts } from 'net'; import { TcpSocketConnectOpts } from 'net';
import { PubSubType, PubSubListener, PubSubTypeListeners, ChannelListeners } from './pub-sub'; import { PubSubType, PubSubListener, PubSubTypeListeners, ChannelListeners } from './pub-sub';
import { Command, CommandArguments, CommandSignature, Flags, CommanderConfig, RedisFunction, RedisFunctions, RedisModules, RedisScript, RedisScripts, ReplyUnion, RespVersions, RedisArgument } from '../RESP/types'; import { Command, CommandArguments, CommandSignature, TypeMapping, CommanderConfig, RedisFunction, RedisFunctions, RedisModules, RedisScript, RedisScripts, ReplyUnion, RespVersions, RedisArgument } from '../RESP/types';
import RedisClientMultiCommand, { RedisClientMultiCommandType } from './multi-command'; import RedisClientMultiCommand, { RedisClientMultiCommandType } from './multi-command';
import { RedisMultiQueuedCommand } from '../multi-command'; import { RedisMultiQueuedCommand } from '../multi-command';
import HELLO, { HelloOptions } from '../commands/HELLO'; import HELLO, { HelloOptions } from '../commands/HELLO';
import { ReplyWithFlags, CommandReply } from '../RESP/types'; import { ReplyWithTypeMapping, CommandReply } from '../RESP/types';
import SCAN, { ScanOptions, ScanCommonOptions } from '../commands/SCAN'; import SCAN, { ScanOptions, ScanCommonOptions } from '../commands/SCAN';
import { RedisLegacyClient, RedisLegacyClientType } from './legacy-mode'; import { RedisLegacyClient, RedisLegacyClientType } from './legacy-mode';
import { RedisClientPool } from './pool'; // import { RedisClientPool } from './pool';
export interface RedisClientOptions< export interface RedisClientOptions<
M extends RedisModules = RedisModules, M extends RedisModules = RedisModules,
@@ -69,37 +69,37 @@ export interface RedisClientOptions<
type WithCommands< type WithCommands<
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[P in keyof typeof COMMANDS]: CommandSignature<(typeof COMMANDS)[P], RESP, FLAGS>; [P in keyof typeof COMMANDS]: CommandSignature<(typeof COMMANDS)[P], RESP, TYPE_MAPPING>;
}; };
type WithModules< type WithModules<
M extends RedisModules, M extends RedisModules,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[P in keyof M]: { [P in keyof M]: {
[C in keyof M[P]]: CommandSignature<M[P][C], RESP, FLAGS>; [C in keyof M[P]]: CommandSignature<M[P][C], RESP, TYPE_MAPPING>;
}; };
}; };
type WithFunctions< type WithFunctions<
F extends RedisFunctions, F extends RedisFunctions,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[L in keyof F]: { [L in keyof F]: {
[C in keyof F[L]]: CommandSignature<F[L][C], RESP, FLAGS>; [C in keyof F[L]]: CommandSignature<F[L][C], RESP, TYPE_MAPPING>;
}; };
}; };
type WithScripts< type WithScripts<
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[P in keyof S]: CommandSignature<S[P], RESP, FLAGS>; [P in keyof S]: CommandSignature<S[P], RESP, TYPE_MAPPING>;
}; };
export type RedisClientType< export type RedisClientType<
@@ -107,20 +107,20 @@ export type RedisClientType<
F extends RedisFunctions = {}, F extends RedisFunctions = {},
S extends RedisScripts = {}, S extends RedisScripts = {},
RESP extends RespVersions = 2, RESP extends RespVersions = 2,
FLAGS extends Flags = {} TYPE_MAPPING extends TypeMapping = {}
> = ( > = (
RedisClient<M, F, S, RESP, FLAGS> & RedisClient<M, F, S, RESP, TYPE_MAPPING> &
WithCommands<RESP, FLAGS> & WithCommands<RESP, TYPE_MAPPING> &
WithModules<M, RESP, FLAGS> & WithModules<M, RESP, TYPE_MAPPING> &
WithFunctions<F, RESP, FLAGS> & WithFunctions<F, RESP, TYPE_MAPPING> &
WithScripts<S, RESP, FLAGS> WithScripts<S, RESP, TYPE_MAPPING>
); );
export interface ClientCommandOptions extends QueueCommandOptions { export interface ClientCommandOptions extends QueueCommandOptions {
// isolated?: boolean; // isolated?: boolean;
} }
type ProxyClient = RedisClient<{}, {}, {}, RespVersions, Flags> & { commandOptions?: ClientCommandOptions }; type ProxyClient = RedisClient<{}, {}, {}, RespVersions, TypeMapping> & { commandOptions?: ClientCommandOptions };
type NamespaceProxyClient = { self: ProxyClient }; type NamespaceProxyClient = { self: ProxyClient };
@@ -133,7 +133,7 @@ export default class RedisClient<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> extends EventEmitter { > extends EventEmitter {
private static _createCommand(command: Command, resp: RespVersions) { private static _createCommand(command: Command, resp: RespVersions) {
const transformReply = getTransformReply(command, resp); const transformReply = getTransformReply(command, resp);
@@ -396,7 +396,15 @@ export default class RedisClient<
}; };
return new RedisSocket(socketInitiator, this._options?.socket) return new RedisSocket(socketInitiator, this._options?.socket)
.on('data', chunk => this._queue.decoder.write(chunk)) .on('data', chunk => {
try {
this._queue.decoder.write(chunk);
} catch (err) {
this._queue.decoder.reset();
this.emit('error', err);
}
})
.on('error', err => { .on('error', err => {
this.emit('error', err); this.emit('error', err);
if (this._socket.isOpen && !this._options?.disableOfflineQueue) { if (this._socket.isOpen && !this._options?.disableOfflineQueue) {
@@ -440,7 +448,7 @@ export default class RedisClient<
F, F,
S, S,
RESP, RESP,
T['flags'] extends Flags ? T['flags'] : {} T['typeMapping'] extends TypeMapping ? T['typeMapping'] : {}
>; >;
} }
@@ -459,17 +467,20 @@ export default class RedisClient<
F, F,
S, S,
RESP, RESP,
K extends 'flags' ? V extends Flags ? V : {} : FLAGS K extends 'typeMapping' ? V extends TypeMapping ? V : {} : TYPE_MAPPING
>; >;
} }
/** /**
* Override the `flags` command option * Override the `typeMapping` command option
*/ */
withFlags<FLAGS extends Flags>(flags: FLAGS) { withTypeMapping<TYPE_MAPPING extends TypeMapping>(typeMapping: TYPE_MAPPING) {
return this._commandOptionsProxy('flags', flags); return this._commandOptionsProxy('typeMapping', typeMapping);
} }
/**
* Override the `abortSignal` command option
*/
withAbortSignal(abortSignal: AbortSignal) { withAbortSignal(abortSignal: AbortSignal) {
return this._commandOptionsProxy('abortSignal', abortSignal); return this._commandOptionsProxy('abortSignal', abortSignal);
} }
@@ -482,7 +493,7 @@ export default class RedisClient<
} }
/** /**
* Get the "legacy" (v3/callback) interface * Create the "legacy" (v3/callback) interface
*/ */
legacy(): RedisLegacyClientType { legacy(): RedisLegacyClientType {
return new RedisLegacyClient( return new RedisLegacyClient(
@@ -493,11 +504,11 @@ export default class RedisClient<
/** /**
* Create `RedisClientPool` using this client as a prototype * Create `RedisClientPool` using this client as a prototype
*/ */
pool() { // pool() {
return RedisClientPool.fromClient( // return RedisClientPool.fromClient(
this as unknown as RedisClientType<M, F, S, RESP> // this as unknown as RedisClientType<M, F, S, RESP>
); // );
} // }
duplicate(overrides?: Partial<RedisClientOptions<M, F, S, RESP>>) { duplicate(overrides?: Partial<RedisClientOptions<M, F, S, RESP>>) {
return new (Object.getPrototypeOf(this).constructor)({ return new (Object.getPrototypeOf(this).constructor)({
@@ -679,12 +690,12 @@ export default class RedisClient<
private _addMultiCommands( private _addMultiCommands(
commands: Array<RedisMultiQueuedCommand>, commands: Array<RedisMultiQueuedCommand>,
chainId?: symbol, chainId?: symbol,
flags?: Flags typeMapping?: TypeMapping
) { ) {
return Promise.all( return Promise.all(
commands.map(({ args }) => this._queue.addCommand(args, { commands.map(({ args }) => this._queue.addCommand(args, {
chainId, chainId,
flags typeMapping
})) }))
); );
} }
@@ -699,7 +710,7 @@ export default class RedisClient<
const promise = Promise.all( const promise = Promise.all(
commands.map(({ args }) => this._queue.addCommand(args, { commands.map(({ args }) => this._queue.addCommand(args, {
flags: (this as ProxyClient).commandOptions?.flags typeMapping: (this as ProxyClient).commandOptions?.typeMapping
})) }))
); );
this._tick(); this._tick();
@@ -710,24 +721,24 @@ export default class RedisClient<
* @internal * @internal
*/ */
async executeMulti( async executeMulti(
commands: Array<RedisMultiQueuedCommand>, commands: Array<RedisMultiQueuedCommand>,
selectedDB?: number selectedDB?: number
) { ) {
if (!this._socket.isOpen) { if (!this._socket.isOpen) {
return Promise.reject(new ClientClosedError()); return Promise.reject(new ClientClosedError());
} }
const flags = (this as ProxyClient).commandOptions?.flags, const typeMapping = (this as ProxyClient).commandOptions?.typeMapping,
chainId = Symbol('MULTI Chain'), chainId = Symbol('MULTI Chain'),
promises = [ promises = [
this._queue.addCommand(['MULTI'], { chainId }), this._queue.addCommand(['MULTI'], { chainId }),
]; ];
for (const { args } of commands) { for (const { args } of commands) {
promises.push( promises.push(
this._queue.addCommand(args, { this._queue.addCommand(args, {
chainId, chainId,
flags typeMapping
}) })
); );
} }
@@ -736,7 +747,7 @@ export default class RedisClient<
this._queue.addCommand(['EXEC'], { chainId }) this._queue.addCommand(['EXEC'], { chainId })
); );
this._tick(); this._tick();
const results = await Promise.all(promises), const results = await Promise.all(promises),
execResult = results[results.length - 1]; execResult = results[results.length - 1];
@@ -745,23 +756,23 @@ export default class RedisClient<
throw new WatchError(); throw new WatchError();
} }
if (selectedDB !== undefined) { if (selectedDB !== undefined) {
this._selectedDB = selectedDB; this._selectedDB = selectedDB;
} }
return execResult as Array<unknown>; return execResult as Array<unknown>;
} }
MULTI(): RedisClientMultiCommandType<[], M, F, S, RESP, FLAGS> { MULTI(): RedisClientMultiCommandType<[], M, F, S, RESP, TYPE_MAPPING> {
return new (this as any).Multi(this); return new (this as any).Multi(this);
} }
multi = this.MULTI; multi = this.MULTI;
async* scanIterator( async* scanIterator(
this: RedisClientType<M, F, S, RESP, FLAGS>, this: RedisClientType<M, F, S, RESP, TYPE_MAPPING>,
options?: ScanOptions & ScanIteratorOptions options?: ScanOptions & ScanIteratorOptions
): AsyncIterable<ReplyWithFlags<CommandReply<typeof SCAN, RESP>['keys'], FLAGS>> { ): AsyncIterable<ReplyWithTypeMapping<CommandReply<typeof SCAN, RESP>['keys'], TYPE_MAPPING>> {
let cursor = options?.cursor ?? 0; let cursor = options?.cursor ?? 0;
do { do {
const reply = await this.scan(cursor, options); const reply = await this.scan(cursor, options);
@@ -771,7 +782,7 @@ export default class RedisClient<
} }
async* hScanIterator( async* hScanIterator(
this: RedisClientType<M, F, S, RESP, FLAGS>, this: RedisClientType<M, F, S, RESP, TYPE_MAPPING>,
key: RedisArgument, key: RedisArgument,
options?: ScanCommonOptions & ScanIteratorOptions options?: ScanCommonOptions & ScanIteratorOptions
) { ) {
@@ -784,7 +795,7 @@ export default class RedisClient<
} }
async* sScanIterator( async* sScanIterator(
this: RedisClientType<M, F, S, RESP, FLAGS>, this: RedisClientType<M, F, S, RESP, TYPE_MAPPING>,
key: RedisArgument, key: RedisArgument,
options?: ScanCommonOptions & ScanIteratorOptions options?: ScanCommonOptions & ScanIteratorOptions
) { ) {
@@ -797,7 +808,7 @@ export default class RedisClient<
} }
async* zScanIterator( async* zScanIterator(
this: RedisClientType<M, F, S, RESP, FLAGS>, this: RedisClientType<M, F, S, RESP, TYPE_MAPPING>,
key: RedisArgument, key: RedisArgument,
options?: ScanCommonOptions & ScanIteratorOptions options?: ScanCommonOptions & ScanIteratorOptions
) { ) {

View File

@@ -1,4 +1,4 @@
import { RedisModules, RedisFunctions, RedisScripts, RespVersions, Flags, Command, CommandArguments, ReplyUnion } from '../RESP/types'; import { RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping, Command, CommandArguments, ReplyUnion } from '../RESP/types';
import { RedisClientType } from '.'; import { RedisClientType } from '.';
import { getTransformReply } from '../commander'; import { getTransformReply } from '../commander';
import { ErrorReply } from '../errors'; import { ErrorReply } from '../errors';

View File

@@ -1,6 +1,6 @@
import COMMANDS from '../commands'; import COMMANDS from '../commands';
import RedisMultiCommand, { MULTI_REPLY, MultiReply, MultiReplyType } from '../multi-command'; import RedisMultiCommand, { MULTI_REPLY, MultiReply, MultiReplyType } from '../multi-command';
import { ReplyWithFlags, CommandReply, Command, CommandArguments, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TransformReply, RedisScript, RedisFunction, Flags, ReplyUnion } from '../RESP/types'; import { ReplyWithTypeMapping, CommandReply, Command, CommandArguments, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TransformReply, RedisScript, RedisFunction, TypeMapping, ReplyUnion } from '../RESP/types';
import { attachConfig, functionArgumentsPrefix, getTransformReply } from '../commander'; import { attachConfig, functionArgumentsPrefix, getTransformReply } from '../commander';
import { RedisClientType } from '.'; import { RedisClientType } from '.';
@@ -11,14 +11,14 @@ type CommandSignature<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = (...args: Parameters<C['transformArguments']>) => RedisClientMultiCommandType< > = (...args: Parameters<C['transformArguments']>) => RedisClientMultiCommandType<
[...REPLIES, ReplyWithFlags<CommandReply<C, RESP>, FLAGS>], [...REPLIES, ReplyWithTypeMapping<CommandReply<C, RESP>, TYPE_MAPPING>],
M, M,
F, F,
S, S,
RESP, RESP,
FLAGS TYPE_MAPPING
>; >;
type WithCommands< type WithCommands<
@@ -27,9 +27,9 @@ type WithCommands<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[P in keyof typeof COMMANDS]: CommandSignature<REPLIES, (typeof COMMANDS)[P], M, F, S, RESP, FLAGS>; [P in keyof typeof COMMANDS]: CommandSignature<REPLIES, (typeof COMMANDS)[P], M, F, S, RESP, TYPE_MAPPING>;
}; };
type WithModules< type WithModules<
@@ -38,10 +38,10 @@ type WithModules<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[P in keyof M]: { [P in keyof M]: {
[C in keyof M[P]]: CommandSignature<REPLIES, M[P][C], M, F, S, RESP, FLAGS>; [C in keyof M[P]]: CommandSignature<REPLIES, M[P][C], M, F, S, RESP, TYPE_MAPPING>;
}; };
}; };
@@ -51,10 +51,10 @@ type WithFunctions<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[L in keyof F]: { [L in keyof F]: {
[C in keyof F[L]]: CommandSignature<REPLIES, F[L][C], M, F, S, RESP, FLAGS>; [C in keyof F[L]]: CommandSignature<REPLIES, F[L][C], M, F, S, RESP, TYPE_MAPPING>;
}; };
}; };
@@ -64,9 +64,9 @@ type WithScripts<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[P in keyof S]: CommandSignature<REPLIES, S[P], M, F, S, RESP, FLAGS>; [P in keyof S]: CommandSignature<REPLIES, S[P], M, F, S, RESP, TYPE_MAPPING>;
}; };
export type RedisClientMultiCommandType< export type RedisClientMultiCommandType<
@@ -75,13 +75,13 @@ export type RedisClientMultiCommandType<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = ( > = (
RedisClientMultiCommand<REPLIES> & RedisClientMultiCommand<REPLIES> &
WithCommands<REPLIES, M, F, S, RESP, FLAGS> & WithCommands<REPLIES, M, F, S, RESP, TYPE_MAPPING> &
WithModules<REPLIES, M, F, S, RESP, FLAGS> & WithModules<REPLIES, M, F, S, RESP, TYPE_MAPPING> &
WithFunctions<REPLIES, M, F, S, RESP, FLAGS> & WithFunctions<REPLIES, M, F, S, RESP, TYPE_MAPPING> &
WithScripts<REPLIES, M, F, S, RESP, FLAGS> WithScripts<REPLIES, M, F, S, RESP, TYPE_MAPPING>
); );
export default class RedisClientMultiCommand<REPLIES = []> { export default class RedisClientMultiCommand<REPLIES = []> {

View File

@@ -46,7 +46,7 @@ interface CreateSocketReturn<T> {
export type RedisSocketInitiator = () => Promise<void>; export type RedisSocketInitiator = () => Promise<void>;
export default class RedisSocket extends EventEmitter { export default class RedisSocket extends EventEmitter {
static #initiateOptions(options?: RedisSocketOptions): RedisSocketOptions { private static _initiateOptions(options?: RedisSocketOptions): RedisSocketOptions {
options ??= {}; options ??= {};
if (!(options as net.IpcSocketConnectOpts).path) { if (!(options as net.IpcSocketConnectOpts).path) {
(options as net.TcpSocketConnectOpts).port ??= 6379; (options as net.TcpSocketConnectOpts).port ??= 6379;
@@ -60,7 +60,7 @@ export default class RedisSocket extends EventEmitter {
return options; return options;
} }
static #isTlsSocket(options: RedisSocketOptions): options is RedisTlsSocketOptions { private static _isTlsSocket(options: RedisSocketOptions): options is RedisTlsSocketOptions {
return (options as RedisTlsSocketOptions).tls === true; return (options as RedisTlsSocketOptions).tls === true;
} }
@@ -96,7 +96,7 @@ export default class RedisSocket extends EventEmitter {
super(); super();
this._initiator = initiator; this._initiator = initiator;
this._options = RedisSocket.#initiateOptions(options); this._options = RedisSocket._initiateOptions(options);
} }
private _reconnectStrategy(retries: number, cause: Error) { private _reconnectStrategy(retries: number, cause: Error) {
@@ -176,7 +176,7 @@ export default class RedisSocket extends EventEmitter {
private _createSocket(): Promise<net.Socket | tls.TLSSocket> { private _createSocket(): Promise<net.Socket | tls.TLSSocket> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const { connectEvent, socket } = RedisSocket.#isTlsSocket(this._options) ? const { connectEvent, socket } = RedisSocket._isTlsSocket(this._options) ?
this._createTlsSocket() : this._createTlsSocket() :
this._createNetSocket(); this._createNetSocket();

View File

@@ -1,6 +1,6 @@
import COMMANDS from '../commands'; import COMMANDS from '../commands';
import RedisMultiCommand, { MULTI_REPLY, MultiReply, MultiReplyType } from '../multi-command'; import RedisMultiCommand, { MULTI_REPLY, MultiReply, MultiReplyType } from '../multi-command';
import { ReplyWithFlags, CommandReply, Command, CommandArguments, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TransformReply, RedisScript, RedisFunction, Flags, ReplyUnion, RedisArgument } from '../RESP/types'; import { ReplyWithTypeMapping, CommandReply, Command, CommandArguments, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TransformReply, RedisScript, RedisFunction, TypeMapping, ReplyUnion, RedisArgument } from '../RESP/types';
import { attachConfig, functionArgumentsPrefix, getTransformReply } from '../commander'; import { attachConfig, functionArgumentsPrefix, getTransformReply } from '../commander';
import RedisCluster, { RedisClusterType } from '.'; import RedisCluster, { RedisClusterType } from '.';
@@ -11,14 +11,14 @@ type CommandSignature<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = (...args: Parameters<C['transformArguments']>) => RedisClusterMultiCommandType< > = (...args: Parameters<C['transformArguments']>) => RedisClusterMultiCommandType<
[...REPLIES, ReplyWithFlags<CommandReply<C, RESP>, FLAGS>], [...REPLIES, ReplyWithTypeMapping<CommandReply<C, RESP>, TYPE_MAPPING>],
M, M,
F, F,
S, S,
RESP, RESP,
FLAGS TYPE_MAPPING
>; >;
type WithCommands< type WithCommands<
@@ -27,9 +27,9 @@ type WithCommands<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[P in keyof typeof COMMANDS]: CommandSignature<REPLIES, (typeof COMMANDS)[P], M, F, S, RESP, FLAGS>; [P in keyof typeof COMMANDS]: CommandSignature<REPLIES, (typeof COMMANDS)[P], M, F, S, RESP, TYPE_MAPPING>;
}; };
type WithModules< type WithModules<
@@ -38,10 +38,10 @@ type WithModules<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[P in keyof M]: { [P in keyof M]: {
[C in keyof M[P]]: CommandSignature<REPLIES, M[P][C], M, F, S, RESP, FLAGS>; [C in keyof M[P]]: CommandSignature<REPLIES, M[P][C], M, F, S, RESP, TYPE_MAPPING>;
}; };
}; };
@@ -51,10 +51,10 @@ type WithFunctions<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[L in keyof F]: { [L in keyof F]: {
[C in keyof F[L]]: CommandSignature<REPLIES, F[L][C], M, F, S, RESP, FLAGS>; [C in keyof F[L]]: CommandSignature<REPLIES, F[L][C], M, F, S, RESP, TYPE_MAPPING>;
}; };
}; };
@@ -64,9 +64,9 @@ type WithScripts<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = { > = {
[P in keyof S]: CommandSignature<REPLIES, S[P], M, F, S, RESP, FLAGS>; [P in keyof S]: CommandSignature<REPLIES, S[P], M, F, S, RESP, TYPE_MAPPING>;
}; };
export type RedisClusterMultiCommandType< export type RedisClusterMultiCommandType<
@@ -75,13 +75,13 @@ export type RedisClusterMultiCommandType<
F extends RedisFunctions, F extends RedisFunctions,
S extends RedisScripts, S extends RedisScripts,
RESP extends RespVersions, RESP extends RespVersions,
FLAGS extends Flags TYPE_MAPPING extends TypeMapping
> = ( > = (
RedisClusterMultiCommand<REPLIES> & RedisClusterMultiCommand<REPLIES> &
WithCommands<REPLIES, M, F, S, RESP, FLAGS> & WithCommands<REPLIES, M, F, S, RESP, TYPE_MAPPING> &
WithModules<REPLIES, M, F, S, RESP, FLAGS> & WithModules<REPLIES, M, F, S, RESP, TYPE_MAPPING> &
WithFunctions<REPLIES, M, F, S, RESP, FLAGS> & WithFunctions<REPLIES, M, F, S, RESP, TYPE_MAPPING> &
WithScripts<REPLIES, M, F, S, RESP, FLAGS> WithScripts<REPLIES, M, F, S, RESP, TYPE_MAPPING>
); );
export default class RedisClusterMultiCommand<REPLIES = []> { export default class RedisClusterMultiCommand<REPLIES = []> {

View File

@@ -1,96 +1,77 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import RedisMultiCommand from './multi-command'; import RedisMultiCommand from './multi-command';
import { WatchError } from './errors';
import { SQUARE_SCRIPT } from './client/index.spec'; import { SQUARE_SCRIPT } from './client/index.spec';
describe('Multi Command', () => { describe('Multi Command', () => {
it('generateChainId', () => { it('addCommand', () => {
assert.equal( const multi = new RedisMultiCommand();
typeof RedisMultiCommand.generateChainId(), multi.addCommand(['PING']);
'symbol'
); assert.deepEqual(
multi.queue[0].args,
['PING']
);
});
describe('addScript', () => {
const multi = new RedisMultiCommand();
it('should use EVAL', () => {
multi.addScript(SQUARE_SCRIPT, ['1']);
assert.deepEqual(
Array.from(multi.queue.at(-1).args),
['EVAL', SQUARE_SCRIPT.SCRIPT, '0', '1']
);
}); });
it('addCommand', () => { it('should use EVALSHA', () => {
const multi = new RedisMultiCommand(); multi.addScript(SQUARE_SCRIPT, ['2']);
multi.addCommand(['PING']); assert.deepEqual(
Array.from(multi.queue.at(-1).args),
assert.deepEqual( ['EVALSHA', SQUARE_SCRIPT.SHA1, '0', '2']
multi.queue[0].args, );
['PING']
);
}); });
it('addScript', () => { it('without NUMBER_OF_KEYS', () => {
const multi = new RedisMultiCommand(); multi.addScript({
...SQUARE_SCRIPT,
NUMBER_OF_KEYS: undefined
}, ['2']);
assert.deepEqual(
Array.from(multi.queue.at(-1).args),
['EVALSHA', SQUARE_SCRIPT.SHA1, '2']
);
});
});
multi.addScript(SQUARE_SCRIPT, ['1']); describe('exec', () => {
assert.equal( it('without commands', () => {
multi.scriptsInUse.has(SQUARE_SCRIPT.SHA1), assert.deepEqual(
true new RedisMultiCommand().queue,
); []
assert.deepEqual( );
multi.queue[0].args,
['EVAL', SQUARE_SCRIPT.SCRIPT, '0', '1']
);
multi.addScript(SQUARE_SCRIPT, ['2']);
assert.equal(
multi.scriptsInUse.has(SQUARE_SCRIPT.SHA1),
true
);
assert.deepEqual(
multi.queue[1].args,
['EVALSHA', SQUARE_SCRIPT.SHA1, '0', '2']
);
}); });
describe('exec', () => { it('with commands', () => {
it('without commands', () => { const multi = new RedisMultiCommand();
assert.deepEqual( multi.addCommand(['PING']);
new RedisMultiCommand().queue,
[]
);
});
it('with commands', () => { assert.deepEqual(
const multi = new RedisMultiCommand(); multi.queue,
multi.addCommand(['PING']); [{
args: ['PING'],
assert.deepEqual( transformReply: undefined
multi.queue, }]
[{ );
args: ['PING'],
transformReply: undefined
}]
);
});
}); });
});
describe('handleExecReplies', () => { it('transformReplies', () => {
it('WatchError', () => { const multi = new RedisMultiCommand();
assert.throws( multi.addCommand(['PING'], (reply: string) => reply.substring(0, 2));
() => new RedisMultiCommand().handleExecReplies([null]), assert.deepEqual(
WatchError multi.transformReplies(['PONG']),
); ['PO']
}); );
});
it('with replies', () => {
const multi = new RedisMultiCommand();
multi.addCommand(['PING']);
assert.deepEqual(
multi.handleExecReplies(['OK', 'QUEUED', ['PONG']]),
['PONG']
);
});
});
it('transformReplies', () => {
const multi = new RedisMultiCommand();
multi.addCommand(['PING'], (reply: string) => reply.substring(0, 2));
assert.deepEqual(
multi.transformReplies(['PONG']),
['PO']
);
});
}); });

View File

@@ -29,6 +29,7 @@ export default class RedisMultiCommand {
addScript(script: RedisScript, args: CommandArguments, transformReply?: TransformReply) { addScript(script: RedisScript, args: CommandArguments, transformReply?: TransformReply) {
const redisArgs: CommandArguments = []; const redisArgs: CommandArguments = [];
redisArgs.preserve = args.preserve;
if (this.scriptsInUse.has(script.SHA1)) { if (this.scriptsInUse.has(script.SHA1)) {
redisArgs.push('EVALSHA', script.SHA1); redisArgs.push('EVALSHA', script.SHA1);
} else { } else {
@@ -41,7 +42,6 @@ export default class RedisMultiCommand {
} }
redisArgs.push(...args); redisArgs.push(...args);
redisArgs.preserve = args.preserve;
this.addCommand(redisArgs, transformReply); this.addCommand(redisArgs, transformReply);
} }