You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-04 15:02:09 +03:00
Add support for T-Digest (#2214)
* wip * close #2216 - add support for TDIGEST.MERGESTORE and make compression optional on TDIGEST.CREATE * fix some tdigest commands, use bloom edge docker * fix index.ts * 2.4-RC2 (v2.4.1) * fix some commands and tests * clean code
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
import Bloom from './bloom';
|
||||
import CountMinSketch from './count-min-sketch';
|
||||
import Cuckoo from './cuckoo';
|
||||
import TopK from './top-k';
|
||||
import bf from './bloom';
|
||||
import cms from './count-min-sketch';
|
||||
import cf from './cuckoo';
|
||||
import tDigest from './t-digest';
|
||||
import topK from './top-k';
|
||||
|
||||
export default {
|
||||
bf: Bloom,
|
||||
cms: CountMinSketch,
|
||||
cf: Cuckoo,
|
||||
topK: TopK
|
||||
bf,
|
||||
cms,
|
||||
cf,
|
||||
tDigest,
|
||||
topK
|
||||
};
|
||||
|
21
packages/bloom/lib/commands/t-digest/ADD.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/ADD.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './ADD';
|
||||
|
||||
describe('TDIGEST.ADD', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', [1, 2]),
|
||||
['TDIGEST.ADD', 'key', '1', '2']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.add', async client => {
|
||||
const [ , reply ] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.add('key', [1])
|
||||
]);
|
||||
|
||||
assert.equal(reply, 'OK');
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
17
packages/bloom/lib/commands/t-digest/ADD.ts
Normal file
17
packages/bloom/lib/commands/t-digest/ADD.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
values: Array<number>
|
||||
): RedisCommandArguments {
|
||||
const args = ['TDIGEST.ADD', key];
|
||||
for (const item of values) {
|
||||
args.push(item.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export declare function transformReply(): 'OK';
|
21
packages/bloom/lib/commands/t-digest/BYRANK.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/BYRANK.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './BYRANK';
|
||||
|
||||
describe('TDIGEST.BYRANK', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', [1, 2]),
|
||||
['TDIGEST.BYRANK', 'key', '1', '2']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.byRank', async client => {
|
||||
const [ , reply ] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.byRank('key', [1])
|
||||
]);
|
||||
|
||||
assert.deepEqual(reply, [NaN]);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
19
packages/bloom/lib/commands/t-digest/BYRANK.ts
Normal file
19
packages/bloom/lib/commands/t-digest/BYRANK.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
ranks: Array<number>
|
||||
): RedisCommandArguments {
|
||||
const args = ['TDIGEST.BYRANK', key];
|
||||
for (const rank of ranks) {
|
||||
args.push(rank.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export { transformDoublesReply as transformReply } from '.';
|
21
packages/bloom/lib/commands/t-digest/BYREVRANK.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/BYREVRANK.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './BYREVRANK';
|
||||
|
||||
describe('TDIGEST.BYREVRANK', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', [1, 2]),
|
||||
['TDIGEST.BYREVRANK', 'key', '1', '2']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.byRevRank', async client => {
|
||||
const [ , reply ] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.byRevRank('key', [1])
|
||||
]);
|
||||
|
||||
assert.deepEqual(reply, [NaN]);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
19
packages/bloom/lib/commands/t-digest/BYREVRANK.ts
Normal file
19
packages/bloom/lib/commands/t-digest/BYREVRANK.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
ranks: Array<number>
|
||||
): RedisCommandArguments {
|
||||
const args = ['TDIGEST.BYREVRANK', key];
|
||||
for (const rank of ranks) {
|
||||
args.push(rank.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export { transformDoublesReply as transformReply } from '.';
|
21
packages/bloom/lib/commands/t-digest/CDF.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/CDF.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './CDF';
|
||||
|
||||
describe('TDIGEST.CDF', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', [1, 2]),
|
||||
['TDIGEST.CDF', 'key', '1', '2']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.cdf', async client => {
|
||||
const [ , reply ] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.cdf('key', [1])
|
||||
]);
|
||||
|
||||
assert.deepEqual(reply, [NaN]);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
19
packages/bloom/lib/commands/t-digest/CDF.ts
Normal file
19
packages/bloom/lib/commands/t-digest/CDF.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
values: Array<number>
|
||||
): RedisCommandArguments {
|
||||
const args = ['TDIGEST.CDF', key];
|
||||
for (const item of values) {
|
||||
args.push(item.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export { transformDoublesReply as transformReply } from '.';
|
30
packages/bloom/lib/commands/t-digest/CREATE.spec.ts
Normal file
30
packages/bloom/lib/commands/t-digest/CREATE.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './CREATE';
|
||||
|
||||
describe('TDIGEST.CREATE', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('without options', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key'),
|
||||
['TDIGEST.CREATE', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
it('with COMPRESSION', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', {
|
||||
COMPRESSION: 100
|
||||
}),
|
||||
['TDIGEST.CREATE', 'key', 'COMPRESSION', '100']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.create', async client => {
|
||||
assert.equal(
|
||||
await client.tDigest.create('key'),
|
||||
'OK'
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
16
packages/bloom/lib/commands/t-digest/CREATE.ts
Normal file
16
packages/bloom/lib/commands/t-digest/CREATE.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
import { CompressionOption, pushCompressionArgument } from '.';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
options?: CompressionOption
|
||||
): RedisCommandArguments {
|
||||
return pushCompressionArgument(
|
||||
['TDIGEST.CREATE', key],
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
export declare function transformReply(): 'OK';
|
25
packages/bloom/lib/commands/t-digest/INFO.spec.ts
Normal file
25
packages/bloom/lib/commands/t-digest/INFO.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './INFO';
|
||||
|
||||
describe('TDIGEST.INFO', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key'),
|
||||
['TDIGEST.INFO', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.info', async client => {
|
||||
await client.tDigest.create('key');
|
||||
|
||||
const info = await client.tDigest.info('key');
|
||||
assert(typeof info.capacity, 'number');
|
||||
assert(typeof info.mergedNodes, 'number');
|
||||
assert(typeof info.unmergedNodes, 'number');
|
||||
assert(typeof info.mergedWeight, 'number');
|
||||
assert(typeof info.unmergedWeight, 'number');
|
||||
assert(typeof info.totalCompression, 'number');
|
||||
assert(typeof info.totalCompression, 'number');
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
51
packages/bloom/lib/commands/t-digest/INFO.ts
Normal file
51
packages/bloom/lib/commands/t-digest/INFO.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(key: RedisCommandArgument): RedisCommandArguments {
|
||||
return [
|
||||
'TDIGEST.INFO',
|
||||
key
|
||||
];
|
||||
}
|
||||
|
||||
type InfoRawReply = [
|
||||
'Compression',
|
||||
number,
|
||||
'Capacity',
|
||||
number,
|
||||
'Merged nodes',
|
||||
number,
|
||||
'Unmerged nodes',
|
||||
number,
|
||||
'Merged weight',
|
||||
string,
|
||||
'Unmerged weight',
|
||||
string,
|
||||
'Total compressions',
|
||||
number
|
||||
];
|
||||
|
||||
interface InfoReply {
|
||||
comperssion: number;
|
||||
capacity: number;
|
||||
mergedNodes: number;
|
||||
unmergedNodes: number;
|
||||
mergedWeight: number;
|
||||
unmergedWeight: number;
|
||||
totalCompression: number;
|
||||
}
|
||||
|
||||
export function transformReply(reply: InfoRawReply): InfoReply {
|
||||
return {
|
||||
comperssion: reply[1],
|
||||
capacity: reply[3],
|
||||
mergedNodes: reply[5],
|
||||
unmergedNodes: reply[7],
|
||||
mergedWeight: Number(reply[9]),
|
||||
unmergedWeight: Number(reply[11]),
|
||||
totalCompression: reply[13]
|
||||
};
|
||||
}
|
21
packages/bloom/lib/commands/t-digest/MAX.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/MAX.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments, transformReply } from './MAX';
|
||||
|
||||
describe('TDIGEST.MAX', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key'),
|
||||
['TDIGEST.MAX', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.max', async client => {
|
||||
const [ , reply ] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.max('key')
|
||||
]);
|
||||
|
||||
assert.deepEqual(reply, NaN);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
14
packages/bloom/lib/commands/t-digest/MAX.ts
Normal file
14
packages/bloom/lib/commands/t-digest/MAX.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(key: RedisCommandArgument): RedisCommandArguments {
|
||||
return [
|
||||
'TDIGEST.MAX',
|
||||
key
|
||||
];
|
||||
}
|
||||
|
||||
export { transformDoubleReply as transformReply } from '.';
|
50
packages/bloom/lib/commands/t-digest/MERGE.spec.ts
Normal file
50
packages/bloom/lib/commands/t-digest/MERGE.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments, transformReply } from './MERGE';
|
||||
|
||||
describe('TDIGEST.MERGE', () => {
|
||||
describe('transformArguments', () => {
|
||||
describe('srcKeys', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('dest', 'src'),
|
||||
['TDIGEST.MERGE', 'dest', '1', 'src']
|
||||
);
|
||||
});
|
||||
|
||||
it('Array', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('dest', ['1', '2']),
|
||||
['TDIGEST.MERGE', 'dest', '2', '1', '2']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('with COMPRESSION', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('dest', 'src', {
|
||||
COMPRESSION: 100
|
||||
}),
|
||||
['TDIGEST.MERGE', 'dest', '1', 'src', 'COMPRESSION', '100']
|
||||
);
|
||||
});
|
||||
|
||||
it('with OVERRIDE', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('dest', 'src', {
|
||||
OVERRIDE: true
|
||||
}),
|
||||
['TDIGEST.MERGE', 'dest', '1', 'src', 'OVERRIDE']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.merge', async client => {
|
||||
const [ , reply ] = await Promise.all([
|
||||
client.tDigest.create('src'),
|
||||
client.tDigest.merge('dest', 'src')
|
||||
]);
|
||||
|
||||
assert.equal(reply, 'OK');
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
30
packages/bloom/lib/commands/t-digest/MERGE.ts
Normal file
30
packages/bloom/lib/commands/t-digest/MERGE.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
import { pushVerdictArgument } from '@redis/client/dist/lib/commands/generic-transformers';
|
||||
import { CompressionOption, pushCompressionArgument } from '.';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
interface MergeOptions extends CompressionOption {
|
||||
OVERRIDE?: boolean;
|
||||
}
|
||||
|
||||
export function transformArguments(
|
||||
destKey: RedisCommandArgument,
|
||||
srcKeys: RedisCommandArgument | Array<RedisCommandArgument>,
|
||||
options?: MergeOptions
|
||||
): RedisCommandArguments {
|
||||
const args = pushVerdictArgument(
|
||||
['TDIGEST.MERGE', destKey],
|
||||
srcKeys
|
||||
);
|
||||
|
||||
pushCompressionArgument(args, options);
|
||||
|
||||
if (options?.OVERRIDE) {
|
||||
args.push('OVERRIDE');
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export declare function transformReply(): 'OK';
|
21
packages/bloom/lib/commands/t-digest/MIN.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/MIN.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments, transformReply } from './MIN';
|
||||
|
||||
describe('TDIGEST.MIN', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key'),
|
||||
['TDIGEST.MIN', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.min', async client => {
|
||||
const [ , reply ] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.min('key')
|
||||
]);
|
||||
|
||||
assert.equal(reply, NaN);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
14
packages/bloom/lib/commands/t-digest/MIN.ts
Normal file
14
packages/bloom/lib/commands/t-digest/MIN.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(key: RedisCommandArgument): RedisCommandArguments {
|
||||
return [
|
||||
'TDIGEST.MIN',
|
||||
key
|
||||
];
|
||||
}
|
||||
|
||||
export { transformDoubleReply as transformReply } from '.';
|
24
packages/bloom/lib/commands/t-digest/QUANTILE.spec.ts
Normal file
24
packages/bloom/lib/commands/t-digest/QUANTILE.spec.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './QUANTILE';
|
||||
|
||||
describe('TDIGEST.QUANTILE', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', [1, 2]),
|
||||
['TDIGEST.QUANTILE', 'key', '1', '2']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.quantile', async client => {
|
||||
const [, reply] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.quantile('key', [1])
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
reply,
|
||||
[NaN]
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
23
packages/bloom/lib/commands/t-digest/QUANTILE.ts
Normal file
23
packages/bloom/lib/commands/t-digest/QUANTILE.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
quantiles: Array<number>
|
||||
): RedisCommandArguments {
|
||||
const args = [
|
||||
'TDIGEST.QUANTILE',
|
||||
key
|
||||
];
|
||||
|
||||
for (const quantile of quantiles) {
|
||||
args.push(quantile.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export { transformDoublesReply as transformReply } from '.';
|
21
packages/bloom/lib/commands/t-digest/RANK.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/RANK.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './RANK';
|
||||
|
||||
describe('TDIGEST.RANK', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', [1, 2]),
|
||||
['TDIGEST.RANK', 'key', '1', '2']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.rank', async client => {
|
||||
const [ , reply ] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.rank('key', [1])
|
||||
]);
|
||||
|
||||
assert.deepEqual(reply, [-2]);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
19
packages/bloom/lib/commands/t-digest/RANK.ts
Normal file
19
packages/bloom/lib/commands/t-digest/RANK.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
values: Array<number>
|
||||
): RedisCommandArguments {
|
||||
const args = ['TDIGEST.RANK', key];
|
||||
for (const item of values) {
|
||||
args.push(item.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<number>;
|
21
packages/bloom/lib/commands/t-digest/RESET.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/RESET.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './RESET';
|
||||
|
||||
describe('TDIGEST.RESET', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key'),
|
||||
['TDIGEST.RESET', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.reset', async client => {
|
||||
const [, reply] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.reset('key')
|
||||
]);
|
||||
|
||||
assert.equal(reply, 'OK');
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
9
packages/bloom/lib/commands/t-digest/RESET.ts
Normal file
9
packages/bloom/lib/commands/t-digest/RESET.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export function transformArguments(key: RedisCommandArgument): RedisCommandArguments {
|
||||
return ['TDIGEST.RESET', key];
|
||||
}
|
||||
|
||||
export declare function transformReply(): 'OK';
|
21
packages/bloom/lib/commands/t-digest/REVRANK.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/REVRANK.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments } from './REVRANK';
|
||||
|
||||
describe('TDIGEST.REVRANK', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', [1, 2]),
|
||||
['TDIGEST.REVRANK', 'key', '1', '2']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.revRank', async client => {
|
||||
const [ , reply ] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.revRank('key', [1])
|
||||
]);
|
||||
|
||||
assert.deepEqual(reply, [-2]);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
19
packages/bloom/lib/commands/t-digest/REVRANK.ts
Normal file
19
packages/bloom/lib/commands/t-digest/REVRANK.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
values: Array<number>
|
||||
): RedisCommandArguments {
|
||||
const args = ['TDIGEST.REVRANK', key];
|
||||
for (const item of values) {
|
||||
args.push(item.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export declare function transformReply(): Array<number>;
|
21
packages/bloom/lib/commands/t-digest/TRIMMED_MEAN.spec.ts
Normal file
21
packages/bloom/lib/commands/t-digest/TRIMMED_MEAN.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../../test-utils';
|
||||
import { transformArguments, transformReply } from './TRIMMED_MEAN';
|
||||
|
||||
describe('TDIGEST.RESET', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('key', 0, 1),
|
||||
['TDIGEST.TRIMMED_MEAN', 'key', '0', '1']
|
||||
);
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.tDigest.trimmedMean', async client => {
|
||||
const [, reply] = await Promise.all([
|
||||
client.tDigest.create('key'),
|
||||
client.tDigest.trimmedMean('key', 0, 1)
|
||||
]);
|
||||
|
||||
assert.equal(reply, NaN);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
20
packages/bloom/lib/commands/t-digest/TRIMMED_MEAN.ts
Normal file
20
packages/bloom/lib/commands/t-digest/TRIMMED_MEAN.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
key: RedisCommandArgument,
|
||||
lowCutPercentile: number,
|
||||
highCutPercentile: number
|
||||
): RedisCommandArguments {
|
||||
return [
|
||||
'TDIGEST.TRIMMED_MEAN',
|
||||
key,
|
||||
lowCutPercentile.toString(),
|
||||
highCutPercentile.toString()
|
||||
];
|
||||
}
|
||||
|
||||
export { transformDoubleReply as transformReply } from '.';
|
55
packages/bloom/lib/commands/t-digest/index.spec.ts
Normal file
55
packages/bloom/lib/commands/t-digest/index.spec.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { pushCompressionArgument, transformDoubleReply, transformDoublesReply } from '.';
|
||||
|
||||
describe('pushCompressionArgument', () => {
|
||||
it('undefined', () => {
|
||||
assert.deepEqual(
|
||||
pushCompressionArgument([]),
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
it('100', () => {
|
||||
assert.deepEqual(
|
||||
pushCompressionArgument([], { COMPRESSION: 100 }),
|
||||
['COMPRESSION', '100']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformDoubleReply', () => {
|
||||
it('inf', () => {
|
||||
assert.equal(
|
||||
transformDoubleReply('inf'),
|
||||
Infinity
|
||||
);
|
||||
});
|
||||
|
||||
it('-inf', () => {
|
||||
assert.equal(
|
||||
transformDoubleReply('-inf'),
|
||||
-Infinity
|
||||
);
|
||||
});
|
||||
|
||||
it('nan', () => {
|
||||
assert.equal(
|
||||
transformDoubleReply('nan'),
|
||||
NaN
|
||||
);
|
||||
});
|
||||
|
||||
it('0', () => {
|
||||
assert.equal(
|
||||
transformDoubleReply('0'),
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('transformDoublesReply', () => {
|
||||
assert.deepEqual(
|
||||
transformDoublesReply(['inf', '-inf', 'nan', '0']),
|
||||
[Infinity, -Infinity, NaN, 0]
|
||||
);
|
||||
});
|
81
packages/bloom/lib/commands/t-digest/index.ts
Normal file
81
packages/bloom/lib/commands/t-digest/index.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
|
||||
import * as ADD from './ADD';
|
||||
import * as BYRANK from './BYRANK';
|
||||
import * as BYREVRANK from './BYREVRANK';
|
||||
import * as CDF from './CDF';
|
||||
import * as CREATE from './CREATE';
|
||||
import * as INFO from './INFO';
|
||||
import * as MAX from './MAX';
|
||||
import * as MERGE from './MERGE';
|
||||
import * as MIN from './MIN';
|
||||
import * as QUANTILE from './QUANTILE';
|
||||
import * as RANK from './RANK';
|
||||
import * as RESET from './RESET';
|
||||
import * as REVRANK from './REVRANK';
|
||||
import * as TRIMMED_MEAN from './TRIMMED_MEAN';
|
||||
|
||||
export default {
|
||||
ADD,
|
||||
add: ADD,
|
||||
BYRANK,
|
||||
byRank: BYRANK,
|
||||
BYREVRANK,
|
||||
byRevRank: BYREVRANK,
|
||||
CDF,
|
||||
cdf: CDF,
|
||||
CREATE,
|
||||
create: CREATE,
|
||||
INFO,
|
||||
info: INFO,
|
||||
MAX,
|
||||
max: MAX,
|
||||
MERGE,
|
||||
merge: MERGE,
|
||||
MIN,
|
||||
min: MIN,
|
||||
QUANTILE,
|
||||
quantile: QUANTILE,
|
||||
RANK,
|
||||
rank: RANK,
|
||||
RESET,
|
||||
reset: RESET,
|
||||
REVRANK,
|
||||
revRank: REVRANK,
|
||||
TRIMMED_MEAN,
|
||||
trimmedMean: TRIMMED_MEAN
|
||||
};
|
||||
|
||||
export interface CompressionOption {
|
||||
COMPRESSION?: number;
|
||||
}
|
||||
|
||||
export function pushCompressionArgument(
|
||||
args: RedisCommandArguments,
|
||||
options?: CompressionOption
|
||||
): RedisCommandArguments {
|
||||
if (options?.COMPRESSION) {
|
||||
args.push('COMPRESSION', options.COMPRESSION.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export function transformDoubleReply(reply: string): number {
|
||||
switch (reply) {
|
||||
case 'inf':
|
||||
return Infinity;
|
||||
|
||||
case '-inf':
|
||||
return -Infinity;
|
||||
|
||||
case 'nan':
|
||||
return NaN;
|
||||
|
||||
default:
|
||||
return parseFloat(reply);
|
||||
}
|
||||
}
|
||||
|
||||
export function transformDoublesReply(reply: Array<string>): Array<number> {
|
||||
return reply.map(transformDoubleReply);
|
||||
}
|
Reference in New Issue
Block a user