Commit 3f167d7f by Torkel Ödegaard

more work on influxdb 0.9 query editor and query builder, can now handle regex…

more work on influxdb 0.9 query editor and query builder, can now handle regex conditions, tag operator  and tag value quotes changes automatically depending if the tag value is a regex or not, #1525
parent dd8d6bc7
...@@ -8,6 +8,13 @@ function (_) { ...@@ -8,6 +8,13 @@ function (_) {
this.target = target; this.target = target;
} }
function renderTagCondition (key, value) {
if (value && value[0] === '/' && value[value.length - 1] === '/') {
return key + ' =~ ' + value;
}
return key + " = '" + value + "'";
}
var p = InfluxQueryBuilder.prototype; var p = InfluxQueryBuilder.prototype;
p.build = function() { p.build = function() {
...@@ -42,12 +49,12 @@ function (_) { ...@@ -42,12 +49,12 @@ function (_) {
if (tag.key === withKey) { if (tag.key === withKey) {
return memo; return memo;
} }
memo.push(' ' + tag.key + '=' + "'" + tag.value + "'"); memo.push(renderTagCondition(tag.key, tag.value));
return memo; return memo;
}, []); }, []);
if (whereConditions.length > 0) { if (whereConditions.length > 0) {
query += ' WHERE' + whereConditions.join('AND'); query += ' WHERE ' + whereConditions.join(' AND ');
} }
} }
...@@ -72,11 +79,11 @@ function (_) { ...@@ -72,11 +79,11 @@ function (_) {
query += aggregationFunc + '(value)'; query += aggregationFunc + '(value)';
query += ' FROM ' + measurement + ' WHERE '; query += ' FROM ' + measurement + ' WHERE ';
var conditions = _.map(target.tags, function(tag) { var conditions = _.map(target.tags, function(tag) {
return tag.key + '=' + "'" + tag.value + "' "; return renderTagCondition(tag.key, tag.value);
}); });
conditions.push('$timeFilter'); conditions.push('$timeFilter');
query += conditions.join('AND '); query += conditions.join(' AND ');
query += ' GROUP BY time($interval)'; query += ' GROUP BY time($interval)';
if (target.groupByTags && target.groupByTags.length > 0) { if (target.groupByTags && target.groupByTags.length > 0) {
......
...@@ -39,7 +39,7 @@ function (angular, _, InfluxQueryBuilder) { ...@@ -39,7 +39,7 @@ function (angular, _, InfluxQueryBuilder) {
$scope.tagSegments.push(MetricSegment.newCondition(tag.condition)); $scope.tagSegments.push(MetricSegment.newCondition(tag.condition));
} }
$scope.tagSegments.push(new MetricSegment({value: tag.key, type: 'key', cssClass: 'query-segment-key' })); $scope.tagSegments.push(new MetricSegment({value: tag.key, type: 'key', cssClass: 'query-segment-key' }));
$scope.tagSegments.push(new MetricSegment({fake: true, value: "=", cssClass: 'query-segment-operator'})); $scope.tagSegments.push(new MetricSegment.newOperator("="));
$scope.tagSegments.push(new MetricSegment({value: tag.value, type: 'value', cssClass: 'query-segment-value'})); $scope.tagSegments.push(new MetricSegment({value: tag.value, type: 'value', cssClass: 'query-segment-value'}));
}); });
...@@ -177,6 +177,7 @@ function (angular, _, InfluxQueryBuilder) { ...@@ -177,6 +177,7 @@ function (angular, _, InfluxQueryBuilder) {
$scope.tagSegmentUpdated = function(segment, index) { $scope.tagSegmentUpdated = function(segment, index) {
$scope.tagSegments[index] = segment; $scope.tagSegments[index] = segment;
// handle remove tag condition
if (segment.value === $scope.removeTagFilterSegment.value) { if (segment.value === $scope.removeTagFilterSegment.value) {
$scope.tagSegments.splice(index, 3); $scope.tagSegments.splice(index, 3);
if ($scope.tagSegments.length === 0) { if ($scope.tagSegments.length === 0) {
...@@ -193,7 +194,7 @@ function (angular, _, InfluxQueryBuilder) { ...@@ -193,7 +194,7 @@ function (angular, _, InfluxQueryBuilder) {
if (index > 2) { if (index > 2) {
$scope.tagSegments.splice(index, 0, MetricSegment.newCondition('AND')); $scope.tagSegments.splice(index, 0, MetricSegment.newCondition('AND'));
} }
$scope.tagSegments.push(MetricSegment.newFake('=', 'operator', 'query-segment-operator')); $scope.tagSegments.push(MetricSegment.newOperator('='));
$scope.tagSegments.push(MetricSegment.newFake('select tag value', 'value', 'query-segment-value')); $scope.tagSegments.push(MetricSegment.newFake('select tag value', 'value', 'query-segment-value'));
segment.type = 'key'; segment.type = 'key';
segment.cssClass = 'query-segment-key'; segment.cssClass = 'query-segment-key';
...@@ -210,7 +211,7 @@ function (angular, _, InfluxQueryBuilder) { ...@@ -210,7 +211,7 @@ function (angular, _, InfluxQueryBuilder) {
$scope.rebuildTargetTagConditions = function() { $scope.rebuildTargetTagConditions = function() {
var tags = []; var tags = [];
var tagIndex = 0; var tagIndex = 0;
_.each($scope.tagSegments, function(segment2) { _.each($scope.tagSegments, function(segment2, index) {
if (segment2.type === 'key') { if (segment2.type === 'key') {
if (tags.length === 0) { if (tags.length === 0) {
tags.push({}); tags.push({});
...@@ -219,6 +220,7 @@ function (angular, _, InfluxQueryBuilder) { ...@@ -219,6 +220,7 @@ function (angular, _, InfluxQueryBuilder) {
} }
else if (segment2.type === 'value') { else if (segment2.type === 'value') {
tags[tagIndex].value = segment2.value; tags[tagIndex].value = segment2.value;
$scope.tagSegments[index-1] = $scope.getTagValueOperator(segment2.value);
} }
else if (segment2.type === 'condition') { else if (segment2.type === 'condition') {
tags.push({ condition: segment2.value }); tags.push({ condition: segment2.value });
...@@ -230,6 +232,14 @@ function (angular, _, InfluxQueryBuilder) { ...@@ -230,6 +232,14 @@ function (angular, _, InfluxQueryBuilder) {
$scope.$parent.get_data(); $scope.$parent.get_data();
}; };
$scope.getTagValueOperator = function(tagValue) {
if (tagValue[0] === '/' && tagValue[tagValue.length - 1] === '/') {
return MetricSegment.newOperator('=~');
}
return MetricSegment.newOperator('=');
};
function MetricSegment(options) { function MetricSegment(options) {
if (options === '*' || options.value === '*') { if (options === '*' || options.value === '*') {
this.value = '*'; this.value = '*';
...@@ -265,6 +275,10 @@ function (angular, _, InfluxQueryBuilder) { ...@@ -265,6 +275,10 @@ function (angular, _, InfluxQueryBuilder) {
return new MetricSegment({value: condition, type: 'condition', cssClass: 'query-keyword' }); return new MetricSegment({value: condition, type: 'condition', cssClass: 'query-keyword' });
}; };
MetricSegment.newOperator = function(op) {
return new MetricSegment({value: op, type: 'operator', cssClass: 'query-segment-operator' });
};
MetricSegment.newPlusButton = function() { MetricSegment.newPlusButton = function() {
return new MetricSegment({fake: true, html: '<i class="fa fa-plus "></i>', type: 'plus-button' }); return new MetricSegment({fake: true, html: '<i class="fa fa-plus "></i>', type: 'plus-button' });
}; };
......
...@@ -27,10 +27,15 @@ define([ ...@@ -27,10 +27,15 @@ define([
var query = builder.build(); var query = builder.build();
it('should generate correct query', function() { it('should generate correct query', function() {
expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE hostname=\'server1\' AND $timeFilter' expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE hostname = \'server1\' AND $timeFilter'
+ ' GROUP BY time($interval) ORDER BY asc'); + ' GROUP BY time($interval) ORDER BY asc');
}); });
it('should switch regex operator with tag value is regex', function() {
var builder = new InfluxQueryBuilder({measurement: 'cpu', tags: [{key: 'app', value: '/e.*/'}]});
var query = builder.build();
expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE app =~ /e.*/ AND $timeFilter GROUP BY time($interval) ORDER BY asc');
});
}); });
describe('series with multiple tags only', function() { describe('series with multiple tags only', function() {
...@@ -42,7 +47,7 @@ define([ ...@@ -42,7 +47,7 @@ define([
var query = builder.build(); var query = builder.build();
it('should generate correct query', function() { it('should generate correct query', function() {
expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE hostname=\'server1\' AND app=\'email\' AND ' + expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE hostname = \'server1\' AND app = \'email\' AND ' +
'$timeFilter GROUP BY time($interval) ORDER BY asc'); '$timeFilter GROUP BY time($interval) ORDER BY asc');
}); });
}); });
...@@ -78,7 +83,7 @@ define([ ...@@ -78,7 +83,7 @@ define([
it('should have where condition in tag keys query with tags', function() { it('should have where condition in tag keys query with tags', function() {
var builder = new InfluxQueryBuilder({ measurement: '', tags: [{key: 'host', value: 'se1'}] }); var builder = new InfluxQueryBuilder({ measurement: '', tags: [{key: 'host', value: 'se1'}] });
var query = builder.buildExploreQuery('TAG_KEYS'); var query = builder.buildExploreQuery('TAG_KEYS');
expect(query).to.be("SHOW TAG KEYS WHERE host='se1'"); expect(query).to.be("SHOW TAG KEYS WHERE host = 'se1'");
}); });
it('should have no conditions in measurement query for query with no tags', function() { it('should have no conditions in measurement query for query with no tags', function() {
...@@ -90,7 +95,7 @@ define([ ...@@ -90,7 +95,7 @@ define([
it('should have where condition in measurement query for query with tags', function() { it('should have where condition in measurement query for query with tags', function() {
var builder = new InfluxQueryBuilder({measurement: '', tags: [{key: 'app', value: 'email'}]}); var builder = new InfluxQueryBuilder({measurement: '', tags: [{key: 'app', value: 'email'}]});
var query = builder.buildExploreQuery('MEASUREMENTS'); var query = builder.buildExploreQuery('MEASUREMENTS');
expect(query).to.be("SHOW MEASUREMENTS WHERE app='email'"); expect(query).to.be("SHOW MEASUREMENTS WHERE app = 'email'");
}); });
it('should have where tag name IN filter in tag values query for query with one tag', function() { it('should have where tag name IN filter in tag values query for query with one tag', function() {
...@@ -102,7 +107,13 @@ define([ ...@@ -102,7 +107,13 @@ define([
it('should have measurement tag condition and tag name IN filter in tag values query', function() { it('should have measurement tag condition and tag name IN filter in tag values query', function() {
var builder = new InfluxQueryBuilder({measurement: 'cpu', tags: [{key: 'app', value: 'email'}, {key: 'host', value: 'server1'}]}); var builder = new InfluxQueryBuilder({measurement: 'cpu', tags: [{key: 'app', value: 'email'}, {key: 'host', value: 'server1'}]});
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=\'server1\''); expect(query).to.be('SHOW TAG VALUES FROM "cpu" WITH KEY = "app" WHERE host = \'server1\'');
});
it('should switch to regex operator in tag condition', function() {
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.*/');
}); });
}); });
......
...@@ -65,6 +65,18 @@ define([ ...@@ -65,6 +65,18 @@ define([
}); });
}); });
describe('when last tag value segment is updated to regex', function() {
beforeEach(function() {
ctx.scope.init();
ctx.scope.tagSegmentUpdated({value: 'asd', type: 'plus-button'}, 0);
ctx.scope.tagSegmentUpdated({value: '/server.*/', type: 'value'}, 2);
});
it('should update operator', function() {
expect(ctx.scope.tagSegments[1].value).to.be('=~');
});
});
describe('when second tag key is added', function() { describe('when second tag key is added', function() {
beforeEach(function() { beforeEach(function() {
ctx.scope.init(); ctx.scope.init();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment