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

close #2192 close #2193 close #2194 close #2195 close #2196 close #2197 close #2198 - support for TimeSeries 1.8 (#2200)

This commit is contained in:
Leibale Eidelman
2022-08-31 09:25:13 -04:00
committed by GitHub
parent b10a6567dc
commit 5dd7d3149a
25 changed files with 369 additions and 181 deletions

View File

@@ -1,4 +1,5 @@
import { strict as assert } from 'assert';
import { TimeSeriesDuplicatePolicies } from '.';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './ALTER';
@@ -20,6 +21,24 @@ describe('ALTER', () => {
);
});
it('with CHUNK_SIZE', () => {
assert.deepEqual(
transformArguments('key', {
CHUNK_SIZE: 1
}),
['TS.ALTER', 'key', 'CHUNK_SIZE', '1']
);
});
it('with DUPLICATE_POLICY', () => {
assert.deepEqual(
transformArguments('key', {
DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.BLOCK
}),
['TS.ALTER', 'key', 'DUPLICATE_POLICY', 'BLOCK']
);
});
it('with LABELS', () => {
assert.deepEqual(
transformArguments('key', {
@@ -29,19 +48,21 @@ describe('ALTER', () => {
);
});
it('with RETENTION, LABELS', () => {
it('with RETENTION, CHUNK_SIZE, DUPLICATE_POLICY, LABELS', () => {
assert.deepEqual(
transformArguments('key', {
RETENTION: 1,
CHUNK_SIZE: 1,
DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.BLOCK,
LABELS: { label: 'value' }
}),
['TS.ALTER', 'key', 'RETENTION', '1', 'LABELS', 'label', 'value']
['TS.ALTER', 'key', 'RETENTION', '1', 'CHUNK_SIZE', '1', 'DUPLICATE_POLICY', 'BLOCK', 'LABELS', 'label', 'value']
);
});
});
testUtils.testWithClient('client.ts.alter', async client => {
await client.ts.create('key');
await client.ts.create('key');
assert.equal(
await client.ts.alter('key', { RETENTION: 1 }),

View File

@@ -1,9 +1,11 @@
import { pushRetentionArgument, Labels, pushLabelsArgument } from '.';
import { pushRetentionArgument, Labels, pushLabelsArgument, TimeSeriesDuplicatePolicies, pushChunkSizeArgument, pushDuplicatePolicy } from '.';
export const FIRST_KEY_INDEX = 1;
interface AlterOptions {
RETENTION?: number;
CHUNK_SIZE?: number;
DUPLICATE_POLICY?: TimeSeriesDuplicatePolicies;
LABELS?: Labels;
}
@@ -12,6 +14,10 @@ export function transformArguments(key: string, options?: AlterOptions): Array<s
pushRetentionArgument(args, options?.RETENTION);
pushChunkSizeArgument(args, options?.CHUNK_SIZE);
pushDuplicatePolicy(args, options?.DUPLICATE_POLICY);
pushLabelsArgument(args, options?.LABELS);
return args;

View File

@@ -5,7 +5,8 @@ import {
pushChunkSizeArgument,
TimeSeriesDuplicatePolicies,
Labels,
pushLabelsArgument
pushLabelsArgument,
pushDuplicatePolicy
} from '.';
export const FIRST_KEY_INDEX = 1;
@@ -27,12 +28,7 @@ export function transformArguments(key: string, options?: CreateOptions): Array<
pushChunkSizeArgument(args, options?.CHUNK_SIZE);
if (options?.DUPLICATE_POLICY) {
args.push(
'DUPLICATE_POLICY',
options.DUPLICATE_POLICY
);
}
pushDuplicatePolicy(args, options?.DUPLICATE_POLICY);
pushLabelsArgument(args, options?.LABELS);

View File

@@ -4,11 +4,20 @@ import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './CREATERULE';
describe('CREATERULE', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('source', 'destination', TimeSeriesAggregationType.AVERAGE, 1),
['TS.CREATERULE', 'source', 'destination', 'AGGREGATION', 'avg', '1']
);
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
transformArguments('source', 'destination', TimeSeriesAggregationType.AVERAGE, 1),
['TS.CREATERULE', 'source', 'destination', 'AGGREGATION', 'AVG', '1']
);
});
it('with alignTimestamp', () => {
assert.deepEqual(
transformArguments('source', 'destination', TimeSeriesAggregationType.AVERAGE, 1, 1),
['TS.CREATERULE', 'source', 'destination', 'AGGREGATION', 'AVG', '1', '1']
);
});
});
testUtils.testWithClient('client.ts.createRule', async client => {

View File

@@ -6,16 +6,23 @@ export function transformArguments(
sourceKey: string,
destinationKey: string,
aggregationType: TimeSeriesAggregationType,
timeBucket: number
bucketDuration: number,
alignTimestamp?: number
): Array<string> {
return [
const args = [
'TS.CREATERULE',
sourceKey,
destinationKey,
'AGGREGATION',
aggregationType,
timeBucket.toString()
bucketDuration.toString()
];
if (alignTimestamp) {
args.push(alignTimestamp.toString());
}
return args;
}
export declare function transformReply(): 'OK';

View File

@@ -4,7 +4,7 @@ export function transformArguments(sourceKey: string, destinationKey: string): A
return [
'TS.DELETERULE',
sourceKey,
destinationKey,
destinationKey
];
}

View File

@@ -3,11 +3,22 @@ import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './GET';
describe('GET', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('key'),
['TS.GET', 'key']
);
describe('transformArguments', () => {
it('without options', () => {
assert.deepEqual(
transformArguments('key'),
['TS.GET', 'key']
);
});
it('with LATEST', () => {
assert.deepEqual(
transformArguments('key', {
LATEST: true
}),
['TS.GET', 'key', 'LATEST']
);
});
});
describe('client.ts.get', () => {

View File

@@ -1,11 +1,16 @@
import { SampleRawReply, SampleReply, transformSampleReply } from '.';
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { pushLatestArgument, SampleRawReply, SampleReply, transformSampleReply } from '.';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
export function transformArguments(key: string): Array<string> {
return ['TS.GET', key];
interface GetOptions {
LATEST?: boolean;
}
export function transformArguments(key: string, options?: GetOptions): RedisCommandArguments {
return pushLatestArgument(['TS.GET', key], options?.LATEST);
}
export function transformReply(reply: [] | SampleRawReply): null | SampleReply {

View File

@@ -1,7 +1,7 @@
import { strict as assert } from 'assert';
import { TimeSeriesAggregationType, TimeSeriesDuplicatePolicies } from '.';
import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './INFO';
import { InfoReply, transformArguments } from './INFO';
describe('INFO', () => {
it('transformArguments', () => {
@@ -14,7 +14,7 @@ describe('INFO', () => {
testUtils.testWithClient('client.ts.info', async client => {
await Promise.all([
client.ts.create('key', {
LABELS: { id: "2" },
LABELS: { id: '1' },
DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.LAST
}),
client.ts.create('key2'),
@@ -22,29 +22,32 @@ describe('INFO', () => {
client.ts.add('key', 1, 10)
]);
assert.deepEqual(
await client.ts.info('key'),
{
totalSamples: 1,
memoryUsage: 4261,
firstTimestamp: 1,
lastTimestamp: 1,
retentionTime: 0,
chunkCount: 1,
chunkSize: 4096,
chunkType: 'compressed',
duplicatePolicy: 'last',
labels: [{
name: 'id',
value: '2'
}],
rules: [{
aggregationType: 'COUNT',
key: 'key2',
timeBucket: 5
}],
sourceKey: null
}
);
assertInfo(await client.ts.info('key'));
}, GLOBAL.SERVERS.OPEN);
});
export function assertInfo(info: InfoReply): void {
assert.equal(typeof info.totalSamples, 'number');
assert.equal(typeof info.memoryUsage, 'number');
assert.equal(typeof info.firstTimestamp, 'number');
assert.equal(typeof info.lastTimestamp, 'number');
assert.equal(typeof info.retentionTime, 'number');
assert.equal(typeof info.chunkCount, 'number');
assert.equal(typeof info.chunkSize, 'number');
assert.equal(typeof info.chunkType, 'string');
assert.equal(typeof info.duplicatePolicy, 'string');
assert.ok(Array.isArray(info.labels));
for (const label of info.labels) {
assert.equal(typeof label, 'object');
assert.equal(typeof label.name, 'string');
assert.equal(typeof label.value, 'string');
}
assert.ok(Array.isArray(info.rules));
for (const rule of info.rules) {
assert.equal(typeof rule, 'object');
assert.equal(typeof rule.aggregationType, 'string');
assert.equal(typeof rule.key, 'string');
assert.equal(typeof rule.timeBucket, 'number');
}
assert.ok(info.sourceKey === null || typeof info.sourceKey === 'string');
}

View File

@@ -9,30 +9,30 @@ export function transformArguments(key: string): Array<string> {
}
export type InfoRawReply = [
_: string,
totalSamples: number,
_: string,
memoryUsage: number,
_: string,
firstTimestamp: number,
_: string,
lastTimestamp: number,
_: string,
retentionTime: number,
_: string,
chunkCount: number,
_: string,
chunkSize: number,
_: string,
chunkType: string,
_: string,
duplicatePolicy: TimeSeriesDuplicatePolicies | null,
_: string,
labels: Array<[name: string, value: string]>,
_: string,
sourceKey: string | null,
_: string,
rules: Array<[key: string, timeBucket: number, aggregationType: TimeSeriesAggregationType]>
'totalSamples',
number,
'memoryUsage',
number,
'firstTimestamp',
number,
'lastTimestamp',
number,
'retentionTime',
number,
'chunkCount',
number,
'chunkSize',
number,
'chunkType',
string,
'duplicatePolicy',
TimeSeriesDuplicatePolicies | null,
'labels',
Array<[name: string, value: string]>,
'sourceKey',
string | null,
'rules',
Array<[key: string, timeBucket: number, aggregationType: TimeSeriesAggregationType]>
];
export interface InfoReply {

View File

@@ -1,6 +1,7 @@
import { strict as assert } from 'assert';
import { TimeSeriesAggregationType, TimeSeriesDuplicatePolicies } from '.';
import testUtils, { GLOBAL } from '../test-utils';
import { assertInfo } from './INFO.spec';
import { transformArguments } from './INFO_DEBUG';
describe('INFO_DEBUG', () => {
@@ -14,7 +15,7 @@ describe('INFO_DEBUG', () => {
testUtils.testWithClient('client.ts.get', async client => {
await Promise.all([
client.ts.create('key', {
LABELS: { id: "2" },
LABELS: { id: '1' },
DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.LAST
}),
client.ts.create('key2'),
@@ -22,37 +23,17 @@ describe('INFO_DEBUG', () => {
client.ts.add('key', 1, 10)
]);
assert.deepEqual(
await client.ts.infoDebug('key'),
{
totalSamples: 1,
memoryUsage: 4261,
firstTimestamp: 1,
lastTimestamp: 1,
retentionTime: 0,
chunkCount: 1,
chunkSize: 4096,
chunkType: 'compressed',
duplicatePolicy: 'last',
labels: [{
name: 'id',
value: '2'
}],
sourceKey: null,
rules: [{
aggregationType: 'COUNT',
key: 'key2',
timeBucket: 5
}],
keySelfName: 'key',
chunks: [{
startTimestamp: 1,
endTimestamp: 1,
samples: 1,
size: 4096,
bytesPerSample: '4096'
}]
}
);
const infoDebug = await client.ts.infoDebug('key');
assertInfo(infoDebug);
assert.equal(typeof infoDebug.keySelfName, 'string');
assert.ok(Array.isArray(infoDebug.chunks));
for (const chunk of infoDebug.chunks) {
assert.equal(typeof chunk, 'object');
assert.equal(typeof chunk.startTimestamp, 'number');
assert.equal(typeof chunk.endTimestamp, 'number');
assert.equal(typeof chunk.samples, 'number');
assert.equal(typeof chunk.size, 'number');
assert.equal(typeof chunk.bytesPerSample, 'string');
}
}, GLOBAL.SERVERS.OPEN);
});

View File

@@ -14,23 +14,23 @@ export function transformArguments(key: string): Array<string> {
}
type InfoDebugRawReply = [
...infoArgs: InfoRawReply,
_: string,
keySelfName: string,
_: string,
chunks: Array<[
_: string,
startTimestamp: number,
_: string,
endTimestamp: number,
_: string,
samples: number,
_: string,
size: number,
_: string,
bytesPerSample: string
...InfoRawReply,
'keySelfName',
string,
'chunks',
Array<[
'startTimestamp',
number,
'endTimestamp',
number,
'samples',
number,
'size',
number,
'bytesPerSample',
string
]>
]
];
interface InfoDebugReply extends InfoReply {
keySelfName: string;

View File

@@ -3,11 +3,22 @@ import testUtils, { GLOBAL } from '../test-utils';
import { transformArguments } from './MGET';
describe('MGET', () => {
it('transformArguments', () => {
assert.deepEqual(
transformArguments('label=value'),
['TS.MGET', 'FILTER', 'label=value']
);
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']
);
});
});
testUtils.testWithClient('client.ts.mGet', async client => {

View File

@@ -1,10 +1,15 @@
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
import { Filter, pushFilterArgument, RawLabels, SampleRawReply, SampleReply, transformSampleReply } from '.';
import { Filter, pushFilterArgument, pushLatestArgument, RawLabels, SampleRawReply, SampleReply, transformSampleReply } from '.';
export const IS_READ_ONLY = true;
export function transformArguments(filter: Filter): RedisCommandArguments {
return pushFilterArgument(['TS.MGET'], filter);
export interface MGetOptions {
LATEST?: boolean;
}
export function transformArguments(filter: Filter, options?: MGetOptions): RedisCommandArguments {
const args = pushLatestArgument(['TS.MGET'], options?.LATEST);
return pushFilterArgument(args, filter);
}
export type MGetRawReply = Array<[

View File

@@ -7,12 +7,12 @@ import {
Filter,
pushFilterArgument
} from '.';
import { MGetRawReply, MGetReply } from './MGET';
import { MGetOptions, MGetRawReply, MGetReply } from './MGET';
import { RedisCommandArguments } from '@redis/client/dist/lib/commands';
export const IS_READ_ONLY = true;
interface MGetWithLabelsOptions {
interface MGetWithLabelsOptions extends MGetOptions {
SELECTED_LABELS?: SelectedLabels;
}

View File

@@ -24,8 +24,8 @@ describe('MRANGE', () => {
},
}),
['TS.MRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'avg', '1', 'FILTER', 'label=value',
'GROUPBY', 'label', 'REDUCE', 'sum']
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'FILTER', 'label=value',
'GROUPBY', 'label', 'REDUCE', 'SUM']
);
});

View File

@@ -25,8 +25,8 @@ describe('MRANGE_WITHLABELS', () => {
},
}),
['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']
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'SELECTED_LABELS', 'label',
'FILTER', 'label=value', 'GROUPBY', 'label', 'REDUCE', 'SUM']
);
});

View File

@@ -24,8 +24,8 @@ describe('MREVRANGE', () => {
},
}),
['TS.MREVRANGE', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE', '0', '1',
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'avg', '1', 'FILTER', 'label=value',
'GROUPBY', 'label', 'REDUCE', 'sum']
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'FILTER', 'label=value',
'GROUPBY', 'label', 'REDUCE', 'SUM']
);
});

View File

@@ -25,8 +25,8 @@ describe('MREVRANGE_WITHLABELS', () => {
},
}),
['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']
'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1', 'SELECTED_LABELS', 'label',
'FILTER', 'label=value', 'GROUPBY', 'label', 'REDUCE', 'SUM']
);
});

View File

@@ -20,7 +20,7 @@ describe('RANGE', () => {
}
}),
['TS.RANGE', 'key', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE',
'1', '2', 'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'avg', '1']
'1', '2', 'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1']
);
});

