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

View File

@ -65,15 +65,15 @@
<div ng-hide="target.rawQuery"> <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"> <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>
</li> </li>
<li ng-repeat="part in selectModel.modelParts"> <li ng-repeat="part in selectParts">
<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> <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 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> </li>
</ul> </ul>
<div class="clearfix"></div> <div class="clearfix"></div>

View File

@ -1,6 +1,5 @@
<div class="tight-form-func-controls"> <div class="tight-form-func-controls">
<span class="pointer fa fa-question-circle"></span> <span class="pointer fa fa-remove" ng-click="removeActionInternal()" ></span>
<span class="pointer fa fa-remove" ng-click="removeAction()" ></span>
</div> </div>
<a ng-click="toggleControls()">{{part.def.name}}</a><span>(</span><span class="query-part-parameters"></span><span>)</span> <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.addSelectPart = function(selectParts, cat, subitem) {
$scope.queryModel.addSelectPart(selectModel, subitem.value); $scope.queryModel.addSelectPart(selectParts, subitem.value);
$scope.get_data(); $scope.get_data();
}; };
$scope.removeSelectPart = function(selectModel, part) { $scope.removeSelectPart = function(selectParts, part) {
$scope.queryModel.removeSelectPart(selectModel, part); $scope.queryModel.removeSelectPart(selectParts, part);
$scope.get_data(); $scope.get_data();
}; };

View File

@ -11,17 +11,23 @@ var categories = {
Fields: [], Fields: [],
}; };
var groupByTimeFunctions = [];
class QueryPartDef { class QueryPartDef {
name: string; name: string;
params: any[]; params: any[];
defaultParams: any[]; defaultParams: any[];
renderer: any; renderer: any;
category: any;
addStrategy: 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; this.renderer = options.renderer;
this.category = options.category;
this.addStrategy = options.addStrategy;
} }
static register(options: any) { static register(options: any) {
@ -65,6 +71,67 @@ function quotedIdentityRenderer(part, innerExpr) {
return '"' + part.params[0] + '"'; 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({ QueryPartDef.register({
name: 'field', name: 'field',
category: categories.Fields, category: categories.Fields,
@ -75,6 +142,7 @@ QueryPartDef.register({
QueryPartDef.register({ QueryPartDef.register({
name: 'mean', name: 'mean',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations, category: categories.Aggregations,
params: [], params: [],
defaultParams: [], defaultParams: [],
@ -83,6 +151,7 @@ QueryPartDef.register({
QueryPartDef.register({ QueryPartDef.register({
name: 'sum', name: 'sum',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations, category: categories.Aggregations,
params: [], params: [],
defaultParams: [], defaultParams: [],
@ -91,6 +160,7 @@ QueryPartDef.register({
QueryPartDef.register({ QueryPartDef.register({
name: 'derivative', name: 'derivative',
addStrategy: addTransformationStrategy,
category: categories.Transformations, category: categories.Transformations,
params: [{ name: "duration", 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'],
@ -99,7 +169,7 @@ QueryPartDef.register({
QueryPartDef.register({ QueryPartDef.register({
name: 'time', name: 'time',
category: categories.Transformations, category: groupByTimeFunctions,
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, renderer: functionRenderer,
@ -107,6 +177,7 @@ QueryPartDef.register({
QueryPartDef.register({ QueryPartDef.register({
name: 'math', name: 'math',
addStrategy: addMathStrategy,
category: categories.Math, category: categories.Math,
params: [{ name: "expr", type: "string"}], params: [{ name: "expr", type: "string"}],
defaultParams: [' / 100'], defaultParams: [' / 100'],
@ -115,6 +186,7 @@ QueryPartDef.register({
QueryPartDef.register({ QueryPartDef.register({
name: 'alias', name: 'alias',
addStrategy: addAliasStrategy,
category: categories.Aliasing, category: categories.Aliasing,
params: [{ name: "name", type: "string", quote: 'double'}], params: [{ name: "name", type: "string", quote: 'double'}],
defaultParams: ['alias'], defaultParams: ['alias'],

View File

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