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:
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 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">
|
<ul class="tight-form-list">
|
||||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
||||||
<span ng-show="$index === 0">SELECT</span>
|
<span ng-show="$index === 0">SELECT</span>
|
||||||
@@ -85,13 +85,13 @@
|
|||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</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">
|
<ul class="tight-form-list">
|
||||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
||||||
<span ng-show="$index === 0">GROUP BY</span>
|
<span ng-show="$index === 0">GROUP BY</span>
|
||||||
</li>
|
</li>
|
||||||
<li ng-if="groupBy.type === 'time'">
|
<li>
|
||||||
<influx-query-part-editor part="groupByParts" class="tight-form-item tight-form-func"></influx-query-part-editor>
|
<influx-query-part-editor part="part" class="tight-form-item tight-form-func"></influx-query-part-editor>
|
||||||
</li>
|
</li>
|
||||||
<!-- <li class="dropdown" ng-if="groupBy.type === 'time'"> -->
|
<!-- <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"> -->
|
<!-- <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 (_) {
|
function (_) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function InfluxQueryBuilder(target) {
|
function InfluxQueryBuilder(target, queryModel) {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
this.model = queryModel;
|
||||||
|
|
||||||
if (target.groupByTags) {
|
if (target.groupByTags) {
|
||||||
target.groupBy = [{type: 'time', interval: 'auto'}];
|
target.groupBy = [{type: 'time', interval: 'auto'}];
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ define([
|
|||||||
'angular',
|
'angular',
|
||||||
'lodash',
|
'lodash',
|
||||||
'./query_builder',
|
'./query_builder',
|
||||||
'./query_part',
|
'./influx_query',
|
||||||
'./query_part_editor',
|
'./query_part_editor',
|
||||||
],
|
],
|
||||||
function (angular, _, InfluxQueryBuilder, queryPart) {
|
function (angular, _, InfluxQueryBuilder, InfluxQuery) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
var module = angular.module('grafana.controllers');
|
||||||
@@ -15,29 +15,18 @@ function (angular, _, InfluxQueryBuilder, queryPart) {
|
|||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
if (!$scope.target) { return; }
|
if (!$scope.target) { return; }
|
||||||
|
|
||||||
var target = $scope.target;
|
$scope.target = $scope.target;
|
||||||
target.tags = target.tags || [];
|
$scope.queryModel = new InfluxQuery($scope.target);
|
||||||
target.groupBy = target.groupBy || [{type: 'time', interval: 'auto'}];
|
$scope.queryBuilder = new InfluxQueryBuilder($scope.target);
|
||||||
target.fields = target.fields || [{name: 'value'}];
|
|
||||||
target.select = target.select || [[
|
|
||||||
{name: 'field', params: ['value']},
|
|
||||||
{name: 'mean', params: []},
|
|
||||||
]];
|
|
||||||
|
|
||||||
$scope.updateSelectParts();
|
if (!$scope.target.measurement) {
|
||||||
|
|
||||||
$scope.groupByParts = queryPart.create({name: 'time', params:['$interval']});
|
|
||||||
|
|
||||||
$scope.queryBuilder = new InfluxQueryBuilder(target);
|
|
||||||
|
|
||||||
if (!target.measurement) {
|
|
||||||
$scope.measurementSegment = uiSegmentSrv.newSelectMeasurement();
|
$scope.measurementSegment = uiSegmentSrv.newSelectMeasurement();
|
||||||
} else {
|
} else {
|
||||||
$scope.measurementSegment = uiSegmentSrv.newSegment(target.measurement);
|
$scope.measurementSegment = uiSegmentSrv.newSegment($scope.target.measurement);
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.tagSegments = [];
|
$scope.tagSegments = [];
|
||||||
_.each(target.tags, function(tag) {
|
_.each($scope.target.tags, function(tag) {
|
||||||
if (!tag.operator) {
|
if (!tag.operator) {
|
||||||
if (/^\/.*\/$/.test(tag.value)) {
|
if (/^\/.*\/$/.test(tag.value)) {
|
||||||
tag.operator = "=~";
|
tag.operator = "=~";
|
||||||
@@ -78,32 +67,14 @@ function (angular, _, InfluxQueryBuilder, queryPart) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.addSelect = function() {
|
$scope.addSelect = function() {
|
||||||
$scope.target.select.push([
|
$scope.queryModel.addSelect();
|
||||||
{name: 'field', params: ['value']},
|
|
||||||
{name: 'mean', params: []},
|
|
||||||
]);
|
|
||||||
$scope.updateSelectParts();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.removeSelect = function(index) {
|
$scope.removeSelect = function(index) {
|
||||||
$scope.target.select.splice(index, 1);
|
$scope.queryModel.removeSelect(index);
|
||||||
$scope.updateSelectParts();
|
|
||||||
$scope.get_data();
|
$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.measurementChanged = function() {
|
||||||
$scope.target.measurement = $scope.measurementSegment.value;
|
$scope.target.measurement = $scope.measurementSegment.value;
|
||||||
$scope.$parent.get_data();
|
$scope.$parent.get_data();
|
||||||
@@ -125,22 +96,6 @@ function (angular, _, InfluxQueryBuilder, queryPart) {
|
|||||||
.then($scope.transformToSegments(true), $scope.handleQueryError);
|
.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.handleQueryError = function(err) {
|
||||||
$scope.parserError = err.message || 'Failed to issue metric query';
|
$scope.parserError = err.message || 'Failed to issue metric query';
|
||||||
return [];
|
return [];
|
||||||
@@ -202,18 +157,6 @@ function (angular, _, InfluxQueryBuilder, queryPart) {
|
|||||||
.then(null, $scope.handleQueryError);
|
.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() {
|
$scope.getTagOptions = function() {
|
||||||
var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
|
var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,13 @@ class QueryPartDef {
|
|||||||
name: string;
|
name: string;
|
||||||
params: any[];
|
params: any[];
|
||||||
defaultParams: any[];
|
defaultParams: any[];
|
||||||
|
renderer: any;
|
||||||
|
|
||||||
constructor(options: any) {
|
constructor(options: any) {
|
||||||
this.name = options.name;
|
this.name = options.name;
|
||||||
this.params = options.params;
|
this.params = options.params;
|
||||||
this.defaultParams = options.defaultParams;
|
this.defaultParams = options.defaultParams;
|
||||||
|
this.renderer = options.renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static register(options: any) {
|
static register(options: any) {
|
||||||
@@ -27,25 +29,55 @@ class QueryPartDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryPartDef.register({
|
function functionRenderer(part, innerExpr) {
|
||||||
name: 'field',
|
var str = part.def.name + '(';
|
||||||
category: categories.Transform,
|
var parameters = _.map(part.params, (value, index) => {
|
||||||
params: [{type: 'field'}],
|
var paramType = part.def.params[index];
|
||||||
defaultParams: ['value'],
|
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({
|
QueryPartDef.register({
|
||||||
name: 'mean',
|
name: 'mean',
|
||||||
category: categories.Transform,
|
category: categories.Transform,
|
||||||
params: [],
|
params: [{type: 'field', quote: 'double'}],
|
||||||
defaultParams: [],
|
defaultParams: ['value'],
|
||||||
|
renderer: functionRenderer,
|
||||||
});
|
});
|
||||||
|
|
||||||
QueryPartDef.register({
|
QueryPartDef.register({
|
||||||
name: 'derivate',
|
name: 'derivative',
|
||||||
category: categories.Transform,
|
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'],
|
defaultParams: ['10s'],
|
||||||
|
renderer: functionRenderer,
|
||||||
});
|
});
|
||||||
|
|
||||||
QueryPartDef.register({
|
QueryPartDef.register({
|
||||||
@@ -53,6 +85,7 @@ QueryPartDef.register({
|
|||||||
category: categories.Transform,
|
category: categories.Transform,
|
||||||
params: [{ name: "rate", type: "interval", options: ['$interval', '1s', '10s', '1m', '5min', '10m', '15m', '1h'] }],
|
params: [{ name: "rate", type: "interval", options: ['$interval', '1s', '10s', '1m', '5min', '10m', '15m', '1h'] }],
|
||||||
defaultParams: ['$interval'],
|
defaultParams: ['$interval'],
|
||||||
|
renderer: functionRenderer,
|
||||||
});
|
});
|
||||||
|
|
||||||
QueryPartDef.register({
|
QueryPartDef.register({
|
||||||
@@ -60,13 +93,16 @@ QueryPartDef.register({
|
|||||||
category: categories.Transform,
|
category: categories.Transform,
|
||||||
params: [{ name: "expr", type: "string"}],
|
params: [{ name: "expr", type: "string"}],
|
||||||
defaultParams: [' / 100'],
|
defaultParams: [' / 100'],
|
||||||
|
renderer: suffixRenderer,
|
||||||
});
|
});
|
||||||
|
|
||||||
QueryPartDef.register({
|
QueryPartDef.register({
|
||||||
name: 'alias',
|
name: 'alias',
|
||||||
category: categories.Transform,
|
category: categories.Transform,
|
||||||
params: [{ name: "name", type: "string"}],
|
params: [{ name: "name", type: "string", quote: 'double'}],
|
||||||
defaultParams: ['alias'],
|
defaultParams: ['alias'],
|
||||||
|
renderMode: 'suffix',
|
||||||
|
renderer: aliasRenderer,
|
||||||
});
|
});
|
||||||
|
|
||||||
class QueryPart {
|
class QueryPart {
|
||||||
@@ -83,29 +119,11 @@ class QueryPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.params = part.params || _.clone(this.def.defaultParams);
|
this.params = part.params || _.clone(this.def.defaultParams);
|
||||||
|
this.updateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
render(innerExpr: string) {
|
render(innerExpr: string) {
|
||||||
var str = this.def.name + '(';
|
return this.def.renderer(this, innerExpr);
|
||||||
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(', ') + ')';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasMultipleParamsInString (strValue, index) {
|
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() {
|
describe('series with mesurement only', function() {
|
||||||
it('should generate correct query', function() {
|
it('should generate correct query', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
var builder = new InfluxQueryBuilder({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
groupBy: [{type: 'time', interval: 'auto'}]
|
groupBy: [{type: 'time', interval: 'auto'}]
|
||||||
});
|
});
|
||||||
|
|
||||||
var query = builder.build();
|
var query = builder.build();
|
||||||
@@ -22,9 +22,9 @@ describe('InfluxQueryBuilder', function() {
|
|||||||
describe('series with math expr and as expr', function() {
|
describe('series with math expr and as expr', function() {
|
||||||
it('should generate correct query', function() {
|
it('should generate correct query', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
var builder = new InfluxQueryBuilder({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
fields: [{name: 'test', func: 'max', mathExpr: '*2', asExpr: 'new_name'}],
|
fields: [{name: 'test', func: 'max', mathExpr: '*2', asExpr: 'new_name'}],
|
||||||
groupBy: [{type: 'time', interval: 'auto'}]
|
groupBy: [{type: 'time', interval: 'auto'}]
|
||||||
});
|
});
|
||||||
|
|
||||||
var query = builder.build();
|
var query = builder.build();
|
||||||
@@ -36,22 +36,22 @@ describe('InfluxQueryBuilder', function() {
|
|||||||
describe('series with single tag only', function() {
|
describe('series with single tag only', function() {
|
||||||
it('should generate correct query', function() {
|
it('should generate correct query', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
var builder = new InfluxQueryBuilder({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
groupBy: [{type: 'time', interval: 'auto'}],
|
groupBy: [{type: 'time', interval: 'auto'}],
|
||||||
tags: [{key: 'hostname', value: 'server1'}]
|
tags: [{key: 'hostname', value: 'server1'}]
|
||||||
});
|
});
|
||||||
|
|
||||||
var query = builder.build();
|
var query = builder.build();
|
||||||
|
|
||||||
expect(query).to.be('SELECT mean("value") AS "value" FROM "cpu" WHERE "hostname" = \'server1\' AND $timeFilter'
|
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() {
|
it('should switch regex operator with tag value is regex', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
var builder = new InfluxQueryBuilder({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
groupBy: [{type: 'time', interval: 'auto'}],
|
groupBy: [{type: 'time', interval: 'auto'}],
|
||||||
tags: [{key: 'app', value: '/e.*/'}]
|
tags: [{key: 'app', value: '/e.*/'}]
|
||||||
});
|
});
|
||||||
|
|
||||||
var query = builder.build();
|
var query = builder.build();
|
||||||
@@ -62,57 +62,57 @@ describe('InfluxQueryBuilder', function() {
|
|||||||
describe('series with multiple fields', function() {
|
describe('series with multiple fields', function() {
|
||||||
it('should generate correct query', function() {
|
it('should generate correct query', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
var builder = new InfluxQueryBuilder({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
tags: [],
|
tags: [],
|
||||||
groupBy: [{type: 'time', interval: 'auto'}],
|
groupBy: [{type: 'time', interval: 'auto'}],
|
||||||
fields: [{ name: 'tx_in', func: 'sum' }, { name: 'tx_out', func: 'mean' }]
|
fields: [{ name: 'tx_in', func: 'sum' }, { name: 'tx_out', func: 'mean' }]
|
||||||
});
|
});
|
||||||
|
|
||||||
var query = builder.build();
|
var query = builder.build();
|
||||||
expect(query).to.be('SELECT sum("tx_in") AS "tx_in", mean("tx_out") AS "tx_out" ' +
|
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() {
|
describe('series with multiple tags only', function() {
|
||||||
it('should generate correct query', function() {
|
it('should generate correct query', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
var builder = new InfluxQueryBuilder({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
groupBy: [{type: 'time', interval: 'auto'}],
|
groupBy: [{type: 'time', interval: 'auto'}],
|
||||||
tags: [{key: 'hostname', value: 'server1'}, {key: 'app', value: 'email', condition: "AND"}]
|
tags: [{key: 'hostname', value: 'server1'}, {key: 'app', value: 'email', condition: "AND"}]
|
||||||
});
|
});
|
||||||
|
|
||||||
var query = builder.build();
|
var query = builder.build();
|
||||||
expect(query).to.be('SELECT mean("value") AS "value" FROM "cpu" WHERE "hostname" = \'server1\' AND "app" = \'email\' AND ' +
|
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() {
|
describe('series with tags OR condition', function() {
|
||||||
it('should generate correct query', function() {
|
it('should generate correct query', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
var builder = new InfluxQueryBuilder({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
groupBy: [{type: 'time', interval: 'auto'}],
|
groupBy: [{type: 'time', interval: 'auto'}],
|
||||||
tags: [{key: 'hostname', value: 'server1'}, {key: 'hostname', value: 'server2', condition: "OR"}]
|
tags: [{key: 'hostname', value: 'server1'}, {key: 'hostname', value: 'server2', condition: "OR"}]
|
||||||
});
|
});
|
||||||
|
|
||||||
var query = builder.build();
|
var query = builder.build();
|
||||||
expect(query).to.be('SELECT mean("value") AS "value" FROM "cpu" WHERE "hostname" = \'server1\' OR "hostname" = \'server2\' AND ' +
|
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() {
|
describe('series with groupByTag', function() {
|
||||||
it('should generate correct query', function() {
|
it('should generate correct query', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
var builder = new InfluxQueryBuilder({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
tags: [],
|
tags: [],
|
||||||
groupBy: [{type: 'time', interval: 'auto'}, {type: 'tag', key: 'host'}],
|
groupBy: [{type: 'time', interval: 'auto'}, {type: 'tag', key: 'host'}],
|
||||||
});
|
});
|
||||||
|
|
||||||
var query = builder.build();
|
var query = builder.build();
|
||||||
expect(query).to.be('SELECT mean("value") AS "value" FROM "cpu" WHERE $timeFilter ' +
|
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() {
|
it('should handle regex measurement in tag keys query', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
var builder = new InfluxQueryBuilder({
|
||||||
measurement: '/.*/',
|
measurement: '/.*/', tags: []
|
||||||
tags: []
|
|
||||||
});
|
});
|
||||||
var query = builder.buildExploreQuery('TAG_KEYS');
|
var query = builder.buildExploreQuery('TAG_KEYS');
|
||||||
expect(query).to.be('SHOW TAG KEYS FROM /.*/');
|
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() {
|
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');
|
var query = builder.buildExploreQuery('TAG_VALUES', 'app');
|
||||||
expect(query).to.be('SHOW TAG VALUES FROM "cpu" WITH KEY = "app" WHERE "host" =~ /server.*/');
|
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"');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user