1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-06 02:15:48 +03:00
This commit is contained in:
Leibale
2023-07-27 11:23:34 -04:00
parent 61c3e8b95b
commit ff07bbf3d3
25 changed files with 745 additions and 630 deletions

View File

@@ -64,7 +64,7 @@ describe('TS.ALTER', () => {
testUtils.testWithClient('client.ts.alter', async client => {
const [, reply] = await Promise.all([
client.ts.create('key'),
client.ts.alter('key', { RETENTION: 1 })
client.ts.alter('key')
]);
assert.equal(reply, 'OK');

View File

@@ -3,7 +3,7 @@ import testUtils, { GLOBAL } from '../test-utils';
import MADD from './MADD';
import { SimpleError } from '@redis/client/lib/errors';
describe.only('TS.MADD', () => {
describe('TS.MADD', () => {
it('transformArguments', () => {
assert.deepEqual(
MADD.transformArguments([{

View File

@@ -1,40 +1,40 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './MGET';
import MGET from './MGET';
describe('TS.MGET', () => {
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
transformArguments('label=value'),
['TS.MGET', 'FILTER', 'label=value']
);
});
it('with LATEST', () => {
assert.deepEqual(
transformArguments('label=value', {
LATEST: true
}),
['TS.MGET', 'LATEST', 'FILTER', 'label=value']
);
});
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
MGET.transformArguments('label=value'),
['TS.MGET', 'FILTER', 'label=value']
);
});
testUtils.testWithClient('client.ts.mGet', async client => {
await client.ts.add('key', 0, 0, {
LABELS: { label: 'value' }
});
it('with LATEST', () => {
assert.deepEqual(
MGET.transformArguments('label=value', {
LATEST: true
}),
['TS.MGET', 'LATEST', 'FILTER', 'label=value']
);
});
});
assert.deepEqual(
await client.ts.mGet('label=value'),
[{
key: 'key',
sample: {
timestamp: 0,
value: 0
}
}]
);
}, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('client.ts.mGet', async client => {
const [, reply] = await Promise.all([
client.ts.add('key', 0, 0, {
LABELS: { label: 'value' }
}),
client.ts.mGet('label=value')
]);
assert.deepEqual(reply, [{
key: 'key',
sample: {
timestamp: 0,
value: 0
}
}]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,31 +1,31 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { Filter, pushFilterArgument, pushLatestArgument, RawLabels, SampleRawReply, SampleReply, transformSampleReply } from '.';
import { CommandArguments, Command } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument, pushVariadicArguments } from '@redis/client/dist/lib/commands/generic-transformers';
export const IS_READ_ONLY = true;
export interface MGetOptions {
LATEST?: boolean;
export interface TsMGetOptions {
LATEST?: boolean;
}
export function transformArguments(filter: Filter, options?: MGetOptions): RedisCommandArguments {
export function pushLatestArgument(args: CommandArguments, latest?: boolean) {
if (latest) {
args.push('LATEST');
}
return args;
}
export function pushFilterArgument(args: CommandArguments, filter: RedisVariadicArgument) {
args.push('FILTER');
return pushVariadicArguments(args, filter);
}
export default {
FIRST_KEY_INDEX: undefined,
IS_READ_ONLY: true,
transformArguments(filter: RedisVariadicArgument, options?: TsMGetOptions) {
const args = pushLatestArgument(['TS.MGET'], options?.LATEST);
return pushFilterArgument(args, filter);
}
export type MGetRawReply = Array<[
key: string,
labels: RawLabels,
sample: SampleRawReply
]>;
export interface MGetReply {
key: string,
sample: SampleReply
}
export function transformReply(reply: MGetRawReply): Array<MGetReply> {
return reply.map(([key, _, sample]) => ({
key,
sample: transformSampleReply(sample)
}));
}
},
// TODO
// transformSampleReply
transformReply: undefined as unknown as () => any
} as const satisfies Command;

View File

@@ -1,39 +1,41 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './MGET_WITHLABELS';
import MGET_WITHLABELS from './MGET_WITHLABELS';
describe('TS.MGET_WITHLABELS', () => {
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
transformArguments('label=value'),
['TS.MGET', 'WITHLABELS', 'FILTER', 'label=value']
);
});
it('with SELECTED_LABELS', () => {
assert.deepEqual(
transformArguments('label=value', { SELECTED_LABELS: 'label' }),
['TS.MGET', 'SELECTED_LABELS', 'label', 'FILTER', 'label=value']
);
});
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
MGET_WITHLABELS.transformArguments('label=value'),
['TS.MGET', 'WITHLABELS', 'FILTER', 'label=value']
);
});
testUtils.testWithClient('client.ts.mGetWithLabels', async client => {
await client.ts.add('key', 0, 0, {
LABELS: { label: 'value' }
});
it('with SELECTED_LABELS', () => {
assert.deepEqual(
MGET_WITHLABELS.transformArguments('label=value', {
SELECTED_LABELS: 'label'
}),
['TS.MGET', 'SELECTED_LABELS', 'label', 'FILTER', 'label=value']
);
});
});
assert.deepEqual(
await client.ts.mGetWithLabels('label=value'),
[{
key: 'key',
labels: { label: 'value'},
sample: {
timestamp: 0,
value: 0
}
}]
);
}, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('client.ts.mGetWithLabels', async client => {
const [, reply] = await Promise.all([
client.ts.add('key', 0, 0, {
LABELS: { label: 'value' }
}),
client.ts.mGetWithLabels('label=value')
]);
assert.deepEqual(reply, [{
key: 'key',
labels: { label: 'value' },
sample: {
timestamp: 0,
value: 0
}
}]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,37 +1,20 @@
import {
SelectedLabels,
pushWithLabelsArgument,
Labels,
transformLablesReply,
transformSampleReply,
Filter,
pushFilterArgument
} from '.';
import { MGetOptions, MGetRawReply, MGetReply } from './MGET';
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { Command } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument } from '@redis/client/dist/lib/commands/generic-transformers';
import { TsMGetOptions, pushLatestArgument, pushFilterArgument } from './MGET';
import { pushWithLabelsArgument } from '.';
export const IS_READ_ONLY = true;
interface MGetWithLabelsOptions extends MGetOptions {
SELECTED_LABELS?: SelectedLabels;
export interface TsMGetWithLabelsOptions extends TsMGetOptions {
SELECTED_LABELS?: RedisVariadicArgument;
}
export function transformArguments(
filter: Filter,
options?: MGetWithLabelsOptions
): RedisCommandArguments {
const args = pushWithLabelsArgument(['TS.MGET'], options?.SELECTED_LABELS);
export default {
FIRST_KEY_INDEX: undefined,
IS_READ_ONLY: true,
transformArguments(filter: RedisVariadicArgument, options?: TsMGetWithLabelsOptions) {
let args = pushLatestArgument(['TS.MGET'], options?.LATEST);
args = pushWithLabelsArgument(args, options?.SELECTED_LABELS);
return pushFilterArgument(args, filter);
}
export interface MGetWithLabelsReply extends MGetReply {
labels: Labels;
};
export function transformReply(reply: MGetRawReply): Array<MGetWithLabelsReply> {
return reply.map(([key, labels, sample]) => ({
key,
labels: transformLablesReply(labels),
sample: transformSampleReply(sample)
}));
}
},
// TODO
transformReply: undefined as unknown as () => any
} as const satisfies Command;

View File

@@ -1,50 +1,54 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './MRANGE';
import MRANGE from './MRANGE';
import { TimeSeriesAggregationType, TimeSeriesReducers } from '.';
describe('TS.MRANGE', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('-', '+', 'label=value', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 0,
max: 1
},
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
},
GROUPBY: {
label: 'label',
reducer: TimeSeriesReducers.SUM
},
}),
['TS.MRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'FILTER', 'label=value',
'GROUPBY', 'label', 'REDUCE', 'SUM']
);
});
it('transformArguments', () => {
assert.deepEqual(
MRANGE.transformArguments('-', '+', 'label=value', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 0,
max: 1
},
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
},
GROUPBY: {
label: 'label',
reducer: TimeSeriesReducers.SUM
},
}),
[
'TS.MRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'FILTER', 'label=value',
'GROUPBY', 'label', 'REDUCE', 'SUM'
]
);
});
testUtils.testWithClient('client.ts.mRange', async client => {
await client.ts.add('key', 0, 0, {
LABELS: { label: 'value'}
});
testUtils.testWithClient('client.ts.mRange', async client => {
const [, reply] = await Promise.all([
client.ts.add('key', 0, 0, {
LABELS: {
label: 'value'
}
}),
client.ts.mRange('-', '+', 'label=value', {
COUNT: 1
})
]);
assert.deepEqual(
await client.ts.mRange('-', '+', 'label=value', {
COUNT: 1
}),
[{
key: 'key',
samples: [{
timestamp: 0,
value: 0
}]
}]
);
}, GLOBAL.SERVERS.OPEN);
assert.deepEqual(reply, [{
key: 'key',
samples: [{
timestamp: 0,
value: 0
}]
}]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,21 +1,68 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { MRangeOptions, Timestamp, pushMRangeArguments, Filter } from '.';
import { RedisArgument, Command, CommandArguments } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument, pushVariadicArguments } from '@redis/client/dist/lib/commands/generic-transformers';
import { Timestamp } from '.';
import { TsRangeOptions, pushRangeArguments } from './RANGE';
import { pushFilterArgument } from './MGET';
export const IS_READ_ONLY = true;
export const TIME_SERIES_REDUCERS = {
AVG: 'AVG',
SUM: 'SUM',
MIN: 'MIN',
MAX: 'MAX',
RANGE: 'RANGE',
COUNT: 'COUNT',
STD_P: 'STD.P',
STD_S: 'STD.S',
VAR_P: 'VAR.P',
VAR_S: 'VAR.S'
};
export function transformArguments(
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filters: Filter,
options?: MRangeOptions
): RedisCommandArguments {
return pushMRangeArguments(
['TS.MRANGE'],
fromTimestamp,
toTimestamp,
filters,
options
);
export type TimeSeriesReducers = typeof TIME_SERIES_REDUCERS[keyof typeof TIME_SERIES_REDUCERS];
export interface TsMRangeOptions extends TsRangeOptions {
GROUPBY?: {
label: RedisArgument;
reducer: TimeSeriesReducers;
};
}
export { transformMRangeReply as transformReply } from '.';
export function pushGroupByArgument(args: CommandArguments, groupBy?: TsMRangeOptions['GROUPBY']) {
if (groupBy) {
args.push(
'GROUPBY',
groupBy.label,
'REDUCE',
groupBy.reducer
);
}
return args;
}
export function transformMRangeArguments(
command: RedisArgument,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filter: RedisVariadicArgument,
options?: TsMRangeOptions
) {
let args = pushRangeArguments(
[command],
fromTimestamp,
toTimestamp,
options
);
args = pushFilterArgument(args, filter);
return pushGroupByArgument(args, options?.GROUPBY);
}
export default {
FIRST_KEY_INDEX: undefined,
IS_READ_ONLY: true,
transformArguments: transformMRangeArguments.bind(undefined, 'TS.MRANGE'),
// TODO
// export { transformMRangeReply as transformReply } from '.';
transformReply: undefined as unknown as () => any
} as const satisfies Command;

View File

@@ -1,52 +1,53 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './MRANGE_WITHLABELS';
import { TimeSeriesAggregationType, TimeSeriesReducers } from '.';
import MRANGE_WITHLABELS from './MRANGE_WITHLABELS';
import { TIME_SERIES_AGGREGATION_TYPE } from './CREATERULE';
import { TIME_SERIES_REDUCERS } from './MRANGE';
describe('TS.MRANGE_WITHLABELS', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('-', '+', 'label=value', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 0,
max: 1
},
SELECTED_LABELS: ['label'],
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
},
GROUPBY: {
label: 'label',
reducer: TimeSeriesReducers.SUM
},
}),
['TS.MRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'SELECTED_LABELS', 'label',
'FILTER', 'label=value', 'GROUPBY', 'label', 'REDUCE', 'SUM']
);
it('transformArguments', () => {
assert.deepEqual(
MRANGE_WITHLABELS.transformArguments('-', '+', 'label=value', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 0,
max: 1
},
SELECTED_LABELS: ['label'],
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TIME_SERIES_AGGREGATION_TYPE.AVG,
timeBucket: 1
},
GROUPBY: {
label: 'label',
reducer: TIME_SERIES_REDUCERS.SUM
},
}),
['TS.MRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'SELECTED_LABELS', 'label',
'FILTER', 'label=value', 'GROUPBY', 'label', 'REDUCE', 'SUM']
);
});
testUtils.testWithClient('client.ts.mRangeWithLabels', async client => {
await client.ts.add('key', 0, 0, {
LABELS: { label: 'value' }
});
testUtils.testWithClient('client.ts.mRangeWithLabels', async client => {
await client.ts.add('key', 0, 0, {
LABELS: { label: 'value'}
});
assert.deepEqual(
await client.ts.mRangeWithLabels('-', '+', 'label=value', {
COUNT: 1
}),
[{
key: 'key',
labels: { label: 'value' },
samples: [{
timestamp: 0,
value: 0
}]
}]
);
}, GLOBAL.SERVERS.OPEN);
assert.deepEqual(
await client.ts.mRangeWithLabels('-', '+', 'label=value', {
COUNT: 1
}),
[{
key: 'key',
labels: { label: 'value' },
samples: [{
timestamp: 0,
value: 0
}]
}]
);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,21 +1,32 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { Timestamp, MRangeWithLabelsOptions, pushMRangeWithLabelsArguments } from '.';
import { RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument } from '@redis/client/dist/lib/commands/generic-transformers';
import { TsMRangeOptions, pushGroupByArgument } from './MRANGE';
import { Timestamp, pushWithLabelsArgument } from '.';
import { pushFilterArgument } from './MGET';
import { pushRangeArguments } from './RANGE';
export const IS_READ_ONLY = true;
export function transformArguments(
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filters: string | Array<string>,
options?: MRangeWithLabelsOptions
): RedisCommandArguments {
return pushMRangeWithLabelsArguments(
['TS.MRANGE'],
fromTimestamp,
toTimestamp,
filters,
options
);
export interface TsMRangeWithLabelsOptions extends TsMRangeOptions {
SELECTED_LABELS?: RedisVariadicArgument;
}
export { transformMRangeWithLabelsReply as transformReply } from '.';
export function transformMRangeWithLabelsArguments(
command: RedisArgument,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filter: RedisVariadicArgument,
options?: TsMRangeWithLabelsOptions
) {
let args = pushRangeArguments([command], fromTimestamp, toTimestamp, options);
args = pushWithLabelsArgument(args, options?.SELECTED_LABELS);
args = pushFilterArgument(args, filter);
return pushGroupByArgument(args, options?.GROUPBY);
}
export default {
FIRST_KEY_INDEX: undefined,
IS_READ_ONLY: true,
transformArguments: transformMRangeWithLabelsArguments.bind(undefined, 'TS.MRANGE'),
// TODO
// export { transformMRangeWithLabelsReply as transformReply } from '.';
transformReply: undefined as unknown as () => any
} as const satisfies Command;

View File

@@ -4,47 +4,49 @@ import { transformArguments } from './MREVRANGE';
import { TimeSeriesAggregationType, TimeSeriesReducers } from '.';
describe('TS.MREVRANGE', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('-', '+', 'label=value', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 0,
max: 1
},
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
},
GROUPBY: {
label: 'label',
reducer: TimeSeriesReducers.SUM
},
}),
['TS.MREVRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'FILTER', 'label=value',
'GROUPBY', 'label', 'REDUCE', 'SUM']
);
});
it('transformArguments', () => {
assert.deepEqual(
transformArguments('-', '+', 'label=value', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 0,
max: 1
},
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
},
GROUPBY: {
label: 'label',
reducer: TimeSeriesReducers.SUM
},
}),
[
'TS.MREVRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'FILTER', 'label=value',
'GROUPBY', 'label', 'REDUCE', 'SUM'
]
);
});
testUtils.testWithClient('client.ts.mRevRange', async client => {
await client.ts.add('key', 0, 0, {
LABELS: { label: 'value'}
});
testUtils.testWithClient('client.ts.mRevRange', async client => {
const [, reply] = await Promise.all([
client.ts.add('key', 0, 0, {
LABELS: { label: 'value' }
}),
client.ts.mRevRange('-', '+', 'label=value', {
COUNT: 1
})
]);
assert.deepEqual(
await client.ts.mRevRange('-', '+', 'label=value', {
COUNT: 1
}),
[{
key: 'key',
samples: [{
timestamp: 0,
value: 0
}]
}]
);
}, GLOBAL.SERVERS.OPEN);
assert.deepEqual(reply, [{
key: 'key',
samples: [{
timestamp: 0,
value: 0
}]
}]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,21 +1,9 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { MRangeOptions, Timestamp, pushMRangeArguments, Filter } from '.';
import { Command } from '@redis/client/dist/lib/RESP/types';
import MRANGE, { transformMRangeArguments } from './MRANGE';
export const IS_READ_ONLY = true;
export function transformArguments(
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filters: Filter,
options?: MRangeOptions
): RedisCommandArguments {
return pushMRangeArguments(
['TS.MREVRANGE'],
fromTimestamp,
toTimestamp,
filters,
options
);
}
export { transformMRangeReply as transformReply } from '.';
export default {
FIRST_KEY_INDEX: MRANGE.FIRST_KEY_INDEX,
IS_READ_ONLY: MRANGE.IS_READ_ONLY,
transformArguments: transformMRangeArguments.bind(undefined, 'TS.MREVRANGE'),
transformReply: MRANGE.transformReply
} as const satisfies Command;

View File

@@ -1,52 +1,54 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './MREVRANGE_WITHLABELS';
import MREVRANGE_WITHLABELS from './MREVRANGE_WITHLABELS';
import { TimeSeriesAggregationType, TimeSeriesReducers } from '.';
describe('TS.MREVRANGE_WITHLABELS', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('-', '+', 'label=value', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 0,
max: 1
},
SELECTED_LABELS: ['label'],
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
},
GROUPBY: {
label: 'label',
reducer: TimeSeriesReducers.SUM
},
}),
['TS.MREVRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'SELECTED_LABELS', 'label',
'FILTER', 'label=value', 'GROUPBY', 'label', 'REDUCE', 'SUM']
);
});
it('transformArguments', () => {
assert.deepEqual(
MREVRANGE_WITHLABELS.transformArguments('-', '+', 'label=value', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 0,
max: 1
},
SELECTED_LABELS: ['label'],
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
},
GROUPBY: {
label: 'label',
reducer: TimeSeriesReducers.SUM
},
}),
[
'TS.MREVRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'SELECTED_LABELS', 'label',
'FILTER', 'label=value', 'GROUPBY', 'label', 'REDUCE', 'SUM'
]
);
});
testUtils.testWithClient('client.ts.mRevRangeWithLabels', async client => {
await client.ts.add('key', 0, 0, {
LABELS: { label: 'value'}
});
testUtils.testWithClient('client.ts.mRevRangeWithLabels', async client => {
const [, reply] = await Promise.all([
client.ts.add('key', 0, 0, {
LABELS: { label: 'value' }
}),
client.ts.mRevRangeWithLabels('-', '+', 'label=value', {
COUNT: 1
})
]);
assert.deepEqual(
await client.ts.mRevRangeWithLabels('-', '+', 'label=value', {
COUNT: 1
}),
[{
key: 'key',
labels: { label: 'value' },
samples: [{
timestamp: 0,
value: 0
}]
}]
);
}, GLOBAL.SERVERS.OPEN);
assert.deepEqual(reply, [{
key: 'key',
labels: { label: 'value' },
samples: [{
timestamp: 0,
value: 0
}]
}]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,21 +1,11 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { Timestamp, MRangeWithLabelsOptions, pushMRangeWithLabelsArguments, Filter } from '.';
import { Command } from '@redis/client/dist/lib/RESP/types';
import { transformMRangeWithLabelsArguments } from './MRANGE_WITHLABELS';
export const IS_READ_ONLY = true;
export function transformArguments(
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filters: Filter,
options?: MRangeWithLabelsOptions
): RedisCommandArguments {
return pushMRangeWithLabelsArguments(
['TS.MREVRANGE'],
fromTimestamp,
toTimestamp,
filters,
options
);
}
export { transformMRangeWithLabelsReply as transformReply } from '.';
export default {
FIRST_KEY_INDEX: undefined,
IS_READ_ONLY: true,
transformArguments: transformMRangeWithLabelsArguments.bind(undefined, 'TS.MREVRANGE'),
// TODO
// export { transformMRangeWithLabelsReply as transformReply } from '.';
transformReply: undefined as unknown as () => any
} as const satisfies Command;

View File

@@ -1,34 +1,34 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './QUERYINDEX';
import QUERYINDEX from './QUERYINDEX';
describe('TS.QUERYINDEX', () => {
describe('transformArguments', () => {
it('single filter', () => {
assert.deepEqual(
transformArguments('*'),
['TS.QUERYINDEX', '*']
);
});
it('multiple filters', () => {
assert.deepEqual(
transformArguments(['a=1', 'b=2']),
['TS.QUERYINDEX', 'a=1', 'b=2']
);
});
describe('transformArguments', () => {
it('single filter', () => {
assert.deepEqual(
QUERYINDEX.transformArguments('*'),
['TS.QUERYINDEX', '*']
);
});
testUtils.testWithClient('client.ts.queryIndex', async client => {
await client.ts.create('key', {
LABELS: {
label: 'value'
}
});
it('multiple filters', () => {
assert.deepEqual(
QUERYINDEX.transformArguments(['a=1', 'b=2']),
['TS.QUERYINDEX', 'a=1', 'b=2']
);
});
});
assert.deepEqual(
await client.ts.queryIndex('label=value'),
['key']
);
}, GLOBAL.SERVERS.OPEN);
testUtils.testWithClient('client.ts.queryIndex', async client => {
const [, reply] = await Promise.all([
client.ts.create('key', {
LABELS: {
label: 'value'
}
}),
client.ts.queryIndex('label=value')
]);
assert.deepEqual(reply, ['key']);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,11 +1,14 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { pushVariadicArguments } from '@redis/client/dist/lib/commands/generic-transformers';
import { Filter } from '.';
import { ArrayReply, BlobStringReply, SetReply, Command } from '@redis/client/dist/lib/RESP/types';
import { RedisVariadicArgument, pushVariadicArguments } from '@redis/client/dist/lib/commands/generic-transformers';
export const IS_READ_ONLY = true;
export function transformArguments(filter: Filter): RedisCommandArguments {
export default {
FIRST_KEY_INDEX: undefined,
IS_READ_ONLY: true,
transformArguments(filter: RedisVariadicArgument) {
return pushVariadicArguments(['TS.QUERYINDEX'], filter);
}
export declare function transformReply(): Array<string>;
},
transformReply: {
2: undefined as unknown as () => ArrayReply<BlobStringReply>,
3: undefined as unknown as () => SetReply<BlobStringReply>
}
} as const satisfies Command;

View File

@@ -1,38 +1,40 @@
import { strict as assert } from 'assert';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './RANGE';
import { TimeSeriesAggregationType } from '.';
import RANGE from './RANGE';
import { TIME_SERIES_AGGREGATION_TYPE } from './CREATERULE';
describe('TS.RANGE', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 1,
max: 2
},
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
}
}),
['TS.RANGE', 'key', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE',
'1', '2', 'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1']
);
});
it('transformArguments', () => {
assert.deepEqual(
RANGE.transformArguments('key', '-', '+', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 1,
max: 2
},
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TIME_SERIES_AGGREGATION_TYPE.AVG,
timeBucket: 1
}
}),
[
'TS.RANGE', 'key', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE',
'1', '2', 'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1'
]
);
});
testUtils.testWithClient('client.ts.range', async client => {
await client.ts.add('key', 1, 2);
testUtils.testWithClient('client.ts.range', async client => {
const [, reply] = await Promise.all([
client.ts.add('key', 1, 2),
client.ts.range('key', '-', '+')
]);
assert.deepEqual(
await client.ts.range('key', '-', '+'),
[{
timestamp: 1,
value: 2
}]
);
}, GLOBAL.SERVERS.OPEN);
assert.deepEqual(reply, [{
timestamp: 1,
value: 2
}]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,24 +1,117 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RangeOptions, Timestamp, pushRangeArguments, SampleRawReply, SampleReply, transformRangeReply } from '.';
import { CommandArguments, RedisArgument, Command } from '@redis/client/dist/lib/RESP/types';
import { Timestamp, transformTimestampArgument } from '.';
import { TimeSeriesAggregationType } from './CREATERULE';
export const FIRST_KEY_INDEX = 1;
export const TIME_SERIES_BUCKET_TIMESTAMP = {
LOW: '-',
MIDDLE: '~',
END: '+'
};
export const IS_READ_ONLY = true;
export type TimeSeriesBucketTimestamp = typeof TIME_SERIES_BUCKET_TIMESTAMP[keyof typeof TIME_SERIES_BUCKET_TIMESTAMP];
export function transformArguments(
key: string,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
options?: RangeOptions
): RedisCommandArguments {
return pushRangeArguments(
['TS.RANGE', key],
fromTimestamp,
toTimestamp,
options
export interface TsRangeOptions {
LATEST?: boolean;
FILTER_BY_TS?: Array<Timestamp>;
FILTER_BY_VALUE?: {
min: number;
max: number;
};
COUNT?: number;
ALIGN?: Timestamp;
AGGREGATION?: {
ALIGN?: Timestamp;
type: TimeSeriesAggregationType;
timeBucket: Timestamp;
BUCKETTIMESTAMP?: TimeSeriesBucketTimestamp;
EMPTY?: boolean;
};
}
export function pushRangeArguments(
args: CommandArguments,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
options?: TsRangeOptions
) {
args.push(
transformTimestampArgument(fromTimestamp),
transformTimestampArgument(toTimestamp)
);
if (options?.LATEST) {
args.push('LATEST');
}
if (options?.FILTER_BY_TS) {
args.push('FILTER_BY_TS');
for (const timestamp of options.FILTER_BY_TS) {
args.push(transformTimestampArgument(timestamp));
}
}
if (options?.FILTER_BY_VALUE) {
args.push(
'FILTER_BY_VALUE',
options.FILTER_BY_VALUE.min.toString(),
options.FILTER_BY_VALUE.max.toString()
);
}
if (options?.COUNT !== undefined) {
args.push('COUNT', options.COUNT.toString());
}
if (options?.AGGREGATION) {
if (options?.ALIGN !== undefined) {
args.push('ALIGN', transformTimestampArgument(options.ALIGN));
}
args.push(
'AGGREGATION',
options.AGGREGATION.type,
transformTimestampArgument(options.AGGREGATION.timeBucket)
);
if (options.AGGREGATION.BUCKETTIMESTAMP) {
args.push(
'BUCKETTIMESTAMP',
options.AGGREGATION.BUCKETTIMESTAMP
);
}
if (options.AGGREGATION.EMPTY) {
args.push('EMPTY');
}
}
return args;
}
export function transformReply(reply: Array<SampleRawReply>): Array<SampleReply> {
return transformRangeReply(reply);
export function transformRangeArguments(
command: RedisArgument,
key: RedisArgument,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
options?: TsRangeOptions
) {
return pushRangeArguments(
[command, key],
fromTimestamp,
toTimestamp,
options
);
}
export default {
FIRST_KEY_INDEX: 1,
IS_READ_ONLY: true,
transformArguments: transformRangeArguments.bind(undefined, 'TS.RANGE'),
// TODO
// import { SampleReply, transformRangeReply } from '.';
// export function transformReply(reply: Array<SampleRawReply>): Array<SampleReply> {
// return transformRangeReply(reply);
// }
transformReply: undefined as unknown as () => any
} as const satisfies Command;

View File

@@ -4,103 +4,101 @@ import { transformArguments } from './REVRANGE';
import { TimeSeriesAggregationType } from '.';
describe('TS.REVRANGE', () => {
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
transformArguments('key', '-', '+'),
['TS.REVRANGE', 'key', '-', '+']
);
});
it('with FILTER_BY_TS', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
FILTER_BY_TS: [0]
}),
['TS.REVRANGE', 'key', '-', '+', 'FILTER_BY_TS', '0']
);
});
it('with FILTER_BY_VALUE', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
FILTER_BY_VALUE: {
min: 1,
max: 2
}
}),
['TS.REVRANGE', 'key', '-', '+', 'FILTER_BY_VALUE', '1', '2']
);
});
it('with COUNT', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
COUNT: 1
}),
['TS.REVRANGE', 'key', '-', '+', 'COUNT', '1']
);
});
it('with ALIGN', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
ALIGN: '-'
}),
['TS.REVRANGE', 'key', '-', '+', 'ALIGN', '-']
);
});
it('with AGGREGATION', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
}
}),
['TS.REVRANGE', 'key', '-', '+', 'AGGREGATION', 'AVG', '1']
);
});
it('with FILTER_BY_TS, FILTER_BY_VALUE, COUNT, ALIGN, AGGREGATION', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 1,
max: 2
},
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
}
}),
[
'TS.REVRANGE', 'key', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE',
'1', '2', 'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1'
]
);
});
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
transformArguments('key', '-', '+'),
['TS.REVRANGE', 'key', '-', '+']
);
});
testUtils.testWithClient('client.ts.revRange', async client => {
await Promise.all([
client.ts.add('key', 0, 1),
client.ts.add('key', 1, 2)
]);
it('with FILTER_BY_TS', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
FILTER_BY_TS: [0]
}),
['TS.REVRANGE', 'key', '-', '+', 'FILTER_BY_TS', '0']
);
});
assert.deepEqual(
await client.ts.revRange('key', '-', '+'),
[{
timestamp: 1,
value: 2
}, {
timestamp: 0,
value: 1
}]
);
}, GLOBAL.SERVERS.OPEN);
it('with FILTER_BY_VALUE', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
FILTER_BY_VALUE: {
min: 1,
max: 2
}
}),
['TS.REVRANGE', 'key', '-', '+', 'FILTER_BY_VALUE', '1', '2']
);
});
it('with COUNT', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
COUNT: 1
}),
['TS.REVRANGE', 'key', '-', '+', 'COUNT', '1']
);
});
it('with ALIGN', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
ALIGN: '-'
}),
['TS.REVRANGE', 'key', '-', '+', 'ALIGN', '-']
);
});
it('with AGGREGATION', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
}
}),
['TS.REVRANGE', 'key', '-', '+', 'AGGREGATION', 'AVG', '1']
);
});
it('with FILTER_BY_TS, FILTER_BY_VALUE, COUNT, ALIGN, AGGREGATION', () => {
assert.deepEqual(
transformArguments('key', '-', '+', {
FILTER_BY_TS: [0],
FILTER_BY_VALUE: {
min: 1,
max: 2
},
COUNT: 1,
ALIGN: '-',
AGGREGATION: {
type: TimeSeriesAggregationType.AVERAGE,
timeBucket: 1
}
}),
[
'TS.REVRANGE', 'key', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE',
'1', '2', 'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1'
]
);
});
});
testUtils.testWithClient('client.ts.revRange', async client => {
const [, , reply] = await Promise.all([
client.ts.add('key', 0, 1),
client.ts.add('key', 1, 2),
client.ts.revRange('key', '-', '+')
]);
assert.deepEqual(reply, [{
timestamp: 1,
value: 2
}, {
timestamp: 0,
value: 1
}]);
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -1,24 +1,9 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { RangeOptions, Timestamp, pushRangeArguments, SampleRawReply, SampleReply, transformRangeReply } from '.';
import { Command } from '@redis/client/dist/lib/RESP/types';
import RANGE, { transformRangeArguments } from './RANGE';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(
key: string,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
options?: RangeOptions
): RedisCommandArguments {
return pushRangeArguments(
['TS.REVRANGE', key],
fromTimestamp,
toTimestamp,
options
);
}
export function transformReply(reply: Array<SampleRawReply>): Array<SampleReply> {
return transformRangeReply(reply);
}
export default {
FIRST_KEY_INDEX: RANGE.FIRST_KEY_INDEX,
IS_READ_ONLY: RANGE.IS_READ_ONLY,
transformArguments: transformRangeArguments.bind(undefined, 'TS.REVRANGE'),
transformReply: RANGE.transformReply
} as const satisfies Command;

View File

@@ -1,4 +1,4 @@
import type { RedisArgument, RedisCommands } from '@redis/client/dist/lib/RESP/types';
import type { BlobStringReply, CommandArguments, DoubleReply, NumberReply, RedisArgument, RedisCommands, TuplesReply, UnwrapReply } from '@redis/client/dist/lib/RESP/types';
import ADD from './ADD';
import ALTER from './ALTER';
import CREATE from './CREATE';
@@ -11,15 +11,16 @@ import INCRBY from './INCRBY';
// import INFO_DEBUG from './INFO_DEBUG';
// import INFO from './INFO';
import MADD from './MADD';
// import MGET from './MGET';
// import MGET_WITHLABELS from './MGET_WITHLABELS';
// import QUERYINDEX from './QUERYINDEX';
// import RANGE from './RANGE';
// import REVRANGE from './REVRANGE';
// import MRANGE from './MRANGE';
// import MRANGE_WITHLABELS from './MRANGE_WITHLABELS';
// import MREVRANGE from './MREVRANGE';
// import MREVRANGE_WITHLABELS from './MREVRANGE_WITHLABELS';
import MGET_WITHLABELS from './MGET_WITHLABELS';
import MGET from './MGET';
import MRANGE_WITHLABELS from './MRANGE_WITHLABELS';
import MRANGE from './MRANGE';
import MREVRANGE_WITHLABELS from './MREVRANGE_WITHLABELS';
import MREVRANGE from './MREVRANGE';
import QUERYINDEX from './QUERYINDEX';
import RANGE from './RANGE';
import REVRANGE from './REVRANGE';
import { RedisVariadicArgument, pushVariadicArguments } from '@redis/client/dist/lib/commands/generic-transformers';
export default {
ADD,
@@ -46,24 +47,24 @@ export default {
// info: INFO,
MADD,
mAdd: MADD,
// MGET,
// mGet: MGET,
// MGET_WITHLABELS,
// mGetWithLabels: MGET_WITHLABELS,
// QUERYINDEX,
// queryIndex: QUERYINDEX,
// RANGE,
// range: RANGE,
// REVRANGE,
// revRange: REVRANGE,
// MRANGE,
// mRange: MRANGE,
// MRANGE_WITHLABELS,
// mRangeWithLabels: MRANGE_WITHLABELS,
// MREVRANGE,
// mRevRange: MREVRANGE,
// MREVRANGE_WITHLABELS,
// mRevRangeWithLabels: MREVRANGE_WITHLABELS
MGET_WITHLABELS,
mGetWithLabels: MGET_WITHLABELS,
MGET,
mGet: MGET,
MRANGE_WITHLABELS,
mRangeWithLabels: MRANGE_WITHLABELS,
MRANGE,
mRange: MRANGE,
MREVRANGE_WITHLABELS,
mRevRangeWithLabels: MREVRANGE_WITHLABELS,
MREVRANGE,
mRevRange: MREVRANGE,
QUERYINDEX,
queryIndex: QUERYINDEX,
RANGE,
range: RANGE,
REVRANGE,
revRange: REVRANGE
} as const satisfies RedisCommands;
export function pushRetentionArgument(args: Array<RedisArgument>, retention?: number) {
@@ -148,20 +149,22 @@ export function pushLabelsArgument(args: Array<RedisArgument>, labels?: Labels)
// return labels
// }
// export type SampleRawReply = [timestamp: number, value: string];
// export interface SampleReply {
// timestamp: number;
// value: number;
// }
// export function transformSampleReply(reply: SampleRawReply): SampleReply {
// return {
// timestamp: reply[0],
// value: Number(reply[1])
// };
// }
export const transformSampleReply = {
2(reply: TuplesReply<[timestamp: NumberReply, value: BlobStringReply]>) {
const [timestamp, value] = reply as unknown as UnwrapReply<typeof reply>;
return {
timestamp,
value: Number(value)
};
},
3(reply: TuplesReply<[timestamp: NumberReply, value: DoubleReply]>) {
const [timestamp, value] = reply as unknown as UnwrapReply<typeof reply>;
return {
timestamp,
value
};
}
};
// export enum TimeSeriesBucketTimestamp {
// LOW = '-',
@@ -293,16 +296,15 @@ export function pushLabelsArgument(args: Array<RedisArgument>, labels?: Labels)
// export type SelectedLabels = string | Array<string>;
// export function pushWithLabelsArgument(args: RedisCommandArguments, selectedLabels?: SelectedLabels): RedisCommandArguments {
// if (!selectedLabels) {
// args.push('WITHLABELS');
// } else {
// args.push('SELECTED_LABELS');
// args = pushVariadicArguments(args, selectedLabels);
// }
// return args;
// }
export function pushWithLabelsArgument(args: CommandArguments, selectedLabels?: RedisVariadicArgument) {
if (!selectedLabels) {
args.push('WITHLABELS');
return args;
} else {
args.push('SELECTED_LABELS');
return pushVariadicArguments(args, selectedLabels);
}
}
// export interface MRangeWithLabelsOptions extends MRangeOptions {
// SELECTED_LABELS?: SelectedLabels;

View File

@@ -4,8 +4,8 @@ export {
TIME_SERIES_ENCODING,
TimeSeriesEncoding,
TIME_SERIES_DUPLICATE_POLICIES,
TimeSeriesDuplicatePolicies,
// TimeSeriesBucketTimestamp
TimeSeriesDuplicatePolicies
} from './commands';
export { TIME_SERIES_AGGREGATION_TYPE, TimeSeriesAggregationType } from './commands/CREATERULE';
export { TIME_SERIES_BUCKET_TIMESTAMP, TimeSeriesBucketTimestamp } from './commands/RANGE';

View File

@@ -5,7 +5,8 @@
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist/"
"dist/",
"!dist/tsconfig.tsbuildinfo"
],
"scripts": {
"test": "nyc -r text-summary -r lcov mocha -r source-map-support/register -r ts-node/register './lib/**/*.spec.ts'"