"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseWhere = exports.parseMeasurement = exports.Measurement = exports.Expression = void 0; const grammar_1 = require("./grammar"); function regexHasFlags(re) { if (typeof re.flags !== "undefined") { return re.flags.length > 0; } return !re.toString().endsWith("/"); } /** * Expression is used to build filtering expressions, like those used in WHERE * clauses. It can be used for fluent and safe building of queries using * untrusted input. * * @example * e => e * .field('host').equals.value('ares.peet.io') * .or * .field('host').matches(/example\.com$/) * .or * .expr(e => e * .field('country').equals.value('US') * .and * .field('state').equals.value('WA')); * * // Generates: * // "host" = 'ares.peet.io' OR "host" ~= /example\.com$/ OR \ * // ("county" = 'US' AND "state" = 'WA') */ class Expression { constructor() { this._query = []; } /** * Inserts a tag reference into the expression; the name will be * automatically escaped. * @param name * @return */ tag(name) { this.field(name); return this; } /** * Inserts a field reference into the expression; the name will be * automatically escaped. * @param name * @return */ field(name) { this._query.push(grammar_1.escape.quoted(name)); return this; } /** * Inserts a subexpression; invokes the function with a new expression * that can be chained on. * @param fn * @return * @example * e.field('a').equals.value('b') * .or.expr(e => * e.field('b').equals.value('b') * .and.field('a').equals.value('c')) * .toString() * // "a" = 'b' OR ("b" = 'b' AND "a" = 'c') */ exp(fn) { this._query.push("(" + fn(new Expression()).toString() + ")"); return this; } /** * Value chains on a value to the expression. * * - Numbers will be inserted verbatim * - Strings will be escaped and inserted * - Booleans will be inserted correctly * - Dates will be formatted and inserted correctly, including INanoDates. * - Regular expressions will be inserted correctly, however an error will * be thrown if they contain flags, as regex flags do not work in Influx * - Otherwise we'll try to call `.toString()` on the value, throwing * if we cannot do so. * * @param value * @return */ value(value) { switch (typeof value) { case "number": this._query.push(value.toString()); return this; case "string": this._query.push(grammar_1.escape.stringLit(value)); return this; case "boolean": this._query.push(value ? "TRUE" : "FALSE"); return this; default: if (value instanceof Date) { this._query.push(grammar_1.formatDate(value)); return this; } if (value instanceof RegExp) { if (regexHasFlags(value)) { throw new Error("Attempted to query using a regex with flags, " + "but Influx doesn't support flags in queries."); } this._query.push("/" + value.source + "/"); return this; } if (value && typeof value.toString === "function") { this._query.push(value.toString()); return this; } throw new Error("node-influx doesn't know how to encode the provided value into a " + "query. If you think this is a bug, open an issue here: https://git.io/influx-err"); } } /** * Chains on an AND clause to the expression. */ get and() { this._query.push("AND"); return this; } /** * Chains on an OR clause to the expression. */ get or() { this._query.push("OR"); return this; } /** * Chains on a `+` operator to the expression. */ get plus() { this._query.push("+"); return this; } /** * Chains on a `*` operator to the expression. */ get times() { this._query.push("*"); return this; } /** * Chains on a `-` operator to the expression. */ get minus() { this._query.push("-"); return this; } /** * Chains on a `/` operator to the expression. */ get div() { this._query.push("/"); return this; } /** * Chains on a `=` conditional to the expression. */ get equals() { this._query.push("="); return this; } /** * Chains on a `=~` conditional to the expression to match regexes. */ get matches() { this._query.push("=~"); return this; } /** * Chains on a `!`` conditional to the expression to match regexes. */ get doesntMatch() { this._query.push("!~"); return this; } /** * Chains on a `!=` conditional to the expression. */ get notEqual() { this._query.push("!="); return this; } /** * Chains on a `>` conditional to the expression. */ get gt() { this._query.push(">"); return this; } /** * Chains on a `>=` conditional to the expression. */ get gte() { this._query.push(">="); return this; } /** * Chains on a `<` conditional to the expression. */ get lt() { this._query.push("<"); return this; } /** * Chains on a `<=` conditional to the expression. */ get lte() { this._query.push("<="); return this; } /** * Converts the expression into its InfluxQL representation. * @return */ toString() { return this._query.join(" "); } } exports.Expression = Expression; /** * Measurement creates a reference to a particular measurement. You can * reference it solely by its name, but you can also specify the retention * policy and database it lives under. * * @example * m.name('my_measurement') // "my_measurement" * m.name('my_measurement').policy('one_day') // "one_day"."my_measurement" * m.name('my_measurement').policy('one_day').db('mydb') // "mydb"."one_day"."my_measurement" */ class Measurement { constructor() { this._parts = [null, null, null]; } /** * Sets the measurement name. * @param name * @return */ name(name) { this._parts[2] = name; return this; } /** * Sets the retention policy name. * @param retentionPolicy * @return */ policy(retentionPolicy) { this._parts[1] = retentionPolicy; return this; } /** * Sets the database name. * @param db * @return */ db(db) { this._parts[0] = db; return this; } /** * Converts the measurement into its InfluxQL representation. * @return * @throws {Error} if a measurement name is not provided */ toString() { if (!this._parts[2]) { throw new Error(`You must specify a measurement name to query! Got \`${this._parts[2]}\``); } return this._parts .filter((p) => Boolean(p)) .map((p) => grammar_1.escape.quoted(p)) .join("."); } } exports.Measurement = Measurement; function parseMeasurement(q) { if (typeof q.measurement === "function") { return q.measurement(new Measurement()).toString(); } return q.measurement; } exports.parseMeasurement = parseMeasurement; function parseWhere(q) { if (typeof q.where === "function") { return q.where(new Expression()).toString(); } return q.where; } exports.parseWhere = parseWhere;