View File

@@ -59,7 +59,7 @@ describe('REVRANGE', () => {
timeBucket: 1
}
}),
['TS.REVRANGE', 'key', '-', '+', 'AGGREGATION', 'avg', '1']
['TS.REVRANGE', 'key', '-', '+', 'AGGREGATION', 'AVG', '1']
);
});
@@ -80,7 +80,7 @@ describe('REVRANGE', () => {
}),
[
'TS.REVRANGE', 'key', '-', '+', 'FILTER_BY_TS', '0', 'FILTER_BY_VALUE',
'1', '2', 'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'avg', '1'
'1', '2', 'COUNT', '1', 'ALIGN', '-', 'AGGREGATION', 'AVG', '1'
]
);
});

View File

@@ -6,6 +6,7 @@ import {
TimeSeriesEncoding,
pushEncodingArgument,
pushChunkSizeArgument,
pushDuplicatePolicy,
pushLabelsArgument,
transformIncrDecrArguments,
transformSampleReply,
@@ -19,7 +20,10 @@ import {
pushMRangeWithLabelsArguments,
transformRangeReply,
transformMRangeReply,
transformMRangeWithLabelsReply
transformMRangeWithLabelsReply,
TimeSeriesDuplicatePolicies,
pushLatestArgument,
TimeSeriesBucketTimestamp
} from '.';
describe('transformTimestampArgument', () => {
@@ -87,6 +91,17 @@ describe('pushChunkSizeArgument', () => {
});
});
describe('pushDuplicatePolicy', () => {
testOptionalArgument(pushDuplicatePolicy);
it('BLOCK', () => {
assert.deepEqual(
pushDuplicatePolicy([], TimeSeriesDuplicatePolicies.BLOCK),
['DUPLICATE_POLICY', 'BLOCK']
);
});
});
describe('pushLabelsArgument', () => {
testOptionalArgument(pushLabelsArgument);
@@ -202,16 +217,44 @@ describe('pushRangeArguments', () => {
);
});
it('with AGGREGATION', () => {
assert.deepEqual(
pushRangeArguments([], '-', '+', {
AGGREGATION: {
type: TimeSeriesAggregationType.FIRST,
timeBucket: 1
}
}),
['-', '+', 'AGGREGATION', 'first', '1']
);
describe('with AGGREGATION', () => {
it('without options', () => {
assert.deepEqual(
pushRangeArguments([], '-', '+', {
AGGREGATION: {
type: TimeSeriesAggregationType.FIRST,
timeBucket: 1
}
}),
['-', '+', 'AGGREGATION', 'FIRST', '1']
);
});
it('with BUCKETTIMESTAMP', () => {
assert.deepEqual(
pushRangeArguments([], '-', '+', {
AGGREGATION: {
type: TimeSeriesAggregationType.FIRST,
timeBucket: 1,
BUCKETTIMESTAMP: TimeSeriesBucketTimestamp.LOW
}
}),
['-', '+', 'AGGREGATION', 'FIRST', '1', 'BUCKETTIMESTAMP', '-']
);
});
it('with BUCKETTIMESTAMP', () => {
assert.deepEqual(
pushRangeArguments([], '-', '+', {
AGGREGATION: {
type: TimeSeriesAggregationType.FIRST,
timeBucket: 1,
EMPTY: true
}
}),
['-', '+', 'AGGREGATION', 'FIRST', '1', 'EMPTY']
);
});
});
it('with FILTER_BY_TS, FILTER_BY_VALUE, COUNT, ALIGN, AGGREGATION', () => {
@@ -226,11 +269,13 @@ describe('pushRangeArguments', () => {
ALIGN: 1,
AGGREGATION: {
type: TimeSeriesAggregationType.FIRST,
timeBucket: 1
timeBucket: 1,
BUCKETTIMESTAMP: TimeSeriesBucketTimestamp.LOW,
EMPTY: true
}
}),
['-', '+', 'FILTER_BY_TS', 'ts', 'FILTER_BY_VALUE', '1', '2',
'COUNT', '1', 'ALIGN', '1', 'AGGREGATION', 'first', '1']
'COUNT', '1', 'ALIGN', '1', 'AGGREGATION', 'FIRST', '1', 'BUCKETTIMESTAMP', '-', 'EMPTY']
);
});
});
@@ -249,7 +294,7 @@ describe('pushMRangeGroupByArguments', () => {
label: 'label',
reducer: TimeSeriesReducers.MAXIMUM
}),
['GROUPBY', 'label', 'REDUCE', 'max']
['GROUPBY', 'label', 'REDUCE', 'MAX']
);
});
});
@@ -286,7 +331,7 @@ describe('pushMRangeArguments', () => {
reducer: TimeSeriesReducers.MAXIMUM
}
}),
['-', '+', 'FILTER', 'label=value', 'GROUPBY', 'label', 'REDUCE', 'max']
['-', '+', 'FILTER', 'label=value', 'GROUPBY', 'label', 'REDUCE', 'MAX']
);
});
});
@@ -369,3 +414,26 @@ describe('transformMRangeWithLabelsReply', () => {
}]
);
});
describe('pushLatestArgument', () => {
it('undefined', () => {
assert.deepEqual(
pushLatestArgument([]),
[]
);
});
it('false', () => {
assert.deepEqual(
pushLatestArgument([], false),
[]
);
});
it('true', () => {
assert.deepEqual(
pushLatestArgument([], true),
['LATEST']
);
});
})

View File

@@ -68,18 +68,25 @@ export default {
};
export enum TimeSeriesAggregationType {
AVERAGE = 'avg',
SUM = 'sum',
MINIMUM = 'min',
MAXIMUM = 'max',
RANGE = 'range',
COUNT = 'count',
FIRST = 'first',
LAST = 'last',
STD_P = 'std.p',
STD_S = 'std.s',
VAR_P = 'var.p',
VAR_S = 'var.s'
AVG = 'AVG',
// @deprecated
AVERAGE = 'AVG',
FIRST = 'FIRST',
LAST = 'LAST',
MIN = 'MIN',
// @deprecated
MINIMUM = 'MIN',
MAX = 'MAX',
// @deprecated
MAXIMUM = 'MAX',
SUM = 'SUM',
RANGE = 'RANGE',
COUNT = 'COUNT',
STD_P = 'STD.P',
STD_S = 'STD.S',
VAR_P = 'VAR.P',
VAR_S = 'VAR.S',
TWA = 'TWA'
}
export enum TimeSeriesDuplicatePolicies {
@@ -92,9 +99,20 @@ export enum TimeSeriesDuplicatePolicies {
}
export enum TimeSeriesReducers {
SUM = 'sum',
MINIMUM = 'min',
MAXIMUM = 'max',
AVG = 'AVG',
SUM = 'SUM',
MIN = 'MIN',
// @deprecated
MINIMUM = 'MIN',
MAX = 'MAX',
// @deprecated
MAXIMUM = 'MAX',
RANGE = 'range',
COUNT = 'COUNT',
STD_P = 'STD.P',
STD_S = 'STD.S',
VAR_P = 'VAR.P',
VAR_S = 'VAR.S',
}
export type Timestamp = number | Date | string;
@@ -147,6 +165,17 @@ export function pushChunkSizeArgument(args: RedisCommandArguments, chunkSize?: n
return args;
}
export function pushDuplicatePolicy(args: RedisCommandArguments, duplicatePolicy?: TimeSeriesDuplicatePolicies): RedisCommandArguments {
if (duplicatePolicy) {
args.push(
'DUPLICATE_POLICY',
duplicatePolicy
);
}
return args;
}
export type RawLabels = Array<[label: string, value: string]>;
export type Labels = {
@@ -226,7 +255,14 @@ export function transformSampleReply(reply: SampleRawReply): SampleReply {
};
}
export enum TimeSeriesBucketTimestamp {
LOW = '-',
HIGH = '+',
MID = '~'
}
export interface RangeOptions {
LATEST?: boolean;
FILTER_BY_TS?: Array<Timestamp>;
FILTER_BY_VALUE?: {
min: number;
@@ -237,6 +273,8 @@ export interface RangeOptions {
AGGREGATION?: {
type: TimeSeriesAggregationType;
timeBucket: Timestamp;
BUCKETTIMESTAMP?: TimeSeriesBucketTimestamp;
EMPTY?: boolean;
};
}
@@ -251,9 +289,11 @@ export function pushRangeArguments(
transformTimestampArgument(toTimestamp)
);
pushLatestArgument(args, options?.LATEST);
if (options?.FILTER_BY_TS) {
args.push('FILTER_BY_TS');
for(const ts of options.FILTER_BY_TS) {
for (const ts of options.FILTER_BY_TS) {
args.push(transformTimestampArgument(ts));
}
}
@@ -286,6 +326,17 @@ export function pushRangeArguments(
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;
@@ -406,3 +457,11 @@ export function transformMRangeWithLabelsReply(reply: MRangeRawReply): Array<MRa
return args;
}
export function pushLatestArgument(args: RedisCommandArguments, latest?: boolean): RedisCommandArguments {
if (latest) {
args.push('LATEST');
}
return args;
}