From f93ac04436fe2287aefdae4de66a644e658cbde9 Mon Sep 17 00:00:00 2001 From: Avital Fine <79420960+AvitalFineRedis@users.noreply.github.com> Date: Wed, 29 Dec 2021 17:55:09 +0100 Subject: [PATCH] Bloom commands (#1786) * ft.alter * bloom commands * tdigest * delete tdigest * uncomment tests * small changes * Update MADD.ts * small changes * clean code * Update README.md * Update README.md Co-authored-by: leibale --- README.md | 3 +- package-lock.json | 30 ++++++++ packages/bloom/.npmignore | 6 ++ packages/bloom/.nycrc.json | 4 ++ packages/bloom/.release-it.json | 10 +++ packages/bloom/README.md | 1 + packages/bloom/lib/commands/bloom/ADD.spec.ts | 19 +++++ packages/bloom/lib/commands/bloom/ADD.ts | 7 ++ .../bloom/lib/commands/bloom/EXISTS.spec.ts | 19 +++++ packages/bloom/lib/commands/bloom/EXISTS.ts | 9 +++ .../bloom/lib/commands/bloom/INFO.spec.ts | 24 +++++++ packages/bloom/lib/commands/bloom/INFO.ts | 38 ++++++++++ .../bloom/lib/commands/bloom/INSERT.spec.ts | 69 +++++++++++++++++++ packages/bloom/lib/commands/bloom/INSERT.ts | 46 +++++++++++++ .../lib/commands/bloom/LOADCHUNK.spec.ts | 11 +++ .../bloom/lib/commands/bloom/LOADCHUNK.ts | 13 ++++ .../bloom/lib/commands/bloom/MADD.spec.ts | 19 +++++ packages/bloom/lib/commands/bloom/MADD.ts | 7 ++ .../bloom/lib/commands/bloom/MEXISTS.spec.ts | 19 +++++ packages/bloom/lib/commands/bloom/MEXISTS.ts | 9 +++ .../bloom/lib/commands/bloom/RESERVE.spec.ts | 49 +++++++++++++ packages/bloom/lib/commands/bloom/RESERVE.ts | 27 ++++++++ .../bloom/lib/commands/bloom/SCANDUMP.spec.ts | 11 +++ packages/bloom/lib/commands/bloom/SCANDUMP.ts | 24 +++++++ packages/bloom/lib/commands/bloom/index.ts | 30 ++++++++ .../commands/count-min-sketch/INCRBY.spec.ts | 41 +++++++++++ .../lib/commands/count-min-sketch/INCRBY.ts | 29 ++++++++ .../commands/count-min-sketch/INFO.spec.ts | 25 +++++++ .../lib/commands/count-min-sketch/INFO.ts | 30 ++++++++ .../count-min-sketch/INITBYDIM.spec.ts | 19 +++++ .../commands/count-min-sketch/INITBYDIM.ts | 7 ++ .../count-min-sketch/INITBYPROB.spec.ts | 19 +++++ .../commands/count-min-sketch/INITBYPROB.ts | 7 ++ .../commands/count-min-sketch/MERGE.spec.ts | 36 ++++++++++ .../lib/commands/count-min-sketch/MERGE.ts | 37 ++++++++++ .../commands/count-min-sketch/QUERY.spec.ts | 22 ++++++ .../lib/commands/count-min-sketch/QUERY.ts | 15 ++++ .../lib/commands/count-min-sketch/index.ts | 21 ++++++ .../bloom/lib/commands/cuckoo/ADD.spec.ts | 19 +++++ packages/bloom/lib/commands/cuckoo/ADD.ts | 7 ++ .../bloom/lib/commands/cuckoo/ADDNX.spec.ts | 21 ++++++ packages/bloom/lib/commands/cuckoo/ADDNX.ts | 7 ++ .../bloom/lib/commands/cuckoo/COUNT.spec.ts | 19 +++++ packages/bloom/lib/commands/cuckoo/COUNT.ts | 7 ++ .../bloom/lib/commands/cuckoo/DEL.spec.ts | 21 ++++++ packages/bloom/lib/commands/cuckoo/DEL.ts | 7 ++ .../bloom/lib/commands/cuckoo/EXISTS.spec.ts | 19 +++++ packages/bloom/lib/commands/cuckoo/EXISTS.ts | 9 +++ .../bloom/lib/commands/cuckoo/INFO.spec.ts | 27 ++++++++ packages/bloom/lib/commands/cuckoo/INFO.ts | 50 ++++++++++++++ .../bloom/lib/commands/cuckoo/INSERT.spec.ts | 22 ++++++ packages/bloom/lib/commands/cuckoo/INSERT.ts | 18 +++++ .../lib/commands/cuckoo/INSERTNX.spec.ts | 22 ++++++ .../bloom/lib/commands/cuckoo/INSERTNX.ts | 18 +++++ .../lib/commands/cuckoo/LOADCHUNK.spec.ts | 11 +++ .../bloom/lib/commands/cuckoo/LOADCHUNK.ts | 7 ++ .../bloom/lib/commands/cuckoo/RESERVE.spec.ts | 48 +++++++++++++ packages/bloom/lib/commands/cuckoo/RESERVE.ts | 31 +++++++++ .../lib/commands/cuckoo/SCANDUMP.spec.ts | 11 +++ .../bloom/lib/commands/cuckoo/SCANDUMP.ts | 22 ++++++ .../bloom/lib/commands/cuckoo/index.spec.ts | 48 +++++++++++++ packages/bloom/lib/commands/cuckoo/index.ts | 62 +++++++++++++++++ packages/bloom/lib/commands/index.ts | 11 +++ packages/bloom/lib/commands/top-k/ADD.spec.ts | 22 ++++++ packages/bloom/lib/commands/top-k/ADD.ts | 13 ++++ .../bloom/lib/commands/top-k/COUNT.spec.ts | 21 ++++++ packages/bloom/lib/commands/top-k/COUNT.ts | 15 ++++ .../bloom/lib/commands/top-k/INCRBY.spec.ts | 42 +++++++++++ packages/bloom/lib/commands/top-k/INCRBY.ts | 29 ++++++++ .../bloom/lib/commands/top-k/INFO.spec.ts | 23 +++++++ packages/bloom/lib/commands/top-k/INFO.ts | 34 +++++++++ .../bloom/lib/commands/top-k/LIST.spec.ts | 21 ++++++ packages/bloom/lib/commands/top-k/LIST.ts | 7 ++ .../bloom/lib/commands/top-k/QUERY.spec.ts | 21 ++++++ packages/bloom/lib/commands/top-k/QUERY.ts | 15 ++++ .../bloom/lib/commands/top-k/RESERVE.spec.ts | 32 +++++++++ packages/bloom/lib/commands/top-k/RESERVE.ts | 27 ++++++++ packages/bloom/lib/commands/top-k/index.ts | 24 +++++++ packages/bloom/lib/index.ts | 1 + packages/bloom/lib/test-utils.ts | 19 +++++ packages/bloom/package.json | 29 ++++++++ packages/bloom/tsconfig.json | 9 +++ packages/client/lib/client/index.spec.ts | 4 +- packages/client/lib/commands/index.ts | 1 - 84 files changed, 1760 insertions(+), 5 deletions(-) create mode 100644 packages/bloom/.npmignore create mode 100644 packages/bloom/.nycrc.json create mode 100644 packages/bloom/.release-it.json create mode 100644 packages/bloom/README.md create mode 100644 packages/bloom/lib/commands/bloom/ADD.spec.ts create mode 100644 packages/bloom/lib/commands/bloom/ADD.ts create mode 100644 packages/bloom/lib/commands/bloom/EXISTS.spec.ts create mode 100644 packages/bloom/lib/commands/bloom/EXISTS.ts create mode 100644 packages/bloom/lib/commands/bloom/INFO.spec.ts create mode 100644 packages/bloom/lib/commands/bloom/INFO.ts create mode 100644 packages/bloom/lib/commands/bloom/INSERT.spec.ts create mode 100644 packages/bloom/lib/commands/bloom/INSERT.ts create mode 100644 packages/bloom/lib/commands/bloom/LOADCHUNK.spec.ts create mode 100644 packages/bloom/lib/commands/bloom/LOADCHUNK.ts create mode 100644 packages/bloom/lib/commands/bloom/MADD.spec.ts create mode 100644 packages/bloom/lib/commands/bloom/MADD.ts create mode 100644 packages/bloom/lib/commands/bloom/MEXISTS.spec.ts create mode 100644 packages/bloom/lib/commands/bloom/MEXISTS.ts create mode 100644 packages/bloom/lib/commands/bloom/RESERVE.spec.ts create mode 100644 packages/bloom/lib/commands/bloom/RESERVE.ts create mode 100644 packages/bloom/lib/commands/bloom/SCANDUMP.spec.ts create mode 100644 packages/bloom/lib/commands/bloom/SCANDUMP.ts create mode 100644 packages/bloom/lib/commands/bloom/index.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/INCRBY.spec.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/INCRBY.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/INFO.spec.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/INFO.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/INITBYDIM.spec.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/INITBYDIM.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/INITBYPROB.spec.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/INITBYPROB.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/MERGE.spec.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/MERGE.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/QUERY.spec.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/QUERY.ts create mode 100644 packages/bloom/lib/commands/count-min-sketch/index.ts create mode 100644 packages/bloom/lib/commands/cuckoo/ADD.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/ADD.ts create mode 100644 packages/bloom/lib/commands/cuckoo/ADDNX.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/ADDNX.ts create mode 100644 packages/bloom/lib/commands/cuckoo/COUNT.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/COUNT.ts create mode 100644 packages/bloom/lib/commands/cuckoo/DEL.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/DEL.ts create mode 100644 packages/bloom/lib/commands/cuckoo/EXISTS.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/EXISTS.ts create mode 100644 packages/bloom/lib/commands/cuckoo/INFO.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/INFO.ts create mode 100644 packages/bloom/lib/commands/cuckoo/INSERT.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/INSERT.ts create mode 100644 packages/bloom/lib/commands/cuckoo/INSERTNX.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/INSERTNX.ts create mode 100644 packages/bloom/lib/commands/cuckoo/LOADCHUNK.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/LOADCHUNK.ts create mode 100644 packages/bloom/lib/commands/cuckoo/RESERVE.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/RESERVE.ts create mode 100644 packages/bloom/lib/commands/cuckoo/SCANDUMP.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/SCANDUMP.ts create mode 100644 packages/bloom/lib/commands/cuckoo/index.spec.ts create mode 100644 packages/bloom/lib/commands/cuckoo/index.ts create mode 100644 packages/bloom/lib/commands/index.ts create mode 100644 packages/bloom/lib/commands/top-k/ADD.spec.ts create mode 100644 packages/bloom/lib/commands/top-k/ADD.ts create mode 100644 packages/bloom/lib/commands/top-k/COUNT.spec.ts create mode 100644 packages/bloom/lib/commands/top-k/COUNT.ts create mode 100644 packages/bloom/lib/commands/top-k/INCRBY.spec.ts create mode 100644 packages/bloom/lib/commands/top-k/INCRBY.ts create mode 100644 packages/bloom/lib/commands/top-k/INFO.spec.ts create mode 100644 packages/bloom/lib/commands/top-k/INFO.ts create mode 100644 packages/bloom/lib/commands/top-k/LIST.spec.ts create mode 100644 packages/bloom/lib/commands/top-k/LIST.ts create mode 100644 packages/bloom/lib/commands/top-k/QUERY.spec.ts create mode 100644 packages/bloom/lib/commands/top-k/QUERY.ts create mode 100644 packages/bloom/lib/commands/top-k/RESERVE.spec.ts create mode 100644 packages/bloom/lib/commands/top-k/RESERVE.ts create mode 100644 packages/bloom/lib/commands/top-k/index.ts create mode 100644 packages/bloom/lib/index.ts create mode 100644 packages/bloom/lib/test-utils.ts create mode 100644 packages/bloom/package.json create mode 100644 packages/bloom/tsconfig.json diff --git a/README.md b/README.md index 911112ac5a..46ee50b90f 100644 --- a/README.md +++ b/README.md @@ -319,12 +319,11 @@ Node Redis is supported with the following versions of Redis: > Node Redis should work with older versions of Redis, but it is not fully tested and we cannot offer support. -## Packages - | Name | Description | |---------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [redis](./) | [![Downloads](https://img.shields.io/npm/dm/redis.svg)](https://www.npmjs.com/package/redis) [![Version](https://img.shields.io/npm/v/redis.svg)](https://www.npmjs.com/package/redis) | | [@node-redis/client](./packages/client) | [![Downloads](https://img.shields.io/npm/dm/@node-redis/client.svg)](https://www.npmjs.com/package/@node-redis/client) [![Version](https://img.shields.io/npm/v/@node-redis/client.svg)](https://www.npmjs.com/package/@node-redis/client) [![Docs](https://img.shields.io/badge/-documentation-dc382c)](https://redis.js.org/documentation/client/) | +| [@node-redis/bloom](./packages/bloom) | [![Downloads](https://img.shields.io/npm/dm/@node-redis/bloom.svg)](https://www.npmjs.com/package/@node-redis/bloom) [![Version](https://img.shields.io/npm/v/@node-redis/bloom.svg)](https://www.npmjs.com/package/@node-redis/bloom) [![Docs](https://img.shields.io/badge/-documentation-dc382c)](https://redis.js.org/documentation/bloom/) [Redis Bloom](https://oss.redis.com/redisbloom/) commands | | [@node-redis/json](./packages/json) | [![Downloads](https://img.shields.io/npm/dm/@node-redis/json.svg)](https://www.npmjs.com/package/@node-redis/json) [![Version](https://img.shields.io/npm/v/@node-redis/json.svg)](https://www.npmjs.com/package/@node-redis/json) [![Docs](https://img.shields.io/badge/-documentation-dc382c)](https://redis.js.org/documentation/json/) [Redis JSON](https://oss.redis.com/redisjson/) commands | | [@node-redis/search](./packages/search) | [![Downloads](https://img.shields.io/npm/dm/@node-redis/search.svg)](https://www.npmjs.com/package/@node-redis/search) [![Version](https://img.shields.io/npm/v/@node-redis/search.svg)](https://www.npmjs.com/package/@node-redis/search) [![Docs](https://img.shields.io/badge/-documentation-dc382c)](https://redis.js.org/documentation/search/) [Redis Search](https://oss.redis.com/redisearch/) commands | | [@node-redis/time-series](./packages/time-series) | [![Downloads](https://img.shields.io/npm/dm/@node-redis/time-series.svg)](https://www.npmjs.com/package/@node-redis/time-series) [![Version](https://img.shields.io/npm/v/@node-redis/time-series.svg)](https://www.npmjs.com/package/@node-redis/time-series) [![Docs](https://img.shields.io/badge/-documentation-dc382c)](https://redis.js.org/documentation/time-series/) [Redis Time-Series](https://oss.redis.com/redistimeseries/) commands | diff --git a/package-lock.json b/package-lock.json index 036227ba09..92f25780ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6648,6 +6648,23 @@ "peerDependencies": { "@node-redis/client": "^1.0.0" } + }, + "packages/time-series": { + "version": "1.0.0-rc.0", + "license": "MIT", + "devDependencies": { + "@istanbuljs/nyc-config-typescript": "^1.0.1", + "@node-redis/test-utils": "*", + "@types/node": "^16.11.7", + "nyc": "^15.1.0", + "release-it": "^14.11.7", + "source-map-support": "^0.5.20", + "ts-node": "^10.4.0", + "typescript": "^4.4.4" + }, + "peerDependencies": { + "@node-redis/client": "^1.0.0" + } } }, "dependencies": { @@ -7192,6 +7209,19 @@ "typescript": "^4.5.4" } }, + "@node-redis/time-series": { + "version": "file:packages/time-series", + "requires": { + "@istanbuljs/nyc-config-typescript": "^1.0.1", + "@node-redis/test-utils": "*", + "@types/node": "^16.11.7", + "nyc": "^15.1.0", + "release-it": "^14.11.7", + "source-map-support": "^0.5.20", + "ts-node": "^10.4.0", + "typescript": "^4.4.4" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", diff --git a/packages/bloom/.npmignore b/packages/bloom/.npmignore new file mode 100644 index 0000000000..bbef2b404f --- /dev/null +++ b/packages/bloom/.npmignore @@ -0,0 +1,6 @@ +.nyc_output/ +coverage/ +lib/ +.nycrc.json +.release-it.json +tsconfig.json diff --git a/packages/bloom/.nycrc.json b/packages/bloom/.nycrc.json new file mode 100644 index 0000000000..b4e671e178 --- /dev/null +++ b/packages/bloom/.nycrc.json @@ -0,0 +1,4 @@ +{ + "extends": "@istanbuljs/nyc-config-typescript", + "exclude": ["**/*.spec.ts", "lib/test-utils.ts"] +} diff --git a/packages/bloom/.release-it.json b/packages/bloom/.release-it.json new file mode 100644 index 0000000000..5d11263645 --- /dev/null +++ b/packages/bloom/.release-it.json @@ -0,0 +1,10 @@ +{ + "git": { + "tagName": "bloom@${version}", + "commitMessage": "Release ${tagName}", + "tagAnnotation": "Release ${tagName}" + }, + "npm": { + "publishArgs": ["--access", "public"] + } +} diff --git a/packages/bloom/README.md b/packages/bloom/README.md new file mode 100644 index 0000000000..d13769e02a --- /dev/null +++ b/packages/bloom/README.md @@ -0,0 +1 @@ +# @node-redis/bloom diff --git a/packages/bloom/lib/commands/bloom/ADD.spec.ts b/packages/bloom/lib/commands/bloom/ADD.spec.ts new file mode 100644 index 0000000000..e7ec340913 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/ADD.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './ADD'; + +describe('BF ADD', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['BF.ADD', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.bf.add', async client => { + assert.equal( + await client.bf.add('key', 'item'), + true + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/bloom/ADD.ts b/packages/bloom/lib/commands/bloom/ADD.ts new file mode 100644 index 0000000000..83dbc23c11 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/ADD.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, item: string): Array { + return ['BF.ADD', key, item]; +} + +export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/bloom/EXISTS.spec.ts b/packages/bloom/lib/commands/bloom/EXISTS.spec.ts new file mode 100644 index 0000000000..1088e739e6 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/EXISTS.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './EXISTS'; + +describe('BF EXISTS', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['BF.EXISTS', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.bf.exists', async client => { + assert.equal( + await client.bf.exists('key', 'item'), + false + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/bloom/EXISTS.ts b/packages/bloom/lib/commands/bloom/EXISTS.ts new file mode 100644 index 0000000000..2f06e60b9b --- /dev/null +++ b/packages/bloom/lib/commands/bloom/EXISTS.ts @@ -0,0 +1,9 @@ +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string, item: string): Array { + return ['BF.EXISTS', key, item]; +} + +export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/bloom/INFO.spec.ts b/packages/bloom/lib/commands/bloom/INFO.spec.ts new file mode 100644 index 0000000000..7a5e5724c2 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/INFO.spec.ts @@ -0,0 +1,24 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INFO'; + +describe('BF INFO', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('bloom'), + ['BF.INFO', 'bloom'] + ); + }); + + testUtils.testWithClient('client.bf.info', async client => { + await client.bf.reserve('key', 0.01, 100); + + const info = await client.bf.info('key'); + assert.equal(typeof info, 'object'); + assert.equal(info.capacity, 100); + assert.equal(typeof info.size, 'number'); + assert.equal(typeof info.numberOfFilters, 'number'); + assert.equal(typeof info.numberOfInsertedItems, 'number'); + assert.equal(typeof info.expansionRate, 'number'); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/bloom/INFO.ts b/packages/bloom/lib/commands/bloom/INFO.ts new file mode 100644 index 0000000000..52e9764640 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/INFO.ts @@ -0,0 +1,38 @@ +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string): Array { + return ['BF.INFO', key]; +} + +export type InfoRawReply = [ + _: string, + capacity: number, + _: string, + size: number, + _: string, + numberOfFilters: number, + _: string, + numberOfInsertedItems: number, + _: string, + expansionRate: number, +]; + +export interface InfoReply { + capacity: number; + size: number; + numberOfFilters: number; + numberOfInsertedItems: number; + expansionRate: number; +} + +export function transformReply(reply: InfoRawReply): InfoReply { + return { + capacity: reply[1], + size: reply[3], + numberOfFilters: reply[5], + numberOfInsertedItems: reply[7], + expansionRate: reply[9] + }; +} diff --git a/packages/bloom/lib/commands/bloom/INSERT.spec.ts b/packages/bloom/lib/commands/bloom/INSERT.spec.ts new file mode 100644 index 0000000000..aff9e6e282 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/INSERT.spec.ts @@ -0,0 +1,69 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INSERT'; + +describe('BF INSERT', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['BF.INSERT', 'key', 'ITEMS', 'item'] + ); + }); + + it('with CAPACITY', () => { + assert.deepEqual( + transformArguments('key', 'item', { CAPACITY: 100 }), + ['BF.INSERT', 'key', 'CAPACITY', '100', 'ITEMS', 'item'] + ); + }); + + it('with ERROR', () => { + assert.deepEqual( + transformArguments('key', 'item', { ERROR: 0.01 }), + ['BF.INSERT', 'key', 'ERROR', '0.01', 'ITEMS', 'item'] + ); + }); + + it('with EXPANSION', () => { + assert.deepEqual( + transformArguments('key', 'item', { EXPANSION: 1 }), + ['BF.INSERT', 'key', 'EXPANSION', '1', 'ITEMS', 'item'] + ); + }); + + it('with NOCREATE', () => { + assert.deepEqual( + transformArguments('key', 'item', { NOCREATE: true }), + ['BF.INSERT', 'key', 'NOCREATE', 'ITEMS', 'item'] + ); + }); + + it('with NONSCALING', () => { + assert.deepEqual( + transformArguments('key', 'item', { NONSCALING: true }), + ['BF.INSERT', 'key', 'NONSCALING', 'ITEMS', 'item'] + ); + }); + + it('with CAPACITY, ERROR, EXPANSION, NOCREATE and NONSCALING', () => { + assert.deepEqual( + transformArguments('key', 'item', { + CAPACITY: 100, + ERROR: 0.01, + EXPANSION: 1, + NOCREATE: true, + NONSCALING: true + }), + ['BF.INSERT', 'key', 'CAPACITY', '100', 'ERROR', '0.01', 'EXPANSION', '1', 'NOCREATE', 'NONSCALING', 'ITEMS', 'item'] + ); + }); + }); + + testUtils.testWithClient('client.bf.insert', async client => { + assert.deepEqual( + await client.bf.insert('key', 'item'), + [true] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/bloom/INSERT.ts b/packages/bloom/lib/commands/bloom/INSERT.ts new file mode 100644 index 0000000000..6bdb5fdf91 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/INSERT.ts @@ -0,0 +1,46 @@ +import { pushVerdictArguments } from '@node-redis/client/dist/lib/commands/generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +interface InsertOptions { + CAPACITY?: number; + ERROR?: number; + EXPANSION?: number; + NOCREATE?: true; + NONSCALING?: true; +} + +export function transformArguments( + key: string, + items: string | Array, + options?: InsertOptions +): Array { + const args = ['BF.INSERT', key]; + + if (options?.CAPACITY) { + args.push('CAPACITY', options.CAPACITY.toString()); + } + + if (options?.ERROR) { + args.push('ERROR', options.ERROR.toString()); + } + + if (options?.EXPANSION) { + args.push('EXPANSION', options.EXPANSION.toString()); + } + + if (options?.NOCREATE) { + args.push('NOCREATE'); + } + + if (options?.NONSCALING) { + args.push('NONSCALING'); + } + + args.push('ITEMS'); + pushVerdictArguments(args, items); + + return args; +} + +export { transformBooleanArrayReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/bloom/LOADCHUNK.spec.ts b/packages/bloom/lib/commands/bloom/LOADCHUNK.spec.ts new file mode 100644 index 0000000000..ea9f0acfa0 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/LOADCHUNK.spec.ts @@ -0,0 +1,11 @@ +import { strict as assert } from 'assert'; +import { transformArguments } from './LOADCHUNK'; + +describe('BF LOADCHUNK', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 0, ''), + ['BF.LOADCHUNK', 'key', '0', ''] + ); + }); +}); diff --git a/packages/bloom/lib/commands/bloom/LOADCHUNK.ts b/packages/bloom/lib/commands/bloom/LOADCHUNK.ts new file mode 100644 index 0000000000..b9c486c73c --- /dev/null +++ b/packages/bloom/lib/commands/bloom/LOADCHUNK.ts @@ -0,0 +1,13 @@ +import { RedisCommandArgument, RedisCommandArguments } from '@node-redis/client/dist/lib/commands'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments( + key: string, + iteretor: number, + chunk: RedisCommandArgument +): RedisCommandArguments { + return ['BF.LOADCHUNK', key, iteretor.toString(), chunk]; +} + +export declare function transformReply(): 'OK'; diff --git a/packages/bloom/lib/commands/bloom/MADD.spec.ts b/packages/bloom/lib/commands/bloom/MADD.spec.ts new file mode 100644 index 0000000000..784f99926f --- /dev/null +++ b/packages/bloom/lib/commands/bloom/MADD.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './MADD'; + +describe('BF MADD', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', ['1', '2']), + ['BF.MADD', 'key', '1', '2'] + ); + }); + + testUtils.testWithClient('client.ts.mAdd', async client => { + assert.deepEqual( + await client.bf.mAdd('key', ['1', '2']), + [true, true] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/bloom/MADD.ts b/packages/bloom/lib/commands/bloom/MADD.ts new file mode 100644 index 0000000000..7a81a3a08a --- /dev/null +++ b/packages/bloom/lib/commands/bloom/MADD.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, items: Array): Array { + return ['BF.MADD', key, ...items]; +} + +export { transformBooleanArrayReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/bloom/MEXISTS.spec.ts b/packages/bloom/lib/commands/bloom/MEXISTS.spec.ts new file mode 100644 index 0000000000..027e51d2c4 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/MEXISTS.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './MEXISTS'; + +describe('BF MEXISTS', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', ['1', '2']), + ['BF.MEXISTS', 'key', '1', '2'] + ); + }); + + testUtils.testWithClient('client.bf.mExists', async client => { + assert.deepEqual( + await client.bf.mExists('key', ['1', '2']), + [false, false] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/bloom/MEXISTS.ts b/packages/bloom/lib/commands/bloom/MEXISTS.ts new file mode 100644 index 0000000000..6b4627318b --- /dev/null +++ b/packages/bloom/lib/commands/bloom/MEXISTS.ts @@ -0,0 +1,9 @@ +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string, items: Array): Array { + return ['BF.MEXISTS', key, ...items]; +} + +export { transformBooleanArrayReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/bloom/RESERVE.spec.ts b/packages/bloom/lib/commands/bloom/RESERVE.spec.ts new file mode 100644 index 0000000000..bc872f9c3f --- /dev/null +++ b/packages/bloom/lib/commands/bloom/RESERVE.spec.ts @@ -0,0 +1,49 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './RESERVE'; + +describe('BF RESERVE', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + transformArguments('key', 0.01, 100), + ['BF.RESERVE', 'key', '0.01', '100'] + ); + }); + + it('with EXPANSION', () => { + assert.deepEqual( + transformArguments('key', 0.01, 100, { + EXPANSION: 1 + }), + ['BF.RESERVE', 'key', '0.01', '100', 'EXPANSION', '1'] + ); + }); + + it('with NONSCALING', () => { + assert.deepEqual( + transformArguments('key', 0.01, 100, { + NONSCALING: true + }), + ['BF.RESERVE', 'key', '0.01', '100', 'NONSCALING'] + ); + }); + + it('with EXPANSION and NONSCALING', () => { + assert.deepEqual( + transformArguments('key', 0.01, 100, { + EXPANSION: 1, + NONSCALING: true + }), + ['BF.RESERVE', 'key', '0.01', '100', 'EXPANSION', '1', 'NONSCALING'] + ); + }); + }); + + testUtils.testWithClient('client.bf.reserve', async client => { + assert.equal( + await client.bf.reserve('bloom', 0.01, 100), + 'OK' + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/bloom/RESERVE.ts b/packages/bloom/lib/commands/bloom/RESERVE.ts new file mode 100644 index 0000000000..18d7002f15 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/RESERVE.ts @@ -0,0 +1,27 @@ +export const FIRST_KEY_INDEX = 1; + +interface ReserveOptions { + EXPANSION?: number; + NONSCALING?: true; +} + +export function transformArguments( + key: string, + errorRate: number, + capacity: number, + options?: ReserveOptions +): Array { + const args = ['BF.RESERVE', key, errorRate.toString(), capacity.toString()]; + + if (options?.EXPANSION) { + args.push('EXPANSION', options.EXPANSION.toString()); + } + + if (options?.NONSCALING) { + args.push('NONSCALING'); + } + + return args; +} + +export declare function transformReply(): 'OK'; diff --git a/packages/bloom/lib/commands/bloom/SCANDUMP.spec.ts b/packages/bloom/lib/commands/bloom/SCANDUMP.spec.ts new file mode 100644 index 0000000000..8344016759 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/SCANDUMP.spec.ts @@ -0,0 +1,11 @@ +import { strict as assert } from 'assert'; +import { transformArguments } from './SCANDUMP'; + +describe('BF SCANDUMP', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 0), + ['BF.SCANDUMP', 'key', '0'] + ); + }); +}); diff --git a/packages/bloom/lib/commands/bloom/SCANDUMP.ts b/packages/bloom/lib/commands/bloom/SCANDUMP.ts new file mode 100644 index 0000000000..04b3edc2a1 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/SCANDUMP.ts @@ -0,0 +1,24 @@ +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string, iterator: number): Array { + return ['BF.SCANDUMP', key, iterator.toString()]; +} + +type ScanDumpRawReply = [ + iterator: number, + chunk: string +]; + +interface ScanDumpReply { + iterator: number; + chunk: string; +} + +export function transformReply([iterator, chunk]: ScanDumpRawReply): ScanDumpReply { + return { + iterator, + chunk + }; +} diff --git a/packages/bloom/lib/commands/bloom/index.ts b/packages/bloom/lib/commands/bloom/index.ts new file mode 100644 index 0000000000..c57b0f7953 --- /dev/null +++ b/packages/bloom/lib/commands/bloom/index.ts @@ -0,0 +1,30 @@ +import * as ADD from './ADD'; +import * as EXISTS from './EXISTS'; +import * as INFO from './INFO'; +import * as INSERT from './INSERT'; +import * as LOADCHUNK from './LOADCHUNK'; +import * as MADD from './MADD'; +import * as MEXISTS from './MEXISTS'; +import * as RESERVE from './RESERVE'; +import * as SCANDUMP from './SCANDUMP'; + +export default { + ADD, + add: ADD, + EXISTS, + exists: EXISTS, + INFO, + info: INFO, + INSERT, + insert: INSERT, + LOADCHUNK, + loadChunk: LOADCHUNK, + MADD, + mAdd: MADD, + MEXISTS, + mExists: MEXISTS, + RESERVE, + reserve: RESERVE, + SCANDUMP, + scanDump: SCANDUMP +}; diff --git a/packages/bloom/lib/commands/count-min-sketch/INCRBY.spec.ts b/packages/bloom/lib/commands/count-min-sketch/INCRBY.spec.ts new file mode 100644 index 0000000000..95bb28e88b --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/INCRBY.spec.ts @@ -0,0 +1,41 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INCRBY'; + +describe('CMS INCRBY', () => { + describe('transformArguments', () => { + it('single item', () => { + assert.deepEqual( + transformArguments('key', { + item: 'item', + incrementBy: 1 + }), + ['CMS.INCRBY', 'key', 'item', '1'] + ); + }); + + it('multiple items', () => { + assert.deepEqual( + transformArguments('key', [{ + item: 'a', + incrementBy: 1 + }, { + item: 'b', + incrementBy: 2 + }]), + ['CMS.INCRBY', 'key', 'a', '1', 'b', '2'] + ); + }); + }); + + testUtils.testWithClient('client.cms.incrBy', async client => { + await client.cms.initByDim('key', 1000, 5); + assert.deepEqual( + await client.cms.incrBy('key', { + item: 'item', + incrementBy: 1 + }), + [1] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/count-min-sketch/INCRBY.ts b/packages/bloom/lib/commands/count-min-sketch/INCRBY.ts new file mode 100644 index 0000000000..e27fb397cd --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/INCRBY.ts @@ -0,0 +1,29 @@ +export const FIRST_KEY_INDEX = 1; + +interface IncrByItem { + item: string; + incrementBy: number; +} + +export function transformArguments( + key: string, + items: IncrByItem | Array +): Array { + const args = ['CMS.INCRBY', key]; + + if (Array.isArray(items)) { + for (const item of items) { + pushIncrByItem(args, item); + } + } else { + pushIncrByItem(args, items); + } + + return args; +} + +function pushIncrByItem(args: Array, { item, incrementBy }: IncrByItem): void { + args.push(item, incrementBy.toString()); +} + +export declare function transformReply(): Array; diff --git a/packages/bloom/lib/commands/count-min-sketch/INFO.spec.ts b/packages/bloom/lib/commands/count-min-sketch/INFO.spec.ts new file mode 100644 index 0000000000..0db8a48447 --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/INFO.spec.ts @@ -0,0 +1,25 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INFO'; + +describe('CMS INFO', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key'), + ['CMS.INFO', 'key'] + ); + }); + + testUtils.testWithClient('client.cms.info', async client => { + await client.cms.initByDim('key', 1000, 5); + + assert.deepEqual( + await client.cms.info('key'), + { + width: 1000, + depth: 5, + count: 0 + } + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/count-min-sketch/INFO.ts b/packages/bloom/lib/commands/count-min-sketch/INFO.ts new file mode 100644 index 0000000000..6dbfffcb0e --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/INFO.ts @@ -0,0 +1,30 @@ +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string): Array { + return ['CMS.INFO', key]; +} + +export type InfoRawReply = [ + _: string, + width: number, + _: string, + depth: number, + _: string, + count: number +]; + +export interface InfoReply { + width: number; + depth: number; + count: number; +} + +export function transformReply(reply: InfoRawReply): InfoReply { + return { + width: reply[1], + depth: reply[3], + count: reply[5] + }; +} diff --git a/packages/bloom/lib/commands/count-min-sketch/INITBYDIM.spec.ts b/packages/bloom/lib/commands/count-min-sketch/INITBYDIM.spec.ts new file mode 100644 index 0000000000..2a9014b765 --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/INITBYDIM.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INITBYDIM'; + +describe('CMS INITBYDIM', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 1000, 5), + ['CMS.INITBYDIM', 'key', '1000', '5'] + ); + }); + + testUtils.testWithClient('client.cms.initByDim', async client => { + assert.equal( + await client.cms.initByDim('key', 1000, 5), + 'OK' + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/count-min-sketch/INITBYDIM.ts b/packages/bloom/lib/commands/count-min-sketch/INITBYDIM.ts new file mode 100644 index 0000000000..4ec6cedd9e --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/INITBYDIM.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, width: number, depth: number): Array { + return ['CMS.INITBYDIM', key, width.toString(), depth.toString()]; +} + +export declare function transformReply(): 'OK'; diff --git a/packages/bloom/lib/commands/count-min-sketch/INITBYPROB.spec.ts b/packages/bloom/lib/commands/count-min-sketch/INITBYPROB.spec.ts new file mode 100644 index 0000000000..004d3df14e --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/INITBYPROB.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INITBYPROB'; + +describe('CMS INITBYPROB', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 0.001, 0.01), + ['CMS.INITBYPROB', 'key', '0.001', '0.01'] + ); + }); + + testUtils.testWithClient('client.cms.initByProb', async client => { + assert.equal( + await client.cms.initByProb('key', 0.001, 0.01), + 'OK' + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/count-min-sketch/INITBYPROB.ts b/packages/bloom/lib/commands/count-min-sketch/INITBYPROB.ts new file mode 100644 index 0000000000..7f0256515f --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/INITBYPROB.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, error: number, probability: number): Array { + return ['CMS.INITBYPROB', key, error.toString(), probability.toString()]; +} + +export declare function transformReply(): 'OK'; diff --git a/packages/bloom/lib/commands/count-min-sketch/MERGE.spec.ts b/packages/bloom/lib/commands/count-min-sketch/MERGE.spec.ts new file mode 100644 index 0000000000..cf234e5734 --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/MERGE.spec.ts @@ -0,0 +1,36 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './MERGE'; + +describe('CMS MERGE', () => { + describe('transformArguments', () => { + it('without WEIGHTS', () => { + assert.deepEqual( + transformArguments('dest', ['src']), + ['CMS.MERGE', 'dest', '1', 'src'] + ); + }); + + it('with WEIGHTS', () => { + assert.deepEqual( + transformArguments('dest', [{ + name: 'src', + weight: 1 + }]), + ['CMS.MERGE', 'dest', '1', 'src', 'WEIGHTS', '1'] + ); + }); + }); + + testUtils.testWithClient('client.cms.merge', async client => { + await Promise.all([ + client.cms.initByDim('src', 1000, 5), + client.cms.initByDim('dest', 1000, 5), + ]); + + assert.equal( + await client.cms.merge('dest', ['src']), + 'OK' + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/count-min-sketch/MERGE.ts b/packages/bloom/lib/commands/count-min-sketch/MERGE.ts new file mode 100644 index 0000000000..6cca4e797c --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/MERGE.ts @@ -0,0 +1,37 @@ +export const FIRST_KEY_INDEX = 1; + +interface Sketch { + name: string; + weight: number; +} + +type Sketches = Array | Array; + +export function transformArguments(dest: string, src: Sketches): Array { + const args = [ + 'CMS.MERGE', + dest, + src.length.toString() + ]; + + if (isStringSketches(src)) { + args.push(...src); + } else { + for (const sketch of src) { + args.push(sketch.name); + } + + args.push('WEIGHTS'); + for (const sketch of src) { + args.push(sketch.weight.toString()); + } + } + + return args; +} + +function isStringSketches(src: Sketches): src is Array { + return typeof src[0] === 'string'; +} + +export declare function transformReply(): 'OK'; diff --git a/packages/bloom/lib/commands/count-min-sketch/QUERY.spec.ts b/packages/bloom/lib/commands/count-min-sketch/QUERY.spec.ts new file mode 100644 index 0000000000..d391ab838b --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/QUERY.spec.ts @@ -0,0 +1,22 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './QUERY'; + +describe('CMS QUERY', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['CMS.QUERY', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.cms.query', async client => { + await client.cms.initByDim('key', 1000, 5); + + assert.deepEqual( + await client.cms.query('key', 'item'), + [0] + ); + + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/count-min-sketch/QUERY.ts b/packages/bloom/lib/commands/count-min-sketch/QUERY.ts new file mode 100644 index 0000000000..4cdf8d6cc2 --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/QUERY.ts @@ -0,0 +1,15 @@ +import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands'; +import { pushVerdictArguments } from '@node-redis/client/dist/lib/commands/generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments( + key: string, + items: string | Array +): RedisCommandArguments { + return pushVerdictArguments(['CMS.QUERY', key], items); +} + +export declare function transformReply(): Array; diff --git a/packages/bloom/lib/commands/count-min-sketch/index.ts b/packages/bloom/lib/commands/count-min-sketch/index.ts new file mode 100644 index 0000000000..1d61734a8d --- /dev/null +++ b/packages/bloom/lib/commands/count-min-sketch/index.ts @@ -0,0 +1,21 @@ +import * as INCRBY from './INCRBY'; +import * as INFO from './INFO'; +import * as INITBYDIM from './INITBYDIM'; +import * as INITBYPROB from './INITBYPROB'; +import * as MERGE from './MERGE'; +import * as QUERY from './QUERY'; + +export default { + INCRBY, + incrBy: INCRBY, + INFO, + info: INFO, + INITBYDIM, + initByDim: INITBYDIM, + INITBYPROB, + initByProb: INITBYPROB, + MERGE, + merge: MERGE, + QUERY, + query: QUERY +}; diff --git a/packages/bloom/lib/commands/cuckoo/ADD.spec.ts b/packages/bloom/lib/commands/cuckoo/ADD.spec.ts new file mode 100644 index 0000000000..f2c029fad3 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/ADD.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments, transformReply } from './ADD'; + +describe('CF ADD', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['CF.ADD', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.cf.add', async client => { + assert.equal( + await client.cf.add('key', 'item'), + true + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/cuckoo/ADD.ts b/packages/bloom/lib/commands/cuckoo/ADD.ts new file mode 100644 index 0000000000..d24f1cfd7a --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/ADD.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, item: string): Array { + return ['CF.ADD', key, item]; +} + +export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/cuckoo/ADDNX.spec.ts b/packages/bloom/lib/commands/cuckoo/ADDNX.spec.ts new file mode 100644 index 0000000000..ddd9f922b1 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/ADDNX.spec.ts @@ -0,0 +1,21 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './ADDNX'; + +describe('CF ADDNX', () => { + describe('transformArguments', () => { + it('basic add', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['CF.ADDNX', 'key', 'item'] + ); + }); + }); + + testUtils.testWithClient('client.cf.add', async client => { + assert.equal( + await client.cf.addNX('key', 'item'), + true + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/cuckoo/ADDNX.ts b/packages/bloom/lib/commands/cuckoo/ADDNX.ts new file mode 100644 index 0000000000..238d156700 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/ADDNX.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, item: string): Array { + return ['CF.ADDNX', key, item]; +} + +export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/cuckoo/COUNT.spec.ts b/packages/bloom/lib/commands/cuckoo/COUNT.spec.ts new file mode 100644 index 0000000000..29f5b41593 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/COUNT.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './COUNT'; + +describe('CF COUNT', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['CF.COUNT', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.cf.count', async client => { + assert.equal( + await client.cf.count('key', 'item'), + 0 + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/cuckoo/COUNT.ts b/packages/bloom/lib/commands/cuckoo/COUNT.ts new file mode 100644 index 0000000000..c9f3e28b38 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/COUNT.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, item: string): Array { + return ['CF.COUNT', key, item]; +} + +export declare function transformReply(): number; diff --git a/packages/bloom/lib/commands/cuckoo/DEL.spec.ts b/packages/bloom/lib/commands/cuckoo/DEL.spec.ts new file mode 100644 index 0000000000..03da65881c --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/DEL.spec.ts @@ -0,0 +1,21 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './DEL'; + +describe('CF DEL', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['CF.DEL', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.cf.del', async client => { + await client.cf.reserve('key', 4); + + assert.equal( + await client.cf.del('key', 'item'), + false + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/cuckoo/DEL.ts b/packages/bloom/lib/commands/cuckoo/DEL.ts new file mode 100644 index 0000000000..d621bd0a0f --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/DEL.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, item: string): Array { + return ['CF.DEL', key, item]; +} + +export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/cuckoo/EXISTS.spec.ts b/packages/bloom/lib/commands/cuckoo/EXISTS.spec.ts new file mode 100644 index 0000000000..e281bde6d8 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/EXISTS.spec.ts @@ -0,0 +1,19 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './EXISTS'; + +describe('CF EXISTS', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['CF.EXISTS', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.cf.exists', async client => { + assert.equal( + await client.cf.exists('key', 'item'), + false + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/cuckoo/EXISTS.ts b/packages/bloom/lib/commands/cuckoo/EXISTS.ts new file mode 100644 index 0000000000..0a43ae55ff --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/EXISTS.ts @@ -0,0 +1,9 @@ +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string, item: string): Array { + return ['CF.EXISTS', key, item]; +} + +export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/cuckoo/INFO.spec.ts b/packages/bloom/lib/commands/cuckoo/INFO.spec.ts new file mode 100644 index 0000000000..c2ac5de6fe --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/INFO.spec.ts @@ -0,0 +1,27 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INFO'; + +describe('CF INFO', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('cuckoo'), + ['CF.INFO', 'cuckoo'] + ); + }); + + testUtils.testWithClient('client.cf.info', async client => { + await client.cf.reserve('key', 4); + + const info = await client.cf.info('key'); + assert.equal(typeof info, 'object'); + assert.equal(typeof info.size, 'number'); + assert.equal(typeof info.numberOfBuckets, 'number'); + assert.equal(typeof info.numberOfFilters, 'number'); + assert.equal(typeof info.numberOfInsertedItems, 'number'); + assert.equal(typeof info.numberOfDeletedItems, 'number'); + assert.equal(typeof info.bucketSize, 'number'); + assert.equal(typeof info.expansionRate, 'number'); + assert.equal(typeof info.maxIteration, 'number'); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/cuckoo/INFO.ts b/packages/bloom/lib/commands/cuckoo/INFO.ts new file mode 100644 index 0000000000..04d6954e37 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/INFO.ts @@ -0,0 +1,50 @@ +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string): Array { + return ['CF.INFO', key]; +} + +export type InfoRawReply = [ + _: string, + size: number, + _: string, + numberOfBuckets: number, + _: string, + numberOfFilters: number, + _: string, + numberOfInsertedItems: number, + _: string, + numberOfDeletedItems: number, + _: string, + bucketSize: number, + _: string, + expansionRate: number, + _: string, + maxIteration: number +]; + +export interface InfoReply { + size: number; + numberOfBuckets: number; + numberOfFilters: number; + numberOfInsertedItems: number; + numberOfDeletedItems: number; + bucketSize: number; + expansionRate: number; + maxIteration: number; +} + +export function transformReply(reply: InfoRawReply): InfoReply { + return { + size: reply[1], + numberOfBuckets: reply[3], + numberOfFilters: reply[5], + numberOfInsertedItems: reply[7], + numberOfDeletedItems: reply[9], + bucketSize: reply[11], + expansionRate: reply[13], + maxIteration: reply[15] + }; +} diff --git a/packages/bloom/lib/commands/cuckoo/INSERT.spec.ts b/packages/bloom/lib/commands/cuckoo/INSERT.spec.ts new file mode 100644 index 0000000000..9b56b86a6b --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/INSERT.spec.ts @@ -0,0 +1,22 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INSERT'; + +describe('CF INSERT', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item', { + CAPACITY: 100, + NOCREATE: true + }), + ['CF.INSERT', 'key', 'CAPACITY', '100', 'NOCREATE', 'ITEMS', 'item'] + ); + }); + + testUtils.testWithClient('client.cf.insert', async client => { + assert.deepEqual( + await client.cf.insert('key', 'item'), + [true] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/cuckoo/INSERT.ts b/packages/bloom/lib/commands/cuckoo/INSERT.ts new file mode 100644 index 0000000000..c2e56b5c35 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/INSERT.ts @@ -0,0 +1,18 @@ +import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands'; +import { InsertOptions, pushInsertOptions } from "."; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments( + key: string, + items: string | Array, + options?: InsertOptions +): RedisCommandArguments { + return pushInsertOptions( + ['CF.INSERT', key], + items, + options + ); +} + +export { transformBooleanArrayReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/cuckoo/INSERTNX.spec.ts b/packages/bloom/lib/commands/cuckoo/INSERTNX.spec.ts new file mode 100644 index 0000000000..7b1d974e5a --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/INSERTNX.spec.ts @@ -0,0 +1,22 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INSERTNX'; + +describe('CF INSERTNX', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item', { + CAPACITY: 100, + NOCREATE: true + }), + ['CF.INSERTNX', 'key', 'CAPACITY', '100', 'NOCREATE', 'ITEMS', 'item'] + ); + }); + + testUtils.testWithClient('client.cf.insertnx', async client => { + assert.deepEqual( + await client.cf.insertNX('key', 'item'), + [true] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/cuckoo/INSERTNX.ts b/packages/bloom/lib/commands/cuckoo/INSERTNX.ts new file mode 100644 index 0000000000..e7104ea4b1 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/INSERTNX.ts @@ -0,0 +1,18 @@ +import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands'; +import { InsertOptions, pushInsertOptions } from "."; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments( + key: string, + items: string | Array, + options?: InsertOptions +): RedisCommandArguments { + return pushInsertOptions( + ['CF.INSERTNX', key], + items, + options + ); +} + +export { transformBooleanArrayReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers'; diff --git a/packages/bloom/lib/commands/cuckoo/LOADCHUNK.spec.ts b/packages/bloom/lib/commands/cuckoo/LOADCHUNK.spec.ts new file mode 100644 index 0000000000..68dff468d4 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/LOADCHUNK.spec.ts @@ -0,0 +1,11 @@ +import { strict as assert } from 'assert'; +import { transformArguments } from './LOADCHUNK'; + +describe('CF LOADCHUNK', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('item', 0, ''), + ['CF.LOADCHUNK', 'item', '0', ''] + ); + }); +}); diff --git a/packages/bloom/lib/commands/cuckoo/LOADCHUNK.ts b/packages/bloom/lib/commands/cuckoo/LOADCHUNK.ts new file mode 100644 index 0000000000..5d22109978 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/LOADCHUNK.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, iterator: number, chunk: string): Array { + return ['CF.LOADCHUNK', key, iterator.toString(), chunk]; +} + +export declare function transformReply(): 'OK'; diff --git a/packages/bloom/lib/commands/cuckoo/RESERVE.spec.ts b/packages/bloom/lib/commands/cuckoo/RESERVE.spec.ts new file mode 100644 index 0000000000..3145a222c5 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/RESERVE.spec.ts @@ -0,0 +1,48 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './RESERVE'; + +describe('CF RESERVE', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + transformArguments('key', 4), + ['CF.RESERVE', 'key', '4'] + ); + }); + + it('with EXPANSION', () => { + assert.deepEqual( + transformArguments('key', 4, { + EXPANSION: 1 + }), + ['CF.RESERVE', 'key', '4', 'EXPANSION', '1'] + ); + }); + + it('with BUCKETSIZE', () => { + assert.deepEqual( + transformArguments('key', 4, { + BUCKETSIZE: 2 + }), + ['CF.RESERVE', 'key', '4', 'BUCKETSIZE', '2'] + ); + }); + + it('with MAXITERATIONS', () => { + assert.deepEqual( + transformArguments('key', 4, { + MAXITERATIONS: 1 + }), + ['CF.RESERVE', 'key', '4', 'MAXITERATIONS', '1'] + ); + }); + }); + + testUtils.testWithClient('client.cf.reserve', async client => { + assert.equal( + await client.cf.reserve('key', 4), + 'OK' + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/cuckoo/RESERVE.ts b/packages/bloom/lib/commands/cuckoo/RESERVE.ts new file mode 100644 index 0000000000..114c1fdf44 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/RESERVE.ts @@ -0,0 +1,31 @@ +export const FIRST_KEY_INDEX = 1; + +interface ReserveOptions { + BUCKETSIZE?: number; + MAXITERATIONS?: number; + EXPANSION?: number; +} + +export function transformArguments( + key: string, + capacity: number, + options?: ReserveOptions +): Array { + const args = ['CF.RESERVE', key, capacity.toString()]; + + if (options?.BUCKETSIZE) { + args.push('BUCKETSIZE', options.BUCKETSIZE.toString()); + } + + if (options?.MAXITERATIONS) { + args.push('MAXITERATIONS', options.MAXITERATIONS.toString()); + } + + if (options?.EXPANSION) { + args.push('EXPANSION', options.EXPANSION.toString()); + } + + return args; +} + +export declare function transformReply(): 'OK'; diff --git a/packages/bloom/lib/commands/cuckoo/SCANDUMP.spec.ts b/packages/bloom/lib/commands/cuckoo/SCANDUMP.spec.ts new file mode 100644 index 0000000000..43b812999f --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/SCANDUMP.spec.ts @@ -0,0 +1,11 @@ +import { strict as assert } from 'assert'; +import { transformArguments } from './SCANDUMP'; + +describe('CF SCANDUMP', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 0), + ['CF.SCANDUMP', 'key', '0'] + ); + }); +}); diff --git a/packages/bloom/lib/commands/cuckoo/SCANDUMP.ts b/packages/bloom/lib/commands/cuckoo/SCANDUMP.ts new file mode 100644 index 0000000000..dcabadb710 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/SCANDUMP.ts @@ -0,0 +1,22 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string, iterator: number): Array { + return ['CF.SCANDUMP', key, iterator.toString()]; +} + +type ScanDumpRawReply = [ + iterator: number, + chunk: string +]; + +interface ScanDumpReply { + iterator: number; + chunk: string; +} + +export function transformReply([iterator, chunk]: ScanDumpRawReply): ScanDumpReply { + return { + iterator, + chunk + }; +} diff --git a/packages/bloom/lib/commands/cuckoo/index.spec.ts b/packages/bloom/lib/commands/cuckoo/index.spec.ts new file mode 100644 index 0000000000..94f3a0ae28 --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/index.spec.ts @@ -0,0 +1,48 @@ +import { strict as assert } from 'assert'; +import { pushInsertOptions } from '.'; + +describe('pushInsertOptions', () => { + describe('single item', () => { + it('single item', () => { + assert.deepEqual( + pushInsertOptions([], 'item'), + ['ITEMS', 'item'] + ); + }); + + it('multiple items', () => { + assert.deepEqual( + pushInsertOptions([], ['1', '2']), + ['ITEMS', '1', '2'] + ); + }); + }); + + it('with CAPACITY', () => { + assert.deepEqual( + pushInsertOptions([], 'item', { + CAPACITY: 100 + }), + ['CAPACITY', '100', 'ITEMS', 'item'] + ); + }); + + it('with NOCREATE', () => { + assert.deepEqual( + pushInsertOptions([], 'item', { + NOCREATE: true + }), + ['NOCREATE', 'ITEMS', 'item'] + ); + }); + + it('with CAPACITY and NOCREATE', () => { + assert.deepEqual( + pushInsertOptions([], 'item', { + CAPACITY: 100, + NOCREATE: true + }), + ['CAPACITY', '100', 'NOCREATE', 'ITEMS', 'item'] + ); + }); +}); diff --git a/packages/bloom/lib/commands/cuckoo/index.ts b/packages/bloom/lib/commands/cuckoo/index.ts new file mode 100644 index 0000000000..71137ceaaf --- /dev/null +++ b/packages/bloom/lib/commands/cuckoo/index.ts @@ -0,0 +1,62 @@ + +import * as ADD from './ADD'; +import * as ADDNX from './ADDNX'; +import * as COUNT from './COUNT'; +import * as DEL from './DEL'; +import * as EXISTS from './EXISTS'; +import * as INFO from './INFO'; +import * as INSERT from './INSERT'; +import * as INSERTNX from './INSERTNX'; +import * as LOADCHUNK from './LOADCHUNK'; +import * as RESERVE from './RESERVE'; +import * as SCANDUMP from './SCANDUMP'; +import { pushVerdictArguments } from '@node-redis/client/lib/commands/generic-transformers'; +import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands'; + +export default { + ADD, + add: ADD, + ADDNX, + addNX: ADDNX, + COUNT, + count: COUNT, + DEL, + del: DEL, + EXISTS, + exists: EXISTS, + INFO, + info: INFO, + INSERT, + insert: INSERT, + INSERTNX, + insertNX: INSERTNX, + LOADCHUNK, + loadChunk: LOADCHUNK, + RESERVE, + reserve: RESERVE, + SCANDUMP, + scanDump: SCANDUMP +}; + +export interface InsertOptions { + CAPACITY?: number; + NOCREATE?: true; +} + +export function pushInsertOptions( + args: RedisCommandArguments, + items: string | Array, + options?: InsertOptions +): RedisCommandArguments { + if (options?.CAPACITY) { + args.push('CAPACITY'); + args.push(options.CAPACITY.toString()); + } + + if (options?.NOCREATE) { + args.push('NOCREATE'); + } + + args.push('ITEMS'); + return pushVerdictArguments(args, items); +} diff --git a/packages/bloom/lib/commands/index.ts b/packages/bloom/lib/commands/index.ts new file mode 100644 index 0000000000..665664a75b --- /dev/null +++ b/packages/bloom/lib/commands/index.ts @@ -0,0 +1,11 @@ +import Bloom from './bloom'; +import CountMinSketch from './count-min-sketch'; +import Cuckoo from './cuckoo'; +import TopK from './top-k'; + +export default { + bf: Bloom, + cms: CountMinSketch, + cf: Cuckoo, + topK: TopK +}; diff --git a/packages/bloom/lib/commands/top-k/ADD.spec.ts b/packages/bloom/lib/commands/top-k/ADD.spec.ts new file mode 100644 index 0000000000..149007f81d --- /dev/null +++ b/packages/bloom/lib/commands/top-k/ADD.spec.ts @@ -0,0 +1,22 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './ADD'; + +describe('TOPK ADD', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['TOPK.ADD', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.topK.add', async client => { + await client.topK.reserve('topK', 3); + + assert.deepEqual( + await client.topK.add('topK', 'item'), + [null] + ); + + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/top-k/ADD.ts b/packages/bloom/lib/commands/top-k/ADD.ts new file mode 100644 index 0000000000..250b75ae04 --- /dev/null +++ b/packages/bloom/lib/commands/top-k/ADD.ts @@ -0,0 +1,13 @@ +import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands'; +import { pushVerdictArguments } from '@node-redis/client/dist/lib/commands/generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export function transformArguments( + key: string, + items: string | Array +): RedisCommandArguments { + return pushVerdictArguments(['TOPK.ADD', key], items); +} + +export declare function transformReply(): Array; diff --git a/packages/bloom/lib/commands/top-k/COUNT.spec.ts b/packages/bloom/lib/commands/top-k/COUNT.spec.ts new file mode 100644 index 0000000000..318fc74c67 --- /dev/null +++ b/packages/bloom/lib/commands/top-k/COUNT.spec.ts @@ -0,0 +1,21 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './COUNT'; + +describe('TOPK COUNT', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['TOPK.COUNT', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.topK.count', async client => { + await client.topK.reserve('key', 3); + + assert.deepEqual( + await client.topK.count('key', 'item'), + [0] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/top-k/COUNT.ts b/packages/bloom/lib/commands/top-k/COUNT.ts new file mode 100644 index 0000000000..854d50d897 --- /dev/null +++ b/packages/bloom/lib/commands/top-k/COUNT.ts @@ -0,0 +1,15 @@ +import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands'; +import { pushVerdictArguments } from '@node-redis/client/dist/lib/commands/generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments( + key: string, + items: string | Array +): RedisCommandArguments { + return pushVerdictArguments(['TOPK.COUNT', key], items); +} + +export declare function transformReply(): Array; diff --git a/packages/bloom/lib/commands/top-k/INCRBY.spec.ts b/packages/bloom/lib/commands/top-k/INCRBY.spec.ts new file mode 100644 index 0000000000..b23ca6e0ed --- /dev/null +++ b/packages/bloom/lib/commands/top-k/INCRBY.spec.ts @@ -0,0 +1,42 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INCRBY'; + +describe('TOPK INCRBY', () => { + describe('transformArguments', () => { + it('single item', () => { + assert.deepEqual( + transformArguments('key', { + item: 'item', + incrementBy: 1 + }), + ['TOPK.INCRBY', 'key', 'item', '1'] + ); + }); + + it('multiple items', () => { + assert.deepEqual( + transformArguments('key', [{ + item: 'a', + incrementBy: 1 + }, { + item: 'b', + incrementBy: 2 + }]), + ['TOPK.INCRBY', 'key', 'a', '1', 'b', '2'] + ); + }); + }); + + testUtils.testWithClient('client.topK.incrby', async client => { + await client.topK.reserve('key', 5); + + assert.deepEqual( + await client.topK.incrBy('key', { + item: 'item', + incrementBy: 1 + }), + [null] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/top-k/INCRBY.ts b/packages/bloom/lib/commands/top-k/INCRBY.ts new file mode 100644 index 0000000000..2533cb0559 --- /dev/null +++ b/packages/bloom/lib/commands/top-k/INCRBY.ts @@ -0,0 +1,29 @@ +export const FIRST_KEY_INDEX = 1; + +interface IncrByItem { + item: string; + incrementBy: number; +} + +export function transformArguments( + key: string, + items: IncrByItem | Array +): Array { + const args = ['TOPK.INCRBY', key]; + + if (Array.isArray(items)) { + for (const item of items) { + pushIncrByItem(args, item); + } + } else { + pushIncrByItem(args, items); + } + + return args; +} + +function pushIncrByItem(args: Array, { item, incrementBy }: IncrByItem): void { + args.push(item, incrementBy.toString()); +} + +export declare function transformReply(): Array; diff --git a/packages/bloom/lib/commands/top-k/INFO.spec.ts b/packages/bloom/lib/commands/top-k/INFO.spec.ts new file mode 100644 index 0000000000..2741a58a8b --- /dev/null +++ b/packages/bloom/lib/commands/top-k/INFO.spec.ts @@ -0,0 +1,23 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './INFO'; + +describe('TOPK INFO', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key'), + ['TOPK.INFO', 'key'] + ); + }); + + testUtils.testWithClient('client.topK.info', async client => { + await client.topK.reserve('key', 3); + + const info = await client.topK.info('key'); + assert.equal(typeof info, 'object'); + assert.equal(info.k, 3); + assert.equal(typeof info.width, 'number'); + assert.equal(typeof info.depth, 'number'); + assert.equal(typeof info.decay, 'number'); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/top-k/INFO.ts b/packages/bloom/lib/commands/top-k/INFO.ts new file mode 100644 index 0000000000..8c9e8d432b --- /dev/null +++ b/packages/bloom/lib/commands/top-k/INFO.ts @@ -0,0 +1,34 @@ +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments(key: string): Array { + return ['TOPK.INFO', key]; +} + +export type InfoRawReply = [ + _: string, + k: number, + _: string, + width: number, + _: string, + depth: number, + _: string, + decay: string +]; + +export interface InfoReply { + k: number, + width: number; + depth: number; + decay: number; +} + +export function transformReply(reply: InfoRawReply): InfoReply { + return { + k: reply[1], + width: reply[3], + depth: reply[5], + decay: Number(reply[7]) + }; +} diff --git a/packages/bloom/lib/commands/top-k/LIST.spec.ts b/packages/bloom/lib/commands/top-k/LIST.spec.ts new file mode 100644 index 0000000000..709ac7ffc3 --- /dev/null +++ b/packages/bloom/lib/commands/top-k/LIST.spec.ts @@ -0,0 +1,21 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './LIST'; + +describe('TOPK LIST', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key'), + ['TOPK.LIST', 'key'] + ); + }); + + testUtils.testWithClient('client.topK.list', async client => { + await client.topK.reserve('key', 3); + + assert.deepEqual( + await client.topK.list('key'), + [] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/top-k/LIST.ts b/packages/bloom/lib/commands/top-k/LIST.ts new file mode 100644 index 0000000000..d8c1654559 --- /dev/null +++ b/packages/bloom/lib/commands/top-k/LIST.ts @@ -0,0 +1,7 @@ +export const FIRST_KEY_INDEX = 1; + +export function transformArguments(key: string): Array { + return ['TOPK.LIST', key]; +} + +export declare function transformReply(): Array; diff --git a/packages/bloom/lib/commands/top-k/QUERY.spec.ts b/packages/bloom/lib/commands/top-k/QUERY.spec.ts new file mode 100644 index 0000000000..ada9e7e2e3 --- /dev/null +++ b/packages/bloom/lib/commands/top-k/QUERY.spec.ts @@ -0,0 +1,21 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './QUERY'; + +describe('TOPK QUERY', () => { + it('transformArguments', () => { + assert.deepEqual( + transformArguments('key', 'item'), + ['TOPK.QUERY', 'key', 'item'] + ); + }); + + testUtils.testWithClient('client.cms.query', async client => { + await client.topK.reserve('key', 3); + + assert.deepEqual( + await client.topK.query('key', 'item'), + [0] + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/top-k/QUERY.ts b/packages/bloom/lib/commands/top-k/QUERY.ts new file mode 100644 index 0000000000..7b261f35b8 --- /dev/null +++ b/packages/bloom/lib/commands/top-k/QUERY.ts @@ -0,0 +1,15 @@ +import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands'; +import { pushVerdictArguments } from '@node-redis/client/dist/lib/commands/generic-transformers'; + +export const FIRST_KEY_INDEX = 1; + +export const IS_READ_ONLY = true; + +export function transformArguments( + key: string, + items: string | Array +): RedisCommandArguments { + return pushVerdictArguments(['TOPK.QUERY', key], items); +} + +export declare function transformReply(): Array; diff --git a/packages/bloom/lib/commands/top-k/RESERVE.spec.ts b/packages/bloom/lib/commands/top-k/RESERVE.spec.ts new file mode 100644 index 0000000000..54600c0e4f --- /dev/null +++ b/packages/bloom/lib/commands/top-k/RESERVE.spec.ts @@ -0,0 +1,32 @@ +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../../test-utils'; +import { transformArguments } from './RESERVE'; + +describe('TOPK RESERVE', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + transformArguments('topK', 3), + ['TOPK.RESERVE', 'topK', '3'] + ); + }); + + it('with options', () => { + assert.deepEqual( + transformArguments('topK', 3, { + width: 8, + depth: 7, + decay: 0.9 + }), + ['TOPK.RESERVE', 'topK', '3', '8', '7', '0.9'] + ); + }); + }); + + testUtils.testWithClient('client.topK.reserve', async client => { + assert.equal( + await client.topK.reserve('topK', 3), + 'OK' + ); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/bloom/lib/commands/top-k/RESERVE.ts b/packages/bloom/lib/commands/top-k/RESERVE.ts new file mode 100644 index 0000000000..6512db51e0 --- /dev/null +++ b/packages/bloom/lib/commands/top-k/RESERVE.ts @@ -0,0 +1,27 @@ +export const FIRST_KEY_INDEX = 1; + +interface ReserveOptions { + width: number; + depth: number; + decay: number; +} + +export function transformArguments( + key: string, + topK: number, + options?: ReserveOptions +): Array { + const args = ['TOPK.RESERVE', key, topK.toString()]; + + if (options) { + args.push( + options.width.toString(), + options.depth.toString(), + options.decay.toString() + ); + } + + return args; +} + +export declare function transformReply(): 'OK'; diff --git a/packages/bloom/lib/commands/top-k/index.ts b/packages/bloom/lib/commands/top-k/index.ts new file mode 100644 index 0000000000..05d6ba87ea --- /dev/null +++ b/packages/bloom/lib/commands/top-k/index.ts @@ -0,0 +1,24 @@ +import * as ADD from './ADD'; +import * as COUNT from './COUNT'; +import * as INCRBY from './INCRBY'; +import * as INFO from './INFO'; +import * as LIST from './LIST'; +import * as QUERY from './QUERY'; +import * as RESERVE from './RESERVE'; + +export default { + ADD, + add: ADD, + COUNT, + count: COUNT, + INCRBY, + incrBy: INCRBY, + INFO, + info: INFO, + LIST, + list: LIST, + QUERY, + query: QUERY, + RESERVE, + reserve: RESERVE +}; diff --git a/packages/bloom/lib/index.ts b/packages/bloom/lib/index.ts new file mode 100644 index 0000000000..bc0e103e8c --- /dev/null +++ b/packages/bloom/lib/index.ts @@ -0,0 +1 @@ +export { default } from './commands'; diff --git a/packages/bloom/lib/test-utils.ts b/packages/bloom/lib/test-utils.ts new file mode 100644 index 0000000000..7c5780a3cd --- /dev/null +++ b/packages/bloom/lib/test-utils.ts @@ -0,0 +1,19 @@ +import TestUtils from '@node-redis/test-utils'; +import RedisBloomModules from '.'; + +export default new TestUtils({ + dockerImageName: 'redislabs/rebloom', + dockerImageVersionArgument: 'redisbloom-version', + defaultDockerVersion: '2.2.9' +}); + +export const GLOBAL = { + SERVERS: { + OPEN: { + serverArguments: ['--loadmodule /usr/lib/redis/modules/redisbloom.so'], + clientOptions: { + modules: RedisBloomModules + } + } + } +}; diff --git a/packages/bloom/package.json b/packages/bloom/package.json new file mode 100644 index 0000000000..10855d64e4 --- /dev/null +++ b/packages/bloom/package.json @@ -0,0 +1,29 @@ +{ + "name": "@node-redis/bloom", + "version": "1.0.0", + "license": "MIT", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "./dist" + ], + "scripts": { + "test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'", + "build": "tsc", + "documentation": "typedoc" + }, + "peerDependencies": { + "@node-redis/client": "^1.0.0" + }, + "devDependencies": { + "@istanbuljs/nyc-config-typescript": "^1.0.2", + "@node-redis/test-utils": "*", + "@types/node": "^17.0.1", + "nyc": "^15.1.0", + "release-it": "^14.11.8", + "source-map-support": "^0.5.21", + "ts-node": "^10.4.0", + "typedoc": "^0.22.10", + "typescript": "^4.5.4" + } +} diff --git a/packages/bloom/tsconfig.json b/packages/bloom/tsconfig.json new file mode 100644 index 0000000000..14fda1d871 --- /dev/null +++ b/packages/bloom/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist" + }, + "include": [ + "./lib/**/*.ts" + ] +} diff --git a/packages/client/lib/client/index.spec.ts b/packages/client/lib/client/index.spec.ts index bf9fa7ae3e..3b5e952c3b 100644 --- a/packages/client/lib/client/index.spec.ts +++ b/packages/client/lib/client/index.spec.ts @@ -321,9 +321,9 @@ describe('Client', () => { testUtils.testWithClient('returnBuffers', async client => { assert.deepEqual( - await client.sendCommand(['PING'], RedisClient.commandOptions({ + await client.sendCommand(['PING'], { returnBuffers: true - }),), + }), Buffer.from('PONG') ); }, GLOBAL.SERVERS.OPEN); diff --git a/packages/client/lib/commands/index.ts b/packages/client/lib/commands/index.ts index c589770a94..d8cfe5332d 100644 --- a/packages/client/lib/commands/index.ts +++ b/packages/client/lib/commands/index.ts @@ -1,6 +1,5 @@ import { RedisScriptConfig, SHA1 } from '../lua-script'; - // https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540 // eslint-disable-next-line @typescript-eslint/no-empty-interface interface RedisCommandRawReplyArray extends Array {}