Skip to content

Commit

Permalink
[data.search.aggs]: Expression functions for metric agg types (#64914)
Browse files Browse the repository at this point in the history
  • Loading branch information
VladLasitsa authored May 5, 2020
1 parent a467fe5 commit 2ccc397
Show file tree
Hide file tree
Showing 65 changed files with 4,105 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/plugins/data/public/search/aggs/agg_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,51 @@ import { aggHistogram } from './buckets/histogram_fn';
import { aggDateHistogram } from './buckets/date_histogram_fn';
import { aggTerms } from './buckets/terms_fn';

/** Metrics: **/
import { aggAvg } from './metrics/avg_fn';
import { aggBucketAvg } from './metrics/bucket_avg_fn';
import { aggBucketMax } from './metrics/bucket_max_fn';
import { aggBucketMin } from './metrics/bucket_min_fn';
import { aggBucketSum } from './metrics/bucket_sum_fn';
import { aggCardinality } from './metrics/cardinality_fn';
import { aggCount } from './metrics/count_fn';
import { aggCumulativeSum } from './metrics/cumulative_sum_fn';
import { aggDerivative } from './metrics/derivative_fn';
import { aggGeoBounds } from './metrics/geo_bounds_fn';
import { aggGeoCentroid } from './metrics/geo_centroid_fn';
import { aggMax } from './metrics/max_fn';
import { aggMedian } from './metrics/median_fn';
import { aggMin } from './metrics/min_fn';
import { aggMovingAvg } from './metrics/moving_avg_fn';
import { aggPercentileRanks } from './metrics/percentile_ranks_fn';
import { aggPercentiles } from './metrics/percentiles_fn';
import { aggSerialDiff } from './metrics/serial_diff_fn';
import { aggStdDeviation } from './metrics/std_deviation_fn';
import { aggSum } from './metrics/sum_fn';
import { aggTopHit } from './metrics/top_hit_fn';

export const getAggTypesFunctions = () => [
aggAvg,
aggBucketAvg,
aggBucketMax,
aggBucketMin,
aggBucketSum,
aggCardinality,
aggCount,
aggCumulativeSum,
aggDerivative,
aggGeoBounds,
aggGeoCentroid,
aggMax,
aggMedian,
aggMin,
aggMovingAvg,
aggPercentileRanks,
aggPercentiles,
aggSerialDiff,
aggStdDeviation,
aggSum,
aggTopHit,
aggFilter,
aggFilters,
aggSignificantTerms,
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/data/public/search/aggs/metrics/avg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ import { MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
import { GetInternalStartServicesFn } from '../../../types';
import { BaseAggParams } from '../types';

const averageTitle = i18n.translate('data.search.aggs.metrics.averageTitle', {
defaultMessage: 'Average',
});

export interface AggParamsAvg extends BaseAggParams {
field: string;
}

export interface AvgMetricAggDependencies {
getInternalStartServices: GetInternalStartServicesFn;
}
Expand Down
64 changes: 64 additions & 0 deletions src/plugins/data/public/search/aggs/metrics/avg_fn.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { functionWrapper } from '../test_helpers';
import { aggAvg } from './avg_fn';

describe('agg_expression_functions', () => {
describe('aggAvg', () => {
const fn = functionWrapper(aggAvg());

test('required args are provided', () => {
const actual = fn({
field: 'machine.os.keyword',
});
expect(actual).toMatchInlineSnapshot(`
Object {
"type": "agg_type",
"value": Object {
"enabled": true,
"id": undefined,
"params": Object {
"customLabel": undefined,
"field": "machine.os.keyword",
"json": undefined,
},
"schema": undefined,
"type": "avg",
},
}
`);
});

test('correctly parses json string argument', () => {
const actual = fn({
field: 'machine.os.keyword',
json: '{ "foo": true }',
});

expect(actual.value.params.json).toEqual({ foo: true });
expect(() => {
fn({
field: 'machine.os.keyword',
json: '/// intentionally malformed json ///',
});
}).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`);
});
});
});
95 changes: 95 additions & 0 deletions src/plugins/data/public/search/aggs/metrics/avg_fn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { i18n } from '@kbn/i18n';
import { ExpressionFunctionDefinition } from '../../../../../expressions/public';
import { AggExpressionType, AggExpressionFunctionArgs, METRIC_TYPES } from '../';
import { getParsedValue } from '../utils/get_parsed_value';

const fnName = 'aggAvg';

type Input = any;
type AggArgs = AggExpressionFunctionArgs<typeof METRIC_TYPES.AVG>;
type Output = AggExpressionType;
type FunctionDefinition = ExpressionFunctionDefinition<typeof fnName, Input, AggArgs, Output>;

export const aggAvg = (): FunctionDefinition => ({
name: fnName,
help: i18n.translate('data.search.aggs.function.metrics.avg.help', {
defaultMessage: 'Generates a serialized agg config for a Avg agg',
}),
type: 'agg_type',
args: {
id: {
types: ['string'],
help: i18n.translate('data.search.aggs.metrics.avg.id.help', {
defaultMessage: 'ID for this aggregation',
}),
},
enabled: {
types: ['boolean'],
default: true,
help: i18n.translate('data.search.aggs.metrics.avg.enabled.help', {
defaultMessage: 'Specifies whether this aggregation should be enabled',
}),
},
schema: {
types: ['string'],
help: i18n.translate('data.search.aggs.metrics.avg.schema.help', {
defaultMessage: 'Schema to use for this aggregation',
}),
},
field: {
types: ['string'],
required: true,
help: i18n.translate('data.search.aggs.metrics.avg.field.help', {
defaultMessage: 'Field to use for this aggregation',
}),
},
json: {
types: ['string'],
help: i18n.translate('data.search.aggs.metrics.avg.json.help', {
defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch',
}),
},
customLabel: {
types: ['string'],
help: i18n.translate('data.search.aggs.metrics.avg.customLabel.help', {
defaultMessage: 'Represents a custom label for this aggregation',
}),
},
},
fn: (input, args) => {
const { id, enabled, schema, ...rest } = args;

return {
type: 'agg_type',
value: {
id,
enabled,
schema,
type: METRIC_TYPES.AVG,
params: {
...rest,
json: getParsedValue(args, 'json'),
},
},
};
},
});
6 changes: 6 additions & 0 deletions src/plugins/data/public/search/aggs/metrics/bucket_avg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,14 @@ import { MetricAggType } from './metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
import { METRIC_TYPES } from './metric_agg_types';
import { AggConfigSerialized, BaseAggParams } from '../types';
import { GetInternalStartServicesFn } from '../../../types';

export interface AggParamsBucketAvg extends BaseAggParams {
customMetric?: AggConfigSerialized;
customBucket?: AggConfigSerialized;
}

export interface BucketAvgMetricAggDependencies {
getInternalStartServices: GetInternalStartServicesFn;
}
Expand Down
78 changes: 78 additions & 0 deletions src/plugins/data/public/search/aggs/metrics/bucket_avg_fn.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { functionWrapper } from '../test_helpers';
import { aggBucketAvg } from './bucket_avg_fn';

describe('agg_expression_functions', () => {
describe('aggBucketAvg', () => {
const fn = functionWrapper(aggBucketAvg());

test('handles customMetric and customBucket as a subexpression', () => {
const actual = fn({
customMetric: fn({}),
customBucket: fn({}),
});

expect(actual.value.params).toMatchInlineSnapshot(`
Object {
"customBucket": Object {
"enabled": true,
"id": undefined,
"params": Object {
"customBucket": undefined,
"customLabel": undefined,
"customMetric": undefined,
"json": undefined,
},
"schema": undefined,
"type": "avg_bucket",
},
"customLabel": undefined,
"customMetric": Object {
"enabled": true,
"id": undefined,
"params": Object {
"customBucket": undefined,
"customLabel": undefined,
"customMetric": undefined,
"json": undefined,
},
"schema": undefined,
"type": "avg_bucket",
},
"json": undefined,
}
`);
});

test('correctly parses json string argument', () => {
const actual = fn({
json: '{ "foo": true }',
});

expect(actual.value.params.json).toEqual({ foo: true });
expect(() => {
fn({
json: '/// intentionally malformed json ///',
});
}).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`);
});
});
});
Loading

0 comments on commit 2ccc397

Please sign in to comment.