You've already forked node-redis
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:
81
packages/time-series/lib/commands/DECRBY.spec.ts
Normal file
81
packages/time-series/lib/commands/DECRBY.spec.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './DECRBY';
|
||||||
|
|
||||||
|
describe('DECRBY', () => {
|
||||||
|
describe('transformArguments', () => {
|
||||||
|
it('without options', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1),
|
||||||
|
['TS.DECRBY', 'key', '1']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with TIMESTAMP', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
TIMESTAMP: '*'
|
||||||
|
}),
|
||||||
|
['TS.DECRBY', 'key', '1', 'TIMESTAMP', '*']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with RETENTION', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
RETENTION: 1
|
||||||
|
}),
|
||||||
|
['TS.DECRBY', 'key', '1', 'RETENTION', '1']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with UNCOMPRESSED', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
UNCOMPRESSED: true
|
||||||
|
}),
|
||||||
|
['TS.DECRBY', 'key', '1', 'UNCOMPRESSED']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with CHUNK_SIZE', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
CHUNK_SIZE: 100
|
||||||
|
}),
|
||||||
|
['TS.DECRBY', 'key', '1', 'CHUNK_SIZE', '100']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with LABELS', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
LABELS: { label: 'value' }
|
||||||
|
}),
|
||||||
|
['TS.DECRBY', 'key', '1', 'LABELS', 'label', 'value']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with TIMESTAMP, RETENTION, UNCOMPRESSED, CHUNK_SIZE and LABELS', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
TIMESTAMP: '*',
|
||||||
|
RETENTION: 1,
|
||||||
|
UNCOMPRESSED: true,
|
||||||
|
CHUNK_SIZE: 2,
|
||||||
|
LABELS: { label: 'value' }
|
||||||
|
}),
|
||||||
|
['TS.DECRBY', 'key', '1', 'TIMESTAMP', '*', 'RETENTION', '1', 'UNCOMPRESSED', 'CHUNK_SIZE', '2', 'LABELS', 'label', 'value']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
testUtils.testWithClient('client.ts.decrBy', async client => {
|
||||||
|
assert.equal(
|
||||||
|
await client.ts.decrBy('key', 1, {
|
||||||
|
TIMESTAMP: 0
|
||||||
|
}),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
21
packages/time-series/lib/commands/DEL.spec.ts
Normal file
21
packages/time-series/lib/commands/DEL.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './DEL';
|
||||||
|
|
||||||
|
describe('DEL', () => {
|
||||||
|
it('transformArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', '-', '+'),
|
||||||
|
['TS.DEL', 'key', '-', '+']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUtils.testWithClient('client.ts.del', async client => {
|
||||||
|
await client.ts.create('key');
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
await client.ts.del('key', '-', '+'),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
26
packages/time-series/lib/commands/DELETERULE.spec.ts
Normal file
26
packages/time-series/lib/commands/DELETERULE.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import { TimeSeriesAggregationType } from '.';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './DELETERULE';
|
||||||
|
|
||||||
|
describe('DELETERULE', () => {
|
||||||
|
it('transformArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('source', 'destination'),
|
||||||
|
['TS.DELETERULE', 'source', 'destination']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUtils.testWithClient('client.ts.deleteRule', async client => {
|
||||||
|
await Promise.all([
|
||||||
|
client.ts.create('source'),
|
||||||
|
client.ts.create('destination'),
|
||||||
|
client.ts.createRule('source', 'destination', TimeSeriesAggregationType.AVARAGE, 1)
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
await client.ts.deleteRule('source', 'destination'),
|
||||||
|
'OK'
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
@@ -1,4 +1,6 @@
|
|||||||
export function transformArguments(sourceKey: string,destinationKey: string,): Array<string> {
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
|
export function transformArguments(sourceKey: string, destinationKey: string): Array<string> {
|
||||||
return [
|
return [
|
||||||
'TS.DELETERULE',
|
'TS.DELETERULE',
|
||||||
sourceKey,
|
sourceKey,
|
||||||
|
35
packages/time-series/lib/commands/GET.spec.ts
Normal file
35
packages/time-series/lib/commands/GET.spec.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './GET';
|
||||||
|
|
||||||
|
describe('GET', () => {
|
||||||
|
it('transformArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key'),
|
||||||
|
['TS.GET', 'key']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('client.ts.get', () => {
|
||||||
|
testUtils.testWithClient('null', async client => {
|
||||||
|
await client.ts.create('key');
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
await client.ts.get('key'),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
|
||||||
|
testUtils.testWithClient('with samples', async client => {
|
||||||
|
await client.ts.add('key', 0, 1);
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.get('key'),
|
||||||
|
{
|
||||||
|
timestamp: 0,
|
||||||
|
value: 1
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
||||||
|
});
|
91
packages/time-series/lib/commands/INCRBY.spec.ts
Normal file
91
packages/time-series/lib/commands/INCRBY.spec.ts
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './INCRBY';
|
||||||
|
|
||||||
|
describe('INCRBY', () => {
|
||||||
|
describe('transformArguments', () => {
|
||||||
|
it('without options', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1),
|
||||||
|
['TS.INCRBY', 'key', '1']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with TIMESTAMP', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
TIMESTAMP: '*'
|
||||||
|
}),
|
||||||
|
['TS.INCRBY', 'key', '1', 'TIMESTAMP', '*']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with RETENTION', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
RETENTION: 1
|
||||||
|
}),
|
||||||
|
['TS.INCRBY', 'key', '1', 'RETENTION', '1']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with UNCOMPRESSED', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
UNCOMPRESSED: true
|
||||||
|
}),
|
||||||
|
['TS.INCRBY', 'key', '1', 'UNCOMPRESSED']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('without UNCOMPRESSED', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
UNCOMPRESSED: false
|
||||||
|
}),
|
||||||
|
['TS.INCRBY', 'key', '1']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with CHUNK_SIZE', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
CHUNK_SIZE: 1
|
||||||
|
}),
|
||||||
|
['TS.INCRBY', 'key', '1', 'CHUNK_SIZE', '1']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with LABELS', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
LABELS: { label: 'value' }
|
||||||
|
}),
|
||||||
|
['TS.INCRBY', 'key', '1', 'LABELS', 'label', 'value']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with TIMESTAMP, RETENTION, UNCOMPRESSED, CHUNK_SIZE and LABELS', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', 1, {
|
||||||
|
TIMESTAMP: '*',
|
||||||
|
RETENTION: 1,
|
||||||
|
UNCOMPRESSED: true,
|
||||||
|
CHUNK_SIZE: 1,
|
||||||
|
LABELS: { label: 'value' }
|
||||||
|
}),
|
||||||
|
['TS.INCRBY', 'key', '1', 'TIMESTAMP', '*', 'RETENTION', '1', 'UNCOMPRESSED',
|
||||||
|
'CHUNK_SIZE', '1', 'LABELS', 'label', 'value']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
testUtils.testWithClient('client.ts.incrBy', async client => {
|
||||||
|
assert.equal(
|
||||||
|
await client.ts.incrBy('key', 1, {
|
||||||
|
TIMESTAMP: 0
|
||||||
|
}),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
50
packages/time-series/lib/commands/INFO.spec.ts
Normal file
50
packages/time-series/lib/commands/INFO.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import { TimeSeriesAggregationType, TimeSeriesDuplicatePolicies } from '.';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './INFO';
|
||||||
|
|
||||||
|
describe('INFO', () => {
|
||||||
|
it('transformArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key'),
|
||||||
|
['TS.INFO', 'key']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUtils.testWithClient('client.ts.info', async client => {
|
||||||
|
await Promise.all([
|
||||||
|
client.ts.create('key', {
|
||||||
|
LABELS: { id: "2" },
|
||||||
|
DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.LAST
|
||||||
|
}),
|
||||||
|
client.ts.create('key2'),
|
||||||
|
client.ts.createRule('key', 'key2', TimeSeriesAggregationType.COUNT, 5),
|
||||||
|
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
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
57
packages/time-series/lib/commands/INFO_DEBUG.spec.ts
Normal file
57
packages/time-series/lib/commands/INFO_DEBUG.spec.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import { TimeSeriesAggregationType, TimeSeriesDuplicatePolicies } from '.';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './INFO_DEBUG';
|
||||||
|
|
||||||
|
describe('INFO_DEBUG', () => {
|
||||||
|
it('transformArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key'),
|
||||||
|
['TS.INFO', 'key', 'DEBUG']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUtils.testWithClient('client.ts.get', async client => {
|
||||||
|
await Promise.all([
|
||||||
|
client.ts.create('key', {
|
||||||
|
LABELS: { id: "2" },
|
||||||
|
DUPLICATE_POLICY: TimeSeriesDuplicatePolicies.LAST
|
||||||
|
}),
|
||||||
|
client.ts.create('key2'),
|
||||||
|
client.ts.createRule('key', 'key2', TimeSeriesAggregationType.COUNT, 5),
|
||||||
|
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
|
||||||
|
}],
|
||||||
|
chunks: [{
|
||||||
|
startTimestamp: 1,
|
||||||
|
endTimestamp: 1,
|
||||||
|
samples: 1,
|
||||||
|
size: 4096,
|
||||||
|
bytesPerSample: '4096'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
39
packages/time-series/lib/commands/MADD.spec.ts
Normal file
39
packages/time-series/lib/commands/MADD.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './MADD';
|
||||||
|
|
||||||
|
describe('MADD', () => {
|
||||||
|
it('transformArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments([{
|
||||||
|
key: '1',
|
||||||
|
timestamp: 0,
|
||||||
|
value: 0
|
||||||
|
}, {
|
||||||
|
key: '2',
|
||||||
|
timestamp: 1,
|
||||||
|
value: 1
|
||||||
|
}]),
|
||||||
|
['TS.MADD', '1', '0', '0', '2', '1', '1']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Should we check empty array?
|
||||||
|
|
||||||
|
testUtils.testWithClient('client.ts.mAdd', async client => {
|
||||||
|
await client.ts.create('key');
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.mAdd([{
|
||||||
|
key: 'key',
|
||||||
|
timestamp: 0,
|
||||||
|
value: 0
|
||||||
|
}, {
|
||||||
|
key: 'key',
|
||||||
|
timestamp: 1,
|
||||||
|
value: 1
|
||||||
|
}]),
|
||||||
|
[0, 1]
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
@@ -1,5 +1,7 @@
|
|||||||
import { Timestamp, transformTimestampArgument } from '.';
|
import { Timestamp, transformTimestampArgument } from '.';
|
||||||
|
|
||||||
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
interface MAddSample {
|
interface MAddSample {
|
||||||
key: string;
|
key: string;
|
||||||
timestamp: Timestamp;
|
timestamp: Timestamp;
|
||||||
|
29
packages/time-series/lib/commands/MGET.spec.ts
Normal file
29
packages/time-series/lib/commands/MGET.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './MGET';
|
||||||
|
|
||||||
|
describe('MGET', () => {
|
||||||
|
it('transformArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
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' }
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.mGet('label=value'),
|
||||||
|
[{
|
||||||
|
key: 'key',
|
||||||
|
sample: {
|
||||||
|
timestamp: 0,
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
@@ -1,31 +1,26 @@
|
|||||||
import { pushVerdictArgument, pushVerdictArguments } from '@node-redis/client/lib/commands/generic-transformers';
|
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
||||||
|
import { Filter, pushFilterArgument, RawLabels, SampleRawReply, SampleReply, transformSampleReply } from '.';
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
interface WithLabels {
|
export function transformArguments(filter: Filter): RedisCommandArguments {
|
||||||
WITHLABELS: true;
|
return pushFilterArgument(['TS.MGET'], filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SelectedLabels {
|
export type MGetRawReply = Array<[
|
||||||
SELECTED_LABELS: string | Array<string>;
|
key: string,
|
||||||
|
labels: RawLabels,
|
||||||
|
sample: SampleRawReply
|
||||||
|
]>;
|
||||||
|
|
||||||
|
export interface MGetReply {
|
||||||
|
key: string,
|
||||||
|
sample: SampleReply
|
||||||
}
|
}
|
||||||
|
|
||||||
type MGetOptions = WithLabels & SelectedLabels;
|
export function transformReply(reply: MGetRawReply): Array<MGetReply> {
|
||||||
|
return reply.map(([key, _, sample]) => ({
|
||||||
export function transformArguments(filter: string, options?: MGetOptions): Array<string> {
|
key,
|
||||||
const args = ['TS.MGET'];
|
sample: transformSampleReply(sample)
|
||||||
|
}));
|
||||||
if (options?.WITHLABELS) {
|
|
||||||
args.push('WITHLABELS');
|
|
||||||
} else if (options?.SELECTED_LABELS) {
|
|
||||||
pushVerdictArguments(args, options.SELECTED_LABELS);
|
|
||||||
}
|
|
||||||
|
|
||||||
args.push('FILTER', filter);
|
|
||||||
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformReply() {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
39
packages/time-series/lib/commands/MGET_WITHLABELS.spec.ts
Normal file
39
packages/time-series/lib/commands/MGET_WITHLABELS.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './MGET_WITHLABELS';
|
||||||
|
|
||||||
|
describe('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']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
testUtils.testWithClient('client.ts.mGetWithLabels', async client => {
|
||||||
|
await client.ts.add('key', 0, 0, {
|
||||||
|
LABELS: { label: 'value' }
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.mGetWithLabels('label=value'),
|
||||||
|
[{
|
||||||
|
key: 'key',
|
||||||
|
labels: { label: 'value'},
|
||||||
|
sample: {
|
||||||
|
timestamp: 0,
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
41
packages/time-series/lib/commands/MGET_WITHLABELS.ts
Normal file
41
packages/time-series/lib/commands/MGET_WITHLABELS.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import {
|
||||||
|
SelectedLabels,
|
||||||
|
pushWithLabelsArgument,
|
||||||
|
Labels,
|
||||||
|
transformLablesReply,
|
||||||
|
transformSampleReply,
|
||||||
|
Filter,
|
||||||
|
pushFilterArgument
|
||||||
|
} from '.';
|
||||||
|
import { MGetRawReply, MGetReply } from './MGET';
|
||||||
|
|
||||||
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
|
interface MGetWithLabelsOptions {
|
||||||
|
SELECTED_LABELS?: SelectedLabels;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformArguments(
|
||||||
|
filter: Filter,
|
||||||
|
options?: MGetWithLabelsOptions
|
||||||
|
): Array<string> {
|
||||||
|
const args = ['TS.MGET'];
|
||||||
|
|
||||||
|
pushWithLabelsArgument(args, options?.SELECTED_LABELS);
|
||||||
|
|
||||||
|
pushFilterArgument(args, filter);
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}));
|
||||||
|
}
|
50
packages/time-series/lib/commands/MRANGE.spec.ts
Normal file
50
packages/time-series/lib/commands/MRANGE.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './MRANGE';
|
||||||
|
import { TimeSeriesAggregationType, TimeSeriesReducers } from '.';
|
||||||
|
|
||||||
|
describe('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.AVARAGE,
|
||||||
|
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'}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.mRange('-', '+', 'label=value', {
|
||||||
|
COUNT: 1
|
||||||
|
}),
|
||||||
|
[{
|
||||||
|
key: 'key',
|
||||||
|
samples: [{
|
||||||
|
timestamp: 0,
|
||||||
|
value: 0
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
21
packages/time-series/lib/commands/MRANGE.ts
Normal file
21
packages/time-series/lib/commands/MRANGE.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
||||||
|
import { MRangeOptions, Timestamp, pushMRangeArguments, Filter } from '.';
|
||||||
|
|
||||||
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
|
export function transformArguments(
|
||||||
|
fromTimestamp: Timestamp,
|
||||||
|
toTimestamp: Timestamp,
|
||||||
|
filters: Filter,
|
||||||
|
options?: MRangeOptions
|
||||||
|
): RedisCommandArguments {
|
||||||
|
return pushMRangeArguments(
|
||||||
|
['TS.MRANGE'],
|
||||||
|
fromTimestamp,
|
||||||
|
toTimestamp,
|
||||||
|
filters,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { transformMRangeReply as transformReply } from '.';
|
52
packages/time-series/lib/commands/MRANGE_WITHLABELS.spec.ts
Normal file
52
packages/time-series/lib/commands/MRANGE_WITHLABELS.spec.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './MRANGE_WITHLABELS';
|
||||||
|
import { TimeSeriesAggregationType, TimeSeriesReducers } from '.';
|
||||||
|
|
||||||
|
describe('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.AVARAGE,
|
||||||
|
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']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
21
packages/time-series/lib/commands/MRANGE_WITHLABELS.ts
Normal file
21
packages/time-series/lib/commands/MRANGE_WITHLABELS.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
||||||
|
import { Timestamp, MRangeWithLabelsOptions, pushMRangeWithLabelsArguments } from '.';
|
||||||
|
|
||||||
|
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 { transformMRangeWithLabelsReply as transformReply } from '.';
|
50
packages/time-series/lib/commands/MREVRANGE.spec.ts
Normal file
50
packages/time-series/lib/commands/MREVRANGE.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './MREVRANGE';
|
||||||
|
import { TimeSeriesAggregationType, TimeSeriesReducers } from '.';
|
||||||
|
|
||||||
|
describe('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.AVARAGE,
|
||||||
|
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'}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.mRevRange('-', '+', 'label=value', {
|
||||||
|
COUNT: 1
|
||||||
|
}),
|
||||||
|
[{
|
||||||
|
key: 'key',
|
||||||
|
samples: [{
|
||||||
|
timestamp: 0,
|
||||||
|
value: 0
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
21
packages/time-series/lib/commands/MREVRANGE.ts
Normal file
21
packages/time-series/lib/commands/MREVRANGE.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
||||||
|
import { MRangeOptions, Timestamp, pushMRangeArguments, Filter } from '.';
|
||||||
|
|
||||||
|
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 '.';
|
@@ -0,0 +1,52 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './MREVRANGE_WITHLABELS';
|
||||||
|
import { TimeSeriesAggregationType, TimeSeriesReducers } from '.';
|
||||||
|
|
||||||
|
describe('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.AVARAGE,
|
||||||
|
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'}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.mRevRangeWithLabels('-', '+', 'label=value', {
|
||||||
|
COUNT: 1
|
||||||
|
}),
|
||||||
|
[{
|
||||||
|
key: 'key',
|
||||||
|
labels: { label: 'value' },
|
||||||
|
samples: [{
|
||||||
|
timestamp: 0,
|
||||||
|
value: 0
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
21
packages/time-series/lib/commands/MREVRANGE_WITHLABELS.ts
Normal file
21
packages/time-series/lib/commands/MREVRANGE_WITHLABELS.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
||||||
|
import { Timestamp, MRangeWithLabelsOptions, pushMRangeWithLabelsArguments, Filter } from '.';
|
||||||
|
|
||||||
|
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 '.';
|
27
packages/time-series/lib/commands/QUERYINDEX.spec.ts
Normal file
27
packages/time-series/lib/commands/QUERYINDEX.spec.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './QUERYINDEX';
|
||||||
|
|
||||||
|
describe('QUERYINDEX', () => {
|
||||||
|
it('transformArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('*'),
|
||||||
|
['TS.QUERYINDEX', '*']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUtils.testWithClient('client.ts.queryIndex', async client => {
|
||||||
|
await Promise.all([
|
||||||
|
client.ts.create('key', {
|
||||||
|
LABELS: {
|
||||||
|
label: 'value'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.queryIndex('label=value'),
|
||||||
|
['key']
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
38
packages/time-series/lib/commands/RANGE.spec.ts
Normal file
38
packages/time-series/lib/commands/RANGE.spec.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './RANGE';
|
||||||
|
import { TimeSeriesAggregationType } from '.';
|
||||||
|
|
||||||
|
describe('RANGE', () => {
|
||||||
|
it('transformArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformArguments('key', '-', '+', {
|
||||||
|
FILTER_BY_TS: [0],
|
||||||
|
FILTER_BY_VALUE: {
|
||||||
|
min: 1,
|
||||||
|
max: 2
|
||||||
|
},
|
||||||
|
COUNT: 1,
|
||||||
|
ALIGN: '-',
|
||||||
|
AGGREGATION: {
|
||||||
|
type: TimeSeriesAggregationType.AVARAGE,
|
||||||
|
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);
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.range('key', '-', '+'),
|
||||||
|
[{
|
||||||
|
timestamp: 1,
|
||||||
|
value: 2
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
@@ -1,21 +1,24 @@
|
|||||||
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
||||||
import { RangeOptions, Timestamp, pushRangeArguments } from '.';
|
import { RangeOptions, Timestamp, pushRangeArguments, SampleRawReply, SampleReply, transformRangeReply } from '.';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(
|
export function transformArguments(
|
||||||
|
key: string,
|
||||||
fromTimestamp: Timestamp,
|
fromTimestamp: Timestamp,
|
||||||
toTimestamp: Timestamp,
|
toTimestamp: Timestamp,
|
||||||
options?: RangeOptions
|
options?: RangeOptions
|
||||||
): RedisCommandArguments {
|
): RedisCommandArguments {
|
||||||
return pushRangeArguments(
|
return pushRangeArguments(
|
||||||
['TS.RANGE'],
|
['TS.RANGE', key],
|
||||||
fromTimestamp,
|
fromTimestamp,
|
||||||
toTimestamp,
|
toTimestamp,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { transformRangeReply } from '.';
|
export function transformReply(reply: Array<SampleRawReply>): Array<SampleReply> {
|
||||||
|
return transformRangeReply(reply);
|
||||||
|
}
|
||||||
|
106
packages/time-series/lib/commands/REVRANGE.spec.ts
Normal file
106
packages/time-series/lib/commands/REVRANGE.spec.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import testUtils, { GLOBAL } from '../test-utils';
|
||||||
|
import { transformArguments } from './REVRANGE';
|
||||||
|
import { TimeSeriesAggregationType } from '.';
|
||||||
|
|
||||||
|
describe('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.AVARAGE,
|
||||||
|
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.AVARAGE,
|
||||||
|
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 => {
|
||||||
|
await Promise.all([
|
||||||
|
client.ts.add('key', 0, 1),
|
||||||
|
client.ts.add('key', 1, 2)
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.ts.revRange('key', '-', '+'),
|
||||||
|
[{
|
||||||
|
timestamp: 1,
|
||||||
|
value: 2
|
||||||
|
}, {
|
||||||
|
timestamp: 0,
|
||||||
|
value: 1
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}, GLOBAL.SERVERS.OPEN);
|
||||||
|
});
|
@@ -1,21 +1,24 @@
|
|||||||
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
import { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
||||||
import { RangeOptions, Timestamp, pushRangeArguments } from '.';
|
import { RangeOptions, Timestamp, pushRangeArguments, SampleRawReply, SampleReply, transformRangeReply } from '.';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(
|
export function transformArguments(
|
||||||
|
key: string,
|
||||||
fromTimestamp: Timestamp,
|
fromTimestamp: Timestamp,
|
||||||
toTimestamp: Timestamp,
|
toTimestamp: Timestamp,
|
||||||
options?: RangeOptions
|
options?: RangeOptions
|
||||||
): RedisCommandArguments {
|
): RedisCommandArguments {
|
||||||
return pushRangeArguments(
|
return pushRangeArguments(
|
||||||
['TS.REVRANGE'],
|
['TS.REVRANGE', key],
|
||||||
fromTimestamp,
|
fromTimestamp,
|
||||||
toTimestamp,
|
toTimestamp,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { transformRangeReply } from '.';
|
export function transformReply(reply: Array<SampleRawReply>): Array<SampleReply> {
|
||||||
|
return transformRangeReply(reply);
|
||||||
|
}
|
||||||
|
@@ -9,9 +9,17 @@ import {
|
|||||||
pushLabelsArgument,
|
pushLabelsArgument,
|
||||||
transformIncrDecrArguments,
|
transformIncrDecrArguments,
|
||||||
transformSampleReply,
|
transformSampleReply,
|
||||||
|
TimeSeriesAggregationType,
|
||||||
pushRangeArguments,
|
pushRangeArguments,
|
||||||
|
pushMRangeGroupByArguments,
|
||||||
|
TimeSeriesReducers,
|
||||||
|
pushFilterArgument,
|
||||||
|
pushMRangeArguments,
|
||||||
|
pushWithLabelsArgument,
|
||||||
|
pushMRangeWithLabelsArguments,
|
||||||
transformRangeReply,
|
transformRangeReply,
|
||||||
TimeSeriesAggregationType
|
transformMRangeReply,
|
||||||
|
transformMRangeWithLabelsReply
|
||||||
} from '.';
|
} from '.';
|
||||||
|
|
||||||
describe('transformTimestampArgument', () => {
|
describe('transformTimestampArgument', () => {
|
||||||
@@ -115,6 +123,15 @@ describe('transformIncrDecrArguments', () => {
|
|||||||
['TS.INCRBY', 'key', '1', 'UNCOMPRESSED']
|
['TS.INCRBY', 'key', '1', 'UNCOMPRESSED']
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('with UNCOMPRESSED false', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformIncrDecrArguments('TS.INCRBY', 'key', 1, {
|
||||||
|
UNCOMPRESSED: false
|
||||||
|
}),
|
||||||
|
['TS.INCRBY', 'key', '1']
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('transformSampleReply', () => {
|
it('transformSampleReply', () => {
|
||||||
@@ -139,7 +156,7 @@ describe('pushRangeArguments', () => {
|
|||||||
it('string', () => {
|
it('string', () => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
pushRangeArguments([], '-', '+', {
|
pushRangeArguments([], '-', '+', {
|
||||||
FILTER_BY_TS: 'ts'
|
FILTER_BY_TS: ['ts']
|
||||||
}),
|
}),
|
||||||
['-', '+', 'FILTER_BY_TS', 'ts']
|
['-', '+', 'FILTER_BY_TS', 'ts']
|
||||||
);
|
);
|
||||||
@@ -200,7 +217,7 @@ describe('pushRangeArguments', () => {
|
|||||||
it('with FILTER_BY_TS, FILTER_BY_VALUE, COUNT, ALIGN, AGGREGATION', () => {
|
it('with FILTER_BY_TS, FILTER_BY_VALUE, COUNT, ALIGN, AGGREGATION', () => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
pushRangeArguments([], '-', '+', {
|
pushRangeArguments([], '-', '+', {
|
||||||
FILTER_BY_TS: 'ts',
|
FILTER_BY_TS: ['ts'],
|
||||||
FILTER_BY_VALUE: {
|
FILTER_BY_VALUE: {
|
||||||
min: 1,
|
min: 1,
|
||||||
max: 2
|
max: 2
|
||||||
@@ -212,11 +229,91 @@ describe('pushRangeArguments', () => {
|
|||||||
timeBucket: 1
|
timeBucket: 1
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
['-', '+', 'FILTER_BY_TS', 'ts', 'FILTER_BY_VALUE', '1', '2', 'COUNT', '1', 'ALIGN', '1', 'AGGREGATION', 'first', '1']
|
['-', '+', 'FILTER_BY_TS', 'ts', 'FILTER_BY_VALUE', '1', '2',
|
||||||
|
'COUNT', '1', 'ALIGN', '1', 'AGGREGATION', 'first', '1']
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('pushMRangeGroupByArguments', () => {
|
||||||
|
it('undefined', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
pushMRangeGroupByArguments([]),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with GROUPBY', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
pushMRangeGroupByArguments([], {
|
||||||
|
label: 'label',
|
||||||
|
reducer: TimeSeriesReducers.MAXIMUM
|
||||||
|
}),
|
||||||
|
['GROUPBY', 'label', 'REDUCE', 'max']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('pushFilterArgument', () => {
|
||||||
|
it('string', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
pushFilterArgument([], 'label=value'),
|
||||||
|
['FILTER', 'label=value']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Array', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
pushFilterArgument([], ['1=1', '2=2']),
|
||||||
|
['FILTER', '1=1', '2=2']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('pushMRangeArguments', () => {
|
||||||
|
it('without options', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
pushMRangeArguments([], '-', '+', 'label=value'),
|
||||||
|
['-', '+', 'FILTER', 'label=value']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with GROUPBY', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
pushMRangeArguments([], '-', '+', 'label=value', {
|
||||||
|
GROUPBY: {
|
||||||
|
label: 'label',
|
||||||
|
reducer: TimeSeriesReducers.MAXIMUM
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
['-', '+', 'FILTER', 'label=value', 'GROUPBY', 'label', 'REDUCE', 'max']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('pushWithLabelsArgument', () => {
|
||||||
|
it('without selected labels', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
pushWithLabelsArgument([]),
|
||||||
|
['WITHLABELS']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with selected labels', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
pushWithLabelsArgument([], ['label']),
|
||||||
|
['SELECTED_LABELS', 'label']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('pushMRangeWithLabelsArguments', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
pushMRangeWithLabelsArguments([], '-', '+', 'label=value'),
|
||||||
|
['-', '+', 'WITHLABELS', 'FILTER', 'label=value']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('transformRangeReply', () => {
|
it('transformRangeReply', () => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
transformRangeReply([[1, '1.1'], [2, '2.2']]),
|
transformRangeReply([[1, '1.1'], [2, '2.2']]),
|
||||||
@@ -229,3 +326,46 @@ it('transformRangeReply', () => {
|
|||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('transformMRangeReply', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformMRangeReply([[
|
||||||
|
'key',
|
||||||
|
[],
|
||||||
|
[[1, '1.1'], [2, '2.2']]
|
||||||
|
]]),
|
||||||
|
[{
|
||||||
|
key: 'key',
|
||||||
|
samples: [{
|
||||||
|
timestamp: 1,
|
||||||
|
value: 1.1
|
||||||
|
}, {
|
||||||
|
timestamp: 2,
|
||||||
|
value: 2.2
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('transformMRangeWithLabelsReply', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
transformMRangeWithLabelsReply([[
|
||||||
|
'key',
|
||||||
|
[['label', 'value']],
|
||||||
|
[[1, '1.1'], [2, '2.2']]
|
||||||
|
]]),
|
||||||
|
[{
|
||||||
|
key: 'key',
|
||||||
|
labels: {
|
||||||
|
label: 'value'
|
||||||
|
},
|
||||||
|
samples: [{
|
||||||
|
timestamp: 1,
|
||||||
|
value: 1.1
|
||||||
|
}, {
|
||||||
|
timestamp: 2,
|
||||||
|
value: 2.2
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
@@ -11,9 +11,14 @@ import * as INFO_DEBUG from './INFO_DEBUG';
|
|||||||
import * as INFO from './INFO';
|
import * as INFO from './INFO';
|
||||||
import * as MADD from './MADD';
|
import * as MADD from './MADD';
|
||||||
import * as MGET from './MGET';
|
import * as MGET from './MGET';
|
||||||
|
import * as MGET_WITHLABELS from './MGET_WITHLABELS';
|
||||||
import * as QUERYINDEX from './QUERYINDEX';
|
import * as QUERYINDEX from './QUERYINDEX';
|
||||||
import * as RANGE from './RANGE';
|
import * as RANGE from './RANGE';
|
||||||
import * as REVRANGE from './REVRANGE';
|
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 { RedisCommandArguments } from '@node-redis/client/dist/lib/commands';
|
||||||
import { pushVerdictArguments } from '@node-redis/client/lib/commands/generic-transformers';
|
import { pushVerdictArguments } from '@node-redis/client/lib/commands/generic-transformers';
|
||||||
|
|
||||||
@@ -44,12 +49,22 @@ export default {
|
|||||||
mAdd: MADD,
|
mAdd: MADD,
|
||||||
MGET,
|
MGET,
|
||||||
mGet: MGET,
|
mGet: MGET,
|
||||||
|
MGET_WITHLABELS,
|
||||||
|
mGetWithLabels: MGET_WITHLABELS,
|
||||||
QUERYINDEX,
|
QUERYINDEX,
|
||||||
queryIndex: QUERYINDEX,
|
queryIndex: QUERYINDEX,
|
||||||
RANGE,
|
RANGE,
|
||||||
range: RANGE,
|
range: RANGE,
|
||||||
REVRANGE,
|
REVRANGE,
|
||||||
revRange: REVRANGE
|
revRange: REVRANGE,
|
||||||
|
MRANGE,
|
||||||
|
mRange: MRANGE,
|
||||||
|
MRANGE_WITHLABELS,
|
||||||
|
mRangeWithLabels: MRANGE_WITHLABELS,
|
||||||
|
MREVRANGE,
|
||||||
|
mRevRange: MREVRANGE,
|
||||||
|
MREVRANGE_WITHLABELS,
|
||||||
|
mRevRangeWithLabels: MREVRANGE_WITHLABELS
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum TimeSeriesAggregationType {
|
export enum TimeSeriesAggregationType {
|
||||||
@@ -67,6 +82,21 @@ export enum TimeSeriesAggregationType {
|
|||||||
VAR_S = 'var.s'
|
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 type Timestamp = number | Date | string;
|
||||||
|
|
||||||
export function transformTimestampArgument(timestamp: Timestamp): string {
|
export function transformTimestampArgument(timestamp: Timestamp): string {
|
||||||
@@ -117,19 +147,22 @@ export function pushChunkSizeArgument(args: RedisCommandArguments, chunkSize?: n
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TimeSeriesDuplicatePolicies {
|
export type RawLabels = Array<[label: string, value: string]>;
|
||||||
BLOCK = 'BLOCK',
|
|
||||||
FIRST = 'FIRST',
|
|
||||||
LAST = 'LAST',
|
|
||||||
MIN = 'MIN',
|
|
||||||
MAX = 'MAX',
|
|
||||||
SUM = 'SUM'
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Labels = {
|
export type Labels = {
|
||||||
[label: string]: string;
|
[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 {
|
export function pushLabelsArgument(args: RedisCommandArguments, labels?: Labels): RedisCommandArguments {
|
||||||
if (labels) {
|
if (labels) {
|
||||||
args.push('LABELS');
|
args.push('LABELS');
|
||||||
@@ -162,7 +195,7 @@ export function transformIncrDecrArguments(
|
|||||||
value.toString()
|
value.toString()
|
||||||
];
|
];
|
||||||
|
|
||||||
if (options?.TIMESTAMP) {
|
if (options?.TIMESTAMP !== undefined && options?.TIMESTAMP !== null) {
|
||||||
args.push('TIMESTAMP', transformTimestampArgument(options.TIMESTAMP));
|
args.push('TIMESTAMP', transformTimestampArgument(options.TIMESTAMP));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +227,7 @@ export function transformSampleReply(reply: SampleRawReply): SampleReply {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface RangeOptions {
|
export interface RangeOptions {
|
||||||
FILTER_BY_TS?: string | Array<string>;
|
FILTER_BY_TS?: Array<Timestamp>;
|
||||||
FILTER_BY_VALUE?: {
|
FILTER_BY_VALUE?: {
|
||||||
min: number;
|
min: number;
|
||||||
max: number;
|
max: number;
|
||||||
@@ -220,7 +253,9 @@ export function pushRangeArguments(
|
|||||||
|
|
||||||
if (options?.FILTER_BY_TS) {
|
if (options?.FILTER_BY_TS) {
|
||||||
args.push('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) {
|
if (options?.FILTER_BY_VALUE) {
|
||||||
@@ -256,6 +291,121 @@ export function pushRangeArguments(
|
|||||||
return args;
|
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> {
|
export function transformRangeReply(reply: Array<SampleRawReply>): Array<SampleReply> {
|
||||||
return reply.map(transformSampleReply);
|
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;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user