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

Support RedisTimeSeries (#1757)

* Implement missing commands and add test

* Update DECRBY.spec.ts

* Small changes

* clean code

* Update MGET_WITHLABELS.ts

Use map in transformReply

Co-authored-by: leibale <leibale1998@gmail.com>
This commit is contained in:
Avital Fine
2021-12-12 14:41:44 +01:00
committed by GitHub
parent bb75b06d67
commit 7110f23369
30 changed files with 1310 additions and 47 deletions

View File

@@ -11,9 +11,14 @@ import * as INFO_DEBUG from './INFO_DEBUG';
import * as INFO from './INFO';
import * as MADD from './MADD';
import * as MGET from './MGET';
import * as MGET_WITHLABELS from './MGET_WITHLABELS';
import * as QUERYINDEX from './QUERYINDEX';
import * as RANGE from './RANGE';
import * as REVRANGE from './REVRANGE';
import * as MRANGE from './MRANGE';
import * as MRANGE_WITHLABELS from './MRANGE_WITHLABELS';
import * as MREVRANGE from './MREVRANGE';
import * as MREVRANGE_WITHLABELS from './MREVRANGE_WITHLABELS';
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
import { pushVerdictArguments } from '@node-redis/client/lib/commands/generic-transformers';
@@ -44,12 +49,22 @@ export default {
mAdd: MADD,
MGET,
mGet: MGET,
MGET_WITHLABELS,
mGetWithLabels: MGET_WITHLABELS,
QUERYINDEX,
queryIndex: QUERYINDEX,
RANGE,
range: RANGE,
REVRANGE,
revRange: REVRANGE
revRange: REVRANGE,
MRANGE,
mRange: MRANGE,
MRANGE_WITHLABELS,
mRangeWithLabels: MRANGE_WITHLABELS,
MREVRANGE,
mRevRange: MREVRANGE,
MREVRANGE_WITHLABELS,
mRevRangeWithLabels: MREVRANGE_WITHLABELS
};
export enum TimeSeriesAggregationType {
@@ -67,6 +82,21 @@ export enum TimeSeriesAggregationType {
VAR_S = 'var.s'
}
export enum TimeSeriesDuplicatePolicies {
BLOCK = 'BLOCK',
FIRST = 'FIRST',
LAST = 'LAST',
MIN = 'MIN',
MAX = 'MAX',
SUM = 'SUM'
}
export enum TimeSeriesReducers {
SUM = 'sum',
MINIMUM = 'min',
MAXIMUM = 'max',
}
export type Timestamp = number | Date | string;
export function transformTimestampArgument(timestamp: Timestamp): string {
@@ -117,19 +147,22 @@ export function pushChunkSizeArgument(args: RedisCommandArguments, chunkSize?: n
return args;
}
export enum TimeSeriesDuplicatePolicies {
BLOCK = 'BLOCK',
FIRST = 'FIRST',
LAST = 'LAST',
MIN = 'MIN',
MAX = 'MAX',
SUM = 'SUM'
}
export type RawLabels = Array<[label: string, value: string]>;
export type Labels = {
[label: string]: string;
};
export function transformLablesReply(reply: RawLabels): Labels {
const labels: Labels = {};
for (const [key, value] of reply) {
labels[key] = value;
}
return labels
}
export function pushLabelsArgument(args: RedisCommandArguments, labels?: Labels): RedisCommandArguments {
if (labels) {
args.push('LABELS');
@@ -162,7 +195,7 @@ export function transformIncrDecrArguments(
value.toString()
];
if (options?.TIMESTAMP) {
if (options?.TIMESTAMP !== undefined && options?.TIMESTAMP !== null) {
args.push('TIMESTAMP', transformTimestampArgument(options.TIMESTAMP));
}
@@ -194,7 +227,7 @@ export function transformSampleReply(reply: SampleRawReply): SampleReply {
}
export interface RangeOptions {
FILTER_BY_TS?: string | Array<string>;
FILTER_BY_TS?: Array<Timestamp>;
FILTER_BY_VALUE?: {
min: number;
max: number;
@@ -220,7 +253,9 @@ export function pushRangeArguments(
if (options?.FILTER_BY_TS) {
args.push('FILTER_BY_TS');
pushVerdictArguments(args, options.FILTER_BY_TS);
for(const ts of options.FILTER_BY_TS) {
args.push(transformTimestampArgument(ts));
}
}
if (options?.FILTER_BY_VALUE) {
@@ -256,6 +291,121 @@ export function pushRangeArguments(
return args;
}
interface MRangeGroupBy {
label: string;
reducer: TimeSeriesReducers;
}
export function pushMRangeGroupByArguments(args: RedisCommandArguments, groupBy?: MRangeGroupBy): RedisCommandArguments {
if (groupBy) {
args.push(
'GROUPBY',
groupBy.label,
'REDUCE',
groupBy.reducer
);
}
return args;
}
export type Filter = string | Array<string>;
export function pushFilterArgument(args: RedisCommandArguments, filter: string | Array<string>): RedisCommandArguments {
args.push('FILTER');
pushVerdictArguments(args, filter);
return args;
}
export interface MRangeOptions extends RangeOptions {
GROUPBY?: MRangeGroupBy;
}
export function pushMRangeArguments(
args: RedisCommandArguments,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filter: Filter,
options?: MRangeOptions
): RedisCommandArguments {
pushRangeArguments(args, fromTimestamp, toTimestamp, options);
pushFilterArgument(args, filter);
pushMRangeGroupByArguments(args, options?.GROUPBY);
return args;
}
export type SelectedLabels = string | Array<string>;
export function pushWithLabelsArgument(args: RedisCommandArguments, selectedLabels?: SelectedLabels): RedisCommandArguments {
if (!selectedLabels) {
args.push('WITHLABELS');
} else {
args.push('SELECTED_LABELS');
pushVerdictArguments(args, selectedLabels);
}
return args;
}
export interface MRangeWithLabelsOptions extends MRangeOptions {
SELECTED_LABELS?: SelectedLabels;
}
export function pushMRangeWithLabelsArguments(
args: RedisCommandArguments,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filter: Filter,
options?: MRangeWithLabelsOptions
): RedisCommandArguments {
pushRangeArguments(args, fromTimestamp, toTimestamp, options);
pushWithLabelsArgument(args, options?.SELECTED_LABELS);
pushFilterArgument(args, filter);
pushMRangeGroupByArguments(args, options?.GROUPBY);
return args;
}
export function transformRangeReply(reply: Array<SampleRawReply>): Array<SampleReply> {
return reply.map(transformSampleReply);
}
type MRangeRawReply = Array<[
key: string,
labels: RawLabels,
samples: Array<SampleRawReply>
]>;
interface MRangeReplyItem {
key: string;
samples: Array<SampleReply>;
}
export function transformMRangeReply(reply: MRangeRawReply): Array<MRangeReplyItem> {
const args = [];
for (const [key, _, sample] of reply) {
args.push({
key,
samples: sample.map(transformSampleReply)
});
}
return args;
}
export interface MRangeWithLabelsReplyItem extends MRangeReplyItem {
labels: Labels;
}
export function transformMRangeWithLabelsReply(reply: MRangeRawReply): Array<MRangeWithLabelsReplyItem> {
const args = [];
for (const [key, labels, samples] of reply) {
args.push({
key,
labels: transformLablesReply(labels),
samples: samples.map(transformSampleReply)
});
}
return args;
}