From 49770eda43ad26a472ec2f08fcb3953d3f55d057 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Tue, 1 Sep 2020 15:32:40 -0400 Subject: [PATCH 1/4] [APM] Update aggregations to support script sources --- .../apm/typings/elasticsearch/aggregations.ts | 131 +++++++++--------- 1 file changed, 62 insertions(+), 69 deletions(-) diff --git a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts index d25ec8709e3be..104719f4fe2c6 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts @@ -13,11 +13,11 @@ export type SortOptions = SortOrder | SortInstruction | SortInstruction[]; type Script = | string | { - lang?: string; - id?: string; - source?: string; - params?: Record; - }; + lang?: string; + id?: string; + source?: string; + params?: Record; + }; type BucketsPath = string | Record; @@ -25,12 +25,12 @@ type SourceOptions = string | string[]; type MetricsAggregationOptions = | { - field: string; - missing?: number; - } + field: string; + missing?: number; + } | { - script?: Script; - }; + script?: Script; + }; interface MetricsAggregationResponsePart { value: number | null; @@ -43,9 +43,9 @@ interface DateHistogramBucket { type GetCompositeKeys< TAggregationOptionsMap extends AggregationOptionsMap -> = TAggregationOptionsMap extends { - composite: { sources: Array }; -} + > = TAggregationOptionsMap extends { + composite: { sources: Array }; + } ? keyof Source : never; @@ -56,30 +56,27 @@ type CompositeOptionsSource = Record< export interface AggregationOptionsByType { terms: { - field: string; size?: number; missing?: string; order?: SortOptions; execution_hint?: 'map' | 'global_ordinals'; - }; + } & MetricsAggregationOptions; date_histogram: { - field: string; format?: string; min_doc_count?: number; extended_bounds?: { min: number; max: number; }; - } & ({ calendar_interval: string } | { fixed_interval: string }); + } & ({ calendar_interval: string } | { fixed_interval: string }) & MetricsAggregationOptions; histogram: { - field: string; interval: number; min_doc_count?: number; extended_bounds?: { min?: number | string; max?: number | string; }; - }; + } & MetricsAggregationOptions; avg: MetricsAggregationOptions; max: MetricsAggregationOptions; min: MetricsAggregationOptions; @@ -89,10 +86,9 @@ export interface AggregationOptionsByType { precision_threshold?: number; }; percentiles: { - field: string; percents?: number[]; hdr?: { number_of_significant_value_digits: number }; - }; + } & MetricsAggregationOptions; extended_stats: { field: string; }; @@ -133,7 +129,6 @@ export interface AggregationOptionsByType { reduce_script: Script; }; date_range: { - field: string; format?: string; ranges: Array< | { from: string | number } @@ -141,17 +136,15 @@ export interface AggregationOptionsByType { | { from: string | number; to: string | number } >; keyed?: boolean; - }; + } & MetricsAggregationOptions; auto_date_histogram: { - field: string; buckets: number; - }; + } & MetricsAggregationOptions; percentile_ranks: { - field: string; values: string[]; keyed?: boolean; hdr?: { number_of_significant_value_digits: number }; - }; + } & MetricsAggregationOptions; } type AggregationType = keyof AggregationOptionsByType; @@ -178,14 +171,14 @@ export interface AggregationInputMap { type BucketSubAggregationResponse< TAggregationInputMap extends AggregationInputMap | undefined, TDocument -> = TAggregationInputMap extends AggregationInputMap + > = TAggregationInputMap extends AggregationInputMap ? AggregationResponseMap : {}; interface AggregationResponsePart< TAggregationOptionsMap extends AggregationOptionsMap, TDocument -> { + > { terms: { buckets: Array< { @@ -211,7 +204,7 @@ interface AggregationResponsePart< date_histogram: { buckets: Array< DateHistogramBucket & - BucketSubAggregationResponse + BucketSubAggregationResponse >; }; avg: MetricsAggregationResponsePart; @@ -255,38 +248,38 @@ interface AggregationResponsePart< doc_count: number; } & AggregationResponseMap; filters: TAggregationOptionsMap extends { filters: { filters: any[] } } - ? Array< - { doc_count: number } & AggregationResponseMap< - TAggregationOptionsMap['aggs'], - TDocument - > - > - : TAggregationOptionsMap extends { - filters: { - filters: Record; - }; - } - ? { - buckets: { - [key in keyof TAggregationOptionsMap['filters']['filters']]: { - doc_count: number; - } & AggregationResponseMap; - }; - } - : never; + ? Array< + { doc_count: number } & AggregationResponseMap< + TAggregationOptionsMap['aggs'], + TDocument + > + > + : TAggregationOptionsMap extends { + filters: { + filters: Record; + }; + } + ? { + buckets: { + [key in keyof TAggregationOptionsMap['filters']['filters']]: { + doc_count: number; + } & AggregationResponseMap; + }; + } + : never; sampler: { doc_count: number; } & AggregationResponseMap; derivative: - | { - value: number; - } - | undefined; + | { + value: number; + } + | undefined; bucket_script: - | { - value: number | null; - } - | undefined; + | { + value: number | null; + } + | undefined; composite: { after_key: Record< GetCompositeKeys, @@ -310,13 +303,13 @@ interface AggregationResponsePart< }; date_range: { buckets: TAggregationOptionsMap extends { date_range: { keyed: true } } - ? Record - : { buckets: DateRangeBucket[] }; + ? Record + : { buckets: DateRangeBucket[] }; }; auto_date_histogram: { buckets: Array< DateHistogramBucket & - AggregationResponseMap + AggregationResponseMap >; interval: string; }; @@ -325,8 +318,8 @@ interface AggregationResponsePart< values: TAggregationOptionsMap extends { percentile_ranks: { keyed: false }; } - ? Array<{ key: number; value: number }> - : Record; + ? Array<{ key: number; value: number }> + : Record; }; } @@ -347,16 +340,16 @@ interface AggregationResponsePart< // types, e.g. { foo: string; bar?: undefined } | { foo?: undefined; bar: string }; export type ValidAggregationKeysOf< T extends Record -> = keyof (UnionToIntersection extends never ? T : UnionToIntersection); + > = keyof (UnionToIntersection extends never ? T : UnionToIntersection); export type AggregationResponseMap< TAggregationInputMap extends AggregationInputMap | undefined, TDocument -> = TAggregationInputMap extends AggregationInputMap + > = TAggregationInputMap extends AggregationInputMap ? { - [TName in keyof TAggregationInputMap]: AggregationResponsePart< - TAggregationInputMap[TName], - TDocument - >[AggregationType & ValidAggregationKeysOf]; - } + [TName in keyof TAggregationInputMap]: AggregationResponsePart< + TAggregationInputMap[TName], + TDocument + >[AggregationType & ValidAggregationKeysOf]; + } : undefined; From 45a839b6ce2076e6ea96f66913bf0672f40a8af8 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Tue, 1 Sep 2020 15:36:27 -0400 Subject: [PATCH 2/4] Fix whitespace --- .../apm/typings/elasticsearch/aggregations.ts | 113 +++++++++--------- 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts index 104719f4fe2c6..f4f7e41ad8147 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts @@ -13,11 +13,11 @@ export type SortOptions = SortOrder | SortInstruction | SortInstruction[]; type Script = | string | { - lang?: string; - id?: string; - source?: string; - params?: Record; - }; + lang?: string; + id?: string; + source?: string; + params?: Record; + }; type BucketsPath = string | Record; @@ -25,12 +25,12 @@ type SourceOptions = string | string[]; type MetricsAggregationOptions = | { - field: string; - missing?: number; - } + field: string; + missing?: number; + } | { - script?: Script; - }; + script?: Script; + }; interface MetricsAggregationResponsePart { value: number | null; @@ -43,9 +43,9 @@ interface DateHistogramBucket { type GetCompositeKeys< TAggregationOptionsMap extends AggregationOptionsMap - > = TAggregationOptionsMap extends { - composite: { sources: Array }; - } +> = TAggregationOptionsMap extends { + composite: { sources: Array }; +} ? keyof Source : never; @@ -68,7 +68,8 @@ export interface AggregationOptionsByType { min: number; max: number; }; - } & ({ calendar_interval: string } | { fixed_interval: string }) & MetricsAggregationOptions; + } & ({ calendar_interval: string } | { fixed_interval: string }) & + MetricsAggregationOptions; histogram: { interval: number; min_doc_count?: number; @@ -171,14 +172,14 @@ export interface AggregationInputMap { type BucketSubAggregationResponse< TAggregationInputMap extends AggregationInputMap | undefined, TDocument - > = TAggregationInputMap extends AggregationInputMap +> = TAggregationInputMap extends AggregationInputMap ? AggregationResponseMap : {}; interface AggregationResponsePart< TAggregationOptionsMap extends AggregationOptionsMap, TDocument - > { +> { terms: { buckets: Array< { @@ -204,7 +205,7 @@ interface AggregationResponsePart< date_histogram: { buckets: Array< DateHistogramBucket & - BucketSubAggregationResponse + BucketSubAggregationResponse >; }; avg: MetricsAggregationResponsePart; @@ -248,38 +249,38 @@ interface AggregationResponsePart< doc_count: number; } & AggregationResponseMap; filters: TAggregationOptionsMap extends { filters: { filters: any[] } } - ? Array< - { doc_count: number } & AggregationResponseMap< - TAggregationOptionsMap['aggs'], - TDocument - > - > - : TAggregationOptionsMap extends { - filters: { - filters: Record; - }; - } - ? { - buckets: { - [key in keyof TAggregationOptionsMap['filters']['filters']]: { - doc_count: number; - } & AggregationResponseMap; - }; - } - : never; + ? Array< + { doc_count: number } & AggregationResponseMap< + TAggregationOptionsMap['aggs'], + TDocument + > + > + : TAggregationOptionsMap extends { + filters: { + filters: Record; + }; + } + ? { + buckets: { + [key in keyof TAggregationOptionsMap['filters']['filters']]: { + doc_count: number; + } & AggregationResponseMap; + }; + } + : never; sampler: { doc_count: number; } & AggregationResponseMap; derivative: - | { - value: number; - } - | undefined; + | { + value: number; + } + | undefined; bucket_script: - | { - value: number | null; - } - | undefined; + | { + value: number | null; + } + | undefined; composite: { after_key: Record< GetCompositeKeys, @@ -303,13 +304,13 @@ interface AggregationResponsePart< }; date_range: { buckets: TAggregationOptionsMap extends { date_range: { keyed: true } } - ? Record - : { buckets: DateRangeBucket[] }; + ? Record + : { buckets: DateRangeBucket[] }; }; auto_date_histogram: { buckets: Array< DateHistogramBucket & - AggregationResponseMap + AggregationResponseMap >; interval: string; }; @@ -318,8 +319,8 @@ interface AggregationResponsePart< values: TAggregationOptionsMap extends { percentile_ranks: { keyed: false }; } - ? Array<{ key: number; value: number }> - : Record; + ? Array<{ key: number; value: number }> + : Record; }; } @@ -340,16 +341,16 @@ interface AggregationResponsePart< // types, e.g. { foo: string; bar?: undefined } | { foo?: undefined; bar: string }; export type ValidAggregationKeysOf< T extends Record - > = keyof (UnionToIntersection extends never ? T : UnionToIntersection); +> = keyof (UnionToIntersection extends never ? T : UnionToIntersection); export type AggregationResponseMap< TAggregationInputMap extends AggregationInputMap | undefined, TDocument - > = TAggregationInputMap extends AggregationInputMap +> = TAggregationInputMap extends AggregationInputMap ? { - [TName in keyof TAggregationInputMap]: AggregationResponsePart< - TAggregationInputMap[TName], - TDocument - >[AggregationType & ValidAggregationKeysOf]; - } + [TName in keyof TAggregationInputMap]: AggregationResponsePart< + TAggregationInputMap[TName], + TDocument + >[AggregationType & ValidAggregationKeysOf]; + } : undefined; From e8dd7198ee0b9acd6d9cedc351e3f0eacde27981 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Tue, 1 Sep 2020 18:27:43 -0400 Subject: [PATCH 3/4] Fix checks --- .../get_local_filter_query.ts | 14 ++++---- .../apm/typings/elasticsearch/aggregations.ts | 33 +++++++++---------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts index cfbd79d37c041..d8d6f9214f742 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts @@ -23,15 +23,17 @@ export const getLocalFilterQuery = ({ const field = localUIFilters[localUIFilterName]; const filter = getUiFiltersES(omit(uiFilters, field.name)); - const bucketCountAggregation = projection.body.aggs + const projectionSource = + projection.body.aggs && + projection.body.aggs[Object.keys(projection.body.aggs)[0]].terms; + const bucketCountAggregation = projectionSource ? { aggs: { bucket_count: { - cardinality: { - field: - projection.body.aggs[Object.keys(projection.body.aggs)[0]].terms - .field, - }, + cardinality: + 'field' in projectionSource + ? { field: projectionSource.field } + : { script: projectionSource.script }, }, }, } diff --git a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts index f4f7e41ad8147..402e062413108 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts @@ -23,13 +23,13 @@ type BucketsPath = string | Record; type SourceOptions = string | string[]; -type MetricsAggregationOptions = +type AggregationSourceOptions = | { field: string; - missing?: number; + missing?: unknown; } | { - script?: Script; + script: Script; }; interface MetricsAggregationResponsePart { @@ -57,10 +57,9 @@ type CompositeOptionsSource = Record< export interface AggregationOptionsByType { terms: { size?: number; - missing?: string; order?: SortOptions; execution_hint?: 'map' | 'global_ordinals'; - } & MetricsAggregationOptions; + } & AggregationSourceOptions; date_histogram: { format?: string; min_doc_count?: number; @@ -69,7 +68,7 @@ export interface AggregationOptionsByType { max: number; }; } & ({ calendar_interval: string } | { fixed_interval: string }) & - MetricsAggregationOptions; + AggregationSourceOptions; histogram: { interval: number; min_doc_count?: number; @@ -77,19 +76,19 @@ export interface AggregationOptionsByType { min?: number | string; max?: number | string; }; - } & MetricsAggregationOptions; - avg: MetricsAggregationOptions; - max: MetricsAggregationOptions; - min: MetricsAggregationOptions; - sum: MetricsAggregationOptions; - value_count: MetricsAggregationOptions; - cardinality: MetricsAggregationOptions & { + } & AggregationSourceOptions; + avg: AggregationSourceOptions; + max: AggregationSourceOptions; + min: AggregationSourceOptions; + sum: AggregationSourceOptions; + value_count: AggregationSourceOptions; + cardinality: AggregationSourceOptions & { precision_threshold?: number; }; percentiles: { percents?: number[]; hdr?: { number_of_significant_value_digits: number }; - } & MetricsAggregationOptions; + } & AggregationSourceOptions; extended_stats: { field: string; }; @@ -137,15 +136,15 @@ export interface AggregationOptionsByType { | { from: string | number; to: string | number } >; keyed?: boolean; - } & MetricsAggregationOptions; + } & AggregationSourceOptions; auto_date_histogram: { buckets: number; - } & MetricsAggregationOptions; + } & AggregationSourceOptions; percentile_ranks: { values: string[]; keyed?: boolean; hdr?: { number_of_significant_value_digits: number }; - } & MetricsAggregationOptions; + } & AggregationSourceOptions; } type AggregationType = keyof AggregationOptionsByType; From ac1f90b01f85a5fdf68470a08dccff2cbb85d531 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Wed, 2 Sep 2020 19:50:57 +0200 Subject: [PATCH 4/4] Explicitly require field in projection --- .../local_ui_filters/get_local_filter_query.ts | 14 ++++++-------- x-pack/plugins/apm/server/projections/typings.ts | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts index d8d6f9214f742..cfbd79d37c041 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/get_local_filter_query.ts @@ -23,17 +23,15 @@ export const getLocalFilterQuery = ({ const field = localUIFilters[localUIFilterName]; const filter = getUiFiltersES(omit(uiFilters, field.name)); - const projectionSource = - projection.body.aggs && - projection.body.aggs[Object.keys(projection.body.aggs)[0]].terms; - const bucketCountAggregation = projectionSource + const bucketCountAggregation = projection.body.aggs ? { aggs: { bucket_count: { - cardinality: - 'field' in projectionSource - ? { field: projectionSource.field } - : { script: projectionSource.script }, + cardinality: { + field: + projection.body.aggs[Object.keys(projection.body.aggs)[0]].terms + .field, + }, }, }, } diff --git a/x-pack/plugins/apm/server/projections/typings.ts b/x-pack/plugins/apm/server/projections/typings.ts index 77a5beaf54605..332ac533e78c6 100644 --- a/x-pack/plugins/apm/server/projections/typings.ts +++ b/x-pack/plugins/apm/server/projections/typings.ts @@ -15,7 +15,7 @@ export type Projection = Omit & { body: Omit & { aggs?: { [key: string]: { - terms: AggregationOptionsByType['terms']; + terms: AggregationOptionsByType['terms'] & { field: string }; aggs?: AggregationInputMap; }; };