You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-17 19:41:06 +03:00
implement a couple of more commands, make cluster random iterator be per node (instead of per slot)
This commit is contained in:
@@ -239,7 +239,7 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
||||
}
|
||||
|
||||
callback(err);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
for (const name of Object.keys(COMMANDS)) {
|
||||
|
@@ -75,18 +75,17 @@ export default class RedisClusterSlots<M extends RedisModules, S extends RedisLu
|
||||
const promises: Array<Promise<void>> = [],
|
||||
clientsInUse = new Set<string>();
|
||||
for (const master of masters) {
|
||||
const masterClient = this.#initiateClientForNode(master, false, clientsInUse, promises),
|
||||
replicasClients = this.#options.useReplicas ?
|
||||
const slot = {
|
||||
master: this.#initiateClientForNode(master, false, clientsInUse, promises),
|
||||
replicas: this.#options.useReplicas ?
|
||||
master.replicas.map(replica => this.#initiateClientForNode(replica, true, clientsInUse, promises)) :
|
||||
[];
|
||||
[],
|
||||
iterator: undefined // will be initiated in use
|
||||
};
|
||||
|
||||
for (const slot of master.slots) {
|
||||
for (let i = slot.from; i < slot.to; i++) {
|
||||
this.#slots[i] = {
|
||||
master: masterClient,
|
||||
replicas: replicasClients,
|
||||
iterator: undefined // will be initiated in use
|
||||
};
|
||||
for (const { from, to } of master.slots) {
|
||||
for (let i = from; i < to; i++) {
|
||||
this.#slots[i] = slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
lib/commands/CLIENT_INFO.spec.ts
Normal file
42
lib/commands/CLIENT_INFO.spec.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments, transformReply } from './CLIENT_INFO';
|
||||
|
||||
describe('CLIENT INFO', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CLIENT', 'INFO']
|
||||
);
|
||||
});
|
||||
|
||||
it('transformReply', () => {
|
||||
assert.deepEqual(
|
||||
transformReply('id=526512 addr=127.0.0.1:36244 laddr=127.0.0.1:6379 fd=8 name= age=11213 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1\n'),
|
||||
{
|
||||
id: 526512,
|
||||
addr: '127.0.0.1:36244',
|
||||
laddr: '127.0.0.1:6379',
|
||||
fd: 8,
|
||||
name: '',
|
||||
age: 11213,
|
||||
idle: 0,
|
||||
flags: 'N',
|
||||
db: 0,
|
||||
sub: 0,
|
||||
psub: 0,
|
||||
multi: -1,
|
||||
qbuf: 26,
|
||||
qbufFree: 40928,
|
||||
argvMem: 10,
|
||||
obl: 0,
|
||||
oll: 0,
|
||||
omem: 0,
|
||||
totMem: 61466,
|
||||
events: 'r',
|
||||
cmd: 'client',
|
||||
user: 'default',
|
||||
redir: -1
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
36
lib/commands/FLUSHDB.spec.ts
Normal file
36
lib/commands/FLUSHDB.spec.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
import { RedisFlushModes } from './FLUSHALL';
|
||||
import { transformArguments } from './FLUSHDB';
|
||||
|
||||
describe('FLUSHDB', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('default', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['FLUSHDB']
|
||||
);
|
||||
});
|
||||
|
||||
it('ASYNC', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(RedisFlushModes.ASYNC),
|
||||
['FLUSHDB', 'ASYNC']
|
||||
);
|
||||
});
|
||||
|
||||
it('SYNC', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(RedisFlushModes.SYNC),
|
||||
['FLUSHDB', 'SYNC']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.flushDb', async client => {
|
||||
assert.equal(
|
||||
await client.flushDb(),
|
||||
'OK'
|
||||
);
|
||||
});
|
||||
});
|
14
lib/commands/FLUSHDB.ts
Normal file
14
lib/commands/FLUSHDB.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RedisFlushModes } from './FLUSHALL';
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(mode?: RedisFlushModes): Array<string> {
|
||||
const args = ['FLUSHDB'];
|
||||
|
||||
if (mode) {
|
||||
args.push(mode);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
20
lib/commands/LASTSAVE.spec.ts
Normal file
20
lib/commands/LASTSAVE.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils';
|
||||
import { transformArguments } from './LASTSAVE';
|
||||
|
||||
describe('LASTSAVE', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['LASTSAVE']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.lastSave', async client => {
|
||||
assert.ok((await client.lastSave()) instanceof Date);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.lastSave', async cluster => {
|
||||
assert.ok((await cluster.lastSave()) instanceof Date);
|
||||
});
|
||||
});
|
9
lib/commands/LASTSAVE.ts
Normal file
9
lib/commands/LASTSAVE.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['LASTSAVE'];
|
||||
}
|
||||
|
||||
export function transformReply(reply: number): Date {
|
||||
return new Date(reply);
|
||||
}
|
43
lib/commands/LOLWUT.spec.ts
Normal file
43
lib/commands/LOLWUT.spec.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils';
|
||||
import { transformArguments } from './LOLWUT';
|
||||
|
||||
describe('LOLWUT', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['LOLWUT']
|
||||
);
|
||||
});
|
||||
|
||||
it('with version', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(5),
|
||||
['LOLWUT', 'VERSION', '5']
|
||||
);
|
||||
});
|
||||
|
||||
it('with version and optional arguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(5, 1, 2, 3),
|
||||
['LOLWUT', 'VERSION', '5', '1', '2', '3']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.LOLWUT', async client => {
|
||||
assert.equal(
|
||||
typeof (await client.LOLWUT()),
|
||||
'string'
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.LOLWUT', async cluster => {
|
||||
assert.equal(
|
||||
typeof (await cluster.LOLWUT()),
|
||||
'string'
|
||||
);
|
||||
});
|
||||
});
|
19
lib/commands/LOLWUT.ts
Normal file
19
lib/commands/LOLWUT.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(version?: number, ...optionalArguments: Array<number>): Array<string> {
|
||||
const args = ['LOLWUT'];
|
||||
|
||||
if (version) {
|
||||
args.push(
|
||||
'VERSION',
|
||||
version.toString(),
|
||||
...optionalArguments.map(String),
|
||||
);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
26
lib/commands/SETRANGE.spec.ts
Normal file
26
lib/commands/SETRANGE.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils';
|
||||
import { transformArguments } from './SETRANGE';
|
||||
|
||||
describe('SETRANGE', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, 'value'),
|
||||
['SETRANGE', 'key', '0', 'value']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.setRange', async client => {
|
||||
assert.equal(
|
||||
await client.setRange('key', 0, 'value'),
|
||||
5
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.setRange', async cluster => {
|
||||
assert.equal(
|
||||
await cluster.setRange('key', 0, 'value'),
|
||||
5
|
||||
);
|
||||
});
|
||||
});
|
9
lib/commands/SETRANGE.ts
Normal file
9
lib/commands/SETRANGE.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(key: string, offset: number, value: string): Array<string> {
|
||||
return ['SETRANGE', key, offset.toString(), value];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
26
lib/commands/STRLEN.spec.ts
Normal file
26
lib/commands/STRLEN.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils';
|
||||
import { transformArguments } from './STRLEN';
|
||||
|
||||
describe('STRLEN', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key'),
|
||||
['STRLEN', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.strLen', async client => {
|
||||
assert.equal(
|
||||
await client.strLen('key'),
|
||||
0
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.strLen', async cluster => {
|
||||
assert.equal(
|
||||
await cluster.strLen('key'),
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
11
lib/commands/STRLEN.ts
Normal file
11
lib/commands/STRLEN.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(key: string): Array<string> {
|
||||
return ['STRLEN', key];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
@@ -24,6 +24,7 @@ import * as EXISTS from './EXISTS';
|
||||
import * as EXPIRE from './EXPIRE';
|
||||
import * as EXPIREAT from './EXPIREAT';
|
||||
import * as FLUSHALL from './FLUSHALL';
|
||||
import * as FLUSHDB from './FLUSHDB';
|
||||
import * as GET from './GET';
|
||||
import * as HDEL from './HDEL';
|
||||
import * as HEXISTS from './HEXISTS';
|
||||
@@ -45,10 +46,12 @@ import * as INCR from './INCR';
|
||||
import * as INCRBY from './INCRBY';
|
||||
import * as INCRBYFLOAT from './INCRBYFLOAT';
|
||||
import * as KEYS from './KEYS';
|
||||
import * as LASTSAVE from './LASTSAVE';
|
||||
import * as LINDEX from './LINDEX';
|
||||
import * as LINSERT from './LINSERT';
|
||||
import * as LLEN from './LLEN';
|
||||
import * as LMOVE from './LMOVE';
|
||||
import * as LOLWUT from './LOLWUT';
|
||||
import * as LPOP from './LPOP';
|
||||
import * as LPOP_COUNT from './LPOP_COUNT';
|
||||
import * as LPUSH from './LPUSH';
|
||||
@@ -82,6 +85,7 @@ import * as SCARD from './SCARD';
|
||||
import * as SDIFF from './SDIFF';
|
||||
import * as SDIFFSTORE from './SDIFFSTORE';
|
||||
import * as SET from './SET';
|
||||
import * as SETRANGE from './SETRANGE';
|
||||
import * as SINTER from './SINTER';
|
||||
import * as SINTERSTORE from './SINTERSTORE';
|
||||
import * as SISMEMBER from './SISMEMBER';
|
||||
@@ -94,6 +98,7 @@ import * as SRANDMEMBER_COUNT from './SRANDMEMBER_COUNT';
|
||||
import * as SRANDMEMBER from './SRANDMEMBER';
|
||||
import * as SREM from './SREM';
|
||||
import * as SSCAN from './SSCAN';
|
||||
import * as STRLEN from './STRLEN';
|
||||
import * as SUNION from './SUNION';
|
||||
import * as SUNIONSTORE from './SUNIONSTORE';
|
||||
import * as TOUCH from './TOUCH';
|
||||
@@ -211,6 +216,8 @@ export default {
|
||||
expireAt: EXPIREAT,
|
||||
FLUSHALL,
|
||||
flushAll: FLUSHALL,
|
||||
FLUSHDB,
|
||||
flushDb: FLUSHDB,
|
||||
GET,
|
||||
get: GET,
|
||||
HDEL,
|
||||
@@ -253,6 +260,8 @@ export default {
|
||||
incrByFloat: INCRBYFLOAT,
|
||||
KEYS,
|
||||
keys: KEYS,
|
||||
LASTSAVE,
|
||||
lastSave: LASTSAVE,
|
||||
LINDEX,
|
||||
lIndex: LINDEX,
|
||||
LINSERT,
|
||||
@@ -261,6 +270,7 @@ export default {
|
||||
lLen: LLEN,
|
||||
LMOVE,
|
||||
lMove: LMOVE,
|
||||
LOLWUT,
|
||||
LPOP_COUNT,
|
||||
lPopCount: LPOP_COUNT,
|
||||
LPOP,
|
||||
@@ -331,6 +341,8 @@ export default {
|
||||
sInterStore: SINTERSTORE,
|
||||
SET,
|
||||
set: SET,
|
||||
SETRANGE,
|
||||
setRange: SETRANGE,
|
||||
SISMEMBER,
|
||||
sIsMember: SISMEMBER,
|
||||
SMEMBERS,
|
||||
@@ -351,6 +363,8 @@ export default {
|
||||
sRem: SREM,
|
||||
SSCAN,
|
||||
sScan: SSCAN,
|
||||
STRLEN,
|
||||
strLen: STRLEN,
|
||||
SUNION,
|
||||
sUnion: SUNION,
|
||||
SUNIONSTORE,
|
||||
|
@@ -50,9 +50,9 @@ async function spawnPasswordServer(): Promise<void> {
|
||||
}
|
||||
|
||||
async function spawnOpenCluster(): Promise<void> {
|
||||
TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN] = [{
|
||||
port: (await spawnRedisCluster(TestRedisClusters.OPEN, 3))[0]
|
||||
}];
|
||||
TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN] = (await spawnRedisCluster(TestRedisClusters.OPEN, 3)).map(port => ({
|
||||
port
|
||||
}));
|
||||
}
|
||||
|
||||
export function itWithClient(type: TestRedisServers, title: string, fn: (client: RedisClientType<RedisModules, RedisLuaScripts>) => Promise<void>): void {
|
||||
|
Reference in New Issue
Block a user