All files / redis-smq-monitor-app/src/plugins/message-rate/common hash-time-series.ts

92.85% Statements 39/42
80.95% Branches 17/21
100% Functions 11/11
97.29% Lines 36/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 8057x     57x   57x       871x 871x 871x               75x 75x 75x 75x 13x 13x     75x 22x 22x 22x 53x       212x 212x 212x         212x 212x 1x 1x 1x 1x 211x           521x             521x 521x   31040x 521x 521x   521x 31040x       521x            
import { TimeSeries } from './time-series';
import { IHashTimeSeriesParams, TTimeSeriesRange } from '../../../../types';
import { ICallback, TRedisClientMulti } from 'redis-smq-common/dist/types';
import { errors, RedisClient } from 'redis-smq-common';
 
export class HashTimeSeries extends TimeSeries<IHashTimeSeriesParams> {
  protected indexKey: string;
 
  constructor(redisClient: RedisClient, params: IHashTimeSeriesParams) {
    super(redisClient, params);
    const { indexKey } = params;
    this.indexKey = indexKey;
  }
 
  add(
    ts: number,
    value: number,
    mixed: ICallback<void> | TRedisClientMulti,
  ): void {
    const process = (multi: TRedisClientMulti) => {
      multi.hincrby(this.key, String(ts), value);
      multi.zadd(this.indexKey, ts, ts);
      if (this.expireAfter) {
        multi.expire(this.key, this.expireAfter);
        multi.expire(this.indexKey, this.expireAfter);
      }
    };
    if (typeof mixed === 'function') {
      const multi = this.redisClient.multi();
      process(multi);
      this.redisClient.execMulti(multi, (err) => mixed(err));
    } else process(mixed);
  }
 
  cleanUp(cb: ICallback<void>): void {
    const ts = TimeSeries.getCurrentTimestamp();
    const max = ts - this.retentionTime;
    this.redisClient.zrangebyscore(
      this.indexKey,
      '-inf',
      `${max}`,
      (err, reply) => {
        Iif (err) cb(err);
        else if (reply && reply.length) {
          const multi = this.redisClient.multi();
          multi.zrem(this.indexKey, ...reply);
          multi.hdel(this.key, ...reply);
          this.redisClient.execMulti(multi, (err) => cb(err));
        } else cb();
      },
    );
  }
 
  getRange(from: number, to: number, cb: ICallback<TTimeSeriesRange>): void {
    Iif (to <= from) {
      cb(
        new errors.ArgumentError(
          `Expected parameter [to] to be greater than [from]`,
        ),
      );
    } else {
      const length = to - from;
      const timestamps = new Array(length)
        .fill(0)
        .map((_: number, index: number) => String(from + index));
      this.redisClient.hmget(this.key, timestamps, (err, reply) => {
        Iif (err) cb(err);
        else {
          const replyRange = reply ?? [];
          const range = timestamps.map((i, index) => ({
            timestamp: Number(i),
            value: Number(replyRange[index] ?? 0),
          }));
          cb(null, range);
        }
      });
    }
  }
}