297 lines
7.9 KiB
JavaScript
297 lines
7.9 KiB
JavaScript
"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;
|