Elasticsearch: automatically set date_histogram field based on data source configuration (#33840)

This commit is contained in:
Giordano Ricci 2021-05-10 14:28:47 +01:00 committed by GitHub
parent 1a59117343
commit 4c83ab5610
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 19 deletions

View File

@ -10,7 +10,7 @@ import {
changeBucketAggregationType, changeBucketAggregationType,
removeBucketAggregation, removeBucketAggregation,
} from './actions'; } from './actions';
import { reducer } from './reducer'; import { createReducer } from './reducer';
import { initQuery } from '../../state'; import { initQuery } from '../../state';
import { ElasticsearchQuery } from 'app/plugins/datasource/elasticsearch/types'; import { ElasticsearchQuery } from 'app/plugins/datasource/elasticsearch/types';
@ -29,7 +29,7 @@ describe('Bucket Aggregations Reducer', () => {
}; };
reducerTester<ElasticsearchQuery['bucketAggs']>() reducerTester<ElasticsearchQuery['bucketAggs']>()
.givenReducer(reducer, []) .givenReducer(createReducer('@timestamp'), [])
.whenActionIsDispatched(addBucketAggregation(firstAggregation.id)) .whenActionIsDispatched(addBucketAggregation(firstAggregation.id))
.thenStateShouldEqual([firstAggregation]) .thenStateShouldEqual([firstAggregation])
.whenActionIsDispatched(addBucketAggregation(secondAggregation.id)) .whenActionIsDispatched(addBucketAggregation(secondAggregation.id))
@ -48,7 +48,7 @@ describe('Bucket Aggregations Reducer', () => {
}; };
reducerTester<ElasticsearchQuery['bucketAggs']>() reducerTester<ElasticsearchQuery['bucketAggs']>()
.givenReducer(reducer, [firstAggregation, secondAggregation]) .givenReducer(createReducer('@timestamp'), [firstAggregation, secondAggregation])
.whenActionIsDispatched(removeBucketAggregation(firstAggregation.id)) .whenActionIsDispatched(removeBucketAggregation(firstAggregation.id))
.thenStateShouldEqual([secondAggregation]); .thenStateShouldEqual([secondAggregation]);
}); });
@ -70,7 +70,7 @@ describe('Bucket Aggregations Reducer', () => {
}; };
reducerTester<ElasticsearchQuery['bucketAggs']>() reducerTester<ElasticsearchQuery['bucketAggs']>()
.givenReducer(reducer, [firstAggregation, secondAggregation]) .givenReducer(createReducer('@timestamp'), [firstAggregation, secondAggregation])
.whenActionIsDispatched(changeBucketAggregationType(secondAggregation.id, expectedSecondAggregation.type)) .whenActionIsDispatched(changeBucketAggregationType(secondAggregation.id, expectedSecondAggregation.type))
.thenStateShouldEqual([firstAggregation, expectedSecondAggregation]); .thenStateShouldEqual([firstAggregation, expectedSecondAggregation]);
}); });
@ -91,7 +91,7 @@ describe('Bucket Aggregations Reducer', () => {
}; };
reducerTester<ElasticsearchQuery['bucketAggs']>() reducerTester<ElasticsearchQuery['bucketAggs']>()
.givenReducer(reducer, [firstAggregation, secondAggregation]) .givenReducer(createReducer('@timestamp'), [firstAggregation, secondAggregation])
.whenActionIsDispatched(changeBucketAggregationField(secondAggregation.id, expectedSecondAggregation.field)) .whenActionIsDispatched(changeBucketAggregationField(secondAggregation.id, expectedSecondAggregation.field))
.thenStateShouldEqual([firstAggregation, expectedSecondAggregation]); .thenStateShouldEqual([firstAggregation, expectedSecondAggregation]);
}); });
@ -106,7 +106,7 @@ describe('Bucket Aggregations Reducer', () => {
]; ];
reducerTester<ElasticsearchQuery['bucketAggs']>() reducerTester<ElasticsearchQuery['bucketAggs']>()
.givenReducer(reducer, initialState) .givenReducer(createReducer('@timestamp'), initialState)
// If the new metric aggregation is `isSingleMetric` we should remove all bucket aggregations. // If the new metric aggregation is `isSingleMetric` we should remove all bucket aggregations.
.whenActionIsDispatched(changeMetricType('Some id', 'raw_data')) .whenActionIsDispatched(changeMetricType('Some id', 'raw_data'))
.thenStatePredicateShouldEqual((newState) => newState?.length === 0) .thenStatePredicateShouldEqual((newState) => newState?.length === 0)
@ -137,17 +137,34 @@ describe('Bucket Aggregations Reducer', () => {
}; };
reducerTester<ElasticsearchQuery['bucketAggs']>() reducerTester<ElasticsearchQuery['bucketAggs']>()
.givenReducer(reducer, [firstAggregation, secondAggregation]) .givenReducer(createReducer('@timestamp'), [firstAggregation, secondAggregation])
.whenActionIsDispatched( .whenActionIsDispatched(
changeBucketAggregationSetting(firstAggregation, 'min_doc_count', expectedSettings.min_doc_count!) changeBucketAggregationSetting(firstAggregation, 'min_doc_count', expectedSettings.min_doc_count!)
) )
.thenStateShouldEqual([{ ...firstAggregation, settings: expectedSettings }, secondAggregation]); .thenStateShouldEqual([{ ...firstAggregation, settings: expectedSettings }, secondAggregation]);
}); });
it('Should correctly initialize first Bucket Aggregation', () => { describe('Initialization', () => {
it('Correctly adds a default Date Histogram if there is no aggregation', () => {
const defaultTimeField = '@timestamp';
reducerTester<ElasticsearchQuery['bucketAggs']>() reducerTester<ElasticsearchQuery['bucketAggs']>()
.givenReducer(reducer, []) .givenReducer(createReducer(defaultTimeField), [])
.whenActionIsDispatched(initQuery()) .whenActionIsDispatched(initQuery())
.thenStateShouldEqual([defaultBucketAgg('2')]); .thenStateShouldEqual([{ ...defaultBucketAgg('2'), field: defaultTimeField }]);
});
it('Does NOT change aggregations if there is already one', () => {
const bucketAgg: DateHistogram = {
id: '18',
type: 'date_histogram',
field: '@my_time_field',
};
reducerTester<ElasticsearchQuery['bucketAggs']>()
.givenReducer(createReducer('@timestamp'), [bucketAgg])
.whenActionIsDispatched(initQuery())
.thenStateShouldEqual([bucketAgg]);
});
}); });
}); });

View File

@ -15,7 +15,7 @@ import {
import { bucketAggregationConfig } from '../utils'; import { bucketAggregationConfig } from '../utils';
import { removeEmpty } from '../../../../utils'; import { removeEmpty } from '../../../../utils';
export const reducer = ( export const createReducer = (defaultTimeField: string) => (
state: ElasticsearchQuery['bucketAggs'], state: ElasticsearchQuery['bucketAggs'],
action: BucketAggregationAction | ChangeMetricTypeAction | InitAction action: BucketAggregationAction | ChangeMetricTypeAction | InitAction
): ElasticsearchQuery['bucketAggs'] => { ): ElasticsearchQuery['bucketAggs'] => {
@ -78,7 +78,7 @@ export const reducer = (
// Else, if there are no bucket aggregations we restore a default one. // Else, if there are no bucket aggregations we restore a default one.
// This happens when switching from a metric that requires the absence of bucket aggregations to // This happens when switching from a metric that requires the absence of bucket aggregations to
// one that requires it. // one that requires it.
return [defaultBucketAgg()]; return [{ ...defaultBucketAgg('2'), field: defaultTimeField }];
} }
return state; return state;
@ -105,7 +105,8 @@ export const reducer = (
if (state?.length || 0 > 0) { if (state?.length || 0 > 0) {
return state; return state;
} }
return [defaultBucketAgg('2')];
return [{ ...defaultBucketAgg('2'), field: defaultTimeField }];
default: default:
return state; return state;

View File

@ -4,7 +4,7 @@ import { combineReducers, useStatelessReducer, DispatchContext } from '../../hoo
import { ElasticsearchQuery } from '../../types'; import { ElasticsearchQuery } from '../../types';
import { reducer as metricsReducer } from './MetricAggregationsEditor/state/reducer'; import { reducer as metricsReducer } from './MetricAggregationsEditor/state/reducer';
import { reducer as bucketAggsReducer } from './BucketAggregationsEditor/state/reducer'; import { createReducer as createBucketAggsReducer } from './BucketAggregationsEditor/state/reducer';
import { aliasPatternReducer, queryReducer, initQuery } from './state'; import { aliasPatternReducer, queryReducer, initQuery } from './state';
import { TimeRange } from '@grafana/data'; import { TimeRange } from '@grafana/data';
@ -40,7 +40,7 @@ export const ElasticsearchProvider = ({
query: queryReducer, query: queryReducer,
alias: aliasPatternReducer, alias: aliasPatternReducer,
metrics: metricsReducer, metrics: metricsReducer,
bucketAggs: bucketAggsReducer, bucketAggs: createBucketAggsReducer(datasource.timeField),
}); });
const dispatch = useStatelessReducer( const dispatch = useStatelessReducer(

View File

@ -1,4 +1,4 @@
import { BucketAggregation } from './components/QueryEditor/BucketAggregationsEditor/aggregations'; import { DateHistogram } from './components/QueryEditor/BucketAggregationsEditor/aggregations';
import { import {
ExtendedStat, ExtendedStat,
MetricAggregation, MetricAggregation,
@ -36,7 +36,7 @@ export function defaultMetricAgg(id = '1'): MetricAggregation {
return { type: 'count', id }; return { type: 'count', id };
} }
export function defaultBucketAgg(id = '1'): BucketAggregation { export function defaultBucketAgg(id = '1'): DateHistogram {
return { type: 'date_histogram', id, settings: { interval: 'auto' } }; return { type: 'date_histogram', id, settings: { interval: 'auto' } };
} }