UNPKG

@naturalcycles/db-lib

Version:

Lowest Common Denominator API to supported Databases

77 lines (76 loc) 2.69 kB
import { _isTruthy } from '@naturalcycles/js-lib'; import { DBQuery } from '../query/dbQuery.js'; const _TIMESERIES_RAW = '_TIMESERIES_RAW'; /** * TimeSeries DB implementation based on provided CommonDB database. * Turns any CommonDB database into TimeSeries DB. Kind of. * * @experimental */ export class CommonTimeSeriesDao { cfg; constructor(cfg) { this.cfg = cfg; } async ping() { await this.cfg.db.ping(); } async getSeries() { return (await this.cfg.db.getTables()) .map(t => /^(.*)_TIMESERIES_RAW$/.exec(t)?.[1]) .filter(_isTruthy); } // convenience method async save(series, tsMillis, value) { await this.saveBatch(series, [[tsMillis, value]]); } async saveBatch(series, dataPoints) { if (!dataPoints.length) return; const rows = dataPoints.map(([ts, v]) => ({ id: String(ts), // Convert Number id into String id, as per CommonDB ts, // to allow querying by ts, since querying by id is not always available (Datastore is one example) v, })); await this.cfg.db.saveBatch(`${series}${_TIMESERIES_RAW}`, rows); } /** * All ops are executed as a single CommonDB Transaction. */ async commitTransaction(ops) { if (!ops.length) return; await this.cfg.db.runInTransaction(async (tx) => { for (const op of ops) { const rows = op.dataPoints.map(([ts, v]) => ({ id: String(ts), // Convert Number id into String id, as per CommonDB ts, // to allow querying by ts, since querying by id is not always available (Datastore is one example) v, })); await tx.saveBatch(`${op.series}${_TIMESERIES_RAW}`, rows); } }); } async deleteById(series, tsMillis) { await this.deleteByIds(series, [tsMillis]); } async deleteByIds(series, ids) { // Save to _RAW table with v=null await this.saveBatch(series, ids.map(id => [id, null])); } async query(q) { const dbq = DBQuery.create(`${q.series}${_TIMESERIES_RAW}`).order('ts'); if (q.fromIncl) dbq.filter('ts', '>=', q.fromIncl); if (q.toExcl) dbq.filter('ts', '<', q.toExcl); const rows = (await this.cfg.db.runQuery(dbq)).rows; // todo: query from aggregated tables when step is above 'hour' return rows .filter(r => r.v !== null && r.v !== undefined) // can be 0 .map(r => [r.ts, r.v]); } async optimize() { // todo } }