vrack-db
Version:
This is an In Memory database designed for storing time series (graphs).
290 lines (289 loc) • 10.2 kB
JavaScript
;
/*
* Copyright © 2024 Boris Bobylev. All rights reserved.
* Licensed under the Apache License, Version 2.0
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ErrorManager_1 = __importDefault(require("./Errors/ErrorManager"));
const Typing_1 = __importDefault(require("./Typing"));
ErrorManager_1.default.register('UNNdYlOiGduD', 'VDB_INTREVAL_PRECISION', 'Incorrect type given, values must be integer and greater than zero');
ErrorManager_1.default.register('2nWCcqq49P5Y', 'VDB_INTREVAL_TIME', 'Incorrect type given, type integer is required');
ErrorManager_1.default.register('QC93dkEnQAW1', 'VDB_INTREVAL_SECTION', 'Incorrect section - The beginning is greater than the end');
ErrorManager_1.default.register('nuELzbjx0HqG', 'VDB_INTREVAL_PERIOD', 'Incorrect period string, use example `now-1d:now-1h` ');
ErrorManager_1.default.register('T80r57lrQFCb', 'VDB_INTREVAL_PARSE', 'Incorrect interval string, use example `10s` `1m` `1h` ');
ErrorManager_1.default.register('8A2U9F2oIDG4', 'VDB_INTREVAL_RETENTION', 'Incorrect retention string, use example `10s:1m` `1m:15h` `1h:1y` ');
/**
* A class for working with time segments.
*
* This class takes the second as the basis of time, but it may be different for other classes.
* For this reason, this class already introduces such a concept as MTU - minimal time unit.
*
* For this class, MTU = second.
*
* All methods of the class will imply that you are using MTU time. **The exception is the method toTime**
*
* For example, roundTime as before accepts time: number, precision: number, but now this time is not in seconds but in MTU.
*
*/
class Interval {
/**
* Returns the current time in MTU
*/
static now() {
return this.toTime(Date.now());
}
/**
* Converts JS timestamp microseconds to MTU
*
* @see now()
* @param jsTime Time in microseconds
*/
static toTime(jsTime) {
if (!Number.isInteger(jsTime))
throw ErrorManager_1.default.make(new Error, 'VDB_INTREVAL_TIME', { time: jsTime });
return Math.floor(jsTime * this.nowFactor);
}
/**
* Returns the transferred time rounded to precision accuracy
*
* @param {number} time Time for rounding in MTU
* @param {number} precision Accuracy in MTU
*/
static roundTime(time, precision) {
if (!Number.isInteger(time))
throw ErrorManager_1.default.make(new Error, 'VDB_INTREVAL_TIME', { time });
if (!Typing_1.default.isUInt(precision))
throw ErrorManager_1.default.make(new Error, 'VDB_INTREVAL_PRECISION', { precision });
return time - (time % precision);
}
/**
* Splits the period from start to end into intervals of precision size with start and end pre-rounded to precision accuracy
*
* Looks like this:
* [ start, start + precission, start + precission * I, end ]
*
* @param start Start at which the interval report will begin (rounded to “precision”)
* @param end The end to which the time will be divided into intervals (rounded to “precision”)
* @param precision Interval into which the period will be divided
*/
static getIntervals(start, end, precision) {
if (start > end)
throw ErrorManager_1.default.make(new Error, 'VDB_INTREVAL_SECTION', { start, end });
start = this.roundTime(start, precision);
end = this.roundTime(end, precision);
if (start === end)
[start];
const ccount = (end - start) / precision;
const result = [];
for (let i = 0; i < ccount; i++)
result.push(start + (i * precision));
result.push(end);
return result;
}
/**
* Returns the period in carbon retention type format
*
* For example, get the last day's preod: 'now-1d:now'
*
* @see partOfPeriod
* @see parseInterval
*
* @param {string} period Period formatted like a 'now-1d:now-1h'
* @returns {IPeriod} { start: number, end: number }
*/
static period(period, pieces = {}) {
period = period.replace(/ /g, '');
if (period.indexOf(':') === -1)
throw ErrorManager_1.default.make(new Error, 'VDB_INTREVAL_PERIOD', { period });
const parts = period.split(':');
if (parts.length !== 2)
throw ErrorManager_1.default.make(new Error, 'VDB_INTREVAL_PERIOD', { period });
return {
start: this.partOfPeriod(parts[0], pieces),
end: this.partOfPeriod(parts[1], pieces)
};
}
/**
* Allows you to calculate in simple form the part of the period e.g:
*
* - now-10d - Calculates the current time minus 10 days.
* - now+1h - Current time plus 1 hour
* - now-1h-1m - Current time minus 1 hour and minus 1 minute.
*
* Supports 2 operators `+` and `-`
*
* If just an interval is specified, e.g. 10d, the result will be returned.
* calculation of `parseInterval` for interval 10d
*
* @see parseInterval
*
* @param {string} str Calculation string
*/
static partOfPeriod(str, pieces = {}) {
str = str.replace(/ /g, '');
const tokens = str.split(/([-+])/);
let result = 0;
let sign = 1;
for (const token of tokens) {
if (token === '-') {
sign = -1;
continue;
}
else if (token === '+') {
sign = 1;
continue;
}
result += this.prepareInterval(token, pieces) * sign;
}
return result;
}
/**
* Parses the time string at specified intervals
*
* For example the string '10s:1m, 1m:6h, 1h:1w' *
* Will return an array:
*
* ```
* [
* { interval: 10, period: 60 }
* { interval: 60, period: 21600 }
* { interval: 3600, period: 604800 }
* ]
* ```
*
* The function only checks if the string is correct for formatting, but does not check if
* the given set of intervals and periods are correct and make sense
*
* @param {string} str Schema format string graphite-carbon
*
*/
static retentions(str) {
str = str.replace(/ /g, '');
const result = [];
if (str.indexOf(',') !== -1) {
const retons = str.split(',');
for (const sret of retons)
result.push(this.retention(sret));
}
else {
result.push(this.retention(str));
}
return result;
}
/**
* Returns the number of MTU in the specified amount of time
*
* The format is like graphite:
* - 15s - 15 sec
* - 10m - 10 min
*
* Where:
*
* - us - microsecond
* - ms - millisecond
* - s - seconds
* - m - minutes
* - h - hours
* - d - days
* - w - weeks
* - mon - months
* - y - years
*
*
* @param {string} ival String of interval
*/
static parseInterval(ival) {
const match = ival.match(/^(\d+)(\w+)$/);
if (!match || !this.map[match[2]]) {
const r = parseInt(ival);
if (isNaN(r)) {
throw ErrorManager_1.default.make(new Error, 'VDB_INTREVAL_PARSE', { interval: ival });
}
return r;
}
const value = parseInt(match[1]) * this.map[match[2]];
if (value % 1 !== 0)
return Math.round(value);
return value;
}
/**
* Returns the interval (in MTU) for the "start" and "end" period to provide the number of metrics "count".
*
* Can be used to simplify the derivation of fixed number metrics regardless of period size.
*
* @param {number} start - Start of period in secodn
* @param {number} end - end of period in secodn
* @param {number} count - count of metrics
*/
static getIntervalOfFixedCount(start, end, count) {
let cnt = Math.floor(Math.abs(start - end) / count);
if (isNaN(cnt) || cnt < 1)
cnt = 1;
return cnt;
}
/**
* Returns the factor for convert milliseconds to MTUs
*/
static getFactor() {
return this.nowFactor;
}
/**
* Handles additional time objects, such as now
* Since now is not part of the interval concept, it should not be included
* in the parseInterval function, that's why this layer function was created
* which handles additional time parameters
*
* @todo to process the numerical time values
* @param {string} str String of interval
*/
static prepareInterval(str, pieces = {}) {
if (str === 'now')
pieces.now = this.now();
if (pieces[str] !== undefined)
return pieces[str];
return this.parseInterval(str);
}
/**
* Returns an object of type IRetention from a string of type '10s:1m'
*
* @see retentions
* @param {string} ret String of period
*/
static retention(ret) {
const acts = ret.split(':');
if (acts.length !== 2)
throw ErrorManager_1.default.make(new Error, 'VDB_INTREVAL_RETENTION', { retention: ret });
const newRet = {
interval: this.parseInterval(acts[0]),
period: this.parseInterval(acts[1]),
retention: ret
};
return newRet;
}
}
exports.default = Interval;
/**
* Multiplier, to get from the standard JS time to the MTU for this class.
* Other classes like IntervalMs can change this parameter.
*/
Interval.nowFactor = 0.001;
/**
* A map that determines the number of MTUs in a specific time period.
*
* For this class MTU = second and intervals such as "ms" "mcs" that create a fractional part will be rounded.
* All operations occur only with integers.
*/
Interval.map = {
mcs: 0.0000001,
ms: 0.001,
s: 1,
m: 60,
h: 60 * 60,
d: 60 * 60 * 24,
w: 60 * 60 * 24 * 7,
mon: 60 * 60 * 24 * 30,
y: 60 * 60 * 24 * 365
};