You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-06 02:15:48 +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:
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import CONFIG_GET from './CONFIG_GET';
|
||||
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
|
||||
|
||||
describe('GRAPH.CONFIG GET', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
CONFIG_GET.transformArguments('TIMEOUT'),
|
||||
parseArgs(CONFIG_GET, 'TIMEOUT'),
|
||||
['GRAPH.CONFIG', 'GET', 'TIMEOUT']
|
||||
);
|
||||
});
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { RedisArgument, TuplesReply, ArrayReply, BlobStringReply, NumberReply, Command } from '@redis/client/dist/lib/RESP/types';
|
||||
import { RedisArgument, TuplesReply, ArrayReply, BlobStringReply, NumberReply, Command } from '@redis/client/lib/RESP/types';
|
||||
import { CommandParser } from '@redis/client/lib/client/parser';
|
||||
|
||||
type ConfigItemReply = TuplesReply<[
|
||||
configKey: BlobStringReply,
|
||||
@@ -6,10 +7,10 @@ type ConfigItemReply = TuplesReply<[
|
||||
]>;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(configKey: RedisArgument) {
|
||||
return ['GRAPH.CONFIG', 'GET', configKey];
|
||||
parseCommand(parser: CommandParser, configKey: RedisArgument) {
|
||||
parser.push('GRAPH.CONFIG', 'GET', configKey);
|
||||
},
|
||||
transformReply: undefined as unknown as () => ConfigItemReply | ArrayReply<ConfigItemReply>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import CONFIG_SET from './CONFIG_SET';
|
||||
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
|
||||
|
||||
describe('GRAPH.CONFIG SET', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
CONFIG_SET.transformArguments('TIMEOUT', 0),
|
||||
parseArgs(CONFIG_SET, 'TIMEOUT', 0),
|
||||
['GRAPH.CONFIG', 'SET', 'TIMEOUT', '0']
|
||||
);
|
||||
});
|
||||
|
@@ -1,15 +1,11 @@
|
||||
import { RedisArgument, SimpleStringReply, Command } from '@redis/client/dist/lib/RESP/types';
|
||||
import { RedisArgument, SimpleStringReply, Command } from '@redis/client/lib/RESP/types';
|
||||
import { CommandParser } from '@redis/client/lib/client/parser';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(configKey: RedisArgument, value: number) {
|
||||
return [
|
||||
'GRAPH.CONFIG',
|
||||
'SET',
|
||||
configKey,
|
||||
value.toString()
|
||||
];
|
||||
parseCommand(parser: CommandParser, configKey: RedisArgument, value: number) {
|
||||
parser.push('GRAPH.CONFIG', 'SET', configKey, value.toString());
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import DELETE from './DELETE';
|
||||
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
|
||||
|
||||
describe('GRAPH.DELETE', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
DELETE.transformArguments('key'),
|
||||
parseArgs(DELETE, 'key'),
|
||||
['GRAPH.DELETE', 'key']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { RedisArgument, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
|
||||
import { RedisArgument, BlobStringReply, Command } from '@redis/client/lib/RESP/types';
|
||||
import { CommandParser } from '@redis/client/lib/client/parser';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(key: RedisArgument) {
|
||||
return ['GRAPH.DELETE', key];
|
||||
parseCommand(parser: CommandParser, key: RedisArgument) {
|
||||
parser.push('GRAPH.DELETE');
|
||||
parser.pushKey(key);
|
||||
},
|
||||
transformReply: undefined as unknown as () => BlobStringReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import EXPLAIN from './EXPLAIN';
|
||||
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
|
||||
|
||||
describe('GRAPH.EXPLAIN', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
EXPLAIN.transformArguments('key', 'RETURN 0'),
|
||||
parseArgs(EXPLAIN, 'key', 'RETURN 0'),
|
||||
['GRAPH.EXPLAIN', 'key', 'RETURN 0']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,12 @@
|
||||
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
|
||||
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/lib/RESP/types';
|
||||
import { CommandParser } from '@redis/client/lib/client/parser';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(key: RedisArgument, query: RedisArgument) {
|
||||
return ['GRAPH.EXPLAIN', key, query];
|
||||
parseCommand(parser: CommandParser, key: RedisArgument, query: RedisArgument) {
|
||||
parser.push('GRAPH.EXPLAIN');
|
||||
parser.pushKey(key);
|
||||
parser.push(query);
|
||||
},
|
||||
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
|
||||
} as const satisfies Command;
|
||||
|
@@ -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('GRAPH.LIST', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
LIST.transformArguments(),
|
||||
parseArgs(LIST),
|
||||
['GRAPH.LIST']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { ArrayReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
|
||||
import { ArrayReply, BlobStringReply, Command } from '@redis/client/lib/RESP/types';
|
||||
import { CommandParser } from '@redis/client/lib/client/parser';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['GRAPH.LIST'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('GRAPH.LIST');
|
||||
},
|
||||
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import PROFILE from './PROFILE';
|
||||
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
|
||||
|
||||
describe('GRAPH.PROFILE', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
PROFILE.transformArguments('key', 'RETURN 0'),
|
||||
parseArgs(PROFILE, 'key', 'RETURN 0'),
|
||||
['GRAPH.PROFILE', 'key', 'RETURN 0']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,12 @@
|
||||
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/dist/lib/RESP/types';
|
||||
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '@redis/client/lib/RESP/types';
|
||||
import { CommandParser } from '@redis/client/lib/client/parser';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(key: RedisArgument, query: RedisArgument) {
|
||||
return ['GRAPH.PROFILE', key, query];
|
||||
parseCommand(parser: CommandParser, key: RedisArgument, query: RedisArgument) {
|
||||
parser.push('GRAPH.PROFILE');
|
||||
parser.pushKey(key);
|
||||
parser.push(query);
|
||||
},
|
||||
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,12 +1,13 @@
|
||||
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('GRAPH.QUERY', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
QUERY.transformArguments('key', 'query'),
|
||||
parseArgs(QUERY, 'key', 'query'),
|
||||
['GRAPH.QUERY', 'key', 'query']
|
||||
);
|
||||
});
|
||||
@@ -14,7 +15,7 @@ describe('GRAPH.QUERY', () => {
|
||||
describe('params', () => {
|
||||
it('all types', () => {
|
||||
assert.deepEqual(
|
||||
QUERY.transformArguments('key', 'query', {
|
||||
parseArgs(QUERY, 'key', 'query', {
|
||||
params: {
|
||||
null: null,
|
||||
string: '"\\',
|
||||
@@ -30,7 +31,7 @@ describe('GRAPH.QUERY', () => {
|
||||
|
||||
it('TypeError', () => {
|
||||
assert.throws(() => {
|
||||
QUERY.transformArguments('key', 'query', {
|
||||
parseArgs(QUERY, 'key', 'query', {
|
||||
params: {
|
||||
a: Symbol()
|
||||
}
|
||||
@@ -41,7 +42,7 @@ describe('GRAPH.QUERY', () => {
|
||||
|
||||
it('TIMEOUT', () => {
|
||||
assert.deepEqual(
|
||||
QUERY.transformArguments('key', 'query', {
|
||||
parseArgs(QUERY, 'key', 'query', {
|
||||
TIMEOUT: 1
|
||||
}),
|
||||
['GRAPH.QUERY', 'key', 'query', 'TIMEOUT', '1']
|
||||
@@ -50,7 +51,7 @@ describe('GRAPH.QUERY', () => {
|
||||
|
||||
it('compact', () => {
|
||||
assert.deepEqual(
|
||||
QUERY.transformArguments('key', 'query', undefined, true),
|
||||
parseArgs(QUERY, 'key', 'query', undefined, true),
|
||||
['GRAPH.QUERY', 'key', 'query', '--compact']
|
||||
);
|
||||
});
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { RedisArgument, ArrayReply, BlobStringReply, NumberReply, NullReply, TuplesReply, UnwrapReply, Command } from '@redis/client/dist/lib/RESP/types';
|
||||
import { RedisArgument, ArrayReply, BlobStringReply, NumberReply, NullReply, TuplesReply, UnwrapReply, Command } from '@redis/client/lib/RESP/types';
|
||||
import { CommandParser } from '@redis/client/lib/client/parser';
|
||||
|
||||
type Headers = ArrayReply<BlobStringReply>;
|
||||
|
||||
@@ -25,30 +26,28 @@ export interface QueryOptions {
|
||||
TIMEOUT?: number;
|
||||
}
|
||||
|
||||
export function transformQueryArguments(
|
||||
export function parseQueryArguments(
|
||||
command: RedisArgument,
|
||||
parser: CommandParser,
|
||||
graph: RedisArgument,
|
||||
query: RedisArgument,
|
||||
options?: QueryOptions,
|
||||
compact?: boolean
|
||||
) {
|
||||
const args = [
|
||||
command,
|
||||
graph,
|
||||
options?.params ?
|
||||
`CYPHER ${queryParamsToString(options.params)} ${query}` :
|
||||
query
|
||||
];
|
||||
parser.push(command);
|
||||
parser.pushKey(graph);
|
||||
const param = options?.params ?
|
||||
`CYPHER ${queryParamsToString(options.params)} ${query}` :
|
||||
query;
|
||||
parser.push(param);
|
||||
|
||||
if (options?.TIMEOUT !== undefined) {
|
||||
args.push('TIMEOUT', options.TIMEOUT.toString());
|
||||
parser.push('TIMEOUT', options.TIMEOUT.toString());
|
||||
}
|
||||
|
||||
if (compact) {
|
||||
args.push('--compact');
|
||||
parser.push('--compact');
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
function queryParamsToString(params: QueryParams) {
|
||||
@@ -85,9 +84,8 @@ function queryParamToString(param: QueryParam): string {
|
||||
}
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments: transformQueryArguments.bind(undefined, 'GRAPH.QUERY'),
|
||||
parseCommand: parseQueryArguments.bind(undefined, 'GRAPH.QUERY'),
|
||||
transformReply(reply: UnwrapReply<QueryRawReply>) {
|
||||
return reply.length === 1 ? {
|
||||
headers: undefined,
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import RO_QUERY from './RO_QUERY';
|
||||
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
|
||||
|
||||
describe('GRAPH.RO_QUERY', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
RO_QUERY.transformArguments('key', 'query'),
|
||||
parseArgs(RO_QUERY, 'key', 'query'),
|
||||
['GRAPH.RO_QUERY', 'key', 'query']
|
||||
);
|
||||
});
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import { Command } from '@redis/client/dist/lib/RESP/types';
|
||||
import QUERY, { transformQueryArguments } from './QUERY';
|
||||
import { Command } from '@redis/client/lib/RESP/types';
|
||||
import QUERY, { parseQueryArguments } from './QUERY';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: QUERY.FIRST_KEY_INDEX,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments: transformQueryArguments.bind(undefined, 'GRAPH.RO_QUERY'),
|
||||
parseCommand: parseQueryArguments.bind(undefined, 'GRAPH.RO_QUERY'),
|
||||
transformReply: QUERY.transformReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import SLOWLOG from './SLOWLOG';
|
||||
import { parseArgs } from '@redis/client/lib/commands/generic-transformers';
|
||||
|
||||
describe('GRAPH.SLOWLOG', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
SLOWLOG.transformArguments('key'),
|
||||
parseArgs(SLOWLOG, 'key'),
|
||||
['GRAPH.SLOWLOG', 'key']
|
||||
);
|
||||
});
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, UnwrapReply, Command } from '@redis/client/dist/lib/RESP/types';
|
||||
import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, UnwrapReply, Command } from '@redis/client/lib/RESP/types';
|
||||
import { CommandParser } from '@redis/client/lib/client/parser';
|
||||
|
||||
type SlowLogRawReply = ArrayReply<TuplesReply<[
|
||||
timestamp: BlobStringReply,
|
||||
@@ -8,10 +9,10 @@ type SlowLogRawReply = ArrayReply<TuplesReply<[
|
||||
]>>;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(key: RedisArgument) {
|
||||
return ['GRAPH.SLOWLOG', key];
|
||||
parseCommand(parser: CommandParser, key: RedisArgument) {
|
||||
parser.push('GRAPH.SLOWLOG');
|
||||
parser.pushKey(key);
|
||||
},
|
||||
transformReply(reply: UnwrapReply<SlowLogRawReply>) {
|
||||
return reply.map(log => {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import type { RedisCommands } from '@redis/client/dist/lib/RESP/types';
|
||||
import type { RedisCommands } from '@redis/client/lib/RESP/types';
|
||||
import CONFIG_GET from './CONFIG_GET';
|
||||
import CONFIG_SET from './CONFIG_SET';;
|
||||
import DELETE from './DELETE';
|
||||
|
Reference in New Issue
Block a user