"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseSingle = exports.parse = exports.assertNoErrors = exports.ResultError = void 0; const grammar_1 = require("./grammar"); /** * A ResultError is thrown when a query generates errorful results from Influx. */ class ResultError extends Error { constructor(message) { super(); this.message = `Error from InfluxDB: ${message}`; } } exports.ResultError = ResultError; function groupMethod(matcher) { // We do a tiny bit of 'custom' deep equality checking here, taking // advantage of the fact that the tag keys are consistent across all // series results. This lets us match groupings much more efficiently, // ~6000x faster than the fastest vanilla equality checker (lodash) // when operating on large (~100,000 grouping) sets. const srcKeys = this.groupsTagsKeys; const dstKeys = Object.keys(matcher); if (srcKeys.length === 0 || srcKeys.length !== dstKeys.length) { return []; } L: for (let row of this.groupRows) { // eslint-disable-line no-labels for (let src of srcKeys) { if (row.tags[src] !== matcher[src]) { continue L; // eslint-disable-line no-labels } } return row.rows; } return []; } function groupsMethod() { return this.groupRows; } /** * Inner parsing function which unpacks the series into a table and attaches * methods to the array. This is quite optimized and a bit of a mess to read, * but it's all fairly easy procedural logic. * * We do this instead of subclassing Array since subclassing has some * undesirable side-effects. For example, calling .slice() on the array * makes it impossible to preserve groups as would be necessary if it's * subclassed. */ function parseInner(series = [], precision) { const results = []; results.groupsTagsKeys = series.length && series[0].tags ? Object.keys(series[0].tags) : []; const tags = results.groupsTagsKeys; let nextGroup = []; results.groupRows = new Array(series.length); // Tslint:disable-line for (let i = 0; i < series.length; i += 1, results.length) { const { columns = [], values = [] } = series[i]; for (let value of values) { const obj = {}; for (let j = 0; j < columns.length; j += 1) { if (columns[j] === "time") { obj.time = grammar_1.isoOrTimeToDate(value[j], precision); } else { obj[columns[j]] = value[j]; } } for (let tag of tags) { obj[tag] = series[i].tags[tag]; } results.push(obj); nextGroup.push(obj); } results.groupRows[i] = { name: series[i].name, rows: nextGroup, tags: series[i].tags || {}, }; nextGroup = []; } results.group = groupMethod; results.groups = groupsMethod; return results; } /** * Checks if there are any errors in the IResponse and, if so, it throws them. * @private * @throws {ResultError} */ function assertNoErrors(res) { for (let result of res.results) { const { error } = result; if (error) { throw new ResultError(error); } } return res; } exports.assertNoErrors = assertNoErrors; /** * From parses out a response to a result or list of responses. * There are three situations we cover here: * 1. A single query without groups, like `select * from myseries` * 2. A single query with groups, generated with a `group by` statement * which groups by series *tags*, grouping by times is case (1) * 3. Multiple queries of types 1 and 2 * @private */ function parse(res, precision) { assertNoErrors(res); if (res.results.length === 1) { // Normalize case 3 return parseInner(res.results[0].series, precision); } return res.results.map((result) => parseInner(result.series, precision)); } exports.parse = parse; /** * ParseSingle asserts that the response contains a single result, * and returns that result. * @throws {Error} if the number of results is not exactly one * @private */ function parseSingle(res, precision) { assertNoErrors(res); if (res.results.length !== 1) { throw new Error("node-influx expected the results length to equal 1, but " + `it was ${0}. Please report this here: https://git.io/influx-err`); } return parseInner(res.results[0].series, precision); } exports.parseSingle = parseSingle;