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

Merge branch 'master' of github.com:redis/node-redis into v5

This commit is contained in:
Leibale
2023-06-19 18:11:46 -04:00
31 changed files with 620 additions and 49 deletions

View File

@@ -24,9 +24,5 @@ describe('LATENCY GRAPH', () => {
typeof await client.latencyGraph('command'),
'string'
);
}, {
serverArguments: testUtils.isVersionGreaterThan([7]) ?
['--enable-debug-command', 'yes'] :
GLOBAL.SERVERS.OPEN.serverArguments
});
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -0,0 +1,27 @@
import {strict as assert} from 'assert';
import testUtils, {GLOBAL} from '../test-utils';
import { transformArguments } from './LATENCY_LATEST';
describe('LATENCY LATEST', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments(),
['LATENCY', 'LATEST']
);
});
testUtils.testWithClient('client.latencyLatest', async client => {
await Promise.all([
client.configSet('latency-monitor-threshold', '100'),
client.sendCommand(['DEBUG', 'SLEEP', '1'])
]);
const latency = await client.latencyLatest();
assert.ok(Array.isArray(latency));
for (const [name, timestamp, latestLatency, allTimeLatency] of latency) {
assert.equal(typeof name, 'string');
assert.equal(typeof timestamp, 'number');
assert.equal(typeof latestLatency, 'number');
assert.equal(typeof allTimeLatency, 'number');
}
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -0,0 +1,12 @@
import { RedisCommandArguments } from '.';
export function transformArguments(): RedisCommandArguments {
return ['LATENCY', 'LATEST'];
}
export declare function transformReply(): Array<[
name: string,
timestamp: number,
latestLatency: number,
allTimeLatency: number
]>;

View File

@@ -13,17 +13,19 @@
// it('transformReply', () => {
// assert.deepEqual(
// transformReply([
// ['name', 'Alice', 'pending', 1, 'idle', 9104628],
// ['name', 'Bob', 'pending', 1, 'idle', 83841983]
// ['name', 'Alice', 'pending', 1, 'idle', 9104628, 'inactive', 9281221],
// ['name', 'Bob', 'pending', 1, 'idle', 83841983, 'inactive', 7213871]
// ]),
// [{
// name: 'Alice',
// pending: 1,
// idle: 9104628
// idle: 9104628,
// inactive: 9281221,
// }, {
// name: 'Bob',
// pending: 1,
// idle: 83841983
// idle: 83841983,
// inactive: 7213871,
// }]
// );
// });

View File

@@ -15,12 +15,14 @@
// name: RedisCommandArgument;
// pending: number;
// idle: number;
// inactive: number;
// }>;
// export function transformReply(rawReply: Array<any>): XInfoConsumersReply {
// return rawReply.map(consumer => ({
// name: consumer[1],
// pending: consumer[3],
// idle: consumer[5]
// idle: consumer[5],
// inactive: consumer[7]
// }));
// }

View File

@@ -2,18 +2,24 @@ import TestUtils from '@redis/test-utils';
import { SinonSpy } from 'sinon';
import { promiseTimeout } from './utils';
export default new TestUtils({
dockerImageName: 'redis',
dockerImageVersionArgument: 'redis-version'
const utils = new TestUtils({
dockerImageName: 'redis',
dockerImageVersionArgument: 'redis-version'
});
export default utils;
const DEBUG_MODE_ARGS = utils.isVersionGreaterThan([7]) ?
['--enable-debug-command', 'yes'] :
[];
export const GLOBAL = {
SERVERS: {
OPEN: {
serverArguments: []
serverArguments: [...DEBUG_MODE_ARGS]
},
PASSWORD: {
serverArguments: ['--requirepass', 'password'],
serverArguments: ['--requirepass', 'password', ...DEBUG_MODE_ARGS],
clientOptions: {
password: 'password'
}
@@ -21,10 +27,10 @@ export const GLOBAL = {
},
CLUSTERS: {
OPEN: {
serverArguments: []
serverArguments: [...DEBUG_MODE_ARGS]
},
PASSWORD: {
serverArguments: ['--requirepass', 'password'],
serverArguments: ['--requirepass', 'password', ...DEBUG_MODE_ARGS],
clusterConfiguration: {
defaults: {
password: 'password'
@@ -32,7 +38,7 @@ export const GLOBAL = {
}
},
WITH_REPLICAS: {
serverArguments: [],
serverArguments: [...DEBUG_MODE_ARGS],
numberOfMasters: 2,
numberOfReplicas: 1,
clusterConfiguration: {

View File

@@ -68,7 +68,7 @@ describe('Graph', () => {
// check with and without metadata cache
for (let i = 0; i < 2; i++) {
const { data } = await graph.query('CREATE ()-[edge :edge]->() RETURN edge');
const { data } = await graph.query<any>('CREATE ()-[edge :edge]->() RETURN edge');
assert.ok(Array.isArray(data));
assert.equal(data.length, 1);
assert.equal(typeof data[0].edge.id, 'number');
@@ -85,7 +85,7 @@ describe('Graph', () => {
// check with and without metadata cache
for (let i = 0; i < 2; i++) {
const { data } = await graph.query('CREATE (node :node { p: 0 }) RETURN node');
const { data } = await graph.query<any>('CREATE (node :node { p: 0 }) RETURN node');
assert.ok(Array.isArray(data));
assert.equal(data.length, 1);
assert.equal(typeof data[0].node.id, 'number');
@@ -98,7 +98,7 @@ describe('Graph', () => {
const graph = new Graph(client as any, 'graph'),
[, { data }] = await Promise.all([
await graph.query('CREATE ()-[:edge]->()'),
await graph.roQuery('MATCH path = ()-[:edge]->() RETURN path')
await graph.roQuery<any>('MATCH path = ()-[:edge]->() RETURN path')
]);
assert.ok(Array.isArray(data));

View File

@@ -1,6 +1,6 @@
# @redis/json
This package provides support for the [RedisJSON](https://redisjson.io) module, which adds JSON as a native data type to Redis. It extends the [Node Redis client](https://github.com/redis/node-redis) to include functions for each of the RedisJSON commands.
This package provides support for the [RedisJSON](https://redis.io/docs/stack/json/) module, which adds JSON as a native data type to Redis. It extends the [Node Redis client](https://github.com/redis/node-redis) to include functions for each of the RedisJSON commands.
To use these extra commands, your Redis server must have the RedisJSON module installed.
@@ -10,7 +10,7 @@ For a complete example, see [`managing-json.js`](https://github.com/redis/node-r
### Storing JSON Documents in Redis
The [`JSON.SET`](https://oss.redis.com/redisjson/commands/#jsonset) command stores a JSON value at a given JSON Path in a Redis key.
The [`JSON.SET`](https://redis.io/commands/json.set/) command stores a JSON value at a given JSON Path in a Redis key.
Here, we'll store a JSON document in the root of the Redis key "`mydoc`":
@@ -37,11 +37,11 @@ await client.json.set('noderedis:jsondata', '$', {
});
```
For more information about RedisJSON's path syntax, [check out the documentation](https://oss.redis.com/redisjson/path/).
For more information about RedisJSON's path syntax, [check out the documentation](https://redis.io/docs/stack/json/path/).
### Retrieving JSON Documents from Redis
With RedisJSON, we can retrieve all or part(s) of a JSON document using the [`JSON.GET`]() command and one or more JSON Paths. Let's get the name and age of one of the pets:
With RedisJSON, we can retrieve all or part(s) of a JSON document using the [`JSON.GET`](https://redis.io/commands/json.get/) command and one or more JSON Paths. Let's get the name and age of one of the pets:
```javascript
const results = await client.json.get('noderedis:jsondata', {
@@ -62,19 +62,19 @@ const results = await client.json.get('noderedis:jsondata', {
RedisJSON includes commands that can atomically update values in a JSON document, in place in Redis without having to first retrieve the entire document.
Using the [`JSON.NUMINCRBY`](https://oss.redis.com/redisjson/commands/#jsonnumincrby) command, we can update the age of one of the pets like this:
Using the [`JSON.NUMINCRBY`](https://redis.io/commands/json.numincrby/) command, we can update the age of one of the pets like this:
```javascript
await client.json.numIncrBy('noderedis:jsondata', '.pets[1].age', 1);
```
And we can add a new object to the pets array with the [`JSON.ARRAPPEND`](https://oss.redis.com/redisjson/commands/#jsonarrappend) command:
And we can add a new object to the pets array with the [`JSON.ARRAPPEND`](https://redis.io/commands/json.arrappend/) command:
```javascript
await client.json.arrAppend('noderedis:jsondata', '.pets', {
name: 'Robin',
species: 'bird',
age: 1,
isMammal: false
});
await client.json.arrAppend('noderedis:jsondata', '.pets', {
name: 'Robin',
species: 'bird',
age: 1,
isMammal: false
});
```

View File

@@ -454,6 +454,13 @@ describe('AGGREGATE', () => {
['FT.AGGREGATE', 'index', '*', 'DIALECT', '1']
);
});
it('with TIMEOUT', () => {
assert.deepEqual(
transformArguments('index', '*', { TIMEOUT: 10 }),
['FT.AGGREGATE', 'index', '*', 'TIMEOUT', '10']
);
});
});
testUtils.testWithClient('client.ft.aggregate', async client => {

View File

@@ -124,6 +124,7 @@ export interface AggregateOptions {
STEPS?: Array<GroupByStep | SortStep | ApplyStep | LimitStep | FilterStep>;
PARAMS?: Params;
DIALECT?: number;
TIMEOUT?: number;
}
export const FIRST_KEY_INDEX = 1;
@@ -213,6 +214,10 @@ export function pushAggregatehOptions(
args.push('DIALECT', options.DIALECT.toString());
}
if (options?.TIMEOUT !== undefined) {
args.push('TIMEOUT', options.TIMEOUT.toString());
}
return args;
}

View File

@@ -4,15 +4,24 @@ import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './CURSOR_READ';
describe('CURSOR READ', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('index', 0),
['FT.CURSOR', 'READ', 'index', '0']
);
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
transformArguments('index', 0),
['FT.CURSOR', 'READ', 'index', '0']
);
});
it('with COUNT', () => {
assert.deepEqual(
transformArguments('index', 0, { COUNT: 1 }),
['FT.CURSOR', 'READ', 'index', '0', 'COUNT', '1']
);
});
});
testUtils.testWithClient('client.ft.cursorRead', async client => {
const [ ,, { cursor } ] = await Promise.all([
const [, , { cursor }] = await Promise.all([
client.ft.create('idx', {
field: {
type: SchemaFieldTypes.TEXT

View File

@@ -4,16 +4,27 @@ export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
interface CursorReadOptions {
COUNT?: number;
}
export function transformArguments(
index: RedisCommandArgument,
cursor: number
cursor: number,
options?: CursorReadOptions
): RedisCommandArguments {
return [
const args = [
'FT.CURSOR',
'READ',
index,
cursor.toString()
];
if (options?.COUNT) {
args.push('COUNT', options.COUNT.toString());
}
return args;
}
export { transformReply } from './AGGREGATE_WITHCURSOR';

View File

@@ -233,6 +233,15 @@ describe('SEARCH', () => {
['FT.SEARCH', 'index', 'query', 'DIALECT', '1']
);
});
it('with TIMEOUT', () => {
assert.deepEqual(
transformArguments('index', 'query', {
TIMEOUT: 5
}),
['FT.SEARCH', 'index', 'query', 'TIMEOUT', '5']
);
});
});
describe('client.ft.search', () => {

View File

@@ -55,6 +55,7 @@ export interface SearchOptions {
};
PARAMS?: Params;
DIALECT?: number;
TIMEOUT?: number;
}
export function transformArguments(

View File

@@ -510,6 +510,10 @@ export function pushSearchOptions(
args.preserve = true;
}
if (options?.TIMEOUT !== undefined) {
args.push('TIMEOUT', options.TIMEOUT.toString());
}
return args;
}

View File

@@ -1,6 +1,6 @@
{
"name": "@redis/search",
"version": "1.1.2",
"version": "1.1.3",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",