mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(influxdb): query editor is starting to work, can now add group by parts
This commit is contained in:
@@ -16,22 +16,20 @@ class InfluxQuery {
|
|||||||
this.target = target;
|
this.target = target;
|
||||||
|
|
||||||
target.tags = target.tags || [];
|
target.tags = target.tags || [];
|
||||||
target.groupBy = target.groupBy || [{type: 'time', interval: 'auto'}];
|
target.groupBy = target.groupBy || [{type: 'time', params: ['$interval']}];
|
||||||
target.select = target.select || [[
|
target.select = target.select || [[
|
||||||
{type: 'field', params: ['value']},
|
{type: 'field', params: ['value']},
|
||||||
{type: 'mean', params: []},
|
{type: 'mean', params: []},
|
||||||
]];
|
]];
|
||||||
|
|
||||||
this.updateSelectParts();
|
this.updateProjection();
|
||||||
this.groupByParts = [
|
|
||||||
queryPart.create({type: 'time', params: ['$interval']})
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSelectParts() {
|
updateProjection() {
|
||||||
this.selectModels = _.map(this.target.select, function(parts: any) {
|
this.selectModels = _.map(this.target.select, function(parts: any) {
|
||||||
return _.map(parts, queryPart.create);
|
return _.map(parts, queryPart.create);
|
||||||
});
|
});
|
||||||
|
this.groupByParts = _.map(this.target.groupBy, queryPart.create);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePersistedParts() {
|
updatePersistedParts() {
|
||||||
@@ -42,9 +40,32 @@ class InfluxQuery {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasGroupByTime() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasFill() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
addGroupBy(value) {
|
||||||
|
var stringParts = value.match(/^(\w+)\((.*)\)$/);
|
||||||
|
var typePart = stringParts[1];
|
||||||
|
var arg = stringParts[2];
|
||||||
|
console.log(value, stringParts);
|
||||||
|
var partModel = queryPart.create({type: typePart, params: [arg]});
|
||||||
|
this.target.groupBy.push(partModel.part);
|
||||||
|
this.updateProjection();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeGroupByPart(part, index) {
|
||||||
|
this.target.groupBy.splice(index, 1);
|
||||||
|
this.updateProjection();
|
||||||
|
}
|
||||||
|
|
||||||
removeSelect(index: number) {
|
removeSelect(index: number) {
|
||||||
this.target.select.splice(index, 1);
|
this.target.select.splice(index, 1);
|
||||||
this.updateSelectParts();
|
this.updateProjection();
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSelectPart(selectParts, part) {
|
removeSelectPart(selectParts, part) {
|
||||||
@@ -139,14 +160,13 @@ class InfluxQuery {
|
|||||||
query += conditions.join(' ');
|
query += conditions.join(' ');
|
||||||
query += (conditions.length > 0 ? ' AND ' : '') + '$timeFilter';
|
query += (conditions.length > 0 ? ' AND ' : '') + '$timeFilter';
|
||||||
|
|
||||||
query += ' GROUP BY';
|
query += ' GROUP BY ';
|
||||||
for (i = 0; i < target.groupBy.length; i++) {
|
for (i = 0; i < this.groupByParts.length; i++) {
|
||||||
var group = target.groupBy[i];
|
var part = this.groupByParts[i];
|
||||||
if (group.type === 'time') {
|
if (i > 0) {
|
||||||
query += ' time(' + this.getGroupByTimeInterval(group.interval) + ')';
|
query += ', ';
|
||||||
} else {
|
|
||||||
query += ', "' + group.key + '"';
|
|
||||||
}
|
}
|
||||||
|
query += part.render('');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.fill) {
|
if (target.fill) {
|
||||||
|
|||||||
@@ -73,24 +73,22 @@
|
|||||||
<li ng-repeat="part in selectParts">
|
<li ng-repeat="part in selectParts">
|
||||||
<influx-query-part-editor part="part" class="tight-form-item tight-form-func" remove-action="removeSelectPart(selectParts, part)" part-updated="selectPartUpdated(selectParts, part)"></influx-query-part-editor>
|
<influx-query-part-editor part="part" class="tight-form-item tight-form-func" remove-action="removeSelectPart(selectParts, part)" part-updated="selectPartUpdated(selectParts, part)"></influx-query-part-editor>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<metric-segment segment="selectPlusButton" get-options="getSelectOptions(selectParts)" on-change="selectAction(selectParts, $index)"></metric-segment>
|
|
||||||
</li>
|
|
||||||
<li class="dropdown" dropdown-typeahead="selectMenu" dropdown-typeahead-on-select="addSelectPart(selectParts, $item, $subItem)">
|
<li class="dropdown" dropdown-typeahead="selectMenu" dropdown-typeahead-on-select="addSelectPart(selectParts, $item, $subItem)">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tight-form" ng-repeat="part in queryModel.groupByParts">
|
<div class="tight-form">
|
||||||
<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>
|
<li ng-repeat="part in queryModel.groupByParts">
|
||||||
<influx-query-part-editor part="part" class="tight-form-item tight-form-func"></influx-query-part-editor>
|
<influx-query-part-editor part="part" class="tight-form-item tight-form-func" remove-action="removeGroupByPart(part, $index)" part-updated="get_data();"></influx-query-part-editor>
|
||||||
</li>
|
</li>
|
||||||
<li class="dropdown" dropdown-typeahead="groupByMenu" dropdown-typeahead-on-select="groupByMenuAction(parts, $item, $subItem)">
|
<li>
|
||||||
|
<metric-segment segment="groupBySegment" get-options="getGroupByOptions()" on-change="groupByAction(part, $index)"></metric-segment>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ function (angular, _, InfluxQueryBuilder, InfluxQuery, queryPart) {
|
|||||||
$scope.target = $scope.target;
|
$scope.target = $scope.target;
|
||||||
$scope.queryModel = new InfluxQuery($scope.target);
|
$scope.queryModel = new InfluxQuery($scope.target);
|
||||||
$scope.queryBuilder = new InfluxQueryBuilder($scope.target);
|
$scope.queryBuilder = new InfluxQueryBuilder($scope.target);
|
||||||
|
$scope.groupBySegment = uiSegmentSrv.newPlusButton();
|
||||||
|
|
||||||
if (!$scope.target.measurement) {
|
if (!$scope.target.measurement) {
|
||||||
$scope.measurementSegment = uiSegmentSrv.newSelectMeasurement();
|
$scope.measurementSegment = uiSegmentSrv.newSelectMeasurement();
|
||||||
@@ -60,16 +61,39 @@ function (angular, _, InfluxQueryBuilder, InfluxQuery, queryPart) {
|
|||||||
memo.push(menu);
|
memo.push(menu);
|
||||||
return memo;
|
return memo;
|
||||||
}, []);
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.groupByMenu = _.reduce(categories, function(memo, cat, key) {
|
$scope.getGroupByOptions = function() {
|
||||||
var menu = {text: key};
|
var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
|
||||||
menu.submenu = _.map(cat, function(item) {
|
|
||||||
return {text: item.type, value: item.type};
|
return $scope.datasource.metricFindQuery(query)
|
||||||
|
.then(function(tags) {
|
||||||
|
var options = [];
|
||||||
|
if (!$scope.queryModel.hasFill()) {
|
||||||
|
options.push(uiSegmentSrv.newSegment({value: 'fill(option)'}));
|
||||||
|
}
|
||||||
|
if (!$scope.queryModel.hasGroupByTime()) {
|
||||||
|
options.push(uiSegmentSrv.newSegment({value: 'time($interval)'}));
|
||||||
|
}
|
||||||
|
_.each(tags, function(tag) {
|
||||||
|
options.push(uiSegmentSrv.newSegment({value: 'tag(' + tag.text + ')'}));
|
||||||
});
|
});
|
||||||
memo.push(menu);
|
return options;
|
||||||
return memo;
|
})
|
||||||
}, []);
|
.then(null, $scope.handleQueryError);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.groupByAction = function() {
|
||||||
|
$scope.queryModel.addGroupBy($scope.groupBySegment.value);
|
||||||
|
var plusButton = uiSegmentSrv.newPlusButton();
|
||||||
|
$scope.groupBySegment.value = plusButton.value;
|
||||||
|
$scope.groupBySegment.html = plusButton.html;
|
||||||
|
$scope.get_data();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.removeGroupByPart = function(part, index) {
|
||||||
|
$scope.queryModel.removeGroupByPart(part, index);
|
||||||
|
$scope.get_data();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.addSelectPart = function(selectParts, cat, subitem) {
|
$scope.addSelectPart = function(selectParts, cat, subitem) {
|
||||||
@@ -178,12 +202,7 @@ function (angular, _, InfluxQueryBuilder, InfluxQuery, queryPart) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.getTagOptions = function() {
|
$scope.getTagOptions = function() {
|
||||||
var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
|
};
|
||||||
|
|
||||||
return $scope.datasource.metricFindQuery(query)
|
|
||||||
.then($scope.transformToSegments(false))
|
|
||||||
.then(null, $scope.handleQueryError);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.setFill = function(fill) {
|
$scope.setFill = function(fill) {
|
||||||
$scope.target.fill = fill;
|
$scope.target.fill = fill;
|
||||||
|
|||||||
@@ -184,6 +184,14 @@ QueryPartDef.register({
|
|||||||
renderer: functionRenderer,
|
renderer: functionRenderer,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QueryPartDef.register({
|
||||||
|
type: 'tag',
|
||||||
|
category: groupByTimeFunctions,
|
||||||
|
params: [{name: 'tag', type: 'string'}],
|
||||||
|
defaultParams: ['tag'],
|
||||||
|
renderer: quotedIdentityRenderer,
|
||||||
|
});
|
||||||
|
|
||||||
QueryPartDef.register({
|
QueryPartDef.register({
|
||||||
type: 'math',
|
type: 'math',
|
||||||
addStrategy: addMathStrategy,
|
addStrategy: addMathStrategy,
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ describe.only('InfluxQuery', function() {
|
|||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
select: [
|
select: [
|
||||||
[
|
[
|
||||||
{name: 'field', params: ['value']},
|
{type: 'field', params: ['value']},
|
||||||
{name: 'mean', params: []},
|
{type: 'mean', params: []},
|
||||||
{name: 'math', params: ['/100']},
|
{type: 'math', params: ['/100']},
|
||||||
{name: 'alias', params: ['text']},
|
{type: 'alias', params: ['text']},
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@@ -39,56 +39,56 @@ describe.only('InfluxQuery', function() {
|
|||||||
it('should add mean after after field', function() {
|
it('should add mean after after field', function() {
|
||||||
var query = new InfluxQuery({
|
var query = new InfluxQuery({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
select: [[{name: 'field', params: ['value']}]]
|
select: [[{type: 'field', params: ['value']}]]
|
||||||
});
|
});
|
||||||
|
|
||||||
query.addSelectPart(query.selectModels[0], 'mean');
|
query.addSelectPart(query.selectModels[0], 'mean');
|
||||||
expect(query.target.select[0].length).to.be(2);
|
expect(query.target.select[0].length).to.be(2);
|
||||||
expect(query.target.select[0][1].name).to.be('mean');
|
expect(query.target.select[0][1].type).to.be('mean');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should replace sum by mean', function() {
|
it('should replace sum by mean', function() {
|
||||||
var query = new InfluxQuery({
|
var query = new InfluxQuery({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
select: [[{name: 'field', params: ['value']}, {name: 'mean'}]]
|
select: [[{type: 'field', params: ['value']}, {type: 'mean'}]]
|
||||||
});
|
});
|
||||||
|
|
||||||
query.addSelectPart(query.selectModels[0], 'sum');
|
query.addSelectPart(query.selectModels[0], 'sum');
|
||||||
expect(query.target.select[0].length).to.be(2);
|
expect(query.target.select[0].length).to.be(2);
|
||||||
expect(query.target.select[0][1].name).to.be('sum');
|
expect(query.target.select[0][1].type).to.be('sum');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add math before alias', function() {
|
it('should add math before alias', function() {
|
||||||
var query = new InfluxQuery({
|
var query = new InfluxQuery({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
select: [[{name: 'field', params: ['value']}, {name: 'mean'}, {name: 'alias'}]]
|
select: [[{type: 'field', params: ['value']}, {type: 'mean'}, {type: 'alias'}]]
|
||||||
});
|
});
|
||||||
|
|
||||||
query.addSelectPart(query.selectModels[0], 'math');
|
query.addSelectPart(query.selectModels[0], 'math');
|
||||||
expect(query.target.select[0].length).to.be(4);
|
expect(query.target.select[0].length).to.be(4);
|
||||||
expect(query.target.select[0][2].name).to.be('math');
|
expect(query.target.select[0][2].type).to.be('math');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add math last', function() {
|
it('should add math last', function() {
|
||||||
var query = new InfluxQuery({
|
var query = new InfluxQuery({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
select: [[{name: 'field', params: ['value']}, {name: 'mean'}]]
|
select: [[{type: 'field', params: ['value']}, {type: 'mean'}]]
|
||||||
});
|
});
|
||||||
|
|
||||||
query.addSelectPart(query.selectModels[0], 'math');
|
query.addSelectPart(query.selectModels[0], 'math');
|
||||||
expect(query.target.select[0].length).to.be(3);
|
expect(query.target.select[0].length).to.be(3);
|
||||||
expect(query.target.select[0][2].name).to.be('math');
|
expect(query.target.select[0][2].type).to.be('math');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should replace math', function() {
|
it('should replace math', function() {
|
||||||
var query = new InfluxQuery({
|
var query = new InfluxQuery({
|
||||||
measurement: 'cpu',
|
measurement: 'cpu',
|
||||||
select: [[{name: 'field', params: ['value']}, {name: 'mean'}, {name: 'math'}]]
|
select: [[{type: 'field', params: ['value']}, {type: 'mean'}, {type: 'math'}]]
|
||||||
});
|
});
|
||||||
|
|
||||||
query.addSelectPart(query.selectModels[0], 'math');
|
query.addSelectPart(query.selectModels[0], 'math');
|
||||||
expect(query.target.select[0].length).to.be(3);
|
expect(query.target.select[0].length).to.be(3);
|
||||||
expect(query.target.select[0][2].name).to.be('math');
|
expect(query.target.select[0][2].type).to.be('math');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
|
|||||||
|
|
||||||
import queryPart = require('../query_part');
|
import queryPart = require('../query_part');
|
||||||
|
|
||||||
describe('InfluxQueryBuilder', () => {
|
describe('InfluxQueryPart', () => {
|
||||||
|
|
||||||
describe('series with mesurement only', () => {
|
describe('series with mesurement only', () => {
|
||||||
it('should handle nested function parts', () => {
|
it('should handle nested function parts', () => {
|
||||||
var part = queryPart.create({
|
var part = queryPart.create({
|
||||||
name: 'derivative',
|
type: 'derivative',
|
||||||
params: ['10s'],
|
params: ['10s'],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ describe('InfluxQueryBuilder', () => {
|
|||||||
|
|
||||||
it('should handle suffirx parts', () => {
|
it('should handle suffirx parts', () => {
|
||||||
var part = queryPart.create({
|
var part = queryPart.create({
|
||||||
name: 'math',
|
type: 'math',
|
||||||
params: ['/ 100'],
|
params: ['/ 100'],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ describe('InfluxQueryBuilder', () => {
|
|||||||
|
|
||||||
it('should handle alias parts', () => {
|
it('should handle alias parts', () => {
|
||||||
var part = queryPart.create({
|
var part = queryPart.create({
|
||||||
name: 'alias',
|
type: 'alias',
|
||||||
params: ['test'],
|
params: ['test'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user