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

V5 bringing RESP3, Sentinel and TypeMapping to node-redis

RESP3 Support
   - Some commands responses in RESP3 aren't stable yet and therefore return an "untyped" ReplyUnion.
 
Sentinel

TypeMapping

Correctly types Multi commands

Note: some API changes to be further documented in v4-to-v5.md
This commit is contained in:
Shaya Potter
2024-10-15 17:46:52 +03:00
committed by GitHub
parent 2fc79bdfb3
commit b2d35c5286
1174 changed files with 45931 additions and 36274 deletions

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './ADD';
import ADD from './ADD';
describe('TDIGEST.ADD', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.ADD', 'key', '1', '2']
);
});
it('transformArguments', () => {
assert.deepEqual(
ADD.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])
]);
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);
assert.equal(reply, 'OK');
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,17 +1,16 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { SimpleStringReply, Command, RedisArgument } from '@redis/client/dist/lib/RESP/types';
export const FIRST_KEY_INDEX = 1;
export function transformArguments(
key: RedisCommandArgument,
values: Array<number>
): RedisCommandArguments {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, values: Array<number>) {
const args = ['TDIGEST.ADD', key];
for (const item of values) {
args.push(item.toString());
for (const value of values) {
args.push(value.toString());
}
return args;
}
export declare function transformReply(): 'OK';
},
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './BYRANK';
import BYRANK from './BYRANK';
describe('TDIGEST.BYRANK', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.BYRANK', 'key', '1', '2']
);
});
it('transformArguments', () => {
assert.deepEqual(
BYRANK.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])
]);
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);
assert.deepEqual(reply, [NaN]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,19 +1,24 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformDoubleArrayReply } from '@redis/client/dist/lib/commands/generic-transformers';
export const FIRST_KEY_INDEX = 1;
export function transformByRankArguments(
command: RedisArgument,
key: RedisArgument,
ranks: Array<number>
) {
const args = [command, key];
export const IS_READ_ONLY = true;
for (const rank of ranks) {
args.push(rank.toString());
}
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;
return args;
}
export { transformDoublesReply as transformReply } from '.';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments: transformByRankArguments.bind(undefined, 'TDIGEST.BYRANK'),
transformReply: transformDoubleArrayReply
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './BYREVRANK';
import BYREVRANK from './BYREVRANK';
describe('TDIGEST.BYREVRANK', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.BYREVRANK', 'key', '1', '2']
);
});
it('transformArguments', () => {
assert.deepEqual(
BYREVRANK.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])
]);
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);
assert.deepEqual(reply, [NaN]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,19 +1,9 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { Command } from '@redis/client/dist/lib/RESP/types';
import BYRANK, { transformByRankArguments } from './BYRANK';
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 '.';
export default {
FIRST_KEY_INDEX: BYRANK.FIRST_KEY_INDEX,
IS_READ_ONLY: BYRANK.IS_READ_ONLY,
transformArguments: transformByRankArguments.bind(undefined, 'TDIGEST.BYREVRANK'),
transformReply: BYRANK.transformReply
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './CDF';
import CDF from './CDF';
describe('TDIGEST.CDF', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.CDF', 'key', '1', '2']
);
});
it('transformArguments', () => {
assert.deepEqual(
CDF.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])
]);
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);
assert.deepEqual(reply, [NaN]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,19 +1,17 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformDoubleArrayReply } from '@redis/client/dist/lib/commands/generic-transformers';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(
key: RedisCommandArgument,
values: Array<number>
): RedisCommandArguments {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument, values: Array<number>) {
const args = ['TDIGEST.CDF', key];
for (const item of values) {
args.push(item.toString());
args.push(item.toString());
}
return args;
}
export { transformDoublesReply as transformReply } from '.';
},
transformReply: transformDoubleArrayReply
} as const satisfies Command;

View File

@@ -1,30 +1,30 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './CREATE';
import CREATE 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']
);
});
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
CREATE.transformArguments('key'),
['TDIGEST.CREATE', 'key']
);
});
testUtils.testWithClient('client.tDigest.create', async client => {
assert.equal(
await client.tDigest.create('key'),
'OK'
);
}, GLOBAL.SERVERS.OPEN);
it('with COMPRESSION', () => {
assert.deepEqual(
CREATE.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);
});

View File

@@ -1,16 +1,20 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { CompressionOption, pushCompressionArgument } from '.';
import { RedisArgument, SimpleStringReply, Command } from '@redis/client/dist/lib/RESP/types';
export const FIRST_KEY_INDEX = 1;
export function transformArguments(
key: RedisCommandArgument,
options?: CompressionOption
): RedisCommandArguments {
return pushCompressionArgument(
['TDIGEST.CREATE', key],
options
);
export interface TDigestCreateOptions {
COMPRESSION?: number;
}
export declare function transformReply(): 'OK';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument, options?: TDigestCreateOptions) {
const args = ['TDIGEST.CREATE', key];
if (options?.COMPRESSION !== undefined) {
args.push('COMPRESSION', options.COMPRESSION.toString());
}
return args;
},
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
} as const satisfies Command;

View File

@@ -1,25 +1,30 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './INFO';
import INFO from './INFO';
describe('TDIGEST.INFO', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key'),
['TDIGEST.INFO', 'key']
);
});
it('transformArguments', () => {
assert.deepEqual(
INFO.transformArguments('key'),
['TDIGEST.INFO', 'key']
);
});
testUtils.testWithClient('client.tDigest.info', async client => {
await client.tDigest.create('key');
testUtils.testWithClient('client.tDigest.info', async client => {
const [, reply] = await Promise.all([
client.tDigest.create('key'),
client.tDigest.info('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);
assert(typeof reply, 'object');
assert(typeof reply['Compression'], 'number');
assert(typeof reply['Capacity'], 'number');
assert(typeof reply['Merged nodes'], 'number');
assert(typeof reply['Unmerged nodes'], 'number');
assert(typeof reply['Merged weight'], 'number');
assert(typeof reply['Unmerged weight'], 'number');
assert(typeof reply['Observations'], 'number');
assert(typeof reply['Total compressions'], 'number');
assert(typeof reply['Memory usage'], 'number');
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,51 +1,28 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RedisArgument, Command, NumberReply, TuplesToMapReply, UnwrapReply, Resp2Reply, SimpleStringReply, TypeMapping } from '@redis/client/dist/lib/RESP/types';
import { transformInfoV2Reply } from '../bloom';
export const FIRST_KEY_INDEX = 1;
export type TdInfoReplyMap = TuplesToMapReply<[
[SimpleStringReply<'Compression'>, NumberReply],
[SimpleStringReply<'Capacity'>, NumberReply],
[SimpleStringReply<'Merged nodes'>, NumberReply],
[SimpleStringReply<'Unmerged nodes'>, NumberReply],
[SimpleStringReply<'Merged weight'>, NumberReply],
[SimpleStringReply<'Unmerged weight'>, NumberReply],
[SimpleStringReply<'Observations'>, NumberReply],
[SimpleStringReply<'Total compressions'>, NumberReply],
[SimpleStringReply<'Memory usage'>, NumberReply]
]>;
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]
};
}
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument) {
return ['TDIGEST.INFO', key];
},
transformReply: {
2: (reply: UnwrapReply<Resp2Reply<TdInfoReplyMap>>, _, typeMapping?: TypeMapping): TdInfoReplyMap => {
return transformInfoV2Reply<TdInfoReplyMap>(reply, typeMapping);
},
3: undefined as unknown as () => TdInfoReplyMap
}
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments, transformReply } from './MAX';
import MAX from './MAX';
describe('TDIGEST.MAX', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key'),
['TDIGEST.MAX', 'key']
);
});
it('transformArguments', () => {
assert.deepEqual(
MAX.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')
]);
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);
assert.deepEqual(reply, NaN);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,14 +1,11 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformDoubleReply } from '@redis/client/dist/lib/commands/generic-transformers';
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 '.';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument) {
return ['TDIGEST.MAX', key];
},
transformReply: transformDoubleReply
} as const satisfies Command;

View File

@@ -1,50 +1,50 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments, transformReply } from './MERGE';
import MERGE from './MERGE';
describe('TDIGEST.MERGE', () => {
describe('transformArguments', () => {
describe('srcKeys', () => {
it('string', () => {
assert.deepEqual(
transformArguments('dest', 'src'),
['TDIGEST.MERGE', 'dest', '1', 'src']
);
});
describe('transformArguments', () => {
describe('source', () => {
it('string', () => {
assert.deepEqual(
MERGE.transformArguments('destination', 'source'),
['TDIGEST.MERGE', 'destination', '1', 'source']
);
});
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']
);
});
it('Array', () => {
assert.deepEqual(
MERGE.transformArguments('destination', ['1', '2']),
['TDIGEST.MERGE', 'destination', '2', '1', '2']
);
});
});
testUtils.testWithClient('client.tDigest.merge', async client => {
const [ , reply ] = await Promise.all([
client.tDigest.create('src'),
client.tDigest.merge('dest', 'src')
]);
it('with COMPRESSION', () => {
assert.deepEqual(
MERGE.transformArguments('destination', 'source', {
COMPRESSION: 100
}),
['TDIGEST.MERGE', 'destination', '1', 'source', 'COMPRESSION', '100']
);
});
assert.equal(reply, 'OK');
}, GLOBAL.SERVERS.OPEN);
it('with OVERRIDE', () => {
assert.deepEqual(
MERGE.transformArguments('destination', 'source', {
OVERRIDE: true
}),
['TDIGEST.MERGE', 'destination', '1', 'source', 'OVERRIDE']
);
});
});
testUtils.testWithClient('client.tDigest.merge', async client => {
const [, reply] = await Promise.all([
client.tDigest.create('source'),
client.tDigest.merge('destination', 'source')
]);
assert.equal(reply, 'OK');
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,30 +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 '.';
import { RedisArgument, SimpleStringReply, Command } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument, pushVariadicArgument } from '@redis/client/dist/lib/commands/generic-transformers';
export const FIRST_KEY_INDEX = 1;
interface MergeOptions extends CompressionOption {
OVERRIDE?: boolean;
export interface TDigestMergeOptions {
COMPRESSION?: number;
OVERRIDE?: boolean;
}
export function transformArguments(
destKey: RedisCommandArgument,
srcKeys: RedisCommandArgument | Array<RedisCommandArgument>,
options?: MergeOptions
): RedisCommandArguments {
const args = pushVerdictArgument(
['TDIGEST.MERGE', destKey],
srcKeys
);
export default {
FIRST_KEY_INDEX: undefined,
IS_READ_ONLY: false,
transformArguments(
destination: RedisArgument,
source: RedisVariadicArgument,
options?: TDigestMergeOptions
) {
const args = pushVariadicArgument(['TDIGEST.MERGE', destination], source);
pushCompressionArgument(args, options);
if (options?.COMPRESSION !== undefined) {
args.push('COMPRESSION', options.COMPRESSION.toString());
}
if (options?.OVERRIDE) {
args.push('OVERRIDE');
args.push('OVERRIDE');
}
return args;
}
export declare function transformReply(): 'OK';
},
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments, transformReply } from './MIN';
import MIN from './MIN';
describe('TDIGEST.MIN', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key'),
['TDIGEST.MIN', 'key']
);
});
it('transformArguments', () => {
assert.deepEqual(
MIN.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')
]);
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);
assert.equal(reply, NaN);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,14 +1,11 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformDoubleReply } from '@redis/client/dist/lib/commands/generic-transformers';
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 '.';
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument) {
return ['TDIGEST.MIN', key];
},
transformReply: transformDoubleReply
} as const satisfies Command;

View File

@@ -1,24 +1,24 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './QUANTILE';
import QUANTILE from './QUANTILE';
describe('TDIGEST.QUANTILE', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.QUANTILE', 'key', '1', '2']
);
});
it('transformArguments', () => {
assert.deepEqual(
QUANTILE.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])
]);
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);
assert.deepEqual(
reply,
[NaN]
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,23 +1,17 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformDoubleArrayReply } from '@redis/client/dist/lib/commands/generic-transformers';
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
];
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(key: RedisArgument, quantiles: Array<number>) {
const args = ['TDIGEST.QUANTILE', key];
for (const quantile of quantiles) {
args.push(quantile.toString());
args.push(quantile.toString());
}
return args;
}
export { transformDoublesReply as transformReply } from '.';
},
transformReply: transformDoubleArrayReply
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './RANK';
import RANK from './RANK';
describe('TDIGEST.RANK', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.RANK', 'key', '1', '2']
);
});
it('transformArguments', () => {
assert.deepEqual(
RANK.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])
]);
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);
assert.deepEqual(reply, [-2]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,19 +1,22 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RedisArgument, ArrayReply, NumberReply, Command } from '@redis/client/dist/lib/RESP/types';
export const FIRST_KEY_INDEX = 1;
export function transformRankArguments(
command: RedisArgument,
key: RedisArgument,
values: Array<number>
) {
const args = [command, key];
export const IS_READ_ONLY = true;
for (const value of values) {
args.push(value.toString());
}
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;
return args;
}
export declare function transformReply(): Array<number>;
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments: transformRankArguments.bind(undefined, 'TDIGEST.RANK'),
transformReply: undefined as unknown as () => ArrayReply<NumberReply>
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './RESET';
import RESET from './RESET';
describe('TDIGEST.RESET', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key'),
['TDIGEST.RESET', 'key']
);
});
it('transformArguments', () => {
assert.deepEqual(
RESET.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')
]);
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);
assert.equal(reply, 'OK');
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,9 +1,10 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RedisArgument, SimpleStringReply, Command } from '@redis/client/dist/lib/RESP/types';
export const FIRST_KEY_INDEX = 1;
export function transformArguments(key: RedisCommandArgument): RedisCommandArguments {
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: false,
transformArguments(key: RedisArgument) {
return ['TDIGEST.RESET', key];
}
export declare function transformReply(): 'OK';
},
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments } from './REVRANK';
import REVRANK from './REVRANK';
describe('TDIGEST.REVRANK', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', [1, 2]),
['TDIGEST.REVRANK', 'key', '1', '2']
);
});
it('transformArguments', () => {
assert.deepEqual(
REVRANK.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])
]);
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);
assert.deepEqual(reply, [-2]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,19 +1,9 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { Command } from '@redis/client/dist/lib/RESP/types';
import RANK, { transformRankArguments } from './RANK';
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>;
export default {
FIRST_KEY_INDEX: RANK.FIRST_KEY_INDEX,
IS_READ_ONLY: RANK.IS_READ_ONLY,
transformArguments: transformRankArguments.bind(undefined, 'TDIGEST.REVRANK'),
transformReply: RANK.transformReply
} as const satisfies Command;

View File

@@ -1,21 +1,21 @@
import { strict as assert } from 'assert';
import { strict as assert } from 'node:assert';
import testUtils, { GLOBAL } from '../../test-utils';
import { transformArguments, transformReply } from './TRIMMED_MEAN';
import TRIMMED_MEAN from './TRIMMED_MEAN';
describe('TDIGEST.RESET', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', 0, 1),
['TDIGEST.TRIMMED_MEAN', 'key', '0', '1']
);
});
describe('TDIGEST.TRIMMED_MEAN', () => {
it('transformArguments', () => {
assert.deepEqual(
TRIMMED_MEAN.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)
]);
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);
assert.equal(reply, NaN);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,20 +1,20 @@
import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { transformDoubleReply } from '@redis/client/dist/lib/commands/generic-transformers';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(
key: RedisCommandArgument,
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments(
key: RedisArgument,
lowCutPercentile: number,
highCutPercentile: number
): RedisCommandArguments {
) {
return [
'TDIGEST.TRIMMED_MEAN',
key,
lowCutPercentile.toString(),
highCutPercentile.toString()
'TDIGEST.TRIMMED_MEAN',
key,
lowCutPercentile.toString(),
highCutPercentile.toString()
];
}
export { transformDoubleReply as transformReply } from '.';
},
transformReply: transformDoubleReply
} as const satisfies Command;

View File

@@ -1,55 +0,0 @@
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]
);
});

View File

@@ -1,81 +1,46 @@
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';
import type { RedisCommands } from '@redis/client/dist/lib/RESP/types';
import ADD from './ADD';
import BYRANK from './BYRANK';
import BYREVRANK from './BYREVRANK';
import CDF from './CDF';
import CREATE from './CREATE';
import INFO from './INFO';
import MAX from './MAX';
import MERGE from './MERGE';
import MIN from './MIN';
import QUANTILE from './QUANTILE';
import RANK from './RANK';
import RESET from './RESET';
import REVRANK from './REVRANK';
import 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);
}
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
} as const satisfies RedisCommands;