You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-09 00:22:08 +03:00
V4 (#1624)
* init v4 * add .gitignore to benchmark * spawn redis-servers for tests, add some tests, fix client auth on connect * add tests coverage report * add tests workflow, replace nyc text reporter with text-summary * run tests with node 16.x & redis 6.x only (for now) * add socket events on client, stop reconnectiong when manually calling disconnect, remove abort signal listener when a command is written on the socket * add isOpen boolean getter on client, add maxLength option to command queue, add test for client.multi * move to use CommonJS * add MULTI and EXEC commands to when executing multi command, make client.multi return type innerit the module commands, clean some tests, exclute spec files from coverage report * missing file from commit61edd4f1b5
* exclude spec files from coverage report * add support for options in a command function (.get, .set, ...), add support for the SELECT command, implement a couple of commands, fix client socket reconnection strategy, add support for using replicas (RO) in cluster, and more.. * fix client.blPop test * use which to find redis-server path * change command options to work with Symbol rather then WeakSet * implement more commands * Add support for lua scripts in client & muilti, fix client socket initiator, implement simple cluster nodes discovery strategy * replace `callbackify` with `legacyMode` * add the SCAN command and client.scanIterator * rename scanIterator * init benchmark workflow * fix benchmark workflow * fix benchmark workflow * fix benchmark workflow * push coverage report to Coveralls * fix Coveralls * generator lcov (for Coveralls) * fix .nycrc.json * PubSub * add support for all set commands (including sScanIterator) * support pipeline * fix KEEPTTL in SET * remove console.log * add HyperLogLog commands * update README.md (thanks to @guyroyse) * add support for most of the "keys commands" * fix EXPIREAT.spec.ts * add support for date in both EXPIREAT & EXPIRE * add tests * better cluster nodes discorvery strategy after MOVED error, add PubSub test * fix PubSub UNSUBSCRIBE/PUNSUBSCRIBE without channel and/or listener * fix PubSub * add release-it to dev dependencies * Release 4.0.0-next.0 * fix .npmignore * Release 4.0.0-next.1 * fix links in README.md * fix .npmignore * Release 4.0.0-next.2 * add support for all sorted set commands * add support for most stream commands * add missing file from commit53de279afe
* lots of todo commends * make PubSub test more stable * clean ZPOPMAX * add support for lua scripts and modules in cluster, spawn cluster for tests, add some cluster tests, fix pubsub listener arguments * GET.spec.ts * add support for List commands, fix some Sorted Set commands, add some cluster commands, spawn cluster for testing, add support for command options in cluster, and more * add missing file from commitfaab94fab2
* clean ZRANK and ZREVRANK * add XREAD and XREADGROUP commands * remove unused files * implement a couple of more commands, make cluster random iterator be per node (instead of per slot) * Release 4.0.0-next.3 * app spec files to npmignore * fix some code analyzers (LGTM, deepsource, codeclimate) issues * fix CLUSTER_NODES, add some tests * add HSCAN, clean some commands, add tests for generic transformers * add missing files from0feb35a1fb
* update README.md (thanks to @guyroyse) * handle ASK errors, add some commands and tests * Release 4.0.0-next.4 * replace "modern" with "v4" * remove unused imports * add all ACL subcommands, all MODULE subcommands, and some other commands * remove 2 unused imports * fix BITFIELD command * fix XTRIM spec file * clean code * fix package.json types field * better modules support, fix some bugs in legacy mode, add some tests * remove unused function * add test for hScanIterator * change node mimimum version to 12 (latest LTS) * update tsconfig.json to support node 12, run tests on Redis 5 & 6 and on all node live versions * remove future node releases :P * remove "lib" from ts compiler options * Update tsconfig.json * fix build * run some tests only on supported redis versions, use coveralls parallel mode * fix tests * Do not use "timers/promises", fix "isRedisVersionGreaterThan" * skip AbortController tests when not available * use 'fs'.promises instead of 'fs/promises' * add some missing commands * run GETDEL tests only if the redis version is greater than 6.2 * implement some GEO commands, improve scan generic transformer, expose RPUSHX * fix GEOSEARCH & GEOSEARCHSTORE * use socket.setNoDelay and queueMicrotask to improve latency * commands-queue.ts: String length / byte length counting issue (#1630) * Update commands-queue.ts Hopefully fixing #1628 * Reverted 2fa5ea6, and implemented test for byte length check * Changed back to Buffer.byteLength, due to issue author input. Updated test to look for 4 bytes. * Fixed. There were two places that length was calculated. * Removed redundant string assignment * add 2 bytes test as well Co-authored-by: Leibale Eidelman <leibale1998@gmail.com> * fix scripts in multi * do not hide bugs in redis * fix fore7bf09644b
* remove unused import * implement WATCH command, fix ZRANGESTORE & GEOSEARCHSTORE tests * update README.md Co-authored-by: @GuyRoyse * use typedoc to auto generate documentation * run "npm install" before "npm run documentation" * clean documentation workflow * fix WATCH spec file * increase "CLUSTER_NODE_TIMEOUT" to 5000ms to avoid "CLUSTERDOWN" errors in tests * pull cluster state every 100 ms * await meetPromises before pulling the cluster state * enhance the way commanders (client/multi/cluster) get extended with modules and scripts * add test for socket retry strategy * implement more commands * set GETEX minimum version to 6.2 * remove unused imports * add support for multi in cluster * upgrade dependencies * Release 4.0.0-next.5 * remove unused imports * improve benchmarking * use the same Multi with duplicated clients * exclude some files from the documentation, add some exports, clean code * fix #1636 - handle null in multi.exec * remove unused import * add supoprt for tuples in HSET * add FIRST_KEY_INDEX to HSET * add a bunch of missing commands, fix MSET and HELLO, add some tests * add FIRST_KEY_INDEX to MSET and MSETNX * upgrade actions * fix coverallsapp/github-action version * Update documentation.yml * Update documentation.yml * clean code * remove unused imports * use "npm ci" instead of "npm install" * fix `self` binding on client modules, use connection pool for `duplicateConnection` * add client.executeIsolated, rename "duplicateConnection" to "isolated", update README.md (thanks to @GuyRoyse and @SimonPrickett) * update README (thanks to @GuyRoyse), add some tests * try to fix "cluster is down" errors in tests * try to fix "cluster is down" errors in tests * upgrade dependencies * update package-lock * Release 4.0.0-next.6 * fix #1636 - fix WatchError * fix forf1bf0beebf
- remove .only from multi tests * Release 4.0.0-next.7 * update README and other markdown files Co-authored-by: @GuyRoyse & @SimonPrickett * Doc updates. (#1640) * update docs, upgrade dependencies * fix README * Release 4.0.0-rc.0 * Update README.md * update docs, add `connectTimeout` options, fix tls Co-authored-by: Guy Royse <guy@guyroyse.com> * npm update, "fix" some tests, clean code * fix AssertionError import * fix #1642 - fix XREAD, XREADGROUP and XTRIM * fix #1644 - add the QUIT command * add socket.noDelay and socket.keepAlive configurations * Update README.md (#1645) * Update README.md Fixed issue with how connection string was specified. Now you can have user@host without having to specify a password, which just makes more sense * Update client-configuration.md as well Co-authored-by: Leibale Eidelman <leibale1998@gmail.com> * update socket.reconnectStrategy description * fix borken link in v3-to-v4.md * increase test coverage, fix bug in cluster redirection strategy, implement CLIENT_ID, remove unused EXEC command Co-authored-by: Nova <novaw@warrenservices.co.uk> Co-authored-by: Simon Prickett <simon@crudworks.org> Co-authored-by: Guy Royse <guy@guyroyse.com>
This commit is contained in:
23
lib/commands/ACL_CAT.spec.ts
Normal file
23
lib/commands/ACL_CAT.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './ACL_CAT';
|
||||
|
||||
describe('ACL CAT', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ACL', 'CAT']
|
||||
);
|
||||
});
|
||||
|
||||
it('with categoryName', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('dangerous'),
|
||||
['ACL', 'CAT', 'dangerous']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
13
lib/commands/ACL_CAT.ts
Normal file
13
lib/commands/ACL_CAT.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { transformReplyStringArray } from './generic-transformers';
|
||||
|
||||
export function transformArguments(categoryName?: string): Array<string> {
|
||||
const args = ['ACL', 'CAT'];
|
||||
|
||||
if (categoryName) {
|
||||
args.push(categoryName);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyStringArray;
|
30
lib/commands/ACL_DELUSER.spec.ts
Normal file
30
lib/commands/ACL_DELUSER.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion, itWithClient, TestRedisServers } from '../test-utils';
|
||||
import { transformArguments } from './ACL_DELUSER';
|
||||
|
||||
describe('ACL DELUSER', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('username'),
|
||||
['ACL', 'DELUSER', 'username']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(['1', '2']),
|
||||
['ACL', 'DELUSER', '1', '2']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.aclDelUser', async client => {
|
||||
assert.equal(
|
||||
await client.aclDelUser('dosenotexists'),
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/ACL_DELUSER.ts
Normal file
7
lib/commands/ACL_DELUSER.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export function transformArguments(username: string | Array<string>): Array<string> {
|
||||
return pushVerdictArguments(['ACL', 'DELUSER'], username);
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
23
lib/commands/ACL_GENPASS.spec.ts
Normal file
23
lib/commands/ACL_GENPASS.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './ACL_GENPASS';
|
||||
|
||||
describe('ACL GENPASS', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ACL', 'GENPASS']
|
||||
);
|
||||
});
|
||||
|
||||
it('with bits', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(128),
|
||||
['ACL', 'GENPASS', '128']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
13
lib/commands/ACL_GENPASS.ts
Normal file
13
lib/commands/ACL_GENPASS.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(bits?: number): Array<string> {
|
||||
const args = ['ACL', 'GENPASS'];
|
||||
|
||||
if (bits) {
|
||||
args.push(bits.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
27
lib/commands/ACL_GETUSER.spec.ts
Normal file
27
lib/commands/ACL_GETUSER.spec.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion, itWithClient, TestRedisServers } from '../test-utils';
|
||||
import { transformArguments } from './ACL_GETUSER';
|
||||
|
||||
describe('ACL GETUSER', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('username'),
|
||||
['ACL', 'GETUSER', 'username']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.aclGetUser', async client => {
|
||||
assert.deepEqual(
|
||||
await client.aclGetUser('default'),
|
||||
{
|
||||
flags: ['on', 'allkeys', 'allchannels', 'allcommands', 'nopass'],
|
||||
passwords: [],
|
||||
commands: '+@all',
|
||||
keys: ['*'],
|
||||
channels: ['*']
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
34
lib/commands/ACL_GETUSER.ts
Normal file
34
lib/commands/ACL_GETUSER.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
export function transformArguments(username: string): Array<string> {
|
||||
return ['ACL', 'GETUSER', username];
|
||||
}
|
||||
|
||||
type AclGetUserRawReply = [
|
||||
_: string,
|
||||
flags: Array<string>,
|
||||
_: string,
|
||||
passwords: Array<string>,
|
||||
_: string,
|
||||
commands: string,
|
||||
_: string,
|
||||
keys: Array<string>,
|
||||
_: string,
|
||||
channels: Array<string>
|
||||
];
|
||||
|
||||
interface AclUser {
|
||||
flags: Array<string>;
|
||||
passwords: Array<string>;
|
||||
commands: string;
|
||||
keys: Array<string>;
|
||||
channels: Array<string>
|
||||
}
|
||||
|
||||
export function transformReply(reply: AclGetUserRawReply): AclUser {
|
||||
return {
|
||||
flags: reply[1],
|
||||
passwords: reply[3],
|
||||
commands: reply[5],
|
||||
keys: reply[7],
|
||||
channels: reply[9]
|
||||
};
|
||||
}
|
14
lib/commands/ACL_LIST.spec.ts
Normal file
14
lib/commands/ACL_LIST.spec.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './ACL_LIST';
|
||||
|
||||
describe('ACL LIST', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ACL', 'LIST']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/ACL_LIST.ts
Normal file
7
lib/commands/ACL_LIST.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyStringArray } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['ACL', 'LIST'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyStringArray;
|
14
lib/commands/ACL_LOAD.spec.ts
Normal file
14
lib/commands/ACL_LOAD.spec.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './ACL_SAVE';
|
||||
|
||||
describe('ACL SAVE', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ACL', 'SAVE']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/ACL_LOAD.ts
Normal file
7
lib/commands/ACL_LOAD.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['ACL', 'LOAD'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
53
lib/commands/ACL_LOG.spec.ts
Normal file
53
lib/commands/ACL_LOG.spec.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments, transformReply } from './ACL_LOG';
|
||||
|
||||
describe('ACL LOG', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ACL', 'LOG']
|
||||
);
|
||||
});
|
||||
|
||||
it('with count', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(10),
|
||||
['ACL', 'LOG', '10']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('transformReply', () => {
|
||||
assert.deepEqual(
|
||||
transformReply([[
|
||||
'count',
|
||||
1,
|
||||
'reason',
|
||||
'auth',
|
||||
'context',
|
||||
'toplevel',
|
||||
'object',
|
||||
'AUTH',
|
||||
'username',
|
||||
'someuser',
|
||||
'age-seconds',
|
||||
'4.096',
|
||||
'client-info',
|
||||
'id=6 addr=127.0.0.1:63026 fd=8 name= age=9 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=48 qbuf-free=32720 obl=0 oll=0 omem=0 events=r cmd=auth user=default'
|
||||
]]),
|
||||
[{
|
||||
count: 1,
|
||||
reason: 'auth',
|
||||
context: 'toplevel',
|
||||
object: 'AUTH',
|
||||
username: 'someuser',
|
||||
ageSeconds: 4.096,
|
||||
clientInfo: 'id=6 addr=127.0.0.1:63026 fd=8 name= age=9 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=48 qbuf-free=32720 obl=0 oll=0 omem=0 events=r cmd=auth user=default'
|
||||
}]
|
||||
);
|
||||
});
|
||||
});
|
48
lib/commands/ACL_LOG.ts
Normal file
48
lib/commands/ACL_LOG.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
export function transformArguments(count?: number): Array<string> {
|
||||
const args = ['ACL', 'LOG'];
|
||||
|
||||
if (count) {
|
||||
args.push(count.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
type AclLogRawReply = [
|
||||
_: string,
|
||||
count: number,
|
||||
_: string,
|
||||
reason: string,
|
||||
_: string,
|
||||
context: string,
|
||||
_: string,
|
||||
object: string,
|
||||
_: string,
|
||||
username: string,
|
||||
_: string,
|
||||
ageSeconds: string,
|
||||
_: string,
|
||||
clientInfo: string
|
||||
];
|
||||
|
||||
interface AclLog {
|
||||
count: number;
|
||||
reason: string;
|
||||
context: string;
|
||||
object: string;
|
||||
username: string;
|
||||
ageSeconds: number;
|
||||
clientInfo: string;
|
||||
}
|
||||
|
||||
export function transformReply(reply: Array<AclLogRawReply>): Array<AclLog> {
|
||||
return reply.map(log => ({
|
||||
count: log[1],
|
||||
reason: log[3],
|
||||
context: log[5],
|
||||
object: log[7],
|
||||
username: log[9],
|
||||
ageSeconds: Number(log[11]),
|
||||
clientInfo: log[13]
|
||||
}));
|
||||
}
|
14
lib/commands/ACL_LOG_RESET.spec.ts
Normal file
14
lib/commands/ACL_LOG_RESET.spec.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './ACL_LOG_RESET';
|
||||
|
||||
describe('ACL LOG RESET', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ACL', 'LOG', 'RESET']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/ACL_LOG_RESET.ts
Normal file
7
lib/commands/ACL_LOG_RESET.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['ACL', 'LOG', 'RESET'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
14
lib/commands/ACL_SAVE.spec.ts
Normal file
14
lib/commands/ACL_SAVE.spec.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './ACL_LOAD';
|
||||
|
||||
describe('ACL LOAD', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ACL', 'LOAD']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/ACL_SAVE.ts
Normal file
7
lib/commands/ACL_SAVE.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['ACL', 'SAVE'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
23
lib/commands/ACL_SETUSER.spec.ts
Normal file
23
lib/commands/ACL_SETUSER.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './ACL_SETUSER';
|
||||
|
||||
describe('ACL SETUSER', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('username', 'allkeys'),
|
||||
['ACL', 'SETUSER', 'username', 'allkeys']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('username', ['allkeys', 'allchannels']),
|
||||
['ACL', 'SETUSER', 'username', 'allkeys', 'allchannels']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
7
lib/commands/ACL_SETUSER.ts
Normal file
7
lib/commands/ACL_SETUSER.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(username: string, rule: string | Array<string>): Array<string> {
|
||||
return pushVerdictArguments(['ACL', 'SETUSER', username], rule);
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
14
lib/commands/ACL_USERS.spec.ts
Normal file
14
lib/commands/ACL_USERS.spec.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './ACL_USERS';
|
||||
|
||||
describe('ACL USERS', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ACL', 'USERS']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/ACL_USERS.ts
Normal file
7
lib/commands/ACL_USERS.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyStringArray } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['ACL', 'USERS'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyStringArray;
|
14
lib/commands/ACL_WHOAMI.spec.ts
Normal file
14
lib/commands/ACL_WHOAMI.spec.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './ACL_WHOAMI';
|
||||
|
||||
describe('ACL WHOAMI', () => {
|
||||
describeHandleMinimumRedisVersion([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ACL', 'WHOAMI']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/ACL_WHOAMI.ts
Normal file
7
lib/commands/ACL_WHOAMI.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['ACL', 'WHOAMI'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
11
lib/commands/APPEND.spec.ts
Normal file
11
lib/commands/APPEND.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './APPEND';
|
||||
|
||||
describe('AUTH', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 'value'),
|
||||
['APPEND', 'key', 'value']
|
||||
);
|
||||
});
|
||||
});
|
9
lib/commands/APPEND.ts
Normal file
9
lib/commands/APPEND.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(key: string, value: string): Array<string> {
|
||||
return ['APPEND', key, value];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
11
lib/commands/ASKING.spec.ts
Normal file
11
lib/commands/ASKING.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './ASKING';
|
||||
|
||||
describe('ASKING', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['ASKING']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/ASKING.ts
Normal file
7
lib/commands/ASKING.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['ASKING'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
25
lib/commands/AUTH.spec.ts
Normal file
25
lib/commands/AUTH.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './AUTH';
|
||||
|
||||
describe('AUTH', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('password only', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments({
|
||||
password: 'password'
|
||||
}),
|
||||
['AUTH', 'password']
|
||||
);
|
||||
});
|
||||
|
||||
it('username & password', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments({
|
||||
username: 'username',
|
||||
password: 'password'
|
||||
}),
|
||||
['AUTH', 'username', 'password']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
16
lib/commands/AUTH.ts
Normal file
16
lib/commands/AUTH.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export interface AuthOptions {
|
||||
username?: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export function transformArguments({username, password}: AuthOptions): Array<string> {
|
||||
if (!username) {
|
||||
return ['AUTH', password];
|
||||
}
|
||||
|
||||
return ['AUTH', username, password];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
11
lib/commands/BGREWRITEAOF.spec.ts
Normal file
11
lib/commands/BGREWRITEAOF.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './BGREWRITEAOF';
|
||||
|
||||
describe('BGREWRITEAOF', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['BGREWRITEAOF']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/BGREWRITEAOF.ts
Normal file
7
lib/commands/BGREWRITEAOF.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['BGREWRITEAOF'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
23
lib/commands/BGSAVE.spec.ts
Normal file
23
lib/commands/BGSAVE.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { describe } from 'mocha';
|
||||
import { transformArguments } from './BGSAVE';
|
||||
|
||||
describe('BGSAVE', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['BGSAVE']
|
||||
);
|
||||
});
|
||||
|
||||
it('with SCHEDULE', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments({
|
||||
SCHEDULE: true
|
||||
}),
|
||||
['BGSAVE', 'SCHEDULE']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
17
lib/commands/BGSAVE.ts
Normal file
17
lib/commands/BGSAVE.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
interface BgSaveOptions {
|
||||
SCHEDULE?: true;
|
||||
}
|
||||
|
||||
export function transformArguments(options?: BgSaveOptions): Array<string> {
|
||||
const args = ['BGSAVE'];
|
||||
|
||||
if (options?.SCHEDULE) {
|
||||
args.push('SCHEDULE');
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
31
lib/commands/BITCOUNT.spec.ts
Normal file
31
lib/commands/BITCOUNT.spec.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
import { transformArguments } from './BITCOUNT';
|
||||
|
||||
describe('BITCOUNT', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key'),
|
||||
['BITCOUNT', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
it('with range', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', {
|
||||
start: 0,
|
||||
end: 1
|
||||
}),
|
||||
['BITCOUNT', 'key', '0', '1']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.bitCount', async client => {
|
||||
assert.equal(
|
||||
await client.bitCount('key'),
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
25
lib/commands/BITCOUNT.ts
Normal file
25
lib/commands/BITCOUNT.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
interface BitCountRange {
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
export function transformArguments(key: string, range?: BitCountRange): Array<string> {
|
||||
const args = ['BITCOUNT', key];
|
||||
|
||||
if (range) {
|
||||
args.push(
|
||||
range.start.toString(),
|
||||
range.end.toString()
|
||||
);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
42
lib/commands/BITFIELD.spec.ts
Normal file
42
lib/commands/BITFIELD.spec.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
import { transformArguments } from './BITFIELD';
|
||||
|
||||
describe('BITFIELD', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', [{
|
||||
operation: 'OVERFLOW',
|
||||
behavior: 'WRAP'
|
||||
}, {
|
||||
operation: 'GET',
|
||||
type: 'i8',
|
||||
offset: 0
|
||||
}, {
|
||||
operation: 'OVERFLOW',
|
||||
behavior: 'SAT'
|
||||
}, {
|
||||
operation: 'SET',
|
||||
type: 'i16',
|
||||
offset: 1,
|
||||
value: 0
|
||||
}, {
|
||||
operation: 'OVERFLOW',
|
||||
behavior: 'FAIL'
|
||||
}, {
|
||||
operation: 'INCRBY',
|
||||
type: 'i32',
|
||||
offset: 2,
|
||||
increment: 1
|
||||
}]),
|
||||
['BITFIELD', 'key', 'OVERFLOW', 'WRAP', 'GET', 'i8', '0', 'OVERFLOW', 'SAT', 'SET', 'i16', '1', '0', 'OVERFLOW', 'FAIL', 'INCRBY', 'i32', '2', '1']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.bitField', async client => {
|
||||
assert.deepEqual(
|
||||
await client.bitField('key', []),
|
||||
[]
|
||||
);
|
||||
});
|
||||
});
|
84
lib/commands/BITFIELD.ts
Normal file
84
lib/commands/BITFIELD.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { transformReplyNumberNullArray } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
type BitFieldType = string; // TODO 'i[1-64]' | 'u[1-63]'
|
||||
|
||||
interface BitFieldOperation<S extends string> {
|
||||
operation: S;
|
||||
}
|
||||
|
||||
interface BitFieldGetOperation extends BitFieldOperation<'GET'> {
|
||||
type: BitFieldType;
|
||||
offset: number | string;
|
||||
}
|
||||
|
||||
interface BitFieldSetOperation extends BitFieldOperation<'SET'> {
|
||||
type: BitFieldType;
|
||||
offset: number | string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
interface BitFieldIncrByOperation extends BitFieldOperation<'INCRBY'> {
|
||||
type: BitFieldType;
|
||||
offset: number | string;
|
||||
increment: number;
|
||||
}
|
||||
|
||||
interface BitFieldOverflowOperation extends BitFieldOperation<'OVERFLOW'> {
|
||||
behavior: string;
|
||||
}
|
||||
|
||||
type BitFieldOperations = Array<
|
||||
BitFieldGetOperation |
|
||||
BitFieldSetOperation |
|
||||
BitFieldIncrByOperation |
|
||||
BitFieldOverflowOperation
|
||||
>;
|
||||
|
||||
export function transformArguments(key: string, operations: BitFieldOperations): Array<string> {
|
||||
const args = ['BITFIELD', key];
|
||||
|
||||
for (const options of operations) {
|
||||
switch (options.operation) {
|
||||
case 'GET':
|
||||
args.push(
|
||||
'GET',
|
||||
options.type,
|
||||
options.offset.toString()
|
||||
);
|
||||
break;
|
||||
|
||||
case 'SET':
|
||||
args.push(
|
||||
'SET',
|
||||
options.type,
|
||||
options.offset.toString(),
|
||||
options.value.toString()
|
||||
);
|
||||
break;
|
||||
|
||||
case 'INCRBY':
|
||||
args.push(
|
||||
'INCRBY',
|
||||
options.type,
|
||||
options.offset.toString(),
|
||||
options.increment.toString()
|
||||
)
|
||||
break;
|
||||
|
||||
case 'OVERFLOW':
|
||||
args.push(
|
||||
'OVERFLOW',
|
||||
options.behavior
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumberNullArray;
|
35
lib/commands/BITOP.spec.ts
Normal file
35
lib/commands/BITOP.spec.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils';
|
||||
import { transformArguments } from './BITOP';
|
||||
|
||||
describe('BITOP', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single key', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('AND', 'destKey', 'key'),
|
||||
['BITOP', 'AND', 'destKey', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple keys', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('AND', 'destKey', ['1', '2']),
|
||||
['BITOP', 'AND', 'destKey', '1', '2']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.bitOp', async client => {
|
||||
assert.equal(
|
||||
await client.bitOp('AND', 'destKey', 'key'),
|
||||
0
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.bitOp', async cluster => {
|
||||
assert.equal(
|
||||
await cluster.bitOp('AND', '{tag}destKey', '{tag}key'),
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
11
lib/commands/BITOP.ts
Normal file
11
lib/commands/BITOP.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 2;
|
||||
|
||||
type BitOperations = 'AND' | 'OR' | 'XOR' | 'NOT';
|
||||
|
||||
export function transformArguments(operation: BitOperations, destKey: string, key: string | Array<string>): Array<string> {
|
||||
return pushVerdictArguments(['BITOP', operation, destKey], key);
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
42
lib/commands/BITPOS.spec.ts
Normal file
42
lib/commands/BITPOS.spec.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils';
|
||||
import { transformArguments } from './BITPOS';
|
||||
|
||||
describe('BITPOS', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 1),
|
||||
['BITPOS', 'key', '1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with start', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 1, 1),
|
||||
['BITPOS', 'key', '1', '1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with start, end', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 1, 1, -1),
|
||||
['BITPOS', 'key', '1', '1', '-1']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.bitPos', async client => {
|
||||
assert.equal(
|
||||
await client.bitPos('key', 1, 1),
|
||||
-1
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.bitPos', async cluster => {
|
||||
assert.equal(
|
||||
await cluster.bitPos('key', 1, 1),
|
||||
-1
|
||||
);
|
||||
});
|
||||
});
|
21
lib/commands/BITPOS.ts
Normal file
21
lib/commands/BITPOS.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { BitValue, transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(key: string, bit: BitValue, start?: number, end?: number): Array<string> {
|
||||
const args = ['BITPOS', key, bit.toString()];
|
||||
|
||||
if (typeof start === 'number') {
|
||||
args.push(start.toString());
|
||||
}
|
||||
|
||||
if (typeof end === 'number') {
|
||||
args.push(end.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
43
lib/commands/BLMOVE.spec.ts
Normal file
43
lib/commands/BLMOVE.spec.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters, describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments } from './BLMOVE';
|
||||
import { commandOptions } from '../../index';
|
||||
|
||||
describe('BLMOVE', () => {
|
||||
describeHandleMinimumRedisVersion([6, 2]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('source', 'destination', 'LEFT', 'RIGHT', 0),
|
||||
['BLMOVE', 'source', 'destination', 'LEFT', 'RIGHT', '0']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.blMove', async client => {
|
||||
const [blMoveReply] = await Promise.all([
|
||||
client.blMove(commandOptions({
|
||||
isolated: true
|
||||
}), 'source', 'destination', 'LEFT', 'RIGHT', 0),
|
||||
client.lPush('source', 'element')
|
||||
]);
|
||||
|
||||
assert.equal(
|
||||
blMoveReply,
|
||||
'element'
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.blMove', async cluster => {
|
||||
const [blMoveReply] = await Promise.all([
|
||||
cluster.blMove(commandOptions({
|
||||
isolated: true
|
||||
}), '{tag}source', '{tag}destination', 'LEFT', 'RIGHT', 0),
|
||||
cluster.lPush('{tag}source', 'element')
|
||||
]);
|
||||
|
||||
assert.equal(
|
||||
blMoveReply,
|
||||
'element'
|
||||
);
|
||||
});
|
||||
});
|
23
lib/commands/BLMOVE.ts
Normal file
23
lib/commands/BLMOVE.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { transformReplyStringNull } from './generic-transformers';
|
||||
import { LMoveSide } from './LMOVE';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(
|
||||
source: string,
|
||||
destination: string,
|
||||
sourceDirection: LMoveSide,
|
||||
destinationDirection: LMoveSide,
|
||||
timeout: number
|
||||
): Array<string> {
|
||||
return [
|
||||
'BLMOVE',
|
||||
source,
|
||||
destination,
|
||||
sourceDirection,
|
||||
destinationDirection,
|
||||
timeout.toString()
|
||||
];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyStringNull;
|
79
lib/commands/BLPOP.spec.ts
Normal file
79
lib/commands/BLPOP.spec.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils';
|
||||
import { transformArguments, transformReply } from './BLPOP';
|
||||
import { commandOptions } from '../../index';
|
||||
|
||||
describe('BLPOP', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0),
|
||||
['BLPOP', 'key', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(['key1', 'key2'], 0),
|
||||
['BLPOP', 'key1', 'key2', '0']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformReply', () => {
|
||||
it('null', () => {
|
||||
assert.equal(
|
||||
transformReply(null),
|
||||
null
|
||||
);
|
||||
});
|
||||
|
||||
it('member', () => {
|
||||
assert.deepEqual(
|
||||
transformReply(['key', 'element']),
|
||||
{
|
||||
key: 'key',
|
||||
element: 'element'
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.blPop', async client => {
|
||||
const [ blPopReply ] = await Promise.all([
|
||||
client.blPop(
|
||||
commandOptions({ isolated: true }),
|
||||
'key',
|
||||
1
|
||||
),
|
||||
client.lPush('key', 'element'),
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
blPopReply,
|
||||
{
|
||||
key: 'key',
|
||||
element: 'element'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.blPop', async cluster => {
|
||||
const [ blPopReply ] = await Promise.all([
|
||||
cluster.blPop(
|
||||
commandOptions({ isolated: true }),
|
||||
'key',
|
||||
1
|
||||
),
|
||||
cluster.lPush('key', 'element'),
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
blPopReply,
|
||||
{
|
||||
key: 'key',
|
||||
element: 'element'
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
25
lib/commands/BLPOP.ts
Normal file
25
lib/commands/BLPOP.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { pushVerdictArguments } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(keys: string | Array<string>, timeout: number): Array<string> {
|
||||
const args = pushVerdictArguments(['BLPOP'], keys);
|
||||
|
||||
args.push(timeout.toString());
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
type BLPOPReply = null | {
|
||||
key: string;
|
||||
element: string;
|
||||
};
|
||||
|
||||
export function transformReply(reply: null | [string, string]): BLPOPReply {
|
||||
if (reply === null) return null;
|
||||
|
||||
return {
|
||||
key: reply[0],
|
||||
element: reply[1]
|
||||
};
|
||||
}
|
79
lib/commands/BRPOP.spec.ts
Normal file
79
lib/commands/BRPOP.spec.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils';
|
||||
import { transformArguments, transformReply } from './BRPOP';
|
||||
import { commandOptions } from '../../index';
|
||||
|
||||
describe('BRPOP', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0),
|
||||
['BRPOP', 'key', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(['key1', 'key2'], 0),
|
||||
['BRPOP', 'key1', 'key2', '0']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformReply', () => {
|
||||
it('null', () => {
|
||||
assert.equal(
|
||||
transformReply(null),
|
||||
null
|
||||
);
|
||||
});
|
||||
|
||||
it('member', () => {
|
||||
assert.deepEqual(
|
||||
transformReply(['key', 'element']),
|
||||
{
|
||||
key: 'key',
|
||||
element: 'element'
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.brPop', async client => {
|
||||
const [ brPopReply ] = await Promise.all([
|
||||
client.brPop(
|
||||
commandOptions({ isolated: true }),
|
||||
'key',
|
||||
1
|
||||
),
|
||||
client.lPush('key', 'element'),
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
brPopReply,
|
||||
{
|
||||
key: 'key',
|
||||
element: 'element'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.brPop', async cluster => {
|
||||
const [ brPopReply ] = await Promise.all([
|
||||
cluster.brPop(
|
||||
commandOptions({ isolated: true }),
|
||||
'key',
|
||||
1
|
||||
),
|
||||
cluster.lPush('key', 'element'),
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
brPopReply,
|
||||
{
|
||||
key: 'key',
|
||||
element: 'element'
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
25
lib/commands/BRPOP.ts
Normal file
25
lib/commands/BRPOP.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { pushVerdictArguments } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(key: string | Array<string>, timeout: number): Array<string> {
|
||||
const args = pushVerdictArguments(['BRPOP'], key);
|
||||
|
||||
args.push(timeout.toString());
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
type BRPOPReply = null | {
|
||||
key: string;
|
||||
element: string;
|
||||
};
|
||||
|
||||
export function transformReply(reply: null | [string, string]): BRPOPReply {
|
||||
if (reply === null) return null;
|
||||
|
||||
return {
|
||||
key: reply[0],
|
||||
element: reply[1]
|
||||
};
|
||||
}
|
47
lib/commands/BRPOPLPUSH.spec.ts
Normal file
47
lib/commands/BRPOPLPUSH.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils';
|
||||
import { transformArguments } from './BRPOPLPUSH';
|
||||
import { commandOptions } from '../../index';
|
||||
|
||||
describe('BRPOPLPUSH', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('source', 'destination', 0),
|
||||
['BRPOPLPUSH', 'source', 'destination', '0']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.brPopLPush', async client => {
|
||||
const [ popReply ] = await Promise.all([
|
||||
client.brPopLPush(
|
||||
commandOptions({ isolated: true }),
|
||||
'source',
|
||||
'destination',
|
||||
0
|
||||
),
|
||||
client.lPush('source', 'element')
|
||||
]);
|
||||
|
||||
assert.equal(
|
||||
popReply,
|
||||
'element'
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.brPopLPush', async cluster => {
|
||||
const [ popReply ] = await Promise.all([
|
||||
cluster.brPopLPush(
|
||||
commandOptions({ isolated: true }),
|
||||
'{tag}source',
|
||||
'{tag}destination',
|
||||
0
|
||||
),
|
||||
cluster.lPush('{tag}source', 'element')
|
||||
]);
|
||||
|
||||
assert.equal(
|
||||
popReply,
|
||||
'element'
|
||||
);
|
||||
});
|
||||
});
|
9
lib/commands/BRPOPLPUSH.ts
Normal file
9
lib/commands/BRPOPLPUSH.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { transformReplyNumberNull } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(source: string, destination: string, timeout: number): Array<string> {
|
||||
return ['BRPOPLPUSH', source, destination, timeout.toString()];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumberNull;
|
66
lib/commands/BZPOPMAX.spec.ts
Normal file
66
lib/commands/BZPOPMAX.spec.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
import { transformArguments, transformReply } from './BZPOPMAX';
|
||||
import { commandOptions } from '../../index';
|
||||
import { describe } from 'mocha';
|
||||
|
||||
describe('BZPOPMAX', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0),
|
||||
['BZPOPMAX', 'key', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(['1', '2'], 0),
|
||||
['BZPOPMAX', '1', '2', '0']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformReply', () => {
|
||||
it('null', () => {
|
||||
assert.equal(
|
||||
transformReply(null),
|
||||
null
|
||||
);
|
||||
});
|
||||
|
||||
it('member', () => {
|
||||
assert.deepEqual(
|
||||
transformReply(['key', 'value', '1']),
|
||||
{
|
||||
key: 'key',
|
||||
value: 'value',
|
||||
score: 1
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.bzPopMax', async client => {
|
||||
const [ bzPopMaxReply ] = await Promise.all([
|
||||
client.bzPopMax(
|
||||
commandOptions({ isolated: true }),
|
||||
'key',
|
||||
0
|
||||
),
|
||||
client.zAdd('key', [{
|
||||
value: '1',
|
||||
score: 1
|
||||
}])
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
bzPopMaxReply,
|
||||
{
|
||||
key: 'key',
|
||||
value: '1',
|
||||
score: 1
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
27
lib/commands/BZPOPMAX.ts
Normal file
27
lib/commands/BZPOPMAX.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(key: string | Array<string>, timeout: number): Array<string> {
|
||||
const args = pushVerdictArguments(['BZPOPMAX'], key);
|
||||
|
||||
args.push(timeout.toString());
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
interface ZMemberWithKey extends ZMember {
|
||||
key: string;
|
||||
}
|
||||
|
||||
type BZPopMaxReply = ZMemberWithKey | null;
|
||||
|
||||
export function transformReply(reply: [key: string, value: string, score: string] | null): BZPopMaxReply | null {
|
||||
if (!reply) return null;
|
||||
|
||||
return {
|
||||
key: reply[0],
|
||||
value: reply[1],
|
||||
score: transformReplyNumberInfinity(reply[2])
|
||||
};
|
||||
}
|
65
lib/commands/BZPOPMIN.spec.ts
Normal file
65
lib/commands/BZPOPMIN.spec.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
import { transformArguments, transformReply } from './BZPOPMIN';
|
||||
import { commandOptions } from '../../index';
|
||||
|
||||
describe('BZPOPMIN', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0),
|
||||
['BZPOPMIN', 'key', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(['1', '2'], 0),
|
||||
['BZPOPMIN', '1', '2', '0']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformReply', () => {
|
||||
it('null', () => {
|
||||
assert.equal(
|
||||
transformReply(null),
|
||||
null
|
||||
);
|
||||
});
|
||||
|
||||
it('member', () => {
|
||||
assert.deepEqual(
|
||||
transformReply(['key', 'value', '1']),
|
||||
{
|
||||
key: 'key',
|
||||
value: 'value',
|
||||
score: 1
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.bzPopMin', async client => {
|
||||
const [ bzPopMinReply ] = await Promise.all([
|
||||
client.bzPopMin(
|
||||
commandOptions({ isolated: true }),
|
||||
'key',
|
||||
0
|
||||
),
|
||||
client.zAdd('key', [{
|
||||
value: '1',
|
||||
score: 1
|
||||
}])
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
bzPopMinReply,
|
||||
{
|
||||
key: 'key',
|
||||
value: '1',
|
||||
score: 1
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
27
lib/commands/BZPOPMIN.ts
Normal file
27
lib/commands/BZPOPMIN.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(key: string | Array<string>, timeout: number): Array<string> {
|
||||
const args = pushVerdictArguments(['BZPOPMIN'], key);
|
||||
|
||||
args.push(timeout.toString());
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
interface ZMemberWithKey extends ZMember {
|
||||
key: string;
|
||||
}
|
||||
|
||||
type BZPopMinReply = ZMemberWithKey | null;
|
||||
|
||||
export function transformReply(reply: [key: string, value: string, score: string] | null): BZPopMinReply | null {
|
||||
if (!reply) return null;
|
||||
|
||||
return {
|
||||
key: reply[0],
|
||||
value: reply[1],
|
||||
score: transformReplyNumberInfinity(reply[2])
|
||||
};
|
||||
}
|
19
lib/commands/CLIENT_ID.spec.ts
Normal file
19
lib/commands/CLIENT_ID.spec.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
import { transformArguments } from './CLIENT_ID';
|
||||
|
||||
describe('CLIENT ID', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CLIENT', 'ID']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.clientId', async client => {
|
||||
assert.equal(
|
||||
typeof (await client.clientId()),
|
||||
'number'
|
||||
);
|
||||
});
|
||||
});
|
9
lib/commands/CLIENT_ID.ts
Normal file
9
lib/commands/CLIENT_ID.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['CLIENT', 'ID'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
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
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
85
lib/commands/CLIENT_INFO.ts
Normal file
85
lib/commands/CLIENT_INFO.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['CLIENT', 'INFO'];
|
||||
}
|
||||
|
||||
interface ClientInfoReply {
|
||||
id: number;
|
||||
addr: string;
|
||||
laddr: string;
|
||||
fd: number;
|
||||
name: string;
|
||||
age: number;
|
||||
idle: number;
|
||||
flags: string;
|
||||
db: number;
|
||||
sub: number;
|
||||
psub: number;
|
||||
multi: number;
|
||||
qbuf: number;
|
||||
qbufFree: number;
|
||||
argvMem: number;
|
||||
obl: number;
|
||||
oll: number;
|
||||
omem: number;
|
||||
totMem: number;
|
||||
events: string;
|
||||
cmd: string;
|
||||
user: string;
|
||||
redir: number;
|
||||
}
|
||||
|
||||
const REGEX = /=([^\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)];
|
||||
|
||||
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)
|
||||
};
|
||||
}
|
20
lib/commands/CLUSTER_ADDSLOTS.spec.ts
Normal file
20
lib/commands/CLUSTER_ADDSLOTS.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './CLUSTER_ADDSLOTS';
|
||||
|
||||
describe('CLUSTER ADDSLOTS', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(0),
|
||||
['CLUSTER', 'ADDSLOTS', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments([0, 1]),
|
||||
['CLUSTER', 'ADDSLOTS', '0', '1']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
15
lib/commands/CLUSTER_ADDSLOTS.ts
Normal file
15
lib/commands/CLUSTER_ADDSLOTS.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(slots: number | Array<number>): Array<string> {
|
||||
const args = ['CLUSTER', 'ADDSLOTS'];
|
||||
|
||||
if (typeof slots === 'number') {
|
||||
args.push(slots.toString());
|
||||
} else {
|
||||
args.push(...slots.map(String));
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
11
lib/commands/CLUSTER_FLUSHSLOTS.spec.ts
Normal file
11
lib/commands/CLUSTER_FLUSHSLOTS.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './CLUSTER_FLUSHSLOTS';
|
||||
|
||||
describe('CLUSTER FLUSHSLOTS', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CLUSTER', 'FLUSHSLOTS']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/CLUSTER_FLUSHSLOTS.ts
Normal file
7
lib/commands/CLUSTER_FLUSHSLOTS.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['CLUSTER', 'FLUSHSLOTS'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
11
lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts
Normal file
11
lib/commands/CLUSTER_GETKEYSINSLOT.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './CLUSTER_GETKEYSINSLOT';
|
||||
|
||||
describe('CLUSTER GETKEYSINSLOT', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(0, 10),
|
||||
['CLUSTER', 'GETKEYSINSLOT', '0', '10']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/CLUSTER_GETKEYSINSLOT.ts
Normal file
7
lib/commands/CLUSTER_GETKEYSINSLOT.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(slot: number, count: number): Array<string> {
|
||||
return ['CLUSTER', 'GETKEYSINSLOT', slot.toString(), count.toString()];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
64
lib/commands/CLUSTER_INFO.spec.ts
Normal file
64
lib/commands/CLUSTER_INFO.spec.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { itWithCluster, TestRedisClusters } from '../test-utils';
|
||||
import { transformArguments, transformReply } from './CLUSTER_INFO';
|
||||
|
||||
describe('CLUSTER INFO', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CLUSTER', 'INFO']
|
||||
);
|
||||
});
|
||||
|
||||
it('transformReply', () => {
|
||||
assert.deepEqual(
|
||||
transformReply([
|
||||
'cluster_state:ok',
|
||||
'cluster_slots_assigned:16384',
|
||||
'cluster_slots_ok:16384',
|
||||
'cluster_slots_pfail:0',
|
||||
'cluster_slots_fail:0',
|
||||
'cluster_known_nodes:6',
|
||||
'cluster_size:3',
|
||||
'cluster_current_epoch:6',
|
||||
'cluster_my_epoch:2',
|
||||
'cluster_stats_messages_sent:1483972',
|
||||
'cluster_stats_messages_received:1483968'
|
||||
].join('\r\n')),
|
||||
{
|
||||
state: 'ok',
|
||||
slots: {
|
||||
assigned: 16384,
|
||||
ok: 16384,
|
||||
pfail: 0,
|
||||
fail: 0
|
||||
},
|
||||
knownNodes: 6,
|
||||
size: 3,
|
||||
currentEpoch: 6,
|
||||
myEpoch: 2,
|
||||
stats: {
|
||||
messagesSent: 1483972,
|
||||
messagesReceived: 1483968
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.clusterInfo', async cluster => {
|
||||
const info = await cluster.clusterInfo();
|
||||
assert.equal(info.state, 'ok');
|
||||
assert.deepEqual(info.slots, {
|
||||
assigned: 16384,
|
||||
ok: 16384,
|
||||
pfail: 0,
|
||||
fail: 0
|
||||
});
|
||||
assert.equal(info.knownNodes, 3);
|
||||
assert.equal(info.size, 3);
|
||||
assert.equal(typeof info.currentEpoch, 'number');
|
||||
assert.equal(typeof info.myEpoch, 'number');
|
||||
assert.equal(typeof info.stats.messagesReceived, 'number');
|
||||
assert.equal(typeof info.stats.messagesSent, 'number');
|
||||
});
|
||||
});
|
47
lib/commands/CLUSTER_INFO.ts
Normal file
47
lib/commands/CLUSTER_INFO.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['CLUSTER', 'INFO'];
|
||||
}
|
||||
|
||||
interface ClusterInfoReply {
|
||||
state: string;
|
||||
slots: {
|
||||
assigned: number;
|
||||
ok: number;
|
||||
pfail: number;
|
||||
fail: number;
|
||||
};
|
||||
knownNodes: number;
|
||||
size: number;
|
||||
currentEpoch: number;
|
||||
myEpoch: number;
|
||||
stats: {
|
||||
messagesSent: number;
|
||||
messagesReceived: number;
|
||||
};
|
||||
}
|
||||
|
||||
export function transformReply(reply: string): ClusterInfoReply {
|
||||
const lines = reply.split('\r\n');
|
||||
|
||||
return {
|
||||
state: extractLineValue(lines[0]),
|
||||
slots: {
|
||||
assigned: Number(extractLineValue(lines[1])),
|
||||
ok: Number(extractLineValue(lines[2])),
|
||||
pfail: Number(extractLineValue(lines[3])),
|
||||
fail: Number(extractLineValue(lines[4]))
|
||||
},
|
||||
knownNodes: Number(extractLineValue(lines[5])),
|
||||
size: Number(extractLineValue(lines[6])),
|
||||
currentEpoch: Number(extractLineValue(lines[7])),
|
||||
myEpoch: Number(extractLineValue(lines[8])),
|
||||
stats: {
|
||||
messagesSent: Number(extractLineValue(lines[9])),
|
||||
messagesReceived: Number(extractLineValue(lines[10]))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function extractLineValue(line: string): string {
|
||||
return line.substring(line.indexOf(':') + 1);
|
||||
}
|
11
lib/commands/CLUSTER_MEET.spec.ts
Normal file
11
lib/commands/CLUSTER_MEET.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './CLUSTER_MEET';
|
||||
|
||||
describe('CLUSTER MEET', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('127.0.0.1', 6379),
|
||||
['CLUSTER', 'MEET', '127.0.0.1', '6379']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/CLUSTER_MEET.ts
Normal file
7
lib/commands/CLUSTER_MEET.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(ip: string, port: number): Array<string> {
|
||||
return ['CLUSTER', 'MEET', ip, port.toString()];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
116
lib/commands/CLUSTER_NODES.spec.ts
Normal file
116
lib/commands/CLUSTER_NODES.spec.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { itWithCluster, TestRedisClusters } from '../test-utils';
|
||||
import { RedisClusterNodeLinkStates, transformArguments, transformReply } from './CLUSTER_NODES';
|
||||
|
||||
describe('CLUSTER NODES', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CLUSTER', 'NODES']
|
||||
);
|
||||
});
|
||||
|
||||
describe('transformReply', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformReply([
|
||||
'master 127.0.0.1:30001@31001 myself,master - 0 0 1 connected 0-16384',
|
||||
'slave 127.0.0.1:30002@31002 slave master 0 0 1 connected',
|
||||
''
|
||||
].join('\n')),
|
||||
[{
|
||||
id: 'master',
|
||||
url: '127.0.0.1:30001@31001',
|
||||
host: '127.0.0.1',
|
||||
port: 30001,
|
||||
cport: 31001,
|
||||
flags: ['myself', 'master'],
|
||||
pingSent: 0,
|
||||
pongRecv: 0,
|
||||
configEpoch: 1,
|
||||
linkState: RedisClusterNodeLinkStates.CONNECTED,
|
||||
slots: [{
|
||||
from: 0,
|
||||
to: 16384
|
||||
}],
|
||||
replicas: [{
|
||||
id: 'slave',
|
||||
url: '127.0.0.1:30002@31002',
|
||||
host: '127.0.0.1',
|
||||
port: 30002,
|
||||
cport: 31002,
|
||||
flags: ['slave'],
|
||||
pingSent: 0,
|
||||
pongRecv: 0,
|
||||
configEpoch: 1,
|
||||
linkState: RedisClusterNodeLinkStates.CONNECTED
|
||||
}]
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
it.skip('with importing slots', () => {
|
||||
assert.deepEqual(
|
||||
transformReply(
|
||||
'id 127.0.0.1:30001@31001 master - 0 0 0 connected 0-<-16384\n'
|
||||
),
|
||||
[{
|
||||
id: 'id',
|
||||
url: '127.0.0.1:30001@31001',
|
||||
host: '127.0.0.1',
|
||||
port: 30001,
|
||||
cport: 31001,
|
||||
flags: ['master'],
|
||||
pingSent: 0,
|
||||
pongRecv: 0,
|
||||
configEpoch: 0,
|
||||
linkState: RedisClusterNodeLinkStates.CONNECTED,
|
||||
slots: [], // TODO
|
||||
replicas: []
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
it.skip('with migrating slots', () => {
|
||||
assert.deepEqual(
|
||||
transformReply(
|
||||
'id 127.0.0.1:30001@31001 master - 0 0 0 connected 0->-16384\n'
|
||||
),
|
||||
[{
|
||||
id: 'id',
|
||||
url: '127.0.0.1:30001@31001',
|
||||
host: '127.0.0.1',
|
||||
port: 30001,
|
||||
cport: 31001,
|
||||
flags: ['master'],
|
||||
pingSent: 0,
|
||||
pongRecv: 0,
|
||||
configEpoch: 0,
|
||||
linkState: RedisClusterNodeLinkStates.CONNECTED,
|
||||
slots: [], // TODO
|
||||
replicas: []
|
||||
}]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.clusterNodes', async cluster => {
|
||||
for (const node of (await cluster.clusterNodes())) {
|
||||
assert.equal(typeof node.id, 'string');
|
||||
assert.equal(typeof node.url, 'string');
|
||||
assert.equal(typeof node.host, 'string');
|
||||
assert.equal(typeof node.port, 'number');
|
||||
assert.equal(typeof node.cport, 'number');
|
||||
assert.ok(Array.isArray(node.flags));
|
||||
assert.equal(typeof node.pingSent, 'number');
|
||||
assert.equal(typeof node.pongRecv, 'number');
|
||||
assert.equal(typeof node.configEpoch, 'number');
|
||||
assert.equal(typeof node.linkState, 'string');
|
||||
|
||||
for (const slot of node.slots) {
|
||||
assert.equal(typeof slot.from, 'number');
|
||||
assert.equal(typeof slot.to, 'number');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
96
lib/commands/CLUSTER_NODES.ts
Normal file
96
lib/commands/CLUSTER_NODES.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['CLUSTER', 'NODES'];
|
||||
}
|
||||
|
||||
export enum RedisClusterNodeLinkStates {
|
||||
CONNECTED = 'connected',
|
||||
DISCONNECTED = 'disconnected'
|
||||
}
|
||||
|
||||
interface RedisClusterNodeTransformedUrl {
|
||||
host: string;
|
||||
port: number;
|
||||
cport: number;
|
||||
}
|
||||
|
||||
export interface RedisClusterReplicaNode extends RedisClusterNodeTransformedUrl {
|
||||
id: string;
|
||||
url: string;
|
||||
flags: Array<string>;
|
||||
pingSent: number;
|
||||
pongRecv: number;
|
||||
configEpoch: number;
|
||||
linkState: RedisClusterNodeLinkStates;
|
||||
}
|
||||
|
||||
export interface RedisClusterMasterNode extends RedisClusterReplicaNode {
|
||||
slots: Array<{
|
||||
from: number;
|
||||
to: number;
|
||||
}>;
|
||||
replicas: Array<RedisClusterReplicaNode>;
|
||||
}
|
||||
|
||||
export function transformReply(reply: string): Array<RedisClusterMasterNode> {
|
||||
const lines = reply.split('\n');
|
||||
lines.pop(); // last line is empty
|
||||
|
||||
const mastersMap = new Map<string, RedisClusterMasterNode>(),
|
||||
replicasMap = new Map<string, Array<RedisClusterReplicaNode>>();
|
||||
|
||||
for (const line of lines) {
|
||||
const [id, url, flags, masterId, pingSent, pongRecv, configEpoch, linkState, ...slots] = line.split(' '),
|
||||
node = {
|
||||
id,
|
||||
url,
|
||||
...transformNodeUrl(url),
|
||||
flags: flags.split(','),
|
||||
pingSent: Number(pingSent),
|
||||
pongRecv: Number(pongRecv),
|
||||
configEpoch: Number(configEpoch),
|
||||
linkState: (linkState as RedisClusterNodeLinkStates)
|
||||
};
|
||||
|
||||
if (masterId === '-') {
|
||||
let replicas = replicasMap.get(id);
|
||||
if (!replicas) {
|
||||
replicas = [];
|
||||
replicasMap.set(id, replicas);
|
||||
}
|
||||
|
||||
mastersMap.set(id, {
|
||||
...node,
|
||||
slots: slots.map(slot => {
|
||||
// TODO: importing & exporting (https://redis.io/commands/cluster-nodes#special-slot-entries)
|
||||
const [fromString, toString] = slot.split('-', 2),
|
||||
from = Number(fromString);
|
||||
return {
|
||||
from,
|
||||
to: toString ? Number(toString) : from
|
||||
};
|
||||
}),
|
||||
replicas
|
||||
});
|
||||
} else {
|
||||
const replicas = replicasMap.get(masterId);
|
||||
if (!replicas) {
|
||||
replicasMap.set(masterId, [node]);
|
||||
} else {
|
||||
replicas.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [...mastersMap.values()];
|
||||
}
|
||||
|
||||
function transformNodeUrl(url: string): RedisClusterNodeTransformedUrl {
|
||||
const indexOfColon = url.indexOf(':'),
|
||||
indexOfAt = url.indexOf('@', indexOfColon);
|
||||
|
||||
return {
|
||||
host: url.substring(0, indexOfColon),
|
||||
port: Number(url.substring(indexOfColon + 1, indexOfAt)),
|
||||
cport: Number(url.substring(indexOfAt + 1))
|
||||
};
|
||||
}
|
27
lib/commands/CLUSTER_RESET.spec.ts
Normal file
27
lib/commands/CLUSTER_RESET.spec.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './CLUSTER_RESET';
|
||||
|
||||
describe('CLUSTER RESET', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CLUSTER', 'RESET']
|
||||
);
|
||||
});
|
||||
|
||||
it('HARD', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('HARD'),
|
||||
['CLUSTER', 'RESET', 'HARD']
|
||||
);
|
||||
});
|
||||
|
||||
it('SOFT', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('SOFT'),
|
||||
['CLUSTER', 'RESET', 'SOFT']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
15
lib/commands/CLUSTER_RESET.ts
Normal file
15
lib/commands/CLUSTER_RESET.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export type ClusterResetModes = 'HARD' | 'SOFT';
|
||||
|
||||
export function transformArguments(mode?: ClusterResetModes): Array<string> {
|
||||
const args = ['CLUSTER', 'RESET'];
|
||||
|
||||
if (mode) {
|
||||
args.push(mode);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
20
lib/commands/CLUSTER_SETSLOT.spec.ts
Normal file
20
lib/commands/CLUSTER_SETSLOT.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { ClusterSlotStates, transformArguments } from './CLUSTER_SETSLOT';
|
||||
|
||||
describe('CLUSTER SETSLOT', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(0, ClusterSlotStates.IMPORTING),
|
||||
['CLUSTER', 'SETSLOT', '0', 'IMPORTING']
|
||||
);
|
||||
});
|
||||
|
||||
it('with nodeId', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(0, ClusterSlotStates.IMPORTING, 'nodeId'),
|
||||
['CLUSTER', 'SETSLOT', '0', 'IMPORTING', 'nodeId']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
20
lib/commands/CLUSTER_SETSLOT.ts
Normal file
20
lib/commands/CLUSTER_SETSLOT.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export enum ClusterSlotStates {
|
||||
IMPORTING = 'IMPORTING',
|
||||
MIGRATING = 'MIGRATING',
|
||||
STABLE = 'STABLE',
|
||||
NODE = 'NODE'
|
||||
}
|
||||
|
||||
export function transformArguments(slot: number, state: ClusterSlotStates, nodeId?: string): Array<string> {
|
||||
const args = ['CLUSTER', 'SETSLOT', slot.toString(), state];
|
||||
|
||||
if (nodeId) {
|
||||
args.push(nodeId);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
11
lib/commands/CONFIG_GET.spec.ts
Normal file
11
lib/commands/CONFIG_GET.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './CONFIG_GET';
|
||||
|
||||
describe('CONFIG GET', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('*'),
|
||||
['CONFIG', 'GET', '*']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/CONFIG_GET.ts
Normal file
7
lib/commands/CONFIG_GET.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyTuples } from './generic-transformers';
|
||||
|
||||
export function transformArguments(parameter: string): Array<string> {
|
||||
return ['CONFIG', 'GET', parameter];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyTuples;
|
11
lib/commands/CONFIG_RESETSTAT.spec.ts
Normal file
11
lib/commands/CONFIG_RESETSTAT.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './CONFIG_RESETSTAT';
|
||||
|
||||
describe('CONFIG RESETSTAT', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CONFIG', 'RESETSTAT']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/CONFIG_RESETSTAT.ts
Normal file
7
lib/commands/CONFIG_RESETSTAT.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['CONFIG', 'RESETSTAT'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
11
lib/commands/CONFIG_REWRITE.spec.ts
Normal file
11
lib/commands/CONFIG_REWRITE.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './CONFIG_REWRITE';
|
||||
|
||||
describe('CONFIG REWRITE', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['CONFIG', 'REWRITE']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/CONFIG_REWRITE.ts
Normal file
7
lib/commands/CONFIG_REWRITE.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['CONFIG', 'REWRITE'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
11
lib/commands/CONFIG_SET.spec.ts
Normal file
11
lib/commands/CONFIG_SET.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './CONFIG_SET';
|
||||
|
||||
describe('CONFIG SET', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('parameter', 'value'),
|
||||
['CONFIG', 'SET', 'parameter', 'value']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/CONFIG_SET.ts
Normal file
7
lib/commands/CONFIG_SET.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(parameter: string, value: string): Array<string> {
|
||||
return ['CONFIG', 'SET', parameter, value];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
67
lib/commands/COPY.spec.ts
Normal file
67
lib/commands/COPY.spec.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils';
|
||||
import { transformArguments, transformReply } from './COPY';
|
||||
|
||||
describe('COPY', () => {
|
||||
describeHandleMinimumRedisVersion([6, 2]);
|
||||
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('source', 'destination'),
|
||||
['COPY', 'source', 'destination']
|
||||
);
|
||||
});
|
||||
|
||||
it('with destination DB flag', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('source', 'destination', {
|
||||
destinationDb: 1
|
||||
}),
|
||||
['COPY', 'source', 'destination', 'DB', '1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with replace flag', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('source', 'destination', {
|
||||
replace: true
|
||||
}),
|
||||
['COPY', 'source', 'destination', 'REPLACE']
|
||||
);
|
||||
});
|
||||
|
||||
it('with both flags', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('source', 'destination', {
|
||||
destinationDb: 1,
|
||||
replace: true
|
||||
}),
|
||||
['COPY', 'source', 'destination', 'DB', '1', 'REPLACE']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformReply', () => {
|
||||
it('0', () => {
|
||||
assert.equal(
|
||||
transformReply(0),
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('1', () => {
|
||||
assert.equal(
|
||||
transformReply(1),
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.copy', async client => {
|
||||
assert.equal(
|
||||
await client.copy('source', 'destination'),
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
24
lib/commands/COPY.ts
Normal file
24
lib/commands/COPY.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { transformReplyBoolean } from './generic-transformers';
|
||||
|
||||
interface CopyCommandOptions {
|
||||
destinationDb?: number;
|
||||
replace?: boolean;
|
||||
}
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(source: string, destination: string, options?: CopyCommandOptions): Array<string> {
|
||||
const args = ['COPY', source, destination];
|
||||
|
||||
if (options?.destinationDb) {
|
||||
args.push('DB', options.destinationDb.toString());
|
||||
}
|
||||
|
||||
if (options?.replace) {
|
||||
args.push('REPLACE');
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyBoolean;
|
26
lib/commands/DBSIZE.spec.ts
Normal file
26
lib/commands/DBSIZE.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils';
|
||||
import { transformArguments } from './DBSIZE';
|
||||
|
||||
describe('DBSIZE', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['DBSIZE']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.dbSize', async client => {
|
||||
assert.equal(
|
||||
await client.dbSize(),
|
||||
0
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.dbSize', async cluster => {
|
||||
assert.equal(
|
||||
await cluster.dbSize(),
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
9
lib/commands/DBSIZE.ts
Normal file
9
lib/commands/DBSIZE.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['DBSIZE'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
19
lib/commands/DECR.spec.ts
Normal file
19
lib/commands/DECR.spec.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
import { transformArguments } from './DECR';
|
||||
|
||||
describe('DECR', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key'),
|
||||
['DECR', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.decr', async client => {
|
||||
assert.equal(
|
||||
await client.decr('key'),
|
||||
-1
|
||||
);
|
||||
});
|
||||
});
|
9
lib/commands/DECR.ts
Normal file
9
lib/commands/DECR.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(key: string): Array<string> {
|
||||
return ['DECR', key];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
19
lib/commands/DECRBY.spec.ts
Normal file
19
lib/commands/DECRBY.spec.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
import { transformArguments } from './DECRBY';
|
||||
|
||||
describe('DECRBY', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 2),
|
||||
['DECRBY', 'key', '2']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.decrBy', async client => {
|
||||
assert.equal(
|
||||
await client.decrBy('key', 2),
|
||||
-2
|
||||
);
|
||||
});
|
||||
});
|
9
lib/commands/DECRBY.ts
Normal file
9
lib/commands/DECRBY.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(key: string, decrement: number): Array<string> {
|
||||
return ['DECRBY', key, decrement.toString()];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
28
lib/commands/DEL.spec.ts
Normal file
28
lib/commands/DEL.spec.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
import { transformArguments } from './DEL';
|
||||
|
||||
describe('DEL', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key'),
|
||||
['DEL', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(['key1', 'key2']),
|
||||
['DEL', 'key1', 'key2']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.del', async client => {
|
||||
assert.equal(
|
||||
await client.del('key'),
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/DEL.ts
Normal file
7
lib/commands/DEL.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||
|
||||
export function transformArguments(keys: string | Array<string>): Array<string> {
|
||||
return pushVerdictArguments(['DEL'], keys);
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyNumber;
|
11
lib/commands/DISCARD.spec.ts
Normal file
11
lib/commands/DISCARD.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { transformArguments } from './DISCARD';
|
||||
|
||||
describe('DISCARD', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments(),
|
||||
['DISCARD']
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/DISCARD.ts
Normal file
7
lib/commands/DISCARD.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(): Array<string> {
|
||||
return ['DISCARD'];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
11
lib/commands/DUMP.spec.ts
Normal file
11
lib/commands/DUMP.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient } from '../test-utils';
|
||||
|
||||
describe('DUMP', () => {
|
||||
itWithClient(TestRedisServers.OPEN, 'client.dump', async client => {
|
||||
assert.equal(
|
||||
await client.dump('key'),
|
||||
null
|
||||
);
|
||||
});
|
||||
});
|
7
lib/commands/DUMP.ts
Normal file
7
lib/commands/DUMP.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export function transformArguments(key: string): Array<string> {
|
||||
return ['DUMP', key];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
26
lib/commands/ECHO.spec.ts
Normal file
26
lib/commands/ECHO.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils';
|
||||
import { transformArguments } from './ECHO';
|
||||
|
||||
describe('ECHO', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('message'),
|
||||
['ECHO', 'message']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.echo', async client => {
|
||||
assert.equal(
|
||||
await client.echo('message'),
|
||||
'message'
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.echo', async cluster => {
|
||||
assert.equal(
|
||||
await cluster.echo('message'),
|
||||
'message'
|
||||
);
|
||||
});
|
||||
});
|
9
lib/commands/ECHO.ts
Normal file
9
lib/commands/ECHO.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { transformReplyString } from './generic-transformers';
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(message: string): Array<string> {
|
||||
return ['ECHO', message];
|
||||
}
|
||||
|
||||
export const transformReply = transformReplyString;
|
29
lib/commands/EVAL.spec.ts
Normal file
29
lib/commands/EVAL.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils';
|
||||
import { transformArguments } from './EVAL';
|
||||
|
||||
describe('EVAL', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('return KEYS[1] + ARGV[1]', {
|
||||
keys: ['key'],
|
||||
arguments: ['argument']
|
||||
}),
|
||||
['EVAL', 'return KEYS[1] + ARGV[1]', '1', 'key', 'argument']
|
||||
);
|
||||
});
|
||||
|
||||
itWithClient(TestRedisServers.OPEN, 'client.eval', async client => {
|
||||
assert.equal(
|
||||
await client.eval('return 1'),
|
||||
1
|
||||
);
|
||||
});
|
||||
|
||||
itWithCluster(TestRedisClusters.OPEN, 'cluster.eval', async cluster => {
|
||||
assert.equal(
|
||||
await cluster.eval('return 1'),
|
||||
1
|
||||
);
|
||||
});
|
||||
});
|
9
lib/commands/EVAL.ts
Normal file
9
lib/commands/EVAL.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { EvalOptions, pushEvalArguments } from './generic-transformers';
|
||||
|
||||
export function transformArguments(script: string, options?: EvalOptions): Array<string> {
|
||||
return pushEvalArguments(['EVAL', script], options);
|
||||
}
|
||||
|
||||
export function transformReply(reply: unknown): unknown {
|
||||
return reply;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user