diff --git a/lib/client.ts b/lib/client.ts index b0365edb31..6bd3b82311 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -239,7 +239,7 @@ export default class RedisClient> = [], clientsInUse = new Set(); for (const master of masters) { - const masterClient = this.#initiateClientForNode(master, false, clientsInUse, promises), - replicasClients = this.#options.useReplicas ? + const slot = { + master: this.#initiateClientForNode(master, false, clientsInUse, promises), + replicas: this.#options.useReplicas ? master.replicas.map(replica => this.#initiateClientForNode(replica, true, clientsInUse, promises)) : - []; + [], + iterator: undefined // will be initiated in use + }; - for (const slot of master.slots) { - for (let i = slot.from; i < slot.to; i++) { - this.#slots[i] = { - master: masterClient, - replicas: replicasClients, - iterator: undefined // will be initiated in use - }; + for (const { from, to } of master.slots) { + for (let i = from; i < to; i++) { + this.#slots[i] = slot; } } } diff --git a/lib/commands/CLIENT_INFO.spec.ts b/lib/commands/CLIENT_INFO.spec.ts new file mode 100644 index 0000000000..ee87df4a19 --- /dev/null +++ b/lib/commands/CLIENT_INFO.spec.ts @@ -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 + } + ); + }); +}); diff --git a/lib/commands/FLUSHDB.spec.ts b/lib/commands/FLUSHDB.spec.ts new file mode 100644 index 0000000000..e237e52768 --- /dev/null +++ b/lib/commands/FLUSHDB.spec.ts @@ -0,0 +1,36 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { RedisFlushModes } from './FLUSHALL'; +import { transformArguments } from './FLUSHDB'; + +describe('FLUSHDB', () => { + describe('transformArguments', () => { + it('default', () => { + assert.deepEqual( + transformArguments(), + ['FLUSHDB'] + ); + }); + + it('ASYNC', () => { + assert.deepEqual( + transformArguments(RedisFlushModes.ASYNC), + ['FLUSHDB', 'ASYNC'] + ); + }); + + it('SYNC', () => { + assert.deepEqual( + transformArguments(RedisFlushModes.SYNC), + ['FLUSHDB', 'SYNC'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.flushDb', async client => { + assert.equal( + await client.flushDb(), + 'OK' + ); + }); +}); diff --git a/lib/commands/FLUSHDB.ts b/lib/commands/FLUSHDB.ts new file mode 100644 index 0000000000..a85c0933c4 --- /dev/null +++ b/lib/commands/FLUSHDB.ts @@ -0,0 +1,14 @@ +import { RedisFlushModes } from './FLUSHALL'; +import { transformReplyString } from './generic-transformers'; + +export function transformArguments(mode?: RedisFlushModes): Array { + const args = ['FLUSHDB']; + + if (mode) { + args.push(mode); + } + + return args; +} + +export const transformReply = transformReplyString; diff --git a/lib/commands/LASTSAVE.spec.ts b/lib/commands/LASTSAVE.spec.ts new file mode 100644 index 0000000000..1b13bed5d2 --- /dev/null +++ b/lib/commands/LASTSAVE.spec.ts @@ -0,0 +1,20 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { transformArguments } from './LASTSAVE'; + +describe('LASTSAVE', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments(), + ['LASTSAVE'] + ); + }); + + itWithClient(TestRedisServers.OPEN, 'client.lastSave', async client => { + assert.ok((await client.lastSave()) instanceof Date); + }); + + itWithCluster(TestRedisClusters.OPEN, 'cluster.lastSave', async cluster => { + assert.ok((await cluster.lastSave()) instanceof Date); + }); +}); diff --git a/lib/commands/LASTSAVE.ts b/lib/commands/LASTSAVE.ts new file mode 100644 index 0000000000..76944d3548 --- /dev/null +++ b/lib/commands/LASTSAVE.ts @@ -0,0 +1,9 @@ +export const IS_READ_ONLY = true; + +export function transformArguments(): Array { + return ['LASTSAVE']; +} + +export function transformReply(reply: number): Date { + return new Date(reply); +} diff --git a/lib/commands/LOLWUT.spec.ts b/lib/commands/LOLWUT.spec.ts new file mode 100644 index 0000000000..8e77b85b59 --- /dev/null +++ b/lib/commands/LOLWUT.spec.ts @@ -0,0 +1,43 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { transformArguments } from './LOLWUT'; + +describe('LOLWUT', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + transformArguments(), + ['LOLWUT'] + ); + }); + + it('with version', () => { + assert.deepEqual( + transformArguments(5), + ['LOLWUT', 'VERSION', '5'] + ); + }); + + it('with version and optional arguments', () => { + assert.deepEqual( + transformArguments(5, 1, 2, 3), + ['LOLWUT', 'VERSION', '5', '1', '2', '3'] + ); + }); + }); + + + itWithClient(TestRedisServers.OPEN, 'client.LOLWUT', async client => { + assert.equal( + typeof (await client.LOLWUT()), + 'string' + ); + }); + + itWithCluster(TestRedisClusters.OPEN, 'cluster.LOLWUT', async cluster => { + assert.equal( + typeof (await cluster.LOLWUT()), + 'string' + ); + }); +}); diff --git a/lib/commands/LOLWUT.ts b/lib/commands/LOLWUT.ts new file mode 100644 index 0000000000..f0cd20d447 --- /dev/null +++ b/lib/commands/LOLWUT.ts @@ -0,0 +1,19 @@ +import { transformReplyString } from './generic-transformers'; + +export const IS_READ_ONLY = true; + +export function transformArguments(version?: number, ...optionalArguments: Array): Array { + const args = ['LOLWUT']; + + if (version) { + args.push( + 'VERSION', + version.toString(), + ...optionalArguments.map(String), + ); + } + + return args; +} + +export const transformReply = transformReplyString; diff --git a/lib/commands/SETRANGE.spec.ts b/lib/commands/SETRANGE.spec.ts new file mode 100644 index 0000000000..766c56c5ff --- /dev/null +++ b/lib/commands/SETRANGE.spec.ts @@ -0,0 +1,26 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { transformArguments } from './SETRANGE'; + +describe('SETRANGE', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 0, 'value'), + ['SETRANGE', 'key', '0', 'value'] + ); + }); + + itWithClient(TestRedisServers.OPEN, 'client.setRange', async client => { + assert.equal( + await client.setRange('key', 0, 'value'), + 5 + ); + }); + + itWithCluster(TestRedisClusters.OPEN, 'cluster.setRange', async cluster => { + assert.equal( + await cluster.setRange('key', 0, 'value'), + 5 + ); + }); +}); diff --git a/lib/commands/SETRANGE.ts b/lib/commands/SETRANGE.ts new file mode 100644 index 0000000000..a303487ddd --- /dev/null +++ b/lib/commands/SETRANGE.ts @@ -0,0 +1,9 @@ +import { transformReplyNumber } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, offset: number, value: string): Array { + return ['SETRANGE', key, offset.toString(), value]; +} + +export const transformReply = transformReplyNumber; diff --git a/lib/commands/STRLEN.spec.ts b/lib/commands/STRLEN.spec.ts new file mode 100644 index 0000000000..3d24e36037 --- /dev/null +++ b/lib/commands/STRLEN.spec.ts @@ -0,0 +1,26 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { transformArguments } from './STRLEN'; + +describe('STRLEN', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key'), + ['STRLEN', 'key'] + ); + }); + + itWithClient(TestRedisServers.OPEN, 'client.strLen', async client => { + assert.equal( + await client.strLen('key'), + 0 + ); + }); + + itWithCluster(TestRedisClusters.OPEN, 'cluster.strLen', async cluster => { + assert.equal( + await cluster.strLen('key'), + 0 + ); + }); +}); diff --git a/lib/commands/STRLEN.ts b/lib/commands/STRLEN.ts new file mode 100644 index 0000000000..d8112ce7d1 --- /dev/null +++ b/lib/commands/STRLEN.ts @@ -0,0 +1,11 @@ +import { transformReplyNumber } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string): Array { + return ['STRLEN', key]; +} + +export const transformReply = transformReplyNumber; diff --git a/lib/commands/index.ts b/lib/commands/index.ts index 7f73e0e722..3ff07b0003 100644 --- a/lib/commands/index.ts +++ b/lib/commands/index.ts @@ -24,6 +24,7 @@ import * as EXISTS from './EXISTS'; import * as EXPIRE from './EXPIRE'; import * as EXPIREAT from './EXPIREAT'; import * as FLUSHALL from './FLUSHALL'; +import * as FLUSHDB from './FLUSHDB'; import * as GET from './GET'; import * as HDEL from './HDEL'; import * as HEXISTS from './HEXISTS'; @@ -45,10 +46,12 @@ import * as INCR from './INCR'; import * as INCRBY from './INCRBY'; import * as INCRBYFLOAT from './INCRBYFLOAT'; import * as KEYS from './KEYS'; +import * as LASTSAVE from './LASTSAVE'; import * as LINDEX from './LINDEX'; import * as LINSERT from './LINSERT'; import * as LLEN from './LLEN'; import * as LMOVE from './LMOVE'; +import * as LOLWUT from './LOLWUT'; import * as LPOP from './LPOP'; import * as LPOP_COUNT from './LPOP_COUNT'; import * as LPUSH from './LPUSH'; @@ -82,6 +85,7 @@ import * as SCARD from './SCARD'; import * as SDIFF from './SDIFF'; import * as SDIFFSTORE from './SDIFFSTORE'; import * as SET from './SET'; +import * as SETRANGE from './SETRANGE'; import * as SINTER from './SINTER'; import * as SINTERSTORE from './SINTERSTORE'; import * as SISMEMBER from './SISMEMBER'; @@ -94,6 +98,7 @@ import * as SRANDMEMBER_COUNT from './SRANDMEMBER_COUNT'; import * as SRANDMEMBER from './SRANDMEMBER'; import * as SREM from './SREM'; import * as SSCAN from './SSCAN'; +import * as STRLEN from './STRLEN'; import * as SUNION from './SUNION'; import * as SUNIONSTORE from './SUNIONSTORE'; import * as TOUCH from './TOUCH'; @@ -211,6 +216,8 @@ export default { expireAt: EXPIREAT, FLUSHALL, flushAll: FLUSHALL, + FLUSHDB, + flushDb: FLUSHDB, GET, get: GET, HDEL, @@ -253,6 +260,8 @@ export default { incrByFloat: INCRBYFLOAT, KEYS, keys: KEYS, + LASTSAVE, + lastSave: LASTSAVE, LINDEX, lIndex: LINDEX, LINSERT, @@ -261,6 +270,7 @@ export default { lLen: LLEN, LMOVE, lMove: LMOVE, + LOLWUT, LPOP_COUNT, lPopCount: LPOP_COUNT, LPOP, @@ -331,6 +341,8 @@ export default { sInterStore: SINTERSTORE, SET, set: SET, + SETRANGE, + setRange: SETRANGE, SISMEMBER, sIsMember: SISMEMBER, SMEMBERS, @@ -351,6 +363,8 @@ export default { sRem: SREM, SSCAN, sScan: SSCAN, + STRLEN, + strLen: STRLEN, SUNION, sUnion: SUNION, SUNIONSTORE, diff --git a/lib/test-utils.ts b/lib/test-utils.ts index 5a836fa837..1d3ae12c56 100644 --- a/lib/test-utils.ts +++ b/lib/test-utils.ts @@ -50,9 +50,9 @@ async function spawnPasswordServer(): Promise { } async function spawnOpenCluster(): Promise { - TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN] = [{ - port: (await spawnRedisCluster(TestRedisClusters.OPEN, 3))[0] - }]; + TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN] = (await spawnRedisCluster(TestRedisClusters.OPEN, 3)).map(port => ({ + port + })); } export function itWithClient(type: TestRedisServers, title: string, fn: (client: RedisClientType) => Promise): void {