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

time-series

This commit is contained in:
Leibale
2023-07-11 13:11:13 -04:00
parent c515bc9571
commit 54c3a66c72
32 changed files with 879 additions and 933 deletions

View File

@@ -1,467 +1,367 @@
import * as ADD from './ADD';
import * as ALTER from './ALTER';
import * as CREATE from './CREATE';
import * as CREATERULE from './CREATERULE';
import * as DECRBY from './DECRBY';
import * as DEL from './DEL';
import * as DELETERULE from './DELETERULE';
import * as GET from './GET';
import * as INCRBY from './INCRBY';
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 '@redis/client/dist/lib/commands';
import { pushVariadicArguments } from '@redis/client/dist/lib/commands/generic-transformers';
import type { RedisArgument, RedisCommands } from '@redis/client/dist/lib/RESP/types';
import ADD from './ADD';
import ALTER from './ALTER';
import CREATE from './CREATE';
import CREATERULE from './CREATERULE';
import DECRBY from './DECRBY';
import DEL from './DEL';
import DELETERULE from './DELETERULE';
import GET from './GET';
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';
export default {
ADD,
add: ADD,
ALTER,
alter: ALTER,
CREATE,
create: CREATE,
CREATERULE,
createRule: CREATERULE,
DECRBY,
decrBy: DECRBY,
DEL,
del: DEL,
DELETERULE,
deleteRule: DELETERULE,
GET,
get: GET,
INCRBY,
incrBy: INCRBY,
INFO_DEBUG,
infoDebug: INFO_DEBUG,
INFO,
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
};
ADD,
add: ADD,
ALTER,
alter: ALTER,
CREATE,
create: CREATE,
CREATERULE,
createRule: CREATERULE,
DECRBY,
decrBy: DECRBY,
DEL,
del: DEL,
DELETERULE,
deleteRule: DELETERULE,
GET,
get: GET,
INCRBY,
incrBy: INCRBY,
// INFO_DEBUG,
// infoDebug: INFO_DEBUG,
// INFO,
// 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
} as const satisfies RedisCommands;
export enum TimeSeriesAggregationType {
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 function pushRetentionArgument(args: Array<RedisArgument>, retention?: number) {
if (retention !== undefined) {
args.push('RETENTION', retention.toString());
}
}
export enum TimeSeriesDuplicatePolicies {
BLOCK = 'BLOCK',
FIRST = 'FIRST',
LAST = 'LAST',
MIN = 'MIN',
MAX = 'MAX',
SUM = 'SUM'
export const TIME_SERIES_ENCODING = {
COMPRESSED: 'COMPRESSED',
UNCOMPRESSED: 'UNCOMPRESSED'
} as const;
export type TimeSeriesEncoding = typeof TIME_SERIES_ENCODING[keyof typeof TIME_SERIES_ENCODING];
export function pushEncodingArgument(args: Array<RedisArgument>, encoding?: TimeSeriesEncoding) {
if (encoding !== undefined) {
args.push('ENCODING', encoding);
}
}
export enum TimeSeriesReducers {
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 function pushChunkSizeArgument(args: Array<RedisArgument>, chunkSize?: number) {
if (chunkSize !== undefined) {
args.push('CHUNK_SIZE', chunkSize.toString());
}
}
export const TIME_SERIES_DUPLICATE_POLICIES = {
BLOCK: 'BLOCK',
FIRST: 'FIRST',
LAST: 'LAST',
MIN: 'MIN',
MAX: 'MAX',
SUM: 'SUM'
} as const;
export type TimeSeriesDuplicatePolicies = typeof TIME_SERIES_DUPLICATE_POLICIES[keyof typeof TIME_SERIES_DUPLICATE_POLICIES];
export function pushDuplicatePolicy(args: Array<RedisArgument>, duplicatePolicy?: TimeSeriesDuplicatePolicies) {
if (duplicatePolicy !== undefined) {
args.push('DUPLICATE_POLICY', duplicatePolicy);
}
}
export type Timestamp = number | Date | string;
export function transformTimestampArgument(timestamp: Timestamp): string {
if (typeof timestamp === 'string') return timestamp;
if (typeof timestamp === 'string') return timestamp;
return (
typeof timestamp === 'number' ?
timestamp :
timestamp.getTime()
).toString();
return (
typeof timestamp === 'number' ?
timestamp :
timestamp.getTime()
).toString();
}
export function pushRetentionArgument(args: RedisCommandArguments, retention?: number): RedisCommandArguments {
if (retention !== undefined) {
args.push(
'RETENTION',
retention.toString()
);
}
return args;
}
export enum TimeSeriesEncoding {
COMPRESSED = 'COMPRESSED',
UNCOMPRESSED = 'UNCOMPRESSED'
}
export function pushEncodingArgument(args: RedisCommandArguments, encoding?: TimeSeriesEncoding): RedisCommandArguments {
if (encoding !== undefined) {
args.push(
'ENCODING',
encoding
);
}
return args;
}
export function pushChunkSizeArgument(args: RedisCommandArguments, chunkSize?: number): RedisCommandArguments {
if (chunkSize !== undefined) {
args.push(
'CHUNK_SIZE',
chunkSize.toString()
);
}
return args;
}
export function pushDuplicatePolicy(args: RedisCommandArguments, duplicatePolicy?: TimeSeriesDuplicatePolicies): RedisCommandArguments {
if (duplicatePolicy !== undefined) {
args.push(
'DUPLICATE_POLICY',
duplicatePolicy
);
}
return args;
}
export type RawLabels = Array<[label: string, value: string]>;
export type Labels = {
[label: string]: string;
[label: string]: string;
};
export function transformLablesReply(reply: RawLabels): Labels {
const labels: Labels = {};
export function pushLabelsArgument(args: Array<RedisArgument>, labels?: Labels) {
if (labels) {
args.push('LABELS');
for (const [key, value] of reply) {
labels[key] = value;
for (const [label, value] of Object.entries(labels)) {
args.push(label, value);
}
}
return labels
return args;
}
export function pushLabelsArgument(args: RedisCommandArguments, labels?: Labels): RedisCommandArguments {
if (labels) {
args.push('LABELS');
// export type RawLabelsReply = ArrayReply<TuplesReply<[BlobStringReply, BlobStringReply]>>;
for (const [label, value] of Object.entries(labels)) {
args.push(label, value);
}
}
// export function transformLablesReply(reply: RawLabelsReply) {
// const labels: Record<string, BlobStringReply> = {};
return args;
}
// for (const [key, value] of reply) {
// labels[key.toString()] = value;
// }
export interface IncrDecrOptions {
TIMESTAMP?: Timestamp;
RETENTION?: number;
UNCOMPRESSED?: boolean;
CHUNK_SIZE?: number;
LABELS?: Labels;
}
// return labels
// }
export function transformIncrDecrArguments(
command: 'TS.INCRBY' | 'TS.DECRBY',
key: string,
value: number,
options?: IncrDecrOptions
): RedisCommandArguments {
const args = [
command,
key,
value.toString()
];
if (options?.TIMESTAMP !== undefined && options?.TIMESTAMP !== null) {
args.push('TIMESTAMP', transformTimestampArgument(options.TIMESTAMP));
}
// export type SampleRawReply = [timestamp: number, value: string];
pushRetentionArgument(args, options?.RETENTION);
// export interface SampleReply {
// timestamp: number;
// value: number;
// }
if (options?.UNCOMPRESSED) {
args.push('UNCOMPRESSED');
}
// export function transformSampleReply(reply: SampleRawReply): SampleReply {
// return {
// timestamp: reply[0],
// value: Number(reply[1])
// };
// }
pushChunkSizeArgument(args, options?.CHUNK_SIZE);
// export enum TimeSeriesBucketTimestamp {
// LOW = '-',
// HIGH = '+',
// MID = '~'
// }
pushLabelsArgument(args, options?.LABELS);
// export interface RangeOptions {
// LATEST?: boolean;
// FILTER_BY_TS?: Array<Timestamp>;
// FILTER_BY_VALUE?: {
// min: number;
// max: number;
// };
// COUNT?: number;
// ALIGN?: Timestamp;
// AGGREGATION?: {
// type: TimeSeriesAggregationType;
// timeBucket: Timestamp;
// BUCKETTIMESTAMP?: TimeSeriesBucketTimestamp;
// EMPTY?: boolean;
// };
// }
return args;
}
// export function pushRangeArguments(
// args: RedisCommandArguments,
// fromTimestamp: Timestamp,
// toTimestamp: Timestamp,
// options?: RangeOptions
// ): RedisCommandArguments {
// args.push(
// transformTimestampArgument(fromTimestamp),
// transformTimestampArgument(toTimestamp)
// );
export type SampleRawReply = [timestamp: number, value: string];
// pushLatestArgument(args, options?.LATEST);
export interface SampleReply {
timestamp: number;
value: number;
}
// if (options?.FILTER_BY_TS) {
// args.push('FILTER_BY_TS');
// for (const ts of options.FILTER_BY_TS) {
// args.push(transformTimestampArgument(ts));
// }
// }
export function transformSampleReply(reply: SampleRawReply): SampleReply {
return {
timestamp: reply[0],
value: Number(reply[1])
};
}
// if (options?.FILTER_BY_VALUE) {
// args.push(
// 'FILTER_BY_VALUE',
// options.FILTER_BY_VALUE.min.toString(),
// options.FILTER_BY_VALUE.max.toString()
// );
// }
export enum TimeSeriesBucketTimestamp {
LOW = '-',
HIGH = '+',
MID = '~'
}
// if (options?.COUNT) {
// args.push(
// 'COUNT',
// options.COUNT.toString()
// );
// }
export interface RangeOptions {
LATEST?: boolean;
FILTER_BY_TS?: Array<Timestamp>;
FILTER_BY_VALUE?: {
min: number;
max: number;
};
COUNT?: number;
ALIGN?: Timestamp;
AGGREGATION?: {
type: TimeSeriesAggregationType;
timeBucket: Timestamp;
BUCKETTIMESTAMP?: TimeSeriesBucketTimestamp;
EMPTY?: boolean;
};
}
// if (options?.ALIGN) {
// args.push(
// 'ALIGN',
// transformTimestampArgument(options.ALIGN)
// );
// }
export function pushRangeArguments(
args: RedisCommandArguments,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
options?: RangeOptions
): RedisCommandArguments {
args.push(
transformTimestampArgument(fromTimestamp),
transformTimestampArgument(toTimestamp)
);
// if (options?.AGGREGATION) {
// args.push(
// 'AGGREGATION',
// options.AGGREGATION.type,
// transformTimestampArgument(options.AGGREGATION.timeBucket)
// );
pushLatestArgument(args, options?.LATEST);
// if (options.AGGREGATION.BUCKETTIMESTAMP) {
// args.push(
// 'BUCKETTIMESTAMP',
// options.AGGREGATION.BUCKETTIMESTAMP
// );
// }
if (options?.FILTER_BY_TS) {
args.push('FILTER_BY_TS');
for (const ts of options.FILTER_BY_TS) {
args.push(transformTimestampArgument(ts));
}
}
// if (options.AGGREGATION.EMPTY) {
// args.push('EMPTY');
// }
// }
if (options?.FILTER_BY_VALUE) {
args.push(
'FILTER_BY_VALUE',
options.FILTER_BY_VALUE.min.toString(),
options.FILTER_BY_VALUE.max.toString()
);
}
// return args;
// }
if (options?.COUNT) {
args.push(
'COUNT',
options.COUNT.toString()
);
}
// interface MRangeGroupBy {
// label: string;
// reducer: TimeSeriesReducers;
// }
if (options?.ALIGN) {
args.push(
'ALIGN',
transformTimestampArgument(options.ALIGN)
);
}
// export function pushMRangeGroupByArguments(args: RedisCommandArguments, groupBy?: MRangeGroupBy): RedisCommandArguments {
// if (groupBy) {
// args.push(
// 'GROUPBY',
// groupBy.label,
// 'REDUCE',
// groupBy.reducer
// );
// }
if (options?.AGGREGATION) {
args.push(
'AGGREGATION',
options.AGGREGATION.type,
transformTimestampArgument(options.AGGREGATION.timeBucket)
);
// return args;
// }
if (options.AGGREGATION.BUCKETTIMESTAMP) {
args.push(
'BUCKETTIMESTAMP',
options.AGGREGATION.BUCKETTIMESTAMP
);
}
// export type Filter = string | Array<string>;
if (options.AGGREGATION.EMPTY) {
args.push('EMPTY');
}
}
// export function pushFilterArgument(args: RedisCommandArguments, filter: string | Array<string>): RedisCommandArguments {
// args.push('FILTER');
// return pushVariadicArguments(args, filter);
// }
return args;
}
// export interface MRangeOptions extends RangeOptions {
// GROUPBY?: MRangeGroupBy;
// }
interface MRangeGroupBy {
label: string;
reducer: TimeSeriesReducers;
}
// export function pushMRangeArguments(
// args: RedisCommandArguments,
// fromTimestamp: Timestamp,
// toTimestamp: Timestamp,
// filter: Filter,
// options?: MRangeOptions
// ): RedisCommandArguments {
// args = pushRangeArguments(args, fromTimestamp, toTimestamp, options);
// args = pushFilterArgument(args, filter);
// return pushMRangeGroupByArguments(args, options?.GROUPBY);
// }
export function pushMRangeGroupByArguments(args: RedisCommandArguments, groupBy?: MRangeGroupBy): RedisCommandArguments {
if (groupBy) {
args.push(
'GROUPBY',
groupBy.label,
'REDUCE',
groupBy.reducer
);
}
// export type SelectedLabels = string | Array<string>;
return args;
}
// export function pushWithLabelsArgument(args: RedisCommandArguments, selectedLabels?: SelectedLabels): RedisCommandArguments {
// if (!selectedLabels) {
// args.push('WITHLABELS');
// } else {
// args.push('SELECTED_LABELS');
// args = pushVariadicArguments(args, selectedLabels);
// }
export type Filter = string | Array<string>;
// return args;
// }
export function pushFilterArgument(args: RedisCommandArguments, filter: string | Array<string>): RedisCommandArguments {
args.push('FILTER');
return pushVariadicArguments(args, filter);
}
// export interface MRangeWithLabelsOptions extends MRangeOptions {
// SELECTED_LABELS?: SelectedLabels;
// }
export interface MRangeOptions extends RangeOptions {
GROUPBY?: MRangeGroupBy;
}
// export function pushMRangeWithLabelsArguments(
// args: RedisCommandArguments,
// fromTimestamp: Timestamp,
// toTimestamp: Timestamp,
// filter: Filter,
// options?: MRangeWithLabelsOptions
// ): RedisCommandArguments {
// args = pushRangeArguments(args, fromTimestamp, toTimestamp, options);
// args = pushWithLabelsArgument(args, options?.SELECTED_LABELS);
// args = pushFilterArgument(args, filter);
// return pushMRangeGroupByArguments(args, options?.GROUPBY);
// }
export function pushMRangeArguments(
args: RedisCommandArguments,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filter: Filter,
options?: MRangeOptions
): RedisCommandArguments {
args = pushRangeArguments(args, fromTimestamp, toTimestamp, options);
args = pushFilterArgument(args, filter);
return pushMRangeGroupByArguments(args, options?.GROUPBY);
}
// export function transformRangeReply(reply: Array<SampleRawReply>): Array<SampleReply> {
// return reply.map(transformSampleReply);
// }
export type SelectedLabels = string | Array<string>;
// type MRangeRawReply = Array<[
// key: string,
// labels: RawLabels,
// samples: Array<SampleRawReply>
// ]>;
export function pushWithLabelsArgument(args: RedisCommandArguments, selectedLabels?: SelectedLabels): RedisCommandArguments {
if (!selectedLabels) {
args.push('WITHLABELS');
} else {
args.push('SELECTED_LABELS');
args = pushVariadicArguments(args, selectedLabels);
}
// interface MRangeReplyItem {
// key: string;
// samples: Array<SampleReply>;
// }
return args;
}
// export function transformMRangeReply(reply: MRangeRawReply): Array<MRangeReplyItem> {
// const args = [];
export interface MRangeWithLabelsOptions extends MRangeOptions {
SELECTED_LABELS?: SelectedLabels;
}
// for (const [key, _, sample] of reply) {
// args.push({
// key,
// samples: sample.map(transformSampleReply)
// });
// }
export function pushMRangeWithLabelsArguments(
args: RedisCommandArguments,
fromTimestamp: Timestamp,
toTimestamp: Timestamp,
filter: Filter,
options?: MRangeWithLabelsOptions
): RedisCommandArguments {
args = pushRangeArguments(args, fromTimestamp, toTimestamp, options);
args = pushWithLabelsArgument(args, options?.SELECTED_LABELS);
args = pushFilterArgument(args, filter);
return pushMRangeGroupByArguments(args, options?.GROUPBY);
}
// return args;
// }
// export interface MRangeWithLabelsReplyItem extends MRangeReplyItem {
// labels: Labels;
// }
export function transformRangeReply(reply: Array<SampleRawReply>): Array<SampleReply> {
return reply.map(transformSampleReply);
}
// export function transformMRangeWithLabelsReply(reply: MRangeRawReply): Array<MRangeWithLabelsReplyItem> {
// const args = [];
type MRangeRawReply = Array<[
key: string,
labels: RawLabels,
samples: Array<SampleRawReply>
]>;
// for (const [key, labels, samples] of reply) {
// args.push({
// key,
// labels: transformLablesReply(labels),
// samples: samples.map(transformSampleReply)
// });
// }
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;
}
export function pushLatestArgument(args: RedisCommandArguments, latest?: boolean): RedisCommandArguments {
if (latest) {
args.push('LATEST');
}
return args;
}
// return args;
// }