1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-04 15:02:09 +03:00

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 <leibale1998@gmail.com>
This commit is contained in:
Avital Fine
2021-12-29 17:55:09 +01:00
committed by GitHub
parent fd72a287b7
commit f93ac04436
84 changed files with 1760 additions and 5 deletions

View File

@@ -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);
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, item: string): Array<string> {
return ['BF.ADD', key, item];
}
export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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);
});

View File

@@ -0,0 +1,9 @@
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(key: string, item: string): Array<string> {
return ['BF.EXISTS', key, item];
}
export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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);
});

View File

@@ -0,0 +1,38 @@
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(key: string): Array<string> {
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]
};
}

View File

@@ -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);
});

View File

@@ -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<string>,
options?: InsertOptions
): Array<string> {
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';

View File

@@ -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', '']
);
});
});

View File

@@ -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';

View File

@@ -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);
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, items: Array<string>): Array<string> {
return ['BF.MADD', key, ...items];
}
export { transformBooleanArrayReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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);
});

View File

@@ -0,0 +1,9 @@
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(key: string, items: Array<string>): Array<string> {
return ['BF.MEXISTS', key, ...items];
}
export { transformBooleanArrayReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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);
});

View File

@@ -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<string> {
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';

View File

@@ -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']
);
});
});

View File

@@ -0,0 +1,24 @@
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(key: string, iterator: number): Array<string> {
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
};
}

View File

@@ -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
};

View File

@@ -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);
});

View File

@@ -0,0 +1,29 @@
export const FIRST_KEY_INDEX = 1;
interface IncrByItem {
item: string;
incrementBy: number;
}
export function transformArguments(
key: string,
items: IncrByItem | Array<IncrByItem>
): Array<string> {
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<string>, { item, incrementBy }: IncrByItem): void {
args.push(item, incrementBy.toString());
}
export declare function transformReply(): Array<number>;

View File

@@ -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);
});

View File

@@ -0,0 +1,30 @@
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(key: string): Array<string> {
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]
};
}

View File

@@ -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);
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, width: number, depth: number): Array<string> {
return ['CMS.INITBYDIM', key, width.toString(), depth.toString()];
}
export declare function transformReply(): 'OK';

View File

@@ -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);
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, error: number, probability: number): Array<string> {
return ['CMS.INITBYPROB', key, error.toString(), probability.toString()];
}
export declare function transformReply(): 'OK';

View File

@@ -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);
});

View File

@@ -0,0 +1,37 @@
export const FIRST_KEY_INDEX = 1;
interface Sketch {
name: string;
weight: number;
}
type Sketches = Array<string> | Array<Sketch>;
export function transformArguments(dest: string, src: Sketches): Array<string> {
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<string> {
return typeof src[0] === 'string';
}
export declare function transformReply(): 'OK';

View File

@@ -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);
});

View File

@@ -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<string>
): RedisCommandArguments {
return pushVerdictArguments(['CMS.QUERY', key], items);
}
export declare function transformReply(): Array<number>;

View File

@@ -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
};

View File

@@ -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);
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, item: string): Array<string> {
return ['CF.ADD', key, item];
}
export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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);
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, item: string): Array<string> {
return ['CF.ADDNX', key, item];
}
export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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);
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, item: string): Array<string> {
return ['CF.COUNT', key, item];
}
export declare function transformReply(): number;

View File

@@ -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);
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, item: string): Array<string> {
return ['CF.DEL', key, item];
}
export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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);
});

View File

@@ -0,0 +1,9 @@
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(key: string, item: string): Array<string> {
return ['CF.EXISTS', key, item];
}
export { transformBooleanReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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);
});

View File

@@ -0,0 +1,50 @@
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(key: string): Array<string> {
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]
};
}

View File

@@ -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);
});

View File

@@ -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<string>,
options?: InsertOptions
): RedisCommandArguments {
return pushInsertOptions(
['CF.INSERT', key],
items,
options
);
}
export { transformBooleanArrayReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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);
});

View File

@@ -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<string>,
options?: InsertOptions
): RedisCommandArguments {
return pushInsertOptions(
['CF.INSERTNX', key],
items,
options
);
}
export { transformBooleanArrayReply as transformReply } from '@node-redis/client/dist/lib/commands/generic-transformers';

View File

@@ -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', '']
);
});
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, iterator: number, chunk: string): Array<string> {
return ['CF.LOADCHUNK', key, iterator.toString(), chunk];
}
export declare function transformReply(): 'OK';

View File

@@ -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);
});

View File

@@ -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<string> {
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';

View File

@@ -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']
);
});
});

View File

@@ -0,0 +1,22 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string, iterator: number): Array<string> {
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
};
}

View File

@@ -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']
);
});
});

View File

@@ -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<string>,
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);
}

View File

@@ -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
};

View File

@@ -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);
});

View File

@@ -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<string>
): RedisCommandArguments {
return pushVerdictArguments(['TOPK.ADD', key], items);
}
export declare function transformReply(): Array<null | string>;

View File

@@ -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);
});

View File

@@ -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<string>
): RedisCommandArguments {
return pushVerdictArguments(['TOPK.COUNT', key], items);
}
export declare function transformReply(): Array<number>;

View File

@@ -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);
});

View File

@@ -0,0 +1,29 @@
export const FIRST_KEY_INDEX = 1;
interface IncrByItem {
item: string;
incrementBy: number;
}
export function transformArguments(
key: string,
items: IncrByItem | Array<IncrByItem>
): Array<string> {
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<string>, { item, incrementBy }: IncrByItem): void {
args.push(item, incrementBy.toString());
}
export declare function transformReply(): Array<string | null>;

View File

@@ -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);
});

View File

@@ -0,0 +1,34 @@
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(key: string): Array<string> {
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])
};
}

View File

@@ -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);
});

View File

@@ -0,0 +1,7 @@
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: string): Array<string> {
return ['TOPK.LIST', key];
}
export declare function transformReply(): Array<string | null>;

View File

@@ -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);
});

View File

@@ -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<string>
): RedisCommandArguments {
return pushVerdictArguments(['TOPK.QUERY', key], items);
}
export declare function transformReply(): Array<number>;

View File

@@ -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);
});

View File

@@ -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<string> {
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';

View File

@@ -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
};