feat(influxdb): more work on influxdb editor

This commit is contained in:
Torkel Ödegaard 2015-11-25 10:22:20 +01:00
parent 31e2a8b8e9
commit c9ba856c52
7 changed files with 163 additions and 30 deletions

View File

@ -6,16 +6,6 @@ import queryPart = require('./query_part');
declare var InfluxQueryBuilder: any;
class InfluxSelectModel {
modelParts: any[];
persistedParts: any[];
constructor(persistedParts: any[]) {
this.persistedParts = persistedParts;
this.modelParts = _.map(persistedParts, queryPart.create);
}
}
class InfluxQuery {
target: any;
selectModels: any[];
@ -40,7 +30,15 @@ class InfluxQuery {
updateSelectParts() {
this.selectModels = _.map(this.target.select, function(parts: any) {
return new InfluxSelectModel(parts);
return _.map(parts, queryPart.create);
});
}
updatePersistedParts() {
this.target.select = _.map(this.selectModels, function(selectParts) {
return _.map(selectParts, function(part: any) {
return {name: part.def.name, params: part.params};
});
});
}
@ -49,16 +47,16 @@ class InfluxQuery {
this.updateSelectParts();
}
removeSelectPart(selectModel, part) {
var partIndex = _.indexOf(selectModel.modelParts, part);
selectModel.persistedParts.splice(partIndex, 1);
this.updateSelectParts();
removeSelectPart(selectParts, part) {
var partIndex = _.indexOf(selectParts, part);
selectParts.splice(partIndex, 1);
this.updatePersistedParts();
}
addSelectPart(selectModel, name) {
addSelectPart(selectParts, name) {
var partModel = queryPart.create({name: name});
selectModel.persistedParts.push(partModel.part);
selectModel.modelParts.push(partModel);
partModel.def.addStrategy(selectParts, partModel);
this.updatePersistedParts();
}
addSelect() {
@ -113,7 +111,7 @@ class InfluxQuery {
var query = 'SELECT ';
var i, y;
for (i = 0; i < this.selectModels.length; i++) {
let parts = this.selectModels[i].modelParts;
let parts = this.selectModels[i];
var selectText = "";
for (y = 0; y < parts.length; y++) {
let part = parts[y];

View File

@ -65,15 +65,15 @@
<div ng-hide="target.rawQuery">
<div class="tight-form" ng-repeat="selectModel in queryModel.selectModels">
<div class="tight-form" ng-repeat="selectParts in queryModel.selectModels">
<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>
</li>
<li ng-repeat="part in selectModel.modelParts">
<influx-query-part-editor part="part" class="tight-form-item tight-form-func" remove-action="removeSelectPart(selectModel, part)" part-updated="selectPartUpdated(selectModel, part)"></influx-query-part-editor>
<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>
</li>
<li class="dropdown" dropdown-typeahead="selectMenu" dropdown-typeahead-on-select="selectMenuAction(selectModel, $item, $subItem)">
<li class="dropdown" dropdown-typeahead="selectMenu" dropdown-typeahead-on-select="addSelectPart(selectParts, $item, $subItem)">
</li>
</ul>
<div class="clearfix"></div>

View File

@ -1,6 +1,5 @@
<div class="tight-form-func-controls">
<span class="pointer fa fa-question-circle"></span>
<span class="pointer fa fa-remove" ng-click="removeAction()" ></span>
<span class="pointer fa fa-remove" ng-click="removeActionInternal()" ></span>
</div>
<a ng-click="toggleControls()">{{part.def.name}}</a><span>(</span><span class="query-part-parameters"></span><span>)</span>

View File

@ -62,13 +62,13 @@ function (angular, _, InfluxQueryBuilder, InfluxQuery, queryPart) {
}, []);
};
$scope.selectMenuAction = function(selectModel, cat, subitem) {
$scope.queryModel.addSelectPart(selectModel, subitem.value);
$scope.addSelectPart = function(selectParts, cat, subitem) {
$scope.queryModel.addSelectPart(selectParts, subitem.value);
$scope.get_data();
};
$scope.removeSelectPart = function(selectModel, part) {
$scope.queryModel.removeSelectPart(selectModel, part);
$scope.removeSelectPart = function(selectParts, part) {
$scope.queryModel.removeSelectPart(selectParts, part);
$scope.get_data();
};

View File

@ -11,17 +11,23 @@ var categories = {
Fields: [],
};
var groupByTimeFunctions = [];
class QueryPartDef {
name: string;
params: any[];
defaultParams: any[];
renderer: any;
category: any;
addStrategy: any;
constructor(options: any) {
this.name = options.name;
this.params = options.params;
this.defaultParams = options.defaultParams;
this.renderer = options.renderer;
this.category = options.category;
this.addStrategy = options.addStrategy;
}
static register(options: any) {
@ -65,6 +71,67 @@ function quotedIdentityRenderer(part, innerExpr) {
return '"' + part.params[0] + '"';
}
function replaceAggregationAddStrategy(selectParts, partModel) {
// look for existing aggregation
for (var i = 0; i < selectParts.length; i++) {
var part = selectParts[i];
if (part.def.category === categories.Aggregations) {
selectParts[i] = partModel;
return;
}
}
selectParts.splice(1, 0, partModel);
}
function addTransformationStrategy(selectParts, partModel) {
var i;
// look for index to add transformation
for (i = 0; i < selectParts.length; i++) {
var part = selectParts[i];
if (part.def.category === categories.Math || part.def.category === categories.Aliasing) {
break;
}
}
selectParts.splice(i, 0, partModel);
}
function addMathStrategy(selectParts, partModel) {
var partCount = selectParts.length;
if (partCount > 0) {
// if last is math, replace it
if (selectParts[partCount-1].def.name === 'math') {
selectParts[partCount-1] = partModel;
return;
}
// if next to last is math, replace it
if (selectParts[partCount-2].def.name === 'math') {
selectParts[partCount-2] = partModel;
return;
}
// if last is alias add it before
else if (selectParts[partCount-1].def.name === 'alias') {
selectParts.splice(partCount-1, 0, partModel);
return;
}
}
selectParts.push(partModel);
}
function addAliasStrategy(selectParts, partModel) {
var partCount = selectParts.length;
if (partCount > 0) {
// if last is alias, replace it
if (selectParts[partCount-1].def.name === 'alias') {
selectParts[partCount-1] = partModel;
return;
}
}
selectParts.push(partModel);
}
QueryPartDef.register({
name: 'field',
category: categories.Fields,
@ -75,6 +142,7 @@ QueryPartDef.register({
QueryPartDef.register({
name: 'mean',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
params: [],
defaultParams: [],
@ -83,6 +151,7 @@ QueryPartDef.register({
QueryPartDef.register({
name: 'sum',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
params: [],
defaultParams: [],
@ -91,6 +160,7 @@ QueryPartDef.register({
QueryPartDef.register({
name: 'derivative',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5min', '10m', '15m', '1h']}],
defaultParams: ['10s'],
@ -99,7 +169,7 @@ QueryPartDef.register({
QueryPartDef.register({
name: 'time',
category: categories.Transformations,
category: groupByTimeFunctions,
params: [{ name: "rate", type: "interval", options: ['$interval', '1s', '10s', '1m', '5min', '10m', '15m', '1h'] }],
defaultParams: ['$interval'],
renderer: functionRenderer,
@ -107,6 +177,7 @@ QueryPartDef.register({
QueryPartDef.register({
name: 'math',
addStrategy: addMathStrategy,
category: categories.Math,
params: [{ name: "expr", type: "string"}],
defaultParams: [' / 100'],
@ -115,6 +186,7 @@ QueryPartDef.register({
QueryPartDef.register({
name: 'alias',
addStrategy: addAliasStrategy,
category: categories.Aliasing,
params: [{ name: "name", type: "string", quote: 'double'}],
defaultParams: ['alias'],

View File

@ -117,6 +117,11 @@ function (angular, _, $) {
$controlsContainer.show();
};
$scope.removeActionInternal = function() {
$scope.toggleControls();
$scope.removeAction();
};
function addElementsAndCompile() {
_.each(partDef.params, function(param, index) {
if (param.optional && part.params.length <= index) {

View File

@ -34,4 +34,63 @@ describe.only('InfluxQuery', function() {
});
});
describe('when adding select part', function() {
it('should add mean after after field', function() {
var query = new InfluxQuery({
measurement: 'cpu',
select: [[{name: 'field', params: ['value']}]]
});
query.addSelectPart(query.selectModels[0], 'mean');
expect(query.target.select[0].length).to.be(2);
expect(query.target.select[0][1].name).to.be('mean');
});
it('should replace sum by mean', function() {
var query = new InfluxQuery({
measurement: 'cpu',
select: [[{name: 'field', params: ['value']}, {name: 'mean'}]]
});
query.addSelectPart(query.selectModels[0], 'sum');
expect(query.target.select[0].length).to.be(2);
expect(query.target.select[0][1].name).to.be('sum');
});
it('should add math before alias', function() {
var query = new InfluxQuery({
measurement: 'cpu',
select: [[{name: 'field', params: ['value']}, {name: 'mean'}, {name: 'alias'}]]
});
query.addSelectPart(query.selectModels[0], 'math');
expect(query.target.select[0].length).to.be(4);
expect(query.target.select[0][2].name).to.be('math');
});
it('should add math last', function() {
var query = new InfluxQuery({
measurement: 'cpu',
select: [[{name: 'field', params: ['value']}, {name: 'mean'}]]
});
query.addSelectPart(query.selectModels[0], 'math');
expect(query.target.select[0].length).to.be(3);
expect(query.target.select[0][2].name).to.be('math');
});
it('should replace math', function() {
var query = new InfluxQuery({
measurement: 'cpu',
select: [[{name: 'field', params: ['value']}, {name: 'mean'}, {name: 'math'}]]
});
query.addSelectPart(query.selectModels[0], 'math');
expect(query.target.select[0].length).to.be(3);
expect(query.target.select[0][2].name).to.be('math');
});
});
});