mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(influxdb editor): lots of work on new editor, #2856
This commit is contained in:
parent
f053b41645
commit
83052352dc
141
public/app/plugins/datasource/influxdb/influx_query.ts
Normal file
141
public/app/plugins/datasource/influxdb/influx_query.ts
Normal file
@ -0,0 +1,141 @@
|
||||
///<reference path="../../../headers/common.d.ts" />
|
||||
///<amd-dependency path="./query_builder" name="InfluxQueryBuilder" />
|
||||
|
||||
import _ = require('lodash');
|
||||
import queryPart = require('./query_part');
|
||||
|
||||
declare var InfluxQueryBuilder: any;
|
||||
|
||||
class InfluxQuery {
|
||||
target: any;
|
||||
selectParts: any[];
|
||||
groupByParts: any;
|
||||
queryBuilder: any;
|
||||
|
||||
constructor(target) {
|
||||
this.target = target;
|
||||
|
||||
target.tags = target.tags || [];
|
||||
target.groupBy = target.groupBy || [{type: 'time', interval: 'auto'}];
|
||||
target.select = target.select || [[
|
||||
{name: 'mean', params: ['value']},
|
||||
]];
|
||||
|
||||
this.updateSelectParts();
|
||||
this.groupByParts = [
|
||||
queryPart.create({name: 'time', params: ['$interval']})
|
||||
];
|
||||
}
|
||||
|
||||
updateSelectParts() {
|
||||
this.selectParts = _.map(this.target.select, function(parts: any) {
|
||||
return _.map(parts, function(part: any) {
|
||||
return queryPart.create(part);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeSelect(index: number) {
|
||||
this.target.select.splice(index, 1);
|
||||
this.updateSelectParts();
|
||||
}
|
||||
|
||||
addSelect() {
|
||||
this.target.select.push([
|
||||
{name: 'mean', params: ['value']},
|
||||
]);
|
||||
this.updateSelectParts();
|
||||
}
|
||||
|
||||
private renderTagCondition(tag, index) {
|
||||
var str = "";
|
||||
var operator = tag.operator;
|
||||
var value = tag.value;
|
||||
if (index > 0) {
|
||||
str = (tag.condition || 'AND') + ' ';
|
||||
}
|
||||
|
||||
if (!operator) {
|
||||
if (/^\/.*\/$/.test(tag.value)) {
|
||||
operator = '=~';
|
||||
} else {
|
||||
operator = '=';
|
||||
}
|
||||
}
|
||||
|
||||
// quote value unless regex
|
||||
if (operator !== '=~' && operator !== '!~') {
|
||||
value = "'" + value + "'";
|
||||
}
|
||||
|
||||
return str + '"' + tag.key + '" ' + operator + ' ' + value;
|
||||
}
|
||||
|
||||
private getGroupByTimeInterval(interval) {
|
||||
if (interval === 'auto') {
|
||||
return '$interval';
|
||||
}
|
||||
return interval;
|
||||
}
|
||||
|
||||
render() {
|
||||
var target = this.target;
|
||||
|
||||
if (!target.measurement) {
|
||||
throw "Metric measurement is missing";
|
||||
}
|
||||
|
||||
if (!target.fields) {
|
||||
target.fields = [{name: 'value', func: target.function || 'mean'}];
|
||||
}
|
||||
|
||||
var query = 'SELECT ';
|
||||
var i, y;
|
||||
for (i = 0; i < this.selectParts.length; i++) {
|
||||
let parts = this.selectParts[i];
|
||||
var selectText = "";
|
||||
for (y = 0; y < parts.length; y++) {
|
||||
let part = parts[y];
|
||||
selectText = part.render(selectText);
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
query += ', ';
|
||||
}
|
||||
query += selectText;
|
||||
}
|
||||
|
||||
var measurement = target.measurement;
|
||||
if (!measurement.match('^/.*/') && !measurement.match(/^merge\(.*\)/)) {
|
||||
measurement = '"' + measurement+ '"';
|
||||
}
|
||||
|
||||
query += ' FROM ' + measurement + ' WHERE ';
|
||||
var conditions = _.map(target.tags, (tag, index) => {
|
||||
return this.renderTagCondition(tag, index);
|
||||
});
|
||||
|
||||
query += conditions.join(' ');
|
||||
query += (conditions.length > 0 ? ' AND ' : '') + '$timeFilter';
|
||||
|
||||
query += ' GROUP BY';
|
||||
for (i = 0; i < target.groupBy.length; i++) {
|
||||
var group = target.groupBy[i];
|
||||
if (group.type === 'time') {
|
||||
query += ' time(' + this.getGroupByTimeInterval(group.interval) + ')';
|
||||
} else {
|
||||
query += ', "' + group.key + '"';
|
||||
}
|
||||
}
|
||||
|
||||
if (target.fill) {
|
||||
query += ' fill(' + target.fill + ')';
|
||||
}
|
||||
|
||||
target.query = query;
|
||||
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
||||
export = InfluxQuery;
|
@ -65,7 +65,7 @@
|
||||
|
||||
<div ng-hide="target.rawQuery">
|
||||
|
||||
<div class="tight-form" ng-repeat="parts in selectParts">
|
||||
<div class="tight-form" ng-repeat="parts in queryModel.selectParts">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
||||
<span ng-show="$index === 0">SELECT</span>
|
||||
@ -85,13 +85,13 @@
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form" ng-repeat="groupBy in target.groupBy">
|
||||
<div class="tight-form" ng-repeat="part in queryModel.groupByParts">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
||||
<span ng-show="$index === 0">GROUP BY</span>
|
||||
</li>
|
||||
<li ng-if="groupBy.type === 'time'">
|
||||
<influx-query-part-editor part="groupByParts" class="tight-form-item tight-form-func"></influx-query-part-editor>
|
||||
<li>
|
||||
<influx-query-part-editor part="part" class="tight-form-item tight-form-func"></influx-query-part-editor>
|
||||
</li>
|
||||
<!-- <li class="dropdown" ng-if="groupBy.type === 'time'"> -->
|
||||
<!-- <a class="tight-form-item pointer" data-toggle="dropdown" bs-tooltip="'Insert missing values, important when stacking'" data-placement="right"> -->
|
||||
|
@ -4,8 +4,9 @@ define([
|
||||
function (_) {
|
||||
'use strict';
|
||||
|
||||
function InfluxQueryBuilder(target) {
|
||||
function InfluxQueryBuilder(target, queryModel) {
|
||||
this.target = target;
|
||||
this.model = queryModel;
|
||||
|
||||
if (target.groupByTags) {
|
||||
target.groupBy = [{type: 'time', interval: 'auto'}];
|
||||
|
@ -2,10 +2,10 @@ define([
|
||||
'angular',
|
||||
'lodash',
|
||||
'./query_builder',
|
||||
'./query_part',
|
||||
'./influx_query',
|
||||
'./query_part_editor',
|
||||
],
|
||||
function (angular, _, InfluxQueryBuilder, queryPart) {
|
||||
function (angular, _, InfluxQueryBuilder, InfluxQuery) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
@ -15,29 +15,18 @@ function (angular, _, InfluxQueryBuilder, queryPart) {
|
||||
$scope.init = function() {
|
||||
if (!$scope.target) { return; }
|
||||
|
||||
var target = $scope.target;
|
||||
target.tags = target.tags || [];
|
||||
target.groupBy = target.groupBy || [{type: 'time', interval: 'auto'}];
|
||||
target.fields = target.fields || [{name: 'value'}];
|
||||
target.select = target.select || [[
|
||||
{name: 'field', params: ['value']},
|
||||
{name: 'mean', params: []},
|
||||
]];
|
||||
$scope.target = $scope.target;
|
||||
$scope.queryModel = new InfluxQuery($scope.target);
|
||||
$scope.queryBuilder = new InfluxQueryBuilder($scope.target);
|
||||
|
||||
$scope.updateSelectParts();
|
||||
|
||||
$scope.groupByParts = queryPart.create({name: 'time', params:['$interval']});
|
||||
|
||||
$scope.queryBuilder = new InfluxQueryBuilder(target);
|
||||
|
||||
if (!target.measurement) {
|
||||
if (!$scope.target.measurement) {
|
||||
$scope.measurementSegment = uiSegmentSrv.newSelectMeasurement();
|
||||
} else {
|
||||
$scope.measurementSegment = uiSegmentSrv.newSegment(target.measurement);
|
||||
$scope.measurementSegment = uiSegmentSrv.newSegment($scope.target.measurement);
|
||||
}
|
||||
|
||||
$scope.tagSegments = [];
|
||||
_.each(target.tags, function(tag) {
|
||||
_.each($scope.target.tags, function(tag) {
|
||||
if (!tag.operator) {
|
||||
if (/^\/.*\/$/.test(tag.value)) {
|
||||
tag.operator = "=~";
|
||||
@ -78,32 +67,14 @@ function (angular, _, InfluxQueryBuilder, queryPart) {
|
||||
};
|
||||
|
||||
$scope.addSelect = function() {
|
||||
$scope.target.select.push([
|
||||
{name: 'field', params: ['value']},
|
||||
{name: 'mean', params: []},
|
||||
]);
|
||||
$scope.updateSelectParts();
|
||||
$scope.queryModel.addSelect();
|
||||
};
|
||||
|
||||
$scope.removeSelect = function(index) {
|
||||
$scope.target.select.splice(index, 1);
|
||||
$scope.updateSelectParts();
|
||||
$scope.queryModel.removeSelect(index);
|
||||
$scope.get_data();
|
||||
};
|
||||
|
||||
$scope.updateSelectParts = function() {
|
||||
$scope.selectParts = _.map($scope.target.select, function(parts) {
|
||||
return _.map(parts, function(part) {
|
||||
return queryPart.create(part);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.changeFunction = function(func) {
|
||||
$scope.target.function = func;
|
||||
$scope.$parent.get_data();
|
||||
};
|
||||
|
||||
$scope.measurementChanged = function() {
|
||||
$scope.target.measurement = $scope.measurementSegment.value;
|
||||
$scope.$parent.get_data();
|
||||
@ -125,22 +96,6 @@ function (angular, _, InfluxQueryBuilder, queryPart) {
|
||||
.then($scope.transformToSegments(true), $scope.handleQueryError);
|
||||
};
|
||||
|
||||
$scope.getFunctions = function () {
|
||||
var functionList = ['count', 'mean', 'sum', 'min', 'max', 'mode', 'distinct', 'median',
|
||||
'stddev', 'first', 'last'
|
||||
];
|
||||
return $q.when(_.map(functionList, function(func) {
|
||||
return uiSegmentSrv.newSegment(func);
|
||||
}));
|
||||
};
|
||||
|
||||
$scope.getGroupByTimeIntervals = function () {
|
||||
var times = ['auto', '1s', '10s', '1m', '2m', '5m', '10m', '30m', '1h', '1d'];
|
||||
return $q.when(_.map(times, function(func) {
|
||||
return uiSegmentSrv.newSegment(func);
|
||||
}));
|
||||
};
|
||||
|
||||
$scope.handleQueryError = function(err) {
|
||||
$scope.parserError = err.message || 'Failed to issue metric query';
|
||||
return [];
|
||||
@ -202,18 +157,6 @@ function (angular, _, InfluxQueryBuilder, queryPart) {
|
||||
.then(null, $scope.handleQueryError);
|
||||
};
|
||||
|
||||
$scope.addField = function() {
|
||||
$scope.target.fields.push({name: $scope.addFieldSegment.value, func: 'mean'});
|
||||
_.extend($scope.addFieldSegment, uiSegmentSrv.newPlusButton());
|
||||
};
|
||||
|
||||
$scope.fieldChanged = function(field) {
|
||||
if (field.name === '-- remove from select --') {
|
||||
$scope.target.fields = _.without($scope.target.fields, field);
|
||||
}
|
||||
$scope.get_data();
|
||||
};
|
||||
|
||||
$scope.getTagOptions = function() {
|
||||
var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
|
||||
|
||||
|
@ -15,11 +15,13 @@ class QueryPartDef {
|
||||
name: string;
|
||||
params: any[];
|
||||
defaultParams: any[];
|
||||
renderer: any;
|
||||
|
||||
constructor(options: any) {
|
||||
this.name = options.name;
|
||||
this.params = options.params;
|
||||
this.defaultParams = options.defaultParams;
|
||||
this.renderer = options.renderer;
|
||||
}
|
||||
|
||||
static register(options: any) {
|
||||
@ -27,25 +29,55 @@ class QueryPartDef {
|
||||
}
|
||||
}
|
||||
|
||||
QueryPartDef.register({
|
||||
name: 'field',
|
||||
category: categories.Transform,
|
||||
params: [{type: 'field'}],
|
||||
defaultParams: ['value'],
|
||||
});
|
||||
function functionRenderer(part, innerExpr) {
|
||||
var str = part.def.name + '(';
|
||||
var parameters = _.map(part.params, (value, index) => {
|
||||
var paramType = part.def.params[index];
|
||||
if (paramType.quote === 'single') {
|
||||
return "'" + value + "'";
|
||||
} else if (paramType.quote === 'double') {
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
|
||||
if (innerExpr) {
|
||||
parameters.unshift(innerExpr);
|
||||
}
|
||||
return str + parameters.join(', ') + ')';
|
||||
}
|
||||
|
||||
function aliasRenderer(part, innerExpr) {
|
||||
return innerExpr + ' AS ' + '"' + part.params[0] + '"';
|
||||
}
|
||||
|
||||
function suffixRenderer(part, innerExpr) {
|
||||
return innerExpr + ' ' + part.params[0];
|
||||
}
|
||||
|
||||
function identityRenderer(part, innerExpr) {
|
||||
return part.params[0];
|
||||
}
|
||||
|
||||
function quotedIdentityRenderer(part, innerExpr) {
|
||||
return '"' + part.params[0] + '"';
|
||||
}
|
||||
|
||||
QueryPartDef.register({
|
||||
name: 'mean',
|
||||
category: categories.Transform,
|
||||
params: [],
|
||||
defaultParams: [],
|
||||
params: [{type: 'field', quote: 'double'}],
|
||||
defaultParams: ['value'],
|
||||
renderer: functionRenderer,
|
||||
});
|
||||
|
||||
QueryPartDef.register({
|
||||
name: 'derivate',
|
||||
name: 'derivative',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "rate", type: "interval", options: ['1s', '10s', '1m', '5min', '10m', '15m', '1h'] }],
|
||||
params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5min', '10m', '15m', '1h']}],
|
||||
defaultParams: ['10s'],
|
||||
renderer: functionRenderer,
|
||||
});
|
||||
|
||||
QueryPartDef.register({
|
||||
@ -53,6 +85,7 @@ QueryPartDef.register({
|
||||
category: categories.Transform,
|
||||
params: [{ name: "rate", type: "interval", options: ['$interval', '1s', '10s', '1m', '5min', '10m', '15m', '1h'] }],
|
||||
defaultParams: ['$interval'],
|
||||
renderer: functionRenderer,
|
||||
});
|
||||
|
||||
QueryPartDef.register({
|
||||
@ -60,13 +93,16 @@ QueryPartDef.register({
|
||||
category: categories.Transform,
|
||||
params: [{ name: "expr", type: "string"}],
|
||||
defaultParams: [' / 100'],
|
||||
renderer: suffixRenderer,
|
||||
});
|
||||
|
||||
QueryPartDef.register({
|
||||
name: 'alias',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "name", type: "string"}],
|
||||
params: [{ name: "name", type: "string", quote: 'double'}],
|
||||
defaultParams: ['alias'],
|
||||
renderMode: 'suffix',
|
||||
renderer: aliasRenderer,
|
||||
});
|
||||
|
||||
class QueryPart {
|
||||
@ -83,29 +119,11 @@ class QueryPart {
|
||||
}
|
||||
|
||||
this.params = part.params || _.clone(this.def.defaultParams);
|
||||
this.updateText();
|
||||
}
|
||||
|
||||
render(innerExpr: string) {
|
||||
var str = this.def.name + '(';
|
||||
var parameters = _.map(this.params, (value, index) => {
|
||||
|
||||
var paramType = this.def.params[index].type;
|
||||
if (paramType === 'int' || paramType === 'value_or_series' || paramType === 'boolean') {
|
||||
return value;
|
||||
}
|
||||
else if (paramType === 'int_or_interval' && _.isNumber(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return "'" + value + "'";
|
||||
|
||||
});
|
||||
|
||||
if (innerExpr) {
|
||||
parameters.unshift(innerExpr);
|
||||
}
|
||||
|
||||
return str + parameters.join(', ') + ')';
|
||||
return this.def.renderer(this, innerExpr);
|
||||
}
|
||||
|
||||
hasMultipleParamsInString (strValue, index) {
|
||||
|
@ -0,0 +1,36 @@
|
||||
import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
|
||||
|
||||
import InfluxQuery = require('../influx_query');
|
||||
|
||||
describe.only('InfluxQuery', function() {
|
||||
|
||||
describe('series with mesurement only', function() {
|
||||
it('should generate correct query', function() {
|
||||
var query = new InfluxQuery({
|
||||
measurement: 'cpu',
|
||||
});
|
||||
|
||||
var queryText = query.render();
|
||||
expect(queryText).to.be('SELECT mean("value") FROM "cpu" WHERE $timeFilter GROUP BY time($interval)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('series with math and alias', function() {
|
||||
it('should generate correct query', function() {
|
||||
var query = new InfluxQuery({
|
||||
measurement: 'cpu',
|
||||
select: [
|
||||
[
|
||||
{name: 'mean', params: ['value']},
|
||||
{name: 'math', params: ['/100']},
|
||||
{name: 'alias', params: ['text']},
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
var queryText = query.render();
|
||||
expect(queryText).to.be('SELECT mean("value") /100 AS "text" FROM "cpu" WHERE $timeFilter GROUP BY time($interval)');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -9,8 +9,8 @@ describe('InfluxQueryBuilder', function() {
|
||||
describe('series with mesurement only', function() {
|
||||
it('should generate correct query', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}]
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}]
|
||||
});
|
||||
|
||||
var query = builder.build();
|
||||
@ -22,9 +22,9 @@ describe('InfluxQueryBuilder', function() {
|
||||
describe('series with math expr and as expr', function() {
|
||||
it('should generate correct query', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
fields: [{name: 'test', func: 'max', mathExpr: '*2', asExpr: 'new_name'}],
|
||||
groupBy: [{type: 'time', interval: 'auto'}]
|
||||
measurement: 'cpu',
|
||||
fields: [{name: 'test', func: 'max', mathExpr: '*2', asExpr: 'new_name'}],
|
||||
groupBy: [{type: 'time', interval: 'auto'}]
|
||||
});
|
||||
|
||||
var query = builder.build();
|
||||
@ -36,22 +36,22 @@ describe('InfluxQueryBuilder', function() {
|
||||
describe('series with single tag only', function() {
|
||||
it('should generate correct query', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
tags: [{key: 'hostname', value: 'server1'}]
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
tags: [{key: 'hostname', value: 'server1'}]
|
||||
});
|
||||
|
||||
var query = builder.build();
|
||||
|
||||
expect(query).to.be('SELECT mean("value") AS "value" FROM "cpu" WHERE "hostname" = \'server1\' AND $timeFilter'
|
||||
+ ' GROUP BY time($interval)');
|
||||
+ ' GROUP BY time($interval)');
|
||||
});
|
||||
|
||||
it('should switch regex operator with tag value is regex', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
tags: [{key: 'app', value: '/e.*/'}]
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
tags: [{key: 'app', value: '/e.*/'}]
|
||||
});
|
||||
|
||||
var query = builder.build();
|
||||
@ -62,57 +62,57 @@ describe('InfluxQueryBuilder', function() {
|
||||
describe('series with multiple fields', function() {
|
||||
it('should generate correct query', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
tags: [],
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
fields: [{ name: 'tx_in', func: 'sum' }, { name: 'tx_out', func: 'mean' }]
|
||||
measurement: 'cpu',
|
||||
tags: [],
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
fields: [{ name: 'tx_in', func: 'sum' }, { name: 'tx_out', func: 'mean' }]
|
||||
});
|
||||
|
||||
var query = builder.build();
|
||||
expect(query).to.be('SELECT sum("tx_in") AS "tx_in", mean("tx_out") AS "tx_out" ' +
|
||||
'FROM "cpu" WHERE $timeFilter GROUP BY time($interval)');
|
||||
'FROM "cpu" WHERE $timeFilter GROUP BY time($interval)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('series with multiple tags only', function() {
|
||||
it('should generate correct query', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
tags: [{key: 'hostname', value: 'server1'}, {key: 'app', value: 'email', condition: "AND"}]
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
tags: [{key: 'hostname', value: 'server1'}, {key: 'app', value: 'email', condition: "AND"}]
|
||||
});
|
||||
|
||||
var query = builder.build();
|
||||
expect(query).to.be('SELECT mean("value") AS "value" FROM "cpu" WHERE "hostname" = \'server1\' AND "app" = \'email\' AND ' +
|
||||
'$timeFilter GROUP BY time($interval)');
|
||||
'$timeFilter GROUP BY time($interval)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('series with tags OR condition', function() {
|
||||
it('should generate correct query', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
tags: [{key: 'hostname', value: 'server1'}, {key: 'hostname', value: 'server2', condition: "OR"}]
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', interval: 'auto'}],
|
||||
tags: [{key: 'hostname', value: 'server1'}, {key: 'hostname', value: 'server2', condition: "OR"}]
|
||||
});
|
||||
|
||||
var query = builder.build();
|
||||
expect(query).to.be('SELECT mean("value") AS "value" FROM "cpu" WHERE "hostname" = \'server1\' OR "hostname" = \'server2\' AND ' +
|
||||
'$timeFilter GROUP BY time($interval)');
|
||||
'$timeFilter GROUP BY time($interval)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('series with groupByTag', function() {
|
||||
it('should generate correct query', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
tags: [],
|
||||
groupBy: [{type: 'time', interval: 'auto'}, {type: 'tag', key: 'host'}],
|
||||
measurement: 'cpu',
|
||||
tags: [],
|
||||
groupBy: [{type: 'time', interval: 'auto'}, {type: 'tag', key: 'host'}],
|
||||
});
|
||||
|
||||
var query = builder.build();
|
||||
expect(query).to.be('SELECT mean("value") AS "value" FROM "cpu" WHERE $timeFilter ' +
|
||||
'GROUP BY time($interval), "host"');
|
||||
'GROUP BY time($interval), "host"');
|
||||
});
|
||||
});
|
||||
|
||||
@ -126,8 +126,7 @@ describe('InfluxQueryBuilder', function() {
|
||||
|
||||
it('should handle regex measurement in tag keys query', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: '/.*/',
|
||||
tags: []
|
||||
measurement: '/.*/', tags: []
|
||||
});
|
||||
var query = builder.buildExploreQuery('TAG_KEYS');
|
||||
expect(query).to.be('SHOW TAG KEYS FROM /.*/');
|
||||
@ -170,7 +169,10 @@ describe('InfluxQueryBuilder', function() {
|
||||
});
|
||||
|
||||
it('should switch to regex operator in tag condition', function() {
|
||||
var builder = new InfluxQueryBuilder({measurement: 'cpu', tags: [{key: 'host', value: '/server.*/'}]});
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
tags: [{key: 'host', value: '/server.*/'}]
|
||||
});
|
||||
var query = builder.buildExploreQuery('TAG_VALUES', 'app');
|
||||
expect(query).to.be('SHOW TAG VALUES FROM "cpu" WITH KEY = "app" WHERE "host" =~ /server.*/');
|
||||
});
|
||||
|
@ -0,0 +1,41 @@
|
||||
|
||||
import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
|
||||
|
||||
import queryPart = require('../query_part');
|
||||
|
||||
describe('InfluxQueryBuilder', () => {
|
||||
|
||||
describe('series with mesurement only', () => {
|
||||
it('should handle nested function parts', () => {
|
||||
var part = queryPart.create({
|
||||
name: 'derivative',
|
||||
params: ['10s'],
|
||||
});
|
||||
|
||||
expect(part.text).to.be('derivative(10s)');
|
||||
expect(part.render('mean(value)')).to.be('derivative(mean(value), 10s)');
|
||||
});
|
||||
|
||||
it('should handle suffirx parts', () => {
|
||||
var part = queryPart.create({
|
||||
name: 'math',
|
||||
params: ['/ 100'],
|
||||
});
|
||||
|
||||
expect(part.text).to.be('math(/ 100)');
|
||||
expect(part.render('mean(value)')).to.be('mean(value) / 100');
|
||||
});
|
||||
|
||||
it('should handle alias parts', () => {
|
||||
var part = queryPart.create({
|
||||
name: 'alias',
|
||||
params: ['test'],
|
||||
});
|
||||
|
||||
expect(part.text).to.be('alias(test)');
|
||||
expect(part.render('mean(value)')).to.be('mean(value) AS "test"');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user