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

new "transform arguments" API for better key and metadata extraction (#2733)

* Parser support with all commands

* remove "dist" from all imports for consistency

* address most of my review comments

* small tweak to multi type mapping handling

* tweak multi commands / fix addScript cases

* nits

* addressed all in person review comments

* revert addCommand/addScript changes to multi-commands

addCommand needs to be there for sendCommand like ability within a multi.

If its there, it might as well be used by createCommand() et al, to avoid repeating code.

addScript is there (even though only used once), but now made private to keep the logic for bookkeeping near each other.
This commit is contained in:
Shaya Potter
2024-10-31 18:16:59 +02:00
committed by GitHub
parent 5ace34b9c9
commit 4708736f3b
1016 changed files with 6347 additions and 6542 deletions

View File

@@ -1,11 +1,12 @@
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import ADD from './ADD';
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
describe('TOPK.ADD', () => {
it('transformArguments', () => {
assert.deepEqual(
ADD.transformArguments('key', 'item'),
parseArgs(ADD, 'key', 'item'),
['TOPK.ADD', 'key', 'item']
);
});

View File

@@ -1,11 +1,13 @@
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument, pushVariadicArguments } from '@redis/client/dist/lib/commands/generic-transformers';
import { CommandParser } from '@redis/client/lib/client/parser';
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/lib/RESP/types';
import { RedisVariadicArgument } from '@redis/client/lib/commands/generic-transformers';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, items: RedisVariadicArgument) {
return pushVariadicArguments(['TOPK.ADD', key], items);
parseCommand(parser: CommandParser, key: RedisArgument, items: RedisVariadicArgument) {
parser.push('TOPK.ADD');
parser.pushKey(key);
parser.pushVariadic(items);
},
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
} as const satisfies Command;

View File

@@ -1,11 +1,12 @@
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import COUNT from './COUNT';
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
describe('TOPK.COUNT', () => {
it('transformArguments', () => {
assert.deepEqual(
COUNT.transformArguments('key', 'item'),
parseArgs(COUNT, 'key', 'item'),
['TOPK.COUNT', 'key', 'item']
);
});

View File

@@ -1,11 +1,13 @@
import { RedisArgument, ArrayReply, NumberReply, Command } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument, pushVariadicArguments } from '@redis/client/dist/lib/commands/generic-transformers';
import { CommandParser } from '@redis/client/lib/client/parser';
import { RedisArgument, ArrayReply, NumberReply, Command } from '@redis/client/lib/RESP/types';
import { RedisVariadicArgument } from '@redis/client/lib/commands/generic-transformers';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument, items: RedisVariadicArgument) {
return pushVariadicArguments(['TOPK.COUNT', key], items);
parseCommand(parser: CommandParser, key: RedisArgument, items: RedisVariadicArgument) {
parser.push('TOPK.COUNT');
parser.pushKey(key);
parser.pushVariadic(items);
},
transformReply: undefined as unknown as () => ArrayReply<NumberReply>
} as const satisfies Command;

View File

@@ -1,12 +1,13 @@
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import INCRBY from './INCRBY';
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
describe('TOPK.INCRBY', () => {
describe('transformArguments', () => {
it('single item', () => {
assert.deepEqual(
INCRBY.transformArguments('key', {
parseArgs(INCRBY, 'key', {
item: 'item',
incrementBy: 1
}),
@@ -16,7 +17,7 @@ describe('TOPK.INCRBY', () => {
it('multiple items', () => {
assert.deepEqual(
INCRBY.transformArguments('key', [{
parseArgs(INCRBY, 'key', [{
item: 'a',
incrementBy: 1
}, {

View File

@@ -1,32 +1,32 @@
import { RedisArgument, ArrayReply, SimpleStringReply, NullReply, Command } from '@redis/client/dist/lib/RESP/types';
import { CommandParser } from '@redis/client/lib/client/parser';
import { RedisArgument, ArrayReply, SimpleStringReply, NullReply, Command } from '@redis/client/lib/RESP/types';
export interface TopKIncrByItem {
item: string;
incrementBy: number;
}
function pushIncrByItem(args: Array<RedisArgument>, { item, incrementBy }: TopKIncrByItem) {
args.push(item, incrementBy.toString());
function pushIncrByItem(parser: CommandParser, { item, incrementBy }: TopKIncrByItem) {
parser.push(item, incrementBy.toString());
}
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(
parseCommand(
parser: CommandParser,
key: RedisArgument,
items: TopKIncrByItem | Array<TopKIncrByItem>
) {
const args = ['TOPK.INCRBY', key];
parser.push('TOPK.INCRBY');
parser.pushKey(key);
if (Array.isArray(items)) {
for (const item of items) {
pushIncrByItem(args, item);
pushIncrByItem(parser, item);
}
} else {
pushIncrByItem(args, items);
pushIncrByItem(parser, items);
}
return args;
},
transformReply: undefined as unknown as () => ArrayReply<SimpleStringReply | NullReply>
} as const satisfies Command;

View File

@@ -1,11 +1,12 @@
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import INFO from './INFO';
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
describe('TOPK INFO', () => {
it('transformArguments', () => {
assert.deepEqual(
INFO.transformArguments('key'),
parseArgs(INFO, 'key'),
['TOPK.INFO', 'key']
);
});

View File

@@ -1,5 +1,6 @@
import { transformDoubleReply } from '@redis/client/dist/lib/commands/generic-transformers';
import { RedisArgument, TuplesToMapReply, NumberReply, DoubleReply, UnwrapReply, Resp2Reply, Command, SimpleStringReply, TypeMapping } from '@redis/client/dist/lib/RESP/types';
import { CommandParser } from '@redis/client/lib/client/parser';
import { RedisArgument, TuplesToMapReply, NumberReply, DoubleReply, UnwrapReply, Resp2Reply, Command, SimpleStringReply, TypeMapping } from '@redis/client/lib/RESP/types';
import { transformDoubleReply } from '@redis/client/lib/commands/generic-transformers';
import { transformInfoV2Reply } from '../bloom';
export type TopKInfoReplyMap = TuplesToMapReply<[
@@ -10,10 +11,10 @@ export type TopKInfoReplyMap = TuplesToMapReply<[
]>;
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument) {
return ['TOPK.INFO', key];
parseCommand(parser: CommandParser, key: RedisArgument) {
parser.push('TOPK.INFO');
parser.pushKey(key);
},
transformReply: {
2: (reply: UnwrapReply<Resp2Reply<TopKInfoReplyMap>>, preserve?: any, typeMapping?: TypeMapping): TopKInfoReplyMap => {

View File

@@ -1,11 +1,12 @@
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import LIST from './LIST';
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
describe('TOPK.LIST', () => {
it('transformArguments', () => {
assert.deepEqual(
LIST.transformArguments('key'),
parseArgs(LIST, 'key'),
['TOPK.LIST', 'key']
);
});

View File

@@ -1,10 +1,11 @@
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
import { CommandParser } from '@redis/client/lib/client/parser';
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/lib/RESP/types';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument) {
return ['TOPK.LIST', key];
parseCommand(parser: CommandParser, key: RedisArgument) {
parser.push('TOPK.LIST');
parser.pushKey(key);
},
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
} as const satisfies Command;

View File

@@ -1,13 +1,14 @@
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import LIST_WITHCOUNT from './LIST_WITHCOUNT';
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
describe('TOPK.LIST WITHCOUNT', () => {
testUtils.isVersionGreaterThanHook([2, 2, 9]);
it('transformArguments', () => {
assert.deepEqual(
LIST_WITHCOUNT.transformArguments('key'),
parseArgs(LIST_WITHCOUNT, 'key'),
['TOPK.LIST', 'key', 'WITHCOUNT']
);
});

View File

@@ -1,10 +1,12 @@
import { RedisArgument, ArrayReply, BlobStringReply, NumberReply, UnwrapReply, Command } from '@redis/client/dist/lib/RESP/types';
import { CommandParser } from '@redis/client/lib/client/parser';
import { RedisArgument, ArrayReply, BlobStringReply, NumberReply, UnwrapReply, Command } from '@redis/client/lib/RESP/types';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument) {
return ['TOPK.LIST', key, 'WITHCOUNT'];
parseCommand(parser: CommandParser, key: RedisArgument) {
parser.push('TOPK.LIST');
parser.pushKey(key);
parser.push('WITHCOUNT');
},
transformReply(rawReply: UnwrapReply<ArrayReply<BlobStringReply | NumberReply>>) {
const reply: Array<{

View File

@@ -1,11 +1,12 @@
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import QUERY from './QUERY';
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
describe('TOPK.QUERY', () => {
it('transformArguments', () => {
assert.deepEqual(
QUERY.transformArguments('key', 'item'),
parseArgs(QUERY, 'key', 'item'),
['TOPK.QUERY', 'key', 'item']
);
});

View File

@@ -1,11 +1,13 @@
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument, pushVariadicArguments, transformBooleanArrayReply } from '@redis/client/dist/lib/commands/generic-transformers';
import { CommandParser } from '@redis/client/lib/client/parser';
import { RedisArgument, Command } from '@redis/client/lib/RESP/types';
import { RedisVariadicArgument, transformBooleanArrayReply } from '@redis/client/lib/commands/generic-transformers';
export default {
FIRST_KEY_INDEX: undefined,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, items: RedisVariadicArgument) {
return pushVariadicArguments(['TOPK.QUERY', key], items);
parseCommand(parser: CommandParser, key: RedisArgument, items: RedisVariadicArgument) {
parser.push('TOPK.QUERY');
parser.pushKey(key);
parser.pushVariadic(items);
},
transformReply: transformBooleanArrayReply
} as const satisfies Command;

View File

@@ -1,19 +1,20 @@
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import RESERVE from './RESERVE';
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
describe('TOPK.RESERVE', () => {
describe('transformArguments', () => {
it('simple', () => {
assert.deepEqual(
RESERVE.transformArguments('topK', 3),
parseArgs(RESERVE, 'topK', 3),
['TOPK.RESERVE', 'topK', '3']
);
});
it('with options', () => {
assert.deepEqual(
RESERVE.transformArguments('topK', 3, {
parseArgs(RESERVE, 'topK', 3, {
width: 8,
depth: 7,
decay: 0.9

View File

@@ -1,4 +1,5 @@
import { SimpleStringReply, Command, RedisArgument } from '@redis/client/dist/lib/RESP/types';
import { CommandParser } from '@redis/client/lib/client/parser';
import { SimpleStringReply, Command, RedisArgument } from '@redis/client/lib/RESP/types';
export interface TopKReserveOptions {
width: number;
@@ -7,20 +8,19 @@ export interface TopKReserveOptions {
}
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, topK: number, options?: TopKReserveOptions) {
const args = ['TOPK.RESERVE', key, topK.toString()];
parseCommand(parser: CommandParser, key: RedisArgument, topK: number, options?: TopKReserveOptions) {
parser.push('TOPK.RESERVE');
parser.pushKey(key);
parser.push(topK.toString());
if (options) {
args.push(
parser.push(
options.width.toString(),
options.depth.toString(),
options.decay.toString()
);
}
return args;
},
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
} as const satisfies Command;

View File

@@ -1,4 +1,4 @@
import type { RedisCommands } from '@redis/client/dist/lib/RESP/types';
import type { RedisCommands } from '@redis/client/lib/RESP/types';
import ADD from './ADD';
import COUNT from './COUNT';
import INCRBY from './INCRBY';