From 48fc5edda19a7c426d70a494786a46378722a6b2 Mon Sep 17 00:00:00 2001 From: Kim Christensen Date: Wed, 30 May 2018 09:22:16 +0200 Subject: [PATCH] Support InfluxDB count distinct aggregation (#11658) influxdb: support count distinct aggregation --- pkg/tsdb/influxdb/query_part_test.go | 8 + .../plugins/datasource/influxdb/query_part.ts | 23 +++ .../influxdb/specs/query_part.jest.ts | 144 ++++++++++++++++++ 3 files changed, 175 insertions(+) diff --git a/pkg/tsdb/influxdb/query_part_test.go b/pkg/tsdb/influxdb/query_part_test.go index d23865174c8..cd0863cee9b 100644 --- a/pkg/tsdb/influxdb/query_part_test.go +++ b/pkg/tsdb/influxdb/query_part_test.go @@ -76,5 +76,13 @@ func TestInfluxdbQueryPart(t *testing.T) { res := part.Render(query, queryContext, "mean(value)") So(res, ShouldEqual, `mean(value) AS "test"`) }) + + Convey("render count distinct", func() { + part, err := NewQueryPart("count", []string{}) + So(err, ShouldBeNil) + + res := part.Render(query, queryContext, "distinct(value)") + So(res, ShouldEqual, `count(distinct(value))`) + }) }) } diff --git a/public/app/plugins/datasource/influxdb/query_part.ts b/public/app/plugins/datasource/influxdb/query_part.ts index ce5588abe53..2a2f9f2a4ef 100644 --- a/public/app/plugins/datasource/influxdb/query_part.ts +++ b/public/app/plugins/datasource/influxdb/query_part.ts @@ -44,6 +44,28 @@ function replaceAggregationAddStrategy(selectParts, partModel) { for (var i = 0; i < selectParts.length; i++) { var part = selectParts[i]; if (part.def.category === categories.Aggregations) { + if (part.def.type === partModel.def.type) { + return; + } + // count distinct is allowed + if (part.def.type === 'count' && partModel.def.type === 'distinct') { + break; + } + // remove next aggregation if distinct was replaced + if (part.def.type === 'distinct') { + var morePartsAvailable = selectParts.length >= i + 2; + if (partModel.def.type !== 'count' && morePartsAvailable) { + var nextPart = selectParts[i + 1]; + if (nextPart.def.category === categories.Aggregations) { + selectParts.splice(i + 1, 1); + } + } else if (partModel.def.type === 'count') { + if (!morePartsAvailable || selectParts[i + 1].def.type !== 'count') { + selectParts.splice(i + 1, 0, partModel); + } + return; + } + } selectParts[i] = partModel; return; } @@ -434,4 +456,5 @@ export default { getCategories: function() { return categories; }, + replaceAggregationAdd: replaceAggregationAddStrategy, }; diff --git a/public/app/plugins/datasource/influxdb/specs/query_part.jest.ts b/public/app/plugins/datasource/influxdb/specs/query_part.jest.ts index cabe8bc9b6f..e9e6d216c1e 100644 --- a/public/app/plugins/datasource/influxdb/specs/query_part.jest.ts +++ b/public/app/plugins/datasource/influxdb/specs/query_part.jest.ts @@ -40,5 +40,149 @@ describe('InfluxQueryPart', () => { expect(part.text).toBe('alias(test)'); expect(part.render('mean(value)')).toBe('mean(value) AS "test"'); }); + + it('should nest distinct when count is selected', () => { + var selectParts = [ + queryPart.create({ + type: 'field', + category: queryPart.getCategories().Fields, + }), + queryPart.create({ + type: 'count', + category: queryPart.getCategories().Aggregations, + }), + ]; + var partModel = queryPart.create({ + type: 'distinct', + category: queryPart.getCategories().Aggregations, + }); + + queryPart.replaceAggregationAdd(selectParts, partModel); + + expect(selectParts[1].text).toBe('distinct()'); + expect(selectParts[2].text).toBe('count()'); + }); + + it('should convert to count distinct when distinct is selected and count added', () => { + var selectParts = [ + queryPart.create({ + type: 'field', + category: queryPart.getCategories().Fields, + }), + queryPart.create({ + type: 'distinct', + category: queryPart.getCategories().Aggregations, + }), + ]; + var partModel = queryPart.create({ + type: 'count', + category: queryPart.getCategories().Aggregations, + }); + + queryPart.replaceAggregationAdd(selectParts, partModel); + + expect(selectParts[1].text).toBe('distinct()'); + expect(selectParts[2].text).toBe('count()'); + }); + + it('should replace count distinct if an aggregation is selected', () => { + var selectParts = [ + queryPart.create({ + type: 'field', + category: queryPart.getCategories().Fields, + }), + queryPart.create({ + type: 'distinct', + category: queryPart.getCategories().Aggregations, + }), + queryPart.create({ + type: 'count', + category: queryPart.getCategories().Aggregations, + }), + ]; + var partModel = queryPart.create({ + type: 'mean', + category: queryPart.getCategories().Selectors, + }); + + queryPart.replaceAggregationAdd(selectParts, partModel); + + expect(selectParts[1].text).toBe('mean()'); + expect(selectParts).toHaveLength(2); + }); + + it('should not allowed nested counts when count distinct is selected', () => { + var selectParts = [ + queryPart.create({ + type: 'field', + category: queryPart.getCategories().Fields, + }), + queryPart.create({ + type: 'distinct', + category: queryPart.getCategories().Aggregations, + }), + queryPart.create({ + type: 'count', + category: queryPart.getCategories().Aggregations, + }), + ]; + var partModel = queryPart.create({ + type: 'count', + category: queryPart.getCategories().Aggregations, + }); + + queryPart.replaceAggregationAdd(selectParts, partModel); + + expect(selectParts[1].text).toBe('distinct()'); + expect(selectParts[2].text).toBe('count()'); + expect(selectParts).toHaveLength(3); + }); + + it('should not remove count distinct when distinct is added', () => { + var selectParts = [ + queryPart.create({ + type: 'field', + category: queryPart.getCategories().Fields, + }), + queryPart.create({ + type: 'distinct', + category: queryPart.getCategories().Aggregations, + }), + queryPart.create({ + type: 'count', + category: queryPart.getCategories().Aggregations, + }), + ]; + var partModel = queryPart.create({ + type: 'distinct', + category: queryPart.getCategories().Aggregations, + }); + + queryPart.replaceAggregationAdd(selectParts, partModel); + + expect(selectParts[1].text).toBe('distinct()'); + expect(selectParts[2].text).toBe('count()'); + expect(selectParts).toHaveLength(3); + }); + + it('should remove distinct when sum aggregation is selected', () => { + var selectParts = [ + queryPart.create({ + type: 'field', + category: queryPart.getCategories().Fields, + }), + queryPart.create({ + type: 'distinct', + category: queryPart.getCategories().Aggregations, + }), + ]; + var partModel = queryPart.create({ + type: 'sum', + category: queryPart.getCategories().Aggregations, + }); + queryPart.replaceAggregationAdd(selectParts, partModel); + + expect(selectParts[1].text).toBe('sum()'); + }); }); });