You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-06 02:15:48 +03:00
Update doctest client with latest v4 release (#2844)
This commit is contained in:
@@ -13,32 +13,22 @@ describe('ACL GETUSER', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.aclGetUser', async client => {
|
||||
const expectedReply: any = {
|
||||
passwords: [],
|
||||
commands: '+@all',
|
||||
};
|
||||
const reply = await client.aclGetUser('default');
|
||||
|
||||
assert.ok(Array.isArray(reply.passwords));
|
||||
assert.equal(typeof reply.commands, 'string');
|
||||
assert.ok(Array.isArray(reply.flags));
|
||||
|
||||
if (testUtils.isVersionGreaterThan([7])) {
|
||||
expectedReply.flags = ['on', 'nopass'];
|
||||
expectedReply.keys = '~*';
|
||||
expectedReply.channels = '&*';
|
||||
expectedReply.selectors = [];
|
||||
assert.equal(typeof reply.keys, 'string');
|
||||
assert.equal(typeof reply.channels, 'string');
|
||||
assert.ok(Array.isArray(reply.selectors));
|
||||
} else {
|
||||
expectedReply.keys = ['*'];
|
||||
expectedReply.selectors = undefined;
|
||||
assert.ok(Array.isArray(reply.keys));
|
||||
|
||||
if (testUtils.isVersionGreaterThan([6, 2])) {
|
||||
expectedReply.flags = ['on', 'allkeys', 'allchannels', 'allcommands', 'nopass'];
|
||||
expectedReply.channels = ['*'];
|
||||
} else {
|
||||
expectedReply.flags = ['on', 'allkeys', 'allcommands', 'nopass'];
|
||||
expectedReply.channels = undefined;
|
||||
}
|
||||
if (testUtils.isVersionGreaterThan([6, 2])) {
|
||||
assert.ok(Array.isArray(reply.channels));
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(
|
||||
await client.aclGetUser('default'),
|
||||
expectedReply
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
||||
|
@@ -1,7 +1,10 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments, transformReply } from './CLIENT_INFO';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
|
||||
describe('CLIENT INFO', () => {
|
||||
testUtils.isVersionGreaterThanHook([6, 2]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
@@ -9,34 +12,39 @@ describe('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
|
||||
}
|
||||
);
|
||||
});
|
||||
testUtils.testWithClient('client.clientInfo', async client => {
|
||||
const reply = await client.clientInfo();
|
||||
assert.equal(typeof reply.id, 'number');
|
||||
assert.equal(typeof reply.addr, 'string');
|
||||
assert.equal(typeof reply.laddr, 'string');
|
||||
assert.equal(typeof reply.fd, 'number');
|
||||
assert.equal(typeof reply.name, 'string');
|
||||
assert.equal(typeof reply.age, 'number');
|
||||
assert.equal(typeof reply.idle, 'number');
|
||||
assert.equal(typeof reply.flags, 'string');
|
||||
assert.equal(typeof reply.db, 'number');
|
||||
assert.equal(typeof reply.sub, 'number');
|
||||
assert.equal(typeof reply.psub, 'number');
|
||||
assert.equal(typeof reply.multi, 'number');
|
||||
assert.equal(typeof reply.qbuf, 'number');
|
||||
assert.equal(typeof reply.qbufFree, 'number');
|
||||
assert.equal(typeof reply.argvMem, 'number');
|
||||
assert.equal(typeof reply.obl, 'number');
|
||||
assert.equal(typeof reply.oll, 'number');
|
||||
assert.equal(typeof reply.omem, 'number');
|
||||
assert.equal(typeof reply.totMem, 'number');
|
||||
assert.equal(typeof reply.events, 'string');
|
||||
assert.equal(typeof reply.cmd, 'string');
|
||||
assert.equal(typeof reply.user, 'string');
|
||||
assert.equal(typeof reply.redir, 'number');
|
||||
|
||||
if (testUtils.isVersionGreaterThan([7, 0])) {
|
||||
assert.equal(typeof reply.multiMem, 'number');
|
||||
assert.equal(typeof reply.resp, 'number');
|
||||
}
|
||||
|
||||
if (testUtils.isVersionGreaterThan([7, 0, 3])) {
|
||||
assert.equal(typeof reply.ssub, 'number');
|
||||
}
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
||||
|
@@ -1,11 +1,13 @@
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['CLIENT', 'INFO'];
|
||||
}
|
||||
|
||||
interface ClientInfoReply {
|
||||
export interface ClientInfoReply {
|
||||
id: number;
|
||||
addr: string;
|
||||
laddr: string;
|
||||
laddr?: string; // 6.2
|
||||
fd: number;
|
||||
name: string;
|
||||
age: number;
|
||||
@@ -14,72 +16,79 @@ interface ClientInfoReply {
|
||||
db: number;
|
||||
sub: number;
|
||||
psub: number;
|
||||
ssub?: number; // 7.0.3
|
||||
multi: number;
|
||||
qbuf: number;
|
||||
qbufFree: number;
|
||||
argvMem: number;
|
||||
argvMem?: number; // 6.0
|
||||
multiMem?: number; // 7.0
|
||||
obl: number;
|
||||
oll: number;
|
||||
omem: number;
|
||||
totMem: number;
|
||||
totMem?: number; // 6.0
|
||||
events: string;
|
||||
cmd: string;
|
||||
user: string;
|
||||
redir: number;
|
||||
user?: string; // 6.0
|
||||
redir?: number; // 6.2
|
||||
resp?: number; // 7.0
|
||||
// 7.2
|
||||
libName?: string;
|
||||
libVer?: string;
|
||||
}
|
||||
|
||||
const REGEX = /=([^\s]*)/g;
|
||||
const CLIENT_INFO_REGEX = /([^\s=]+)=([^\s]*)/g;
|
||||
|
||||
export function transformReply(reply: string): ClientInfoReply {
|
||||
const [
|
||||
[, id],
|
||||
[, addr],
|
||||
[, laddr],
|
||||
[, fd],
|
||||
[, name],
|
||||
[, age],
|
||||
[, idle],
|
||||
[, flags],
|
||||
[, db],
|
||||
[, sub],
|
||||
[, psub],
|
||||
[, multi],
|
||||
[, qbuf],
|
||||
[, qbufFree],
|
||||
[, argvMem],
|
||||
[, obl],
|
||||
[, oll],
|
||||
[, omem],
|
||||
[, totMem],
|
||||
[, events],
|
||||
[, cmd],
|
||||
[, user],
|
||||
[, redir]
|
||||
] = [...reply.matchAll(REGEX)];
|
||||
export function transformReply(rawReply: string): ClientInfoReply {
|
||||
const map: Record<string, string> = {};
|
||||
for (const item of rawReply.matchAll(CLIENT_INFO_REGEX)) {
|
||||
map[item[1]] = item[2];
|
||||
}
|
||||
|
||||
return {
|
||||
id: Number(id),
|
||||
addr,
|
||||
laddr,
|
||||
fd: Number(fd),
|
||||
name,
|
||||
age: Number(age),
|
||||
idle: Number(idle),
|
||||
flags,
|
||||
db: Number(db),
|
||||
sub: Number(sub),
|
||||
psub: Number(psub),
|
||||
multi: Number(multi),
|
||||
qbuf: Number(qbuf),
|
||||
qbufFree: Number(qbufFree),
|
||||
argvMem: Number(argvMem),
|
||||
obl: Number(obl),
|
||||
oll: Number(oll),
|
||||
omem: Number(omem),
|
||||
totMem: Number(totMem),
|
||||
events,
|
||||
cmd,
|
||||
user,
|
||||
redir: Number(redir)
|
||||
const reply: ClientInfoReply = {
|
||||
id: Number(map.id),
|
||||
addr: map.addr,
|
||||
fd: Number(map.fd),
|
||||
name: map.name,
|
||||
age: Number(map.age),
|
||||
idle: Number(map.idle),
|
||||
flags: map.flags,
|
||||
db: Number(map.db),
|
||||
sub: Number(map.sub),
|
||||
psub: Number(map.psub),
|
||||
multi: Number(map.multi),
|
||||
qbuf: Number(map.qbuf),
|
||||
qbufFree: Number(map['qbuf-free']),
|
||||
argvMem: Number(map['argv-mem']),
|
||||
obl: Number(map.obl),
|
||||
oll: Number(map.oll),
|
||||
omem: Number(map.omem),
|
||||
totMem: Number(map['tot-mem']),
|
||||
events: map.events,
|
||||
cmd: map.cmd,
|
||||
user: map.user,
|
||||
libName: map['lib-name'],
|
||||
libVer: map['lib-ver'],
|
||||
};
|
||||
|
||||
if (map.laddr !== undefined) {
|
||||
reply.laddr = map.laddr;
|
||||
}
|
||||
|
||||
if (map.redir !== undefined) {
|
||||
reply.redir = Number(map.redir);
|
||||
}
|
||||
|
||||
if (map.ssub !== undefined) {
|
||||
reply.ssub = Number(map.ssub);
|
||||
}
|
||||
|
||||
if (map['multi-mem'] !== undefined) {
|
||||
reply.multiMem = Number(map['multi-mem']);
|
||||
}
|
||||
|
||||
if (map.resp !== undefined) {
|
||||
reply.resp = Number(map.resp);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
@@ -65,6 +65,16 @@ describe('CLIENT KILL', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('MAXAGE', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments({
|
||||
filter: ClientKillFilters.MAXAGE,
|
||||
maxAge: 10
|
||||
}),
|
||||
['CLIENT', 'KILL', 'MAXAGE', '10']
|
||||
);
|
||||
});
|
||||
|
||||
describe('SKIP_ME', () => {
|
||||
it('undefined', () => {
|
||||
assert.deepEqual(
|
||||
|
@@ -6,7 +6,8 @@ export enum ClientKillFilters {
|
||||
ID = 'ID',
|
||||
TYPE = 'TYPE',
|
||||
USER = 'USER',
|
||||
SKIP_ME = 'SKIPME'
|
||||
SKIP_ME = 'SKIPME',
|
||||
MAXAGE = 'MAXAGE'
|
||||
}
|
||||
|
||||
interface KillFilter<T extends ClientKillFilters> {
|
||||
@@ -37,7 +38,11 @@ type KillSkipMe = ClientKillFilters.SKIP_ME | (KillFilter<ClientKillFilters.SKIP
|
||||
skipMe: boolean;
|
||||
});
|
||||
|
||||
type KillFilters = KillAddress | KillLocalAddress | KillId | KillType | KillUser | KillSkipMe;
|
||||
interface KillMaxAge extends KillFilter<ClientKillFilters.MAXAGE> {
|
||||
maxAge: number;
|
||||
}
|
||||
|
||||
type KillFilters = KillAddress | KillLocalAddress | KillId | KillType | KillUser | KillSkipMe | KillMaxAge;
|
||||
|
||||
export function transformArguments(filters: KillFilters | Array<KillFilters>): RedisCommandArguments {
|
||||
const args = ['CLIENT', 'KILL'];
|
||||
@@ -89,6 +94,10 @@ function pushFilter(args: RedisCommandArguments, filter: KillFilters): void {
|
||||
case ClientKillFilters.SKIP_ME:
|
||||
args.push(filter.skipMe ? 'yes' : 'no');
|
||||
break;
|
||||
|
||||
case ClientKillFilters.MAXAGE:
|
||||
args.push(filter.maxAge.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
78
packages/client/lib/commands/CLIENT_LIST.spec.ts
Normal file
78
packages/client/lib/commands/CLIENT_LIST.spec.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments, transformReply } from './CLIENT_LIST';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
|
||||
describe('CLIENT LIST', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CLIENT', 'LIST']
|
||||
);
|
||||
});
|
||||
|
||||
it('with TYPE', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments({
|
||||
TYPE: 'NORMAL'
|
||||
}),
|
||||
['CLIENT', 'LIST', 'TYPE', 'NORMAL']
|
||||
);
|
||||
});
|
||||
|
||||
it('with ID', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments({
|
||||
ID: ['1', '2']
|
||||
}),
|
||||
['CLIENT', 'LIST', 'ID', '1', '2']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.clientList', async client => {
|
||||
const reply = await client.clientList();
|
||||
assert.ok(Array.isArray(reply));
|
||||
|
||||
for (const item of reply) {
|
||||
assert.equal(typeof item.id, 'number');
|
||||
assert.equal(typeof item.addr, 'string');
|
||||
assert.equal(typeof item.fd, 'number');
|
||||
assert.equal(typeof item.name, 'string');
|
||||
assert.equal(typeof item.age, 'number');
|
||||
assert.equal(typeof item.idle, 'number');
|
||||
assert.equal(typeof item.flags, 'string');
|
||||
assert.equal(typeof item.db, 'number');
|
||||
assert.equal(typeof item.sub, 'number');
|
||||
assert.equal(typeof item.psub, 'number');
|
||||
assert.equal(typeof item.multi, 'number');
|
||||
assert.equal(typeof item.qbuf, 'number');
|
||||
assert.equal(typeof item.qbufFree, 'number');
|
||||
assert.equal(typeof item.obl, 'number');
|
||||
assert.equal(typeof item.oll, 'number');
|
||||
assert.equal(typeof item.omem, 'number');
|
||||
assert.equal(typeof item.events, 'string');
|
||||
assert.equal(typeof item.cmd, 'string');
|
||||
|
||||
if (testUtils.isVersionGreaterThan([6, 0])) {
|
||||
assert.equal(typeof item.argvMem, 'number');
|
||||
assert.equal(typeof item.totMem, 'number');
|
||||
assert.equal(typeof item.user, 'string');
|
||||
}
|
||||
|
||||
if (testUtils.isVersionGreaterThan([6, 2])) {
|
||||
assert.equal(typeof item.redir, 'number');
|
||||
assert.equal(typeof item.laddr, 'string');
|
||||
}
|
||||
|
||||
if (testUtils.isVersionGreaterThan([7, 0])) {
|
||||
assert.equal(typeof item.multiMem, 'number');
|
||||
assert.equal(typeof item.resp, 'number');
|
||||
}
|
||||
|
||||
if (testUtils.isVersionGreaterThan([7, 0, 3])) {
|
||||
assert.equal(typeof item.ssub, 'number');
|
||||
}
|
||||
}
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
43
packages/client/lib/commands/CLIENT_LIST.ts
Normal file
43
packages/client/lib/commands/CLIENT_LIST.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { RedisCommandArguments, RedisCommandArgument } from '.';
|
||||
import { pushVerdictArguments } from './generic-transformers';
|
||||
import { transformReply as transformClientInfoReply, ClientInfoReply } from './CLIENT_INFO';
|
||||
|
||||
interface ListFilterType {
|
||||
TYPE: 'NORMAL' | 'MASTER' | 'REPLICA' | 'PUBSUB';
|
||||
ID?: never;
|
||||
}
|
||||
|
||||
interface ListFilterId {
|
||||
ID: Array<RedisCommandArgument>;
|
||||
TYPE?: never;
|
||||
}
|
||||
|
||||
export type ListFilter = ListFilterType | ListFilterId;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(filter?: ListFilter): RedisCommandArguments {
|
||||
let args: RedisCommandArguments = ['CLIENT', 'LIST'];
|
||||
|
||||
if (filter) {
|
||||
if (filter.TYPE !== undefined) {
|
||||
args.push('TYPE', filter.TYPE);
|
||||
} else {
|
||||
args.push('ID');
|
||||
args = pushVerdictArguments(args, filter.ID);
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export function transformReply(rawReply: string): Array<ClientInfoReply> {
|
||||
const split = rawReply.split('\n'),
|
||||
length = split.length - 1,
|
||||
reply: Array<ClientInfoReply> = [];
|
||||
for (let i = 0; i < length; i++) {
|
||||
reply.push(transformClientInfoReply(split[i]));
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
30
packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts
Normal file
30
packages/client/lib/commands/CLIENT_NO-TOUCH.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './CLIENT_NO-TOUCH';
|
||||
|
||||
describe('CLIENT NO-TOUCH', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 2]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('true', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(true),
|
||||
['CLIENT', 'NO-TOUCH', 'ON']
|
||||
);
|
||||
});
|
||||
|
||||
it('false', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(false),
|
||||
['CLIENT', 'NO-TOUCH', 'OFF']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.clientNoTouch', async client => {
|
||||
assert.equal(
|
||||
await client.clientNoTouch(true),
|
||||
'OK'
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
11
packages/client/lib/commands/CLIENT_NO-TOUCH.ts
Normal file
11
packages/client/lib/commands/CLIENT_NO-TOUCH.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { RedisCommandArguments } from '.';
|
||||
|
||||
export function transformArguments(value: boolean): RedisCommandArguments {
|
||||
return [
|
||||
'CLIENT',
|
||||
'NO-TOUCH',
|
||||
value ? 'ON' : 'OFF'
|
||||
];
|
||||
}
|
||||
|
||||
export declare function transformReply(): 'OK' | Buffer;
|
@@ -11,8 +11,9 @@ describe('CLUSTER BUMPEPOCH', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterBumpEpoch', async cluster => {
|
||||
const client = await cluster.nodeClient(cluster.masters[0]);
|
||||
assert.equal(
|
||||
typeof await cluster.getSlotMaster(0).client.clusterBumpEpoch(),
|
||||
typeof await client.clusterBumpEpoch(),
|
||||
'string'
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
|
@@ -11,7 +11,7 @@ describe('CLUSTER COUNT-FAILURE-REPORTS', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterCountFailureReports', async cluster => {
|
||||
const { client } = cluster.getSlotMaster(0);
|
||||
const client = await cluster.nodeClient(cluster.masters[0]);
|
||||
assert.equal(
|
||||
typeof await client.clusterCountFailureReports(
|
||||
await client.clusterMyId()
|
||||
|
@@ -11,8 +11,9 @@ describe('CLUSTER COUNTKEYSINSLOT', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterCountKeysInSlot', async cluster => {
|
||||
const client = await cluster.nodeClient(cluster.masters[0]);
|
||||
assert.equal(
|
||||
typeof await cluster.getSlotMaster(0).client.clusterCountKeysInSlot(0),
|
||||
typeof await client.clusterCountKeysInSlot(0),
|
||||
'number'
|
||||
);
|
||||
}, GLOBAL.CLUSTERS.OPEN);
|
||||
|
@@ -11,7 +11,8 @@ describe('CLUSTER GETKEYSINSLOT', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterGetKeysInSlot', async cluster => {
|
||||
const reply = await cluster.getSlotMaster(0).client.clusterGetKeysInSlot(0, 1);
|
||||
const client = await cluster.nodeClient(cluster.masters[0]),
|
||||
reply = await client.clusterGetKeysInSlot(0, 1);
|
||||
assert.ok(Array.isArray(reply));
|
||||
for (const item of reply) {
|
||||
assert.equal(typeof item, 'string');
|
||||
|
@@ -46,8 +46,9 @@ describe('CLUSTER INFO', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterInfo', async cluster => {
|
||||
const client = await cluster.nodeClient(cluster.masters[0]);
|
||||
assert.notEqual(
|
||||
await cluster.getSlotMaster(0).client.clusterInfo(),
|
||||
await client.clusterInfo(),
|
||||
null
|
||||
);
|
||||
}, GLOBAL.CLUSTERS.OPEN);
|
||||
|
@@ -11,8 +11,9 @@ describe('CLUSTER KEYSLOT', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterKeySlot', async cluster => {
|
||||
const client = await cluster.nodeClient(cluster.masters[0]);
|
||||
assert.equal(
|
||||
typeof await cluster.getSlotMaster(0).client.clusterKeySlot('key'),
|
||||
typeof await client.clusterKeySlot('key'),
|
||||
'number'
|
||||
);
|
||||
}, GLOBAL.CLUSTERS.OPEN);
|
||||
|
@@ -13,7 +13,8 @@ describe('CLUSTER LINKS', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterLinks', async cluster => {
|
||||
const links = await cluster.getSlotMaster(0).client.clusterLinks();
|
||||
const client = await cluster.nodeClient(cluster.masters[0]),
|
||||
links = await client.clusterLinks();
|
||||
assert.ok(Array.isArray(links));
|
||||
for (const link of links) {
|
||||
assert.equal(typeof link.direction, 'string');
|
||||
|
@@ -11,9 +11,11 @@ describe('CLUSTER MYID', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterMyId', async cluster => {
|
||||
const [master] = cluster.masters,
|
||||
client = await cluster.nodeClient(master);
|
||||
assert.equal(
|
||||
typeof await cluster.getSlotMaster(0).client.clusterMyId(),
|
||||
'string'
|
||||
await client.clusterMyId(),
|
||||
master.id
|
||||
);
|
||||
}, GLOBAL.CLUSTERS.OPEN);
|
||||
});
|
||||
|
22
packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts
Normal file
22
packages/client/lib/commands/CLUSTER_MYSHARDID.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './CLUSTER_MYSHARDID';
|
||||
|
||||
describe('CLUSTER MYSHARDID', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 2]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CLUSTER', 'MYSHARDID']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterMyShardId', async cluster => {
|
||||
const client = await cluster.nodeClient(cluster.masters[0]);
|
||||
assert.equal(
|
||||
typeof await client.clusterMyShardId(),
|
||||
'string'
|
||||
);
|
||||
}, GLOBAL.CLUSTERS.OPEN);
|
||||
});
|
7
packages/client/lib/commands/CLUSTER_MYSHARDID.ts
Normal file
7
packages/client/lib/commands/CLUSTER_MYSHARDID.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments() {
|
||||
return ['CLUSTER', 'MYSHARDID'];
|
||||
}
|
||||
|
||||
export declare function transformReply(): string | Buffer;
|
@@ -11,8 +11,9 @@ describe('CLUSTER SAVECONFIG', () => {
|
||||
});
|
||||
|
||||
testUtils.testWithCluster('clusterNode.clusterSaveConfig', async cluster => {
|
||||
const client = await cluster.nodeClient(cluster.masters[0]);
|
||||
assert.equal(
|
||||
await cluster.getSlotMaster(0).client.clusterSaveConfig(),
|
||||
await client.clusterSaveConfig(),
|
||||
'OK'
|
||||
);
|
||||
}, GLOBAL.CLUSTERS.OPEN);
|
||||
|
@@ -13,7 +13,7 @@ type ClusterSlotsRawReply = Array<[
|
||||
...replicas: Array<ClusterSlotsRawNode>
|
||||
]>;
|
||||
|
||||
type ClusterSlotsNode = {
|
||||
export interface ClusterSlotsNode {
|
||||
ip: string;
|
||||
port: number;
|
||||
id: string;
|
||||
|
40
packages/client/lib/commands/HEXPIRE.spec.ts
Normal file
40
packages/client/lib/commands/HEXPIRE.spec.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './HEXPIRE';
|
||||
import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
|
||||
|
||||
describe('HEXPIRE', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field', 1),
|
||||
['HEXPIRE', 'key', '1', 'FIELDS', '1', 'field']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1', 'field2'], 1),
|
||||
['HEXPIRE', 'key', '1', 'FIELDS', '2', 'field1', 'field2']
|
||||
);
|
||||
});
|
||||
|
||||
it('with set option', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1'], 1, 'NX'),
|
||||
['HEXPIRE', 'key', '1', 'NX', 'FIELDS', '1', 'field1']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('hexpire', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hExpire('key', ['field1'], 0),
|
||||
[HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
|
||||
);
|
||||
}, {
|
||||
...GLOBAL.SERVERS.OPEN
|
||||
});
|
||||
});
|
44
packages/client/lib/commands/HEXPIRE.ts
Normal file
44
packages/client/lib/commands/HEXPIRE.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { pushVerdictArgument } from './generic-transformers';
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @enum {number}
|
||||
*/
|
||||
export const HASH_EXPIRATION = {
|
||||
/** @property {number} */
|
||||
/** The field does not exist */
|
||||
FIELD_NOT_EXISTS: -2,
|
||||
/** @property {number} */
|
||||
/** Specified NX | XX | GT | LT condition not met */
|
||||
CONDITION_NOT_MET: 0,
|
||||
/** @property {number} */
|
||||
/** Expiration time was set or updated */
|
||||
UPDATED: 1,
|
||||
/** @property {number} */
|
||||
/** Field deleted because the specified expiration time is in the past */
|
||||
DELETED: 2
|
||||
} as const;
|
||||
|
||||
export type HashExpiration = typeof HASH_EXPIRATION[keyof typeof HASH_EXPIRATION];
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
fields: RedisCommandArgument| Array<RedisCommandArgument>,
|
||||
seconds: number,
|
||||
mode?: 'NX' | 'XX' | 'GT' | 'LT',
|
||||
) {
|
||||
const args = ['HEXPIRE', key, seconds.toString()];
|
||||
|
||||
if (mode) {
|
||||
args.push(mode);
|
||||
}
|
||||
|
||||
args.push('FIELDS');
|
||||
|
||||
return pushVerdictArgument(args, fields);
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<HashExpiration>;
|
49
packages/client/lib/commands/HEXPIREAT.spec.ts
Normal file
49
packages/client/lib/commands/HEXPIREAT.spec.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './HEXPIREAT';
|
||||
import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
|
||||
|
||||
describe('HEXPIREAT', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string + number', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field', 1),
|
||||
['HEXPIREAT', 'key', '1', 'FIELDS', '1', 'field']
|
||||
);
|
||||
});
|
||||
|
||||
it('array + number', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1', 'field2'], 1),
|
||||
['HEXPIREAT', 'key', '1', 'FIELDS', '2', 'field1', 'field2']
|
||||
);
|
||||
});
|
||||
|
||||
it('date', () => {
|
||||
const d = new Date();
|
||||
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1'], d),
|
||||
['HEXPIREAT', 'key', Math.floor(d.getTime() / 1000).toString(), 'FIELDS', '1', 'field1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with set option', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field1', 1, 'GT'),
|
||||
['HEXPIREAT', 'key', '1', 'GT', 'FIELDS', '1', 'field1']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('expireAt', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hExpireAt('key', 'field1', 1),
|
||||
[HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
|
||||
);
|
||||
}, {
|
||||
...GLOBAL.SERVERS.OPEN,
|
||||
});
|
||||
});
|
28
packages/client/lib/commands/HEXPIREAT.ts
Normal file
28
packages/client/lib/commands/HEXPIREAT.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { pushVerdictArgument, transformEXAT } from './generic-transformers';
|
||||
import { HashExpiration } from './HEXPIRE';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
fields: RedisCommandArgument | Array<RedisCommandArgument>,
|
||||
timestamp: number | Date,
|
||||
mode?: 'NX' | 'XX' | 'GT' | 'LT'
|
||||
) {
|
||||
const args = [
|
||||
'HEXPIREAT',
|
||||
key,
|
||||
transformEXAT(timestamp)
|
||||
];
|
||||
|
||||
if (mode) {
|
||||
args.push(mode);
|
||||
}
|
||||
|
||||
args.push('FIELDS')
|
||||
|
||||
return pushVerdictArgument(args, fields);
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<HashExpiration>;
|
32
packages/client/lib/commands/HEXPIRETIME.spec.ts
Normal file
32
packages/client/lib/commands/HEXPIRETIME.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { HASH_EXPIRATION_TIME, transformArguments } from './HEXPIRETIME';
|
||||
|
||||
describe('HEXPIRETIME', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field'),
|
||||
['HEXPIRETIME', 'key', 'FIELDS', '1', 'field']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1', 'field2']),
|
||||
['HEXPIRETIME', 'key', 'FIELDS', '2', 'field1', 'field2']
|
||||
);
|
||||
});
|
||||
})
|
||||
|
||||
testUtils.testWithClient('hExpireTime', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hExpireTime('key', 'field1'),
|
||||
[HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
|
||||
);
|
||||
}, {
|
||||
...GLOBAL.SERVERS.OPEN,
|
||||
});
|
||||
});
|
21
packages/client/lib/commands/HEXPIRETIME.ts
Normal file
21
packages/client/lib/commands/HEXPIRETIME.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { pushVerdictArgument } from './generic-transformers';
|
||||
|
||||
export const HASH_EXPIRATION_TIME = {
|
||||
/** @property {number} */
|
||||
/** The field does not exist */
|
||||
FIELD_NOT_EXISTS: -2,
|
||||
/** @property {number} */
|
||||
/** The field exists but has no associated expire */
|
||||
NO_EXPIRATION: -1,
|
||||
} as const;
|
||||
|
||||
export const FIRST_KEY_INDEX = 1
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
|
||||
return pushVerdictArgument(['HEXPIRETIME', key, 'FIELDS'], fields);
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<number>;
|
33
packages/client/lib/commands/HPERSIST.spec.ts
Normal file
33
packages/client/lib/commands/HPERSIST.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './HPERSIST';
|
||||
import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
|
||||
|
||||
describe('HPERSIST', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field'),
|
||||
['HPERSIST', 'key', 'FIELDS', '1', 'field']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1', 'field2']),
|
||||
['HPERSIST', 'key', 'FIELDS', '2', 'field1', 'field2']
|
||||
);
|
||||
});
|
||||
})
|
||||
|
||||
testUtils.testWithClient('hPersist', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hPersist('key', 'field1'),
|
||||
[HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
|
||||
);
|
||||
}, {
|
||||
...GLOBAL.SERVERS.OPEN,
|
||||
});
|
||||
});
|
10
packages/client/lib/commands/HPERSIST.ts
Normal file
10
packages/client/lib/commands/HPERSIST.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { pushVerdictArgument } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
|
||||
return pushVerdictArgument(['HPERSIST', key, 'FIELDS'], fields);
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<number> | null;
|
40
packages/client/lib/commands/HPEXPIRE.spec.ts
Normal file
40
packages/client/lib/commands/HPEXPIRE.spec.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './HPEXPIRE';
|
||||
import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
|
||||
|
||||
describe('HEXPIRE', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field', 1),
|
||||
['HPEXPIRE', 'key', '1', 'FIELDS', '1', 'field']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1', 'field2'], 1),
|
||||
['HPEXPIRE', 'key', '1', 'FIELDS', '2', 'field1', 'field2']
|
||||
);
|
||||
});
|
||||
|
||||
it('with set option', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1'], 1, 'NX'),
|
||||
['HPEXPIRE', 'key', '1', 'NX', 'FIELDS', '1', 'field1']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('hexpire', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hpExpire('key', ['field1'], 0),
|
||||
[HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
|
||||
);
|
||||
}, {
|
||||
...GLOBAL.SERVERS.OPEN
|
||||
});
|
||||
});
|
24
packages/client/lib/commands/HPEXPIRE.ts
Normal file
24
packages/client/lib/commands/HPEXPIRE.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { pushVerdictArgument } from './generic-transformers';
|
||||
import { HashExpiration } from "./HEXPIRE";
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
fields: RedisCommandArgument | Array<RedisCommandArgument>,
|
||||
ms: number,
|
||||
mode?: 'NX' | 'XX' | 'GT' | 'LT',
|
||||
) {
|
||||
const args = ['HPEXPIRE', key, ms.toString()];
|
||||
|
||||
if (mode) {
|
||||
args.push(mode);
|
||||
}
|
||||
|
||||
args.push('FIELDS')
|
||||
|
||||
return pushVerdictArgument(args, fields);
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<HashExpiration> | null;
|
48
packages/client/lib/commands/HPEXPIREAT.spec.ts
Normal file
48
packages/client/lib/commands/HPEXPIREAT.spec.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './HPEXPIREAT';
|
||||
import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
|
||||
|
||||
describe('HPEXPIREAT', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string + number', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field', 1),
|
||||
['HPEXPIREAT', 'key', '1', 'FIELDS', '1', 'field']
|
||||
);
|
||||
});
|
||||
|
||||
it('array + number', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1', 'field2'], 1),
|
||||
['HPEXPIREAT', 'key', '1', 'FIELDS', '2', 'field1', 'field2']
|
||||
);
|
||||
});
|
||||
|
||||
it('date', () => {
|
||||
const d = new Date();
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1'], d),
|
||||
['HPEXPIREAT', 'key', d.getTime().toString(), 'FIELDS', '1', 'field1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with set option', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1'], 1, 'XX'),
|
||||
['HPEXPIREAT', 'key', '1', 'XX', 'FIELDS', '1', 'field1']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('hpExpireAt', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hpExpireAt('key', ['field1'], 1),
|
||||
[HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
|
||||
);
|
||||
}, {
|
||||
...GLOBAL.SERVERS.OPEN,
|
||||
});
|
||||
});
|
25
packages/client/lib/commands/HPEXPIREAT.ts
Normal file
25
packages/client/lib/commands/HPEXPIREAT.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { pushVerdictArgument, transformEXAT, transformPXAT } from './generic-transformers';
|
||||
import { HashExpiration } from './HEXPIRE';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
fields: RedisCommandArgument | Array<RedisCommandArgument>,
|
||||
timestamp: number | Date,
|
||||
mode?: 'NX' | 'XX' | 'GT' | 'LT'
|
||||
) {
|
||||
const args = ['HPEXPIREAT', key, transformPXAT(timestamp)];
|
||||
|
||||
if (mode) {
|
||||
args.push(mode);
|
||||
}
|
||||
|
||||
args.push('FIELDS')
|
||||
|
||||
return pushVerdictArgument(args, fields);
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<HashExpiration> | null;
|
33
packages/client/lib/commands/HPEXPIRETIME.spec.ts
Normal file
33
packages/client/lib/commands/HPEXPIRETIME.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './HPEXPIRETIME';
|
||||
import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
|
||||
|
||||
describe('HPEXPIRETIME', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field'),
|
||||
['HPEXPIRETIME', 'key', 'FIELDS', '1', 'field']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1', 'field2']),
|
||||
['HPEXPIRETIME', 'key', 'FIELDS', '2', 'field1', 'field2']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('hpExpireTime', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hpExpireTime('key', 'field1'),
|
||||
[HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
|
||||
);
|
||||
}, {
|
||||
...GLOBAL.SERVERS.OPEN
|
||||
});
|
||||
});
|
11
packages/client/lib/commands/HPEXPIRETIME.ts
Normal file
11
packages/client/lib/commands/HPEXPIRETIME.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { pushVerdictArgument } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
|
||||
return pushVerdictArgument(['HPEXPIRETIME', key, 'FIELDS'], fields);
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<number> | null;
|
33
packages/client/lib/commands/HPTTL.spec.ts
Normal file
33
packages/client/lib/commands/HPTTL.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './HPTTL';
|
||||
import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
|
||||
|
||||
describe('HPTTL', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field'),
|
||||
['HPTTL', 'key', 'FIELDS', '1', 'field']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1', 'field2']),
|
||||
['HPTTL', 'key', 'FIELDS', '2', 'field1', 'field2']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('hpTTL', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hpTTL('key', 'field1'),
|
||||
[HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
|
||||
);
|
||||
}, {
|
||||
...GLOBAL.SERVERS.OPEN
|
||||
});
|
||||
});
|
11
packages/client/lib/commands/HPTTL.ts
Normal file
11
packages/client/lib/commands/HPTTL.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { pushVerdictArgument } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
|
||||
return pushVerdictArgument(['HPTTL', key, 'FIELDS'], fields);
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<number> | null;
|
@@ -73,5 +73,18 @@ describe('HSCAN', () => {
|
||||
tuples: []
|
||||
}
|
||||
);
|
||||
|
||||
await Promise.all([
|
||||
client.hSet('key', 'a', '1'),
|
||||
client.hSet('key', 'b', '2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
await client.hScan('key', 0),
|
||||
{
|
||||
cursor: 0,
|
||||
tuples: [{field: 'a', value: '1'}, {field: 'b', value: '2'}]
|
||||
}
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
||||
|
@@ -16,7 +16,7 @@ export function transformArguments(
|
||||
], cursor, options);
|
||||
}
|
||||
|
||||
type HScanRawReply = [RedisCommandArgument, Array<RedisCommandArgument>];
|
||||
export type HScanRawReply = [RedisCommandArgument, Array<RedisCommandArgument>];
|
||||
|
||||
export interface HScanTuple {
|
||||
field: RedisCommandArgument;
|
||||
|
79
packages/client/lib/commands/HSCAN_NOVALUES.spec.ts
Normal file
79
packages/client/lib/commands/HSCAN_NOVALUES.spec.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments, transformReply } from './HSCAN_NOVALUES';
|
||||
|
||||
describe('HSCAN_NOVALUES', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('cusror only', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0),
|
||||
['HSCAN', 'key', '0', 'NOVALUES']
|
||||
);
|
||||
});
|
||||
|
||||
it('with MATCH', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, {
|
||||
MATCH: 'pattern'
|
||||
}),
|
||||
['HSCAN', 'key', '0', 'MATCH', 'pattern', 'NOVALUES']
|
||||
);
|
||||
});
|
||||
|
||||
it('with COUNT', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, {
|
||||
COUNT: 1
|
||||
}),
|
||||
['HSCAN', 'key', '0', 'COUNT', '1', 'NOVALUES']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformReply', () => {
|
||||
it('without keys', () => {
|
||||
assert.deepEqual(
|
||||
transformReply(['0', []]),
|
||||
{
|
||||
cursor: 0,
|
||||
keys: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('with keys', () => {
|
||||
assert.deepEqual(
|
||||
transformReply(['0', ['key1', 'key2']]),
|
||||
{
|
||||
cursor: 0,
|
||||
keys: ['key1', 'key2']
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.hScanNoValues', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hScanNoValues('key', 0),
|
||||
{
|
||||
cursor: 0,
|
||||
keys: []
|
||||
}
|
||||
);
|
||||
|
||||
await Promise.all([
|
||||
client.hSet('key', 'a', '1'),
|
||||
client.hSet('key', 'b', '2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
await client.hScanNoValues('key', 0),
|
||||
{
|
||||
cursor: 0,
|
||||
keys: ['a', 'b']
|
||||
}
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
27
packages/client/lib/commands/HSCAN_NOVALUES.ts
Normal file
27
packages/client/lib/commands/HSCAN_NOVALUES.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '.';
|
||||
import { ScanOptions } from './generic-transformers';
|
||||
import { HScanRawReply, transformArguments as transformHScanArguments } from './HSCAN';
|
||||
|
||||
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './HSCAN';
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
cursor: number,
|
||||
options?: ScanOptions
|
||||
): RedisCommandArguments {
|
||||
const args = transformHScanArguments(key, cursor, options);
|
||||
args.push('NOVALUES');
|
||||
return args;
|
||||
}
|
||||
|
||||
interface HScanNoValuesReply {
|
||||
cursor: number;
|
||||
keys: Array<RedisCommandArgument>;
|
||||
}
|
||||
|
||||
export function transformReply([cursor, rawData]: HScanRawReply): HScanNoValuesReply {
|
||||
return {
|
||||
cursor: Number(cursor),
|
||||
keys: rawData
|
||||
};
|
||||
}
|
34
packages/client/lib/commands/HTTL.spec.ts
Normal file
34
packages/client/lib/commands/HTTL.spec.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './HTTL';
|
||||
import { HASH_EXPIRATION_TIME } from './HEXPIRETIME';
|
||||
|
||||
describe('HTTL', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 4]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'field'),
|
||||
['HTTL', 'key', 'FIELDS', '1', 'field']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', ['field1', 'field2']),
|
||||
['HTTL', 'key', 'FIELDS', '2', 'field1', 'field2']
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
testUtils.testWithClient('hTTL', async client => {
|
||||
assert.deepEqual(
|
||||
await client.hTTL('key', 'field1'),
|
||||
[HASH_EXPIRATION_TIME.FIELD_NOT_EXISTS]
|
||||
);
|
||||
}, {
|
||||
...GLOBAL.SERVERS.OPEN
|
||||
});
|
||||
});
|
11
packages/client/lib/commands/HTTL.ts
Normal file
11
packages/client/lib/commands/HTTL.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { pushVerdictArgument } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(key: RedisCommandArgument, fields: RedisCommandArgument | Array<RedisCommandArgument>) {
|
||||
return pushVerdictArgument(['HTTL', key, 'FIELDS'], fields);
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<number> | null;
|
@@ -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);
|
||||
});
|
||||
|
26
packages/client/lib/commands/LATENCY_HISTORY.spec.ts
Normal file
26
packages/client/lib/commands/LATENCY_HISTORY.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import {strict as assert} from 'assert';
|
||||
import testUtils, {GLOBAL} from '../test-utils';
|
||||
import { transformArguments } from './LATENCY_HISTORY';
|
||||
|
||||
describe('LATENCY HISTORY', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('command'),
|
||||
['LATENCY', 'HISTORY', 'command']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.latencyHistory', async client => {
|
||||
await Promise.all([
|
||||
client.configSet('latency-monitor-threshold', '100'),
|
||||
client.sendCommand(['DEBUG', 'SLEEP', '1'])
|
||||
]);
|
||||
|
||||
const latencyHisRes = await client.latencyHistory('command');
|
||||
assert.ok(Array.isArray(latencyHisRes));
|
||||
for (const [timestamp, latency] of latencyHisRes) {
|
||||
assert.equal(typeof timestamp, 'number');
|
||||
assert.equal(typeof latency, 'number');
|
||||
}
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
27
packages/client/lib/commands/LATENCY_HISTORY.ts
Normal file
27
packages/client/lib/commands/LATENCY_HISTORY.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
export type EventType = (
|
||||
'active-defrag-cycle' |
|
||||
'aof-fsync-always' |
|
||||
'aof-stat' |
|
||||
'aof-rewrite-diff-write' |
|
||||
'aof-rename' |
|
||||
'aof-write' |
|
||||
'aof-write-active-child' |
|
||||
'aof-write-alone' |
|
||||
'aof-write-pending-fsync' |
|
||||
'command' |
|
||||
'expire-cycle' |
|
||||
'eviction-cycle' |
|
||||
'eviction-del' |
|
||||
'fast-command' |
|
||||
'fork' |
|
||||
'rdb-unlink-temp-file'
|
||||
);
|
||||
|
||||
export function transformArguments(event: EventType) {
|
||||
return ['LATENCY', 'HISTORY', event];
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<[
|
||||
timestamp: number,
|
||||
latency: number,
|
||||
]>;
|
27
packages/client/lib/commands/LATENCY_LATEST.spec.ts
Normal file
27
packages/client/lib/commands/LATENCY_LATEST.spec.ts
Normal 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);
|
||||
});
|
12
packages/client/lib/commands/LATENCY_LATEST.ts
Normal file
12
packages/client/lib/commands/LATENCY_LATEST.ts
Normal 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
|
||||
]>;
|
@@ -1,8 +1,24 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import RedisClient from '../client';
|
||||
import { transformArguments } from './PING';
|
||||
|
||||
describe('PING', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('default', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['PING']
|
||||
);
|
||||
});
|
||||
|
||||
it('with message', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('message'),
|
||||
['PING', 'message']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('client.ping', () => {
|
||||
testUtils.testWithClient('string', async client => {
|
||||
assert.equal(
|
||||
@@ -13,7 +29,7 @@ describe('PING', () => {
|
||||
|
||||
testUtils.testWithClient('buffer', async client => {
|
||||
assert.deepEqual(
|
||||
await client.ping(RedisClient.commandOptions({ returnBuffers: true })),
|
||||
await client.ping(client.commandOptions({ returnBuffers: true })),
|
||||
Buffer.from('PONG')
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
|
@@ -1,7 +1,12 @@
|
||||
import { RedisCommandArgument } from '.';
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '.';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['PING'];
|
||||
export function transformArguments(message?: RedisCommandArgument): RedisCommandArguments {
|
||||
const args: RedisCommandArguments = ['PING'];
|
||||
if (message) {
|
||||
args.push(message);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export declare function transformReply(): RedisCommandArgument;
|
||||
|
@@ -1,5 +1,7 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '.';
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
channel: RedisCommandArgument,
|
||||
message: RedisCommandArgument
|
||||
|
30
packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts
Normal file
30
packages/client/lib/commands/PUBSUB_SHARDCHANNELS.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './PUBSUB_SHARDCHANNELS';
|
||||
|
||||
describe('PUBSUB SHARDCHANNELS', () => {
|
||||
testUtils.isVersionGreaterThanHook([7]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('without pattern', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['PUBSUB', 'SHARDCHANNELS']
|
||||
);
|
||||
});
|
||||
|
||||
it('with pattern', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('patter*'),
|
||||
['PUBSUB', 'SHARDCHANNELS', 'patter*']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.pubSubShardChannels', async client => {
|
||||
assert.deepEqual(
|
||||
await client.pubSubShardChannels(),
|
||||
[]
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
13
packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts
Normal file
13
packages/client/lib/commands/PUBSUB_SHARDCHANNELS.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '.';
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
pattern?: RedisCommandArgument
|
||||
): RedisCommandArguments {
|
||||
const args: RedisCommandArguments = ['PUBSUB', 'SHARDCHANNELS'];
|
||||
if (pattern) args.push(pattern);
|
||||
return args;
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<RedisCommandArgument>;
|
48
packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts
Normal file
48
packages/client/lib/commands/PUBSUB_SHARDNUMSUB.spec.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './PUBSUB_SHARDNUMSUB';
|
||||
|
||||
describe('PUBSUB SHARDNUMSUB', () => {
|
||||
testUtils.isVersionGreaterThanHook([7]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['PUBSUB', 'SHARDNUMSUB']
|
||||
);
|
||||
});
|
||||
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('channel'),
|
||||
['PUBSUB', 'SHARDNUMSUB', 'channel']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(['1', '2']),
|
||||
['PUBSUB', 'SHARDNUMSUB', '1', '2']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.pubSubShardNumSub', async client => {
|
||||
assert.deepEqual(
|
||||
await client.pubSubShardNumSub(['foo', 'bar']),
|
||||
Object.create(null, {
|
||||
foo: {
|
||||
value: 0,
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
},
|
||||
bar: {
|
||||
value: 0,
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
}
|
||||
})
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
24
packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts
Normal file
24
packages/client/lib/commands/PUBSUB_SHARDNUMSUB.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { pushVerdictArguments } from './generic-transformers';
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '.';
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
channels?: Array<RedisCommandArgument> | RedisCommandArgument
|
||||
): RedisCommandArguments {
|
||||
const args = ['PUBSUB', 'SHARDNUMSUB'];
|
||||
|
||||
if (channels) return pushVerdictArguments(args, channels);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export function transformReply(rawReply: Array<string | number>): Record<string, number> {
|
||||
const transformedReply = Object.create(null);
|
||||
|
||||
for (let i = 0; i < rawReply.length; i += 2) {
|
||||
transformedReply[rawReply[i]] = rawReply[i + 1];
|
||||
}
|
||||
|
||||
return transformedReply;
|
||||
}
|
74
packages/client/lib/commands/RESTORE.spec.ts
Normal file
74
packages/client/lib/commands/RESTORE.spec.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './RESTORE';
|
||||
|
||||
describe('RESTORE', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, 'value'),
|
||||
['RESTORE', 'key', '0', 'value']
|
||||
);
|
||||
});
|
||||
|
||||
it('with REPLACE', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, 'value', {
|
||||
REPLACE: true
|
||||
}),
|
||||
['RESTORE', 'key', '0', 'value', 'REPLACE']
|
||||
);
|
||||
});
|
||||
|
||||
it('with ABSTTL', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, 'value', {
|
||||
ABSTTL: true
|
||||
}),
|
||||
['RESTORE', 'key', '0', 'value', 'ABSTTL']
|
||||
);
|
||||
});
|
||||
|
||||
it('with IDLETIME', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, 'value', {
|
||||
IDLETIME: 1
|
||||
}),
|
||||
['RESTORE', 'key', '0', 'value', 'IDLETIME', '1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with FREQ', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, 'value', {
|
||||
FREQ: 1
|
||||
}),
|
||||
['RESTORE', 'key', '0', 'value', 'FREQ', '1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with REPLACE, ABSTTL, IDLETIME and FREQ', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, 'value', {
|
||||
REPLACE: true,
|
||||
ABSTTL: true,
|
||||
IDLETIME: 1,
|
||||
FREQ: 2
|
||||
}),
|
||||
['RESTORE', 'key', '0', 'value', 'REPLACE', 'ABSTTL', 'IDLETIME', '1', 'FREQ', '2']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.restore', async client => {
|
||||
const [, dump] = await Promise.all([
|
||||
client.set('source', 'value'),
|
||||
client.dump(client.commandOptions({ returnBuffers: true }), 'source')
|
||||
]);
|
||||
|
||||
assert.equal(
|
||||
await client.restore('destination', 0, dump),
|
||||
'OK'
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
39
packages/client/lib/commands/RESTORE.ts
Normal file
39
packages/client/lib/commands/RESTORE.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '.';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
interface RestoreOptions {
|
||||
REPLACE?: true;
|
||||
ABSTTL?: true;
|
||||
IDLETIME?: number;
|
||||
FREQ?: number;
|
||||
}
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
ttl: number,
|
||||
serializedValue: RedisCommandArgument,
|
||||
options?: RestoreOptions
|
||||
): RedisCommandArguments {
|
||||
const args = ['RESTORE', key, ttl.toString(), serializedValue];
|
||||
|
||||
if (options?.REPLACE) {
|
||||
args.push('REPLACE');
|
||||
}
|
||||
|
||||
if (options?.ABSTTL) {
|
||||
args.push('ABSTTL');
|
||||
}
|
||||
|
||||
if (options?.IDLETIME) {
|
||||
args.push('IDLETIME', options.IDLETIME.toString());
|
||||
}
|
||||
|
||||
if (options?.FREQ) {
|
||||
args.push('FREQ', options.FREQ.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export declare function transformReply(): 'OK';
|
21
packages/client/lib/commands/SPUBLISH.spec.ts
Normal file
21
packages/client/lib/commands/SPUBLISH.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './SPUBLISH';
|
||||
|
||||
describe('SPUBLISH', () => {
|
||||
testUtils.isVersionGreaterThanHook([7]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('channel', 'message'),
|
||||
['SPUBLISH', 'channel', 'message']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.sPublish', async client => {
|
||||
assert.equal(
|
||||
await client.sPublish('channel', 'message'),
|
||||
0
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
14
packages/client/lib/commands/SPUBLISH.ts
Normal file
14
packages/client/lib/commands/SPUBLISH.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '.';
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(
|
||||
channel: RedisCommandArgument,
|
||||
message: RedisCommandArgument
|
||||
): RedisCommandArguments {
|
||||
return ['SPUBLISH', channel, message];
|
||||
}
|
||||
|
||||
export declare function transformReply(): number;
|
@@ -23,20 +23,76 @@ describe('XAUTOCLAIM', () => {
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.xAutoClaim', async client => {
|
||||
await Promise.all([
|
||||
client.xGroupCreate('key', 'group', '$', {
|
||||
MKSTREAM: true
|
||||
}),
|
||||
testUtils.testWithClient('client.xAutoClaim without messages', async client => {
|
||||
const [,, reply] = await Promise.all([
|
||||
client.xGroupCreate('key', 'group', '$', { MKSTREAM: true }),
|
||||
client.xGroupCreateConsumer('key', 'group', 'consumer'),
|
||||
client.xAutoClaim('key', 'group', 'consumer', 1, '0-0')
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
await client.xAutoClaim('key', 'group', 'consumer', 1, '0-0'),
|
||||
{
|
||||
nextId: '0-0',
|
||||
messages: []
|
||||
}
|
||||
);
|
||||
assert.deepEqual(reply, {
|
||||
nextId: '0-0',
|
||||
messages: []
|
||||
});
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
|
||||
testUtils.testWithClient('client.xAutoClaim with messages', async client => {
|
||||
const [,, id,, reply] = await Promise.all([
|
||||
client.xGroupCreate('key', 'group', '$', { MKSTREAM: true }),
|
||||
client.xGroupCreateConsumer('key', 'group', 'consumer'),
|
||||
client.xAdd('key', '*', { foo: 'bar' }),
|
||||
client.xReadGroup('group', 'consumer', { key: 'key', id: '>' }),
|
||||
client.xAutoClaim('key', 'group', 'consumer', 0, '0-0')
|
||||
]);
|
||||
|
||||
assert.deepEqual(reply, {
|
||||
nextId: '0-0',
|
||||
messages: [{
|
||||
id,
|
||||
message: Object.create(null, {
|
||||
foo: {
|
||||
value: 'bar',
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
}
|
||||
})
|
||||
}]
|
||||
});
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
|
||||
testUtils.testWithClient('client.xAutoClaim with trimmed messages', async client => {
|
||||
const [,,,,, id,, reply] = await Promise.all([
|
||||
client.xGroupCreate('key', 'group', '$', { MKSTREAM: true }),
|
||||
client.xGroupCreateConsumer('key', 'group', 'consumer'),
|
||||
client.xAdd('key', '*', { foo: 'bar' }),
|
||||
client.xReadGroup('group', 'consumer', { key: 'key', id: '>' }),
|
||||
client.xTrim('key', 'MAXLEN', 0),
|
||||
client.xAdd('key', '*', { bar: 'baz' }),
|
||||
client.xReadGroup('group', 'consumer', { key: 'key', id: '>' }),
|
||||
client.xAutoClaim('key', 'group', 'consumer', 0, '0-0')
|
||||
]);
|
||||
|
||||
assert.deepEqual(reply, {
|
||||
nextId: '0-0',
|
||||
messages: testUtils.isVersionGreaterThan([7, 0]) ? [{
|
||||
id,
|
||||
message: Object.create(null, {
|
||||
bar: {
|
||||
value: 'baz',
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
}
|
||||
})
|
||||
}] : [null, {
|
||||
id,
|
||||
message: Object.create(null, {
|
||||
bar: {
|
||||
value: 'baz',
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
}
|
||||
})
|
||||
}]
|
||||
});
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '.';
|
||||
import { StreamMessagesReply, transformStreamMessagesReply } from './generic-transformers';
|
||||
import { StreamMessagesNullReply, transformStreamMessagesNullReply } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
@@ -28,12 +28,12 @@ type XAutoClaimRawReply = [RedisCommandArgument, Array<any>];
|
||||
|
||||
interface XAutoClaimReply {
|
||||
nextId: RedisCommandArgument;
|
||||
messages: StreamMessagesReply;
|
||||
messages: StreamMessagesNullReply;
|
||||
}
|
||||
|
||||
export function transformReply(reply: XAutoClaimRawReply): XAutoClaimReply {
|
||||
return {
|
||||
nextId: reply[0],
|
||||
messages: transformStreamMessagesReply(reply[1])
|
||||
messages: transformStreamMessagesNullReply(reply[1])
|
||||
};
|
||||
}
|
||||
|
@@ -83,8 +83,38 @@ describe('XCLAIM', () => {
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
await client.xClaim('key', 'group', 'consumer', 1, '0-0'),
|
||||
await client.xClaim('key', 'group', 'consumer', 0, '0-0'),
|
||||
[]
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
|
||||
testUtils.testWithClient('client.xClaim with a message', async client => {
|
||||
await client.xGroupCreate('key', 'group', '$', { MKSTREAM: true });
|
||||
const id = await client.xAdd('key', '*', { foo: 'bar' });
|
||||
await client.xReadGroup('group', 'consumer', { key: 'key', id: '>' });
|
||||
|
||||
assert.deepEqual(
|
||||
await client.xClaim('key', 'group', 'consumer', 0, id),
|
||||
[{
|
||||
id,
|
||||
message: Object.create(null, { 'foo': {
|
||||
value: 'bar',
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
} })
|
||||
}]
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
|
||||
testUtils.testWithClient('client.xClaim with a trimmed message', async client => {
|
||||
await client.xGroupCreate('key', 'group', '$', { MKSTREAM: true });
|
||||
const id = await client.xAdd('key', '*', { foo: 'bar' });
|
||||
await client.xReadGroup('group', 'consumer', { key: 'key', id: '>' });
|
||||
await client.xTrim('key', 'MAXLEN', 0);
|
||||
|
||||
assert.deepEqual(
|
||||
await client.xClaim('key', 'group', 'consumer', 0, id),
|
||||
testUtils.isVersionGreaterThan([7, 0]) ? []: [null]
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
||||
|
@@ -45,4 +45,4 @@ export function transformArguments(
|
||||
return args;
|
||||
}
|
||||
|
||||
export { transformStreamMessagesReply as transformReply } from './generic-transformers';
|
||||
export { transformStreamMessagesNullReply as transformReply } from './generic-transformers';
|
||||
|
@@ -13,17 +13,19 @@ describe('XINFO CONSUMERS', () => {
|
||||
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,
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
@@ -15,12 +15,14 @@ type XInfoConsumersReply = Array<{
|
||||
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]
|
||||
}));
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import {
|
||||
transformStringNumberInfinityArgument,
|
||||
transformTuplesReply,
|
||||
transformStreamMessagesReply,
|
||||
transformStreamMessagesNullReply,
|
||||
transformStreamsMessagesReply,
|
||||
transformSortedSetWithScoresReply,
|
||||
pushGeoCountArgument,
|
||||
@@ -219,6 +220,38 @@ describe('Generic Transformers', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('transformStreamMessagesNullReply', () => {
|
||||
assert.deepEqual(
|
||||
transformStreamMessagesNullReply([null, ['0-0', ['0key', '0value']]]),
|
||||
[null, {
|
||||
id: '0-0',
|
||||
message: Object.create(null, {
|
||||
'0key': {
|
||||
value: '0value',
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
}
|
||||
})
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
it('transformStreamMessagesNullReply', () => {
|
||||
assert.deepEqual(
|
||||
transformStreamMessagesNullReply([null, ['0-1', ['11key', '11value']]]),
|
||||
[null, {
|
||||
id: '0-1',
|
||||
message: Object.create(null, {
|
||||
'11key': {
|
||||
value: '11value',
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
}
|
||||
})
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
describe('transformStreamsMessagesReply', () => {
|
||||
it('null', () => {
|
||||
assert.equal(
|
||||
|
@@ -92,19 +92,27 @@ export interface StreamMessageReply {
|
||||
message: Record<string, RedisCommandArgument>;
|
||||
}
|
||||
|
||||
export function transformStreamMessageReply([id, message]: Array<any>): StreamMessageReply {
|
||||
return {
|
||||
id,
|
||||
message: transformTuplesReply(message)
|
||||
};
|
||||
}
|
||||
|
||||
export function transformStreamMessageNullReply(reply: Array<any>): StreamMessageReply | null {
|
||||
if (reply === null) return null;
|
||||
return transformStreamMessageReply(reply);
|
||||
}
|
||||
|
||||
|
||||
export type StreamMessagesReply = Array<StreamMessageReply>;
|
||||
|
||||
export function transformStreamMessagesReply(reply: Array<any>): StreamMessagesReply {
|
||||
const messages = [];
|
||||
return reply.map(transformStreamMessageReply);
|
||||
}
|
||||
|
||||
for (const [id, message] of reply) {
|
||||
messages.push({
|
||||
id,
|
||||
message: transformTuplesReply(message)
|
||||
});
|
||||
}
|
||||
|
||||
return messages;
|
||||
export type StreamMessagesNullReply = Array<StreamMessageReply | null>;
|
||||
export function transformStreamMessagesNullReply(reply: Array<any>): StreamMessagesNullReply {
|
||||
return reply.map(transformStreamMessageNullReply);
|
||||
}
|
||||
|
||||
export type StreamsMessagesReply = Array<{
|
||||
@@ -137,7 +145,6 @@ export function transformSortedSetMemberNullReply(
|
||||
export function transformSortedSetMemberReply(
|
||||
reply: [RedisCommandArgument, RedisCommandArgument]
|
||||
): ZMember {
|
||||
|
||||
return {
|
||||
value: reply[0],
|
||||
score: transformNumberInfinityReply(reply[1])
|
||||
|
Reference in New Issue
Block a user