diff --git a/lib/client.spec.ts b/lib/client.spec.ts index 2c3aebe3d8..45678ee469 100644 --- a/lib/client.spec.ts +++ b/lib/client.spec.ts @@ -323,4 +323,23 @@ describe('Client', () => { keys.sort() ); }); + + itWithClient(TestRedisServers.OPEN, 'sScanIterator', async client => { + const keys = []; + for (let i = 0; i < 100; i++) { + keys.push(i.toString()); + } + + await client.sAdd('key', keys); + + const set = new Set(); + for await (const key of client.sScanIterator('key')) { + set.add(key); + } + + assert.deepEqual( + [...set].sort(), + keys.sort() + ); + }); }); \ No newline at end of file diff --git a/lib/client.ts b/lib/client.ts index a7d9e04c08..eb756cb608 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -6,7 +6,8 @@ import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './ import EventEmitter from 'events'; import { CommandOptions, commandOptions, isCommandOptions } from './command-options'; import { RedisLuaScript, RedisLuaScripts } from './lua-script'; -import { ScanOptions } from './commands/SCAN'; +import { ScanOptions } from './commands/generic-transformers'; +import { ScanCommandOptions } from './commands/SCAN'; export interface RedisClientOptions { socket?: RedisSocketOptions; @@ -348,7 +349,7 @@ export default class RedisClient { + async* scanIterator(options?: ScanCommandOptions): AsyncIterable { let cursor = 0; do { const reply = await (this as any).scan(cursor, options); @@ -357,7 +358,18 @@ export default class RedisClient { + let cursor = 0; + do { + const reply = await (this as any).sScan(key, cursor, options); + cursor = reply.cursor; + for (const key of reply.keys) { + yield key; + } + } while (cursor !== 0) + } disconnect(): Promise { this.#queue.flushAll(new Error('Disconnecting')); diff --git a/lib/commands/SADD.spec.ts b/lib/commands/SADD.spec.ts new file mode 100644 index 0000000000..bf1ee48fe7 --- /dev/null +++ b/lib/commands/SADD.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SADD'; + +describe('SADD', () => { + describe('transformArguments', () => { + it('string', () => { + assert.deepEqual( + transformArguments('key', 'member'), + ['SADD', 'key', 'member'] + ); + }); + + it('array', () => { + assert.deepEqual( + transformArguments('key', ['1', '2']), + ['SADD', 'key', '1', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sAdd', async client => { + assert.equal( + await client.sAdd('key', 'member'), + 1 + ); + }); +}); diff --git a/lib/commands/SADD.ts b/lib/commands/SADD.ts new file mode 100644 index 0000000000..ca2a35e2c4 --- /dev/null +++ b/lib/commands/SADD.ts @@ -0,0 +1,17 @@ +import { transformReplyNumber } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, members: string | Array): Array { + const args = ['SADD', key]; + + if (typeof members === 'string') { + args.push(members); + } else { + args.push(...members); + } + + return args; +} + +export const transformReply = transformReplyNumber; diff --git a/lib/commands/SCAN.ts b/lib/commands/SCAN.ts index a4f7cf1afd..36d20257e3 100644 --- a/lib/commands/SCAN.ts +++ b/lib/commands/SCAN.ts @@ -1,22 +1,17 @@ +import { ScanOptions, transformScanArguments, transformScanReply } from './generic-transformers'; + export const IS_READ_ONLY = true; -export interface ScanOptions { - MATCH?: string; - COUNT?: number; +export interface ScanCommandOptions extends ScanOptions { TYPE?: string; } -export function transformArguments(cursor: number, options?: ScanOptions): Array { - const args = ['SCAN', cursor.toString()]; - - if (options?.MATCH) { - args.push('MATCH', options.MATCH); - } - - if (options?.COUNT) { - args.push('COUNT', options.COUNT.toString()); - } - +export function transformArguments(cursor: number, options?: ScanCommandOptions): Array { + const args = [ + 'SCAN', + ...transformScanArguments(cursor, options) + ]; + if (options?.TYPE) { args.push('TYPE', options.TYPE); } @@ -24,14 +19,4 @@ export function transformArguments(cursor: number, options?: ScanOptions): Array return args; } -interface ScanReply { - cursor: number; - keys: Array -} - -export function transformReply(reply: [string, Array]): ScanReply { - return { - cursor: Number(reply[0]), - keys: reply[1] - }; -} +export const transformReply = transformScanReply; diff --git a/lib/commands/SCARD.spec.ts b/lib/commands/SCARD.spec.ts new file mode 100644 index 0000000000..b668169381 --- /dev/null +++ b/lib/commands/SCARD.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SCARD'; + +describe('SCARD', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key'), + ['SCARD', 'key'] + ); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sCard', async client => { + assert.equal( + await client.sCard('key'), + 0 + ); + }); +}); diff --git a/lib/commands/SCARD.ts b/lib/commands/SCARD.ts new file mode 100644 index 0000000000..8a90bd3b02 --- /dev/null +++ b/lib/commands/SCARD.ts @@ -0,0 +1,9 @@ +import { transformReplyNumber } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string): Array { + return ['SCARD', key]; +} + +export const transformReply = transformReplyNumber; diff --git a/lib/commands/SDIFF.spec.ts b/lib/commands/SDIFF.spec.ts new file mode 100644 index 0000000000..82ef2dac6f --- /dev/null +++ b/lib/commands/SDIFF.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SDIFF'; + +describe('SDIFF', () => { + describe('transformArguments', () => { + it('string', () => { + assert.deepEqual( + transformArguments('key'), + ['SDIFF', 'key'] + ); + }); + + it('array', () => { + assert.deepEqual( + transformArguments(['1', '2']), + ['SDIFF', '1', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sDiff', async client => { + assert.deepEqual( + await client.sDiff('key'), + [] + ); + }); +}); diff --git a/lib/commands/SDIFF.ts b/lib/commands/SDIFF.ts new file mode 100644 index 0000000000..7a1d9fca74 --- /dev/null +++ b/lib/commands/SDIFF.ts @@ -0,0 +1,17 @@ +import { transformReplyStringArray } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(keys: string | Array): Array { + const args = ['SDIFF']; + + if (typeof keys === 'string') { + args.push(keys); + } else { + args.push(...keys); + } + + return args; +} + +export const transformReply = transformReplyStringArray; diff --git a/lib/commands/SDIFFSTORE.spec.ts b/lib/commands/SDIFFSTORE.spec.ts new file mode 100644 index 0000000000..1e7f5f6f32 --- /dev/null +++ b/lib/commands/SDIFFSTORE.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SDIFFSTORE'; + +describe('SDIFFSTORE', () => { + describe('transformArguments', () => { + it('string', () => { + assert.deepEqual( + transformArguments('destination', 'key'), + ['SDIFFSTORE', 'destination', 'key'] + ); + }); + + it('array', () => { + assert.deepEqual( + transformArguments('destination', ['1', '2']), + ['SDIFFSTORE', 'destination', '1', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sDiffStore', async client => { + assert.equal( + await client.sDiffStore('destination', 'key'), + 0 + ); + }); +}); diff --git a/lib/commands/SDIFFSTORE.ts b/lib/commands/SDIFFSTORE.ts new file mode 100644 index 0000000000..0eef7dd35f --- /dev/null +++ b/lib/commands/SDIFFSTORE.ts @@ -0,0 +1,17 @@ +import { transformReplyNumber } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(destination: string, keys: string | Array): Array { + const args = ['SDIFFSTORE', destination]; + + if (typeof keys === 'string') { + args.push(keys); + } else { + args.push(...keys); + } + + return args; +} + +export const transformReply = transformReplyNumber; diff --git a/lib/commands/SINTER.spec.ts b/lib/commands/SINTER.spec.ts new file mode 100644 index 0000000000..8fee35427c --- /dev/null +++ b/lib/commands/SINTER.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SINTER'; + +describe('SINTER', () => { + describe('transformArguments', () => { + it('string', () => { + assert.deepEqual( + transformArguments('key'), + ['SINTER', 'key'] + ); + }); + + it('array', () => { + assert.deepEqual( + transformArguments(['1', '2']), + ['SINTER', '1', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sInter', async client => { + assert.deepEqual( + await client.sInter('key'), + [] + ); + }); +}); diff --git a/lib/commands/SINTER.ts b/lib/commands/SINTER.ts new file mode 100644 index 0000000000..63ac569c02 --- /dev/null +++ b/lib/commands/SINTER.ts @@ -0,0 +1,17 @@ +import { transformReplyStringArray } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(keys: string | Array): Array { + const args = ['SINTER']; + + if (typeof keys === 'string') { + args.push(keys); + } else { + args.push(...keys); + } + + return args; +} + +export const transformReply = transformReplyStringArray; diff --git a/lib/commands/SINTERSTORE.spec.ts b/lib/commands/SINTERSTORE.spec.ts new file mode 100644 index 0000000000..013931d231 --- /dev/null +++ b/lib/commands/SINTERSTORE.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SINTERSTORE'; + +describe('SINTERSTORE', () => { + describe('transformArguments', () => { + it('string', () => { + assert.deepEqual( + transformArguments('destination', 'key'), + ['SINTERSTORE', 'destination', 'key'] + ); + }); + + it('array', () => { + assert.deepEqual( + transformArguments('destination', ['1', '2']), + ['SINTERSTORE', 'destination', '1', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sInterStore', async client => { + assert.equal( + await client.sInterStore('destination', 'key'), + 0 + ); + }); +}); diff --git a/lib/commands/SINTERSTORE.ts b/lib/commands/SINTERSTORE.ts new file mode 100644 index 0000000000..5cdeaf5937 --- /dev/null +++ b/lib/commands/SINTERSTORE.ts @@ -0,0 +1,17 @@ +import { transformReplyStringArray } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(destination: string, keys: string | Array): Array { + const args = ['SINTERSTORE', destination]; + + if (typeof keys === 'string') { + args.push(keys); + } else { + args.push(...keys); + } + + return args; +} + +export const transformReply = transformReplyStringArray; diff --git a/lib/commands/SISMEMBER.spec.ts b/lib/commands/SISMEMBER.spec.ts new file mode 100644 index 0000000000..5ce894956f --- /dev/null +++ b/lib/commands/SISMEMBER.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SISMEMBER'; + +describe('SISMEMBER', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'member'), + ['SISMEMBER', 'key', 'member'] + ); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sIsMember', async client => { + assert.equal( + await client.sIsMember('key', 'member'), + false + ); + }); +}); diff --git a/lib/commands/SISMEMBER.ts b/lib/commands/SISMEMBER.ts new file mode 100644 index 0000000000..149fc30289 --- /dev/null +++ b/lib/commands/SISMEMBER.ts @@ -0,0 +1,9 @@ +import { transformReplyBoolean, transformReplyNumber } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, member: string): Array { + return ['SISMEMBER', key, member]; +} + +export const transformReply = transformReplyBoolean; diff --git a/lib/commands/SMEMBERS.spec.ts b/lib/commands/SMEMBERS.spec.ts new file mode 100644 index 0000000000..2398dbaa8c --- /dev/null +++ b/lib/commands/SMEMBERS.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SMEMBERS'; + +describe('SMEMBERS', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key'), + ['SMEMBERS', 'key'] + ); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sMembers', async client => { + assert.deepEqual( + await client.sMembers('key'), + [] + ); + }); +}); diff --git a/lib/commands/SMEMBERS.ts b/lib/commands/SMEMBERS.ts new file mode 100644 index 0000000000..f42e438668 --- /dev/null +++ b/lib/commands/SMEMBERS.ts @@ -0,0 +1,9 @@ +import { transformReplyNumber, transformReplyStringArray } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string): Array { + return ['SMEMBERS', key]; +} + +export const transformReply = transformReplyStringArray; diff --git a/lib/commands/SMISMEMBER.spec.ts b/lib/commands/SMISMEMBER.spec.ts new file mode 100644 index 0000000000..f6130fb53c --- /dev/null +++ b/lib/commands/SMISMEMBER.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SMISMEMBER'; + +describe('SMISMEMBER', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', ['1', '2']), + ['SMISMEMBER', 'key', '1', '2'] + ); + }); + + itWithClient(TestRedisServers.OPEN, 'client.smIsMember', async client => { + assert.deepEqual( + await client.smIsMember('key', ['1', '2']), + [false, false] + ); + }); +}); diff --git a/lib/commands/SMISMEMBER.ts b/lib/commands/SMISMEMBER.ts new file mode 100644 index 0000000000..07637a689b --- /dev/null +++ b/lib/commands/SMISMEMBER.ts @@ -0,0 +1,9 @@ +import { transformReplyBooleanArray } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, members: Array): Array { + return ['SMISMEMBER', key, ...members]; +} + +export const transformReply = transformReplyBooleanArray; diff --git a/lib/commands/SMOVE.spec.ts b/lib/commands/SMOVE.spec.ts new file mode 100644 index 0000000000..97e938a46b --- /dev/null +++ b/lib/commands/SMOVE.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SMOVE'; + +describe('SMOVE', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('source', 'destination', 'member'), + ['SMOVE', 'source', 'destination', 'member'] + ); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sMove', async client => { + assert.equal( + await client.sMove('source', 'destination', 'member'), + false + ); + }); +}); diff --git a/lib/commands/SMOVE.ts b/lib/commands/SMOVE.ts new file mode 100644 index 0000000000..f8922f6ca3 --- /dev/null +++ b/lib/commands/SMOVE.ts @@ -0,0 +1,9 @@ +import { transformReplyBoolean } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(source: string, destination: string, member: string): Array { + return ['SMOVE', source, destination, member]; +} + +export const transformReply = transformReplyBoolean; diff --git a/lib/commands/SPOP.spec.ts b/lib/commands/SPOP.spec.ts new file mode 100644 index 0000000000..238c58f479 --- /dev/null +++ b/lib/commands/SPOP.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SPOP'; + +describe('SPOP', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + transformArguments('key'), + ['SPOP', 'key'] + ); + }); + + it('with count', () => { + assert.deepEqual( + transformArguments('key', 2), + ['SPOP', 'key', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sPop', async client => { + assert.equal( + await client.sPop('key'), + null + ); + }); +}); diff --git a/lib/commands/SPOP.ts b/lib/commands/SPOP.ts new file mode 100644 index 0000000000..a389fed5cc --- /dev/null +++ b/lib/commands/SPOP.ts @@ -0,0 +1,15 @@ +import { transformReplyStringArray } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, count?: number): Array { + const args = ['SPOP', key]; + + if (typeof count === 'number') { + args.push(count.toString()); + } + + return args; +} + +export const transformReply = transformReplyStringArray; diff --git a/lib/commands/SRANDMEMBER.spec.ts b/lib/commands/SRANDMEMBER.spec.ts new file mode 100644 index 0000000000..fa61d437a0 --- /dev/null +++ b/lib/commands/SRANDMEMBER.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SRANDMEMBER'; + +describe('SRANDMEMBER', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + transformArguments('key'), + ['SRANDMEMBER', 'key'] + ); + }); + + it('with count', () => { + assert.deepEqual( + transformArguments('key', 2), + ['SRANDMEMBER', 'key', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sRandMember', async client => { + assert.equal( + await client.sRandMember('key'), + null + ); + }); +}); diff --git a/lib/commands/SRANDMEMBER.ts b/lib/commands/SRANDMEMBER.ts new file mode 100644 index 0000000000..e93bbfe414 --- /dev/null +++ b/lib/commands/SRANDMEMBER.ts @@ -0,0 +1,16 @@ +import { transformReplyStringArray } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, count?: number): Array { + const args = ['SRANDMEMBER', key]; + + if (typeof count === 'number') { + args.push(count.toString()); + } + + return args; +} + +// TODO: without `count` it'll return "bulk string" and not "array" +export const transformReply = transformReplyStringArray; diff --git a/lib/commands/SREM.spec.ts b/lib/commands/SREM.spec.ts new file mode 100644 index 0000000000..c9270624ae --- /dev/null +++ b/lib/commands/SREM.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SREM'; + +describe('SREM', () => { + describe('transformArguments', () => { + it('string', () => { + assert.deepEqual( + transformArguments('key', 'member'), + ['SREM', 'key', 'member'] + ); + }); + + it('array', () => { + assert.deepEqual( + transformArguments('key', ['1', '2']), + ['SREM', 'key', '1', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sRem', async client => { + assert.equal( + await client.sRem('key', 'member'), + 0 + ); + }); +}); diff --git a/lib/commands/SREM.ts b/lib/commands/SREM.ts new file mode 100644 index 0000000000..090ce40360 --- /dev/null +++ b/lib/commands/SREM.ts @@ -0,0 +1,17 @@ +import { transformReplyNumber } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, members: string | Array): Array { + const args = ['SREM', key]; + + if (typeof members === 'string') { + args.push(members); + } else { + args.push(...members); + } + + return args; +} + +export const transformReply = transformReplyNumber; diff --git a/lib/commands/SSCAN.ts b/lib/commands/SSCAN.ts new file mode 100644 index 0000000000..24cd290b7b --- /dev/null +++ b/lib/commands/SSCAN.ts @@ -0,0 +1,13 @@ +import { ScanOptions, transformScanArguments, transformScanReply } from './generic-transformers'; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string, cursor: number, options?: ScanOptions): Array { + return [ + 'SSCAN', + key, + ...transformScanArguments(cursor, options) + ]; +} + +export const transformReply = transformScanReply; diff --git a/lib/commands/SUNION.spec.ts b/lib/commands/SUNION.spec.ts new file mode 100644 index 0000000000..fdf9766897 --- /dev/null +++ b/lib/commands/SUNION.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SUNION'; + +describe('SUNION', () => { + describe('transformArguments', () => { + it('string', () => { + assert.deepEqual( + transformArguments('key'), + ['SUNION', 'key'] + ); + }); + + it('array', () => { + assert.deepEqual( + transformArguments(['1', '2']), + ['SUNION', '1', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sUnion', async client => { + assert.deepEqual( + await client.sUnion('key'), + [] + ); + }); +}); diff --git a/lib/commands/SUNION.ts b/lib/commands/SUNION.ts new file mode 100644 index 0000000000..df2e6e0123 --- /dev/null +++ b/lib/commands/SUNION.ts @@ -0,0 +1,19 @@ +import { transformReplyStringArray } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(keys: string | Array): Array { + const args = ['SUNION']; + + if (typeof keys === 'string') { + args.push(keys); + } else { + args.push(...keys); + } + + return args; +} + +export const transformReply = transformReplyStringArray; diff --git a/lib/commands/SUNIONSTORE.spec.ts b/lib/commands/SUNIONSTORE.spec.ts new file mode 100644 index 0000000000..82c9a03a0b --- /dev/null +++ b/lib/commands/SUNIONSTORE.spec.ts @@ -0,0 +1,28 @@ +import { strict as assert } from 'assert'; +import { TestRedisServers, itWithClient } from '../test-utils'; +import { transformArguments } from './SUNIONSTORE'; + +describe('SUNIONSTORE', () => { + describe('transformArguments', () => { + it('string', () => { + assert.deepEqual( + transformArguments('destination', 'key'), + ['SUNIONSTORE', 'destination', 'key'] + ); + }); + + it('array', () => { + assert.deepEqual( + transformArguments('destination', ['1', '2']), + ['SUNIONSTORE', 'destination', '1', '2'] + ); + }); + }); + + itWithClient(TestRedisServers.OPEN, 'client.sUnionStore', async client => { + assert.equal( + await client.sUnionStore('destination', 'key'), + 0 + ); + }); +}); diff --git a/lib/commands/SUNIONSTORE.ts b/lib/commands/SUNIONSTORE.ts new file mode 100644 index 0000000000..d1695e9432 --- /dev/null +++ b/lib/commands/SUNIONSTORE.ts @@ -0,0 +1,17 @@ +import { transformReplyNumber } from './generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(destination: string, keys: string | Array): Array { + const args = ['SUNIONSTORE', destination]; + + if (typeof keys === 'string') { + args.push(keys); + } else { + args.push(...keys); + } + + return args; +} + +export const transformReply = transformReplyNumber; diff --git a/lib/commands/generic-transformers.ts b/lib/commands/generic-transformers.ts index 70c63bc221..3b73d7bcfb 100644 --- a/lib/commands/generic-transformers.ts +++ b/lib/commands/generic-transformers.ts @@ -13,3 +13,38 @@ export function transformReplyStringArray(reply: Array): Array { export function transformReplyBoolean(reply: number): boolean { return reply === 1; } + +export function transformReplyBooleanArray(reply: Array): Array { + return reply.map(transformReplyBoolean); +} + +export interface ScanOptions { + MATCH?: string; + COUNT?: number; +} + +export function transformScanArguments(cursor: number, options?: ScanOptions): Array { + const args = [cursor.toString()]; + + if (options?.MATCH) { + args.push('MATCH', options.MATCH); + } + + if (options?.COUNT) { + args.push('COUNT', options.COUNT.toString()); + } + + return args; +} + +export interface ScanReply { + cursor: number; + keys: Array +} + +export function transformScanReply([cursor, keys]: [string, Array]): ScanReply { + return { + cursor: Number(cursor), + keys + }; +} diff --git a/lib/commands/index.ts b/lib/commands/index.ts index f8a25203f5..862d349787 100644 --- a/lib/commands/index.ts +++ b/lib/commands/index.ts @@ -35,7 +35,23 @@ import * as LPUSH from './LPUSH'; import * as PING from './PING'; import * as PUBLISH from './PUBLISH'; import * as READONLY from './READONLY'; +import * as SADD from './SADD'; import * as SCAN from './SCAN'; +import * as SCARD from './SCARD'; +import * as SDIFF from './SDIFF'; +import * as SDIFFSTORE from './SDIFFSTORE'; +import * as SINTER from './SINTER'; +import * as SINTERSTORE from './SINTERSTORE'; +import * as SISMEMBER from './SISMEMBER'; +import * as SMEMBERS from './SMEMBERS'; +import * as SMISMEMBER from './SMISMEMBER'; +import * as SMOVE from './SMOVE'; +import * as SPOP from './SPOP'; +import * as SRANDMEMBER from './SRANDMEMBER'; +import * as SREM from './SREM'; +import * as SSCAN from './SSCAN'; +import * as SUNION from './SUNION'; +import * as SUNIONSTORE from './SUNIONSTORE'; import * as SET from './SET'; export default { @@ -113,8 +129,40 @@ export default { publish: PUBLISH, READONLY, readOnly: READONLY, + SADD, + sAdd: SADD, SCAN, scan: SCAN, + SCARD, + sCard: SCARD, + SDIFF, + sDiff: SDIFF, + SDIFFSTORE, + sDiffStore: SDIFFSTORE, + SINTER, + sInter: SINTER, + SINTERSTORE, + sInterStore: SINTERSTORE, + SISMEMBER, + sIsMember: SISMEMBER, + SMEMBERS, + sMembers: SMEMBERS, + SMISMEMBER, + smIsMember: SMISMEMBER, + SMOVE, + sMove: SMOVE, + SPOP, + sPop: SPOP, + SRANDMEMBER, + sRandMember: SRANDMEMBER, + SREM, + sRem: SREM, + SSCAN, + sScan: SSCAN, + SUNION, + sUnion: SUNION, + SUNIONSTORE, + sUnionStore: SUNIONSTORE, SET, set: SET };