ES client : use the new type definitions (#83808)

* Use client from branch

* Get type checking working in core

* Fix types in other plugins

* Update client types + remove type errors from core

* migrate Task Manager Elasticsearch typing from legacy library to client library

* use SortOrder instead o string in alerts

* Update client types + fix core type issues

* fix maps ts errors

* Update Lens types

* Convert Search Profiler body from a string to an object to conform to SearchRequest type.

* Fix SOT types

* Fix/mute Security/Spaces plugins type errors.

* Fix bootstrap types

* Fix painless_lab

* corrected es typing in Event Log

* Use new types from client for inferred search responses

* Latest type defs

* Integrate latest type defs for APM/UX

* fix core errors

* fix telemetry errors

* fix canvas errors

* fix data_enhanced errors

* fix event_log errors

* mute lens errors

* fix or mute maps errors

* fix reporting errors

* fix security errors

* mute errors in task_manager

* fix errors in telemetry_collection_xpack

* fix errors in data plugins

* fix errors in alerts

* mute errors in index_management

* fix task_manager errors

* mute or fix lens errors

* fix upgrade_assistant errors

* fix or mute errors in index_lifecycle_management

* fix discover errors

* fix core tests

* ML changes

* fix core type errors

* mute error in kbn-es-archiver

* fix error in data plugin

* fix error in telemetry plugin

* fix error in discover

* fix discover errors

* fix errors in task_manager

* fix security errors

* fix wrong conflict resolution

* address errors with upstream code

* update deps to the last commit

* remove outdated comments

* fix core errors

* fix errors after update

* adding more expect errors to ML

* pull the lastest changes

* fix core errors

* fix errors in infra plugin

* fix errors in uptime plugin

* fix errors in ml

* fix errors in xpack telemetry

* fix or mute errors in transform

* fix errors in upgrade assistant

* fix or mute fleet errors

* start fixing apm errors

* fix errors in osquery

* fix telemetry tests

* core cleanup

* fix asMutableArray imports

* cleanup

* data_enhanced cleanup

* cleanup events_log

* cleaup

* fix error in kbn-es-archiver

* fix errors in kbn-es-archiver

* fix errors in kbn-es-archiver

* fix ES typings for Hit

* fix SO

* fix actions plugin

* fix fleet

* fix maps

* fix stack_alerts

* fix eslint problems

* fix event_log unit tests

* fix failures in data_enhanced tests

* fix test failure in kbn-es-archiver

* fix test failures in index_pattern_management

* fixing ML test

* remove outdated comment in kbn-es-archiver

* fix error type in ml

* fix eslint errors in osquery plugin

* fix runtime error in infra plugin

* revert changes to event_log cluser exist check

* fix eslint error in osquery

* fixing ML endpoint argument types

* fx types

* Update api-extractor docs

* attempt fix for ese test

* Fix lint error

* Fix types for ts refs

* Fix data_enhanced unit test

* fix lens types

* generate docs

* Fix a number of type issues in monitoring and ml

* fix triggers_actions_ui

* Fix ILM functional test

* Put search.d.ts typings back

* fix data plugin

* Update typings in typings/elasticsearch

* Update snapshots

* mute errors in task_manager

* mute fleet errors

* lens. remove unnecessary ts-expect-errors

* fix errors in stack_alerts

* mute errors in osquery

* fix errors in security_solution

* fix errors in lists

* fix errors in cases

* mute errors in search_examples

* use KibanaClient to enforce promise-based API

* fix errors in test/ folder

* update comment

* fix errors in x-pack/test folder

* fix errors in ml plugin

* fix optional fields in ml api_integartoon tests

* fix another casting problem in ml tests

* fix another ml test failure

* fix fleet problem after conflict resolution

* rollback changes in security_solution. trying to fix test

* Update type for discover rows

* uncomment runtime_mappings as its outdated

* address comments from Wylie

* remove eslint error due to any

* mute error due to incompatibility

* Apply suggestions from code review

Co-authored-by: John Schulz <github.com@jfsiii.org>

* fix type error in lens tests

* Update x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts

Co-authored-by: Alison Goryachev <alisonmllr20@gmail.com>

* Update x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.test.ts

Co-authored-by: Alison Goryachev <alisonmllr20@gmail.com>

* update deps

* fix errors in core types

* fix errors for the new elastic/elasticsearch version

* remove unused type

* remove unnecessary manual type cast and put optional chaining back

* ML: mute Datafeed is missing indices_options

* Apply suggestions from code review

Co-authored-by: Josh Dover <1813008+joshdover@users.noreply.github.com>

* use canary pacakge instead of git commit

Co-authored-by: Josh Dover <me@joshdover.com>
Co-authored-by: Josh Dover <1813008+joshdover@users.noreply.github.com>
Co-authored-by: Gidi Meir Morris <github@gidi.io>
Co-authored-by: Nathan Reese <reese.nathan@gmail.com>
Co-authored-by: Wylie Conlon <wylieconlon@gmail.com>
Co-authored-by: CJ Cenizal <cj@cenizal.com>
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com>
Co-authored-by: Dario Gieselaar <dario.gieselaar@elastic.co>
Co-authored-by: restrry <restrry@gmail.com>
Co-authored-by: James Gowdy <jgowdy@elastic.co>
Co-authored-by: John Schulz <github.com@jfsiii.org>
Co-authored-by: Alison Goryachev <alisonmllr20@gmail.com>
This commit is contained in:
Tomas Della Vedova 2021-03-25 09:47:16 +01:00 committed by GitHub
parent 9724051f92
commit 238791b942
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
541 changed files with 3666 additions and 3051 deletions

View file

@ -1,466 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { Unionize, UnionToIntersection } from 'utility-types';
import { ESSearchHit, MaybeReadonlyArray, ESSourceOptions, ESHitsOf } from '.';
export type SortOrder = 'asc' | 'desc';
type SortInstruction = Record<string, SortOrder | { order: SortOrder }>;
export type SortOptions = SortOrder | SortInstruction | SortInstruction[];
type Script =
| string
| {
lang?: string;
id?: string;
source?: string;
params?: Record<string, string | number>;
};
type BucketsPath = string | Record<string, string>;
type AggregationSourceOptions =
| {
field: string;
missing?: unknown;
}
| {
script: Script;
};
interface MetricsAggregationResponsePart {
value: number | null;
}
interface DateHistogramBucket {
doc_count: number;
key: number;
key_as_string: string;
}
type GetCompositeKeys<
TAggregationOptionsMap extends AggregationOptionsMap
> = TAggregationOptionsMap extends {
composite: { sources: Array<infer Source> };
}
? keyof Source
: never;
type CompositeOptionsSource = Record<
string,
| {
terms: ({ field: string } | { script: Script }) & {
missing_bucket?: boolean;
};
}
| undefined
>;
export interface AggregationOptionsByType {
terms: {
size?: number;
order?: SortOptions;
execution_hint?: 'map' | 'global_ordinals';
} & AggregationSourceOptions;
date_histogram: {
format?: string;
min_doc_count?: number;
extended_bounds?: {
min: number;
max: number;
};
} & ({ calendar_interval: string } | { fixed_interval: string }) &
AggregationSourceOptions;
histogram: {
interval: number;
min_doc_count?: number;
extended_bounds?: {
min?: number | string;
max?: number | string;
};
} & 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 };
} & AggregationSourceOptions;
stats: {
field: string;
};
extended_stats: {
field: string;
};
string_stats: { field: string };
top_hits: {
from?: number;
size?: number;
sort?: SortOptions;
_source?: ESSourceOptions;
fields?: MaybeReadonlyArray<string>;
docvalue_fields?: MaybeReadonlyArray<string>;
};
filter: Record<string, any>;
filters: {
filters: Record<string, any> | any[];
};
sampler: {
shard_size?: number;
};
derivative: {
buckets_path: BucketsPath;
};
bucket_script: {
buckets_path: BucketsPath;
script?: Script;
};
composite: {
size?: number;
sources: CompositeOptionsSource[];
after?: Record<string, string | number | null>;
};
diversified_sampler: {
shard_size?: number;
max_docs_per_value?: number;
} & ({ script: Script } | { field: string }); // TODO use MetricsAggregationOptions if possible
scripted_metric: {
params?: Record<string, any>;
init_script?: Script;
map_script: Script;
combine_script: Script;
reduce_script: Script;
};
date_range: {
format?: string;
ranges: Array<
| { from: string | number }
| { to: string | number }
| { from: string | number; to: string | number }
>;
keyed?: boolean;
} & AggregationSourceOptions;
range: {
field: string;
ranges: Array<
| { key?: string; from: string | number }
| { key?: string; to: string | number }
| { key?: string; from: string | number; to: string | number }
>;
keyed?: boolean;
};
auto_date_histogram: {
buckets: number;
} & AggregationSourceOptions;
percentile_ranks: {
values: Array<string | number>;
keyed?: boolean;
hdr?: { number_of_significant_value_digits: number };
} & AggregationSourceOptions;
bucket_sort: {
sort?: SortOptions;
from?: number;
size?: number;
};
significant_terms: {
size?: number;
field?: string;
background_filter?: Record<string, any>;
} & AggregationSourceOptions;
bucket_selector: {
buckets_path: {
[x: string]: string;
};
script: string;
};
top_metrics: {
metrics: { field: string } | MaybeReadonlyArray<{ field: string }>;
sort: SortOptions;
};
avg_bucket: {
buckets_path: string;
gap_policy?: 'skip' | 'insert_zeros';
format?: string;
};
rate: {
unit: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';
} & (
| {
field: string;
mode: 'sum' | 'value_count';
}
| {}
);
}
type AggregationType = keyof AggregationOptionsByType;
type AggregationOptionsMap = Unionize<
{
[TAggregationType in AggregationType]: AggregationOptionsByType[TAggregationType];
}
> & { aggs?: AggregationInputMap };
interface DateRangeBucket {
key: string;
to?: number;
from?: number;
to_as_string?: string;
from_as_string?: string;
doc_count: number;
}
export interface AggregationInputMap {
[key: string]: AggregationOptionsMap;
}
type SubAggregationResponseOf<
TAggregationInputMap extends AggregationInputMap | undefined,
TDocument
> = TAggregationInputMap extends AggregationInputMap
? AggregationResponseMap<TAggregationInputMap, TDocument>
: {};
interface AggregationResponsePart<TAggregationOptionsMap extends AggregationOptionsMap, TDocument> {
terms: {
buckets: Array<
{
doc_count: number;
key: string | number;
} & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>
>;
doc_count_error_upper_bound?: number;
sum_other_doc_count?: number;
};
histogram: {
buckets: Array<
{
doc_count: number;
key: number;
} & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>
>;
};
date_histogram: {
buckets: Array<
DateHistogramBucket & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>
>;
};
avg: MetricsAggregationResponsePart;
sum: MetricsAggregationResponsePart;
max: MetricsAggregationResponsePart;
min: MetricsAggregationResponsePart;
value_count: { value: number };
cardinality: {
value: number;
};
percentiles: {
values: Record<string, number | null>;
};
stats: {
count: number;
min: number | null;
max: number | null;
avg: number | null;
sum: number | null;
};
extended_stats: {
count: number;
min: number | null;
max: number | null;
avg: number | null;
sum: number | null;
sum_of_squares: number | null;
variance: number | null;
std_deviation: number | null;
std_deviation_bounds: {
upper: number | null;
lower: number | null;
};
};
string_stats: {
count: number;
min_length: number;
max_length: number;
avg_length: number;
entropy: number;
};
top_hits: {
hits: {
total: {
value: number;
relation: 'eq' | 'gte';
};
max_score: number | null;
hits: TAggregationOptionsMap extends { top_hits: AggregationOptionsByType['top_hits'] }
? ESHitsOf<TAggregationOptionsMap['top_hits'], TDocument>
: ESSearchHit[];
};
};
filter: {
doc_count: number;
} & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>;
filters: TAggregationOptionsMap extends { filters: { filters: any[] } }
? Array<
{ doc_count: number } & AggregationResponseMap<TAggregationOptionsMap['aggs'], TDocument>
>
: TAggregationOptionsMap extends {
filters: {
filters: Record<string, any>;
};
}
? {
buckets: {
[key in keyof TAggregationOptionsMap['filters']['filters']]: {
doc_count: number;
} & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>;
};
}
: never;
sampler: {
doc_count: number;
} & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>;
derivative:
| {
value: number;
}
| undefined;
bucket_script:
| {
value: number | null;
}
| undefined;
composite: {
after_key: {
[key in GetCompositeKeys<TAggregationOptionsMap>]: TAggregationOptionsMap;
};
buckets: Array<
{
key: Record<GetCompositeKeys<TAggregationOptionsMap>, string | number>;
doc_count: number;
} & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>
>;
};
diversified_sampler: {
doc_count: number;
} & AggregationResponseMap<TAggregationOptionsMap['aggs'], TDocument>;
scripted_metric: {
value: unknown;
};
date_range: {
buckets: TAggregationOptionsMap extends { date_range: { keyed: true } }
? Record<string, DateRangeBucket>
: { buckets: DateRangeBucket[] };
};
range: {
buckets: TAggregationOptionsMap extends { range: { keyed: true } }
? Record<
string,
DateRangeBucket & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>
>
: Array<
DateRangeBucket & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>
>;
};
auto_date_histogram: {
buckets: Array<
DateHistogramBucket & AggregationResponseMap<TAggregationOptionsMap['aggs'], TDocument>
>;
interval: string;
};
percentile_ranks: {
values: TAggregationOptionsMap extends {
percentile_ranks: { keyed: false };
}
? Array<{ key: number; value: number }>
: Record<string, number>;
};
significant_terms: {
doc_count: number;
bg_count: number;
buckets: Array<
{
score: number;
bg_count: number;
doc_count: number;
key: string | number;
} & SubAggregationResponseOf<TAggregationOptionsMap['aggs'], TDocument>
>;
};
bucket_sort: undefined;
bucket_selector: undefined;
top_metrics: {
top: [
{
sort: [string | number];
metrics: UnionToIntersection<
TAggregationOptionsMap extends {
top_metrics: { metrics: { field: infer TFieldName } };
}
? TopMetricsMap<TFieldName>
: TAggregationOptionsMap extends {
top_metrics: { metrics: MaybeReadonlyArray<{ field: infer TFieldName }> };
}
? TopMetricsMap<TFieldName>
: TopMetricsMap<string>
>;
}
];
};
avg_bucket: {
value: number | null;
};
rate: {
value: number | null;
};
}
type TopMetricsMap<TFieldName> = TFieldName extends string
? Record<TFieldName, string | number | null>
: Record<string, string | number>;
// Type for debugging purposes. If you see an error in AggregationResponseMap
// similar to "cannot be used to index type", uncomment the type below and hover
// over it to see what aggregation response types are missing compared to the
// input map.
// type MissingAggregationResponseTypes = Exclude<
// AggregationType,
// keyof AggregationResponsePart<{}, unknown>
// >;
// ensures aggregations work with requests where aggregation options are a union type,
// e.g. { transaction_groups: { composite: any } | { terms: any } }.
// Union keys are not included in keyof. The type will fall back to keyof T if
// UnionToIntersection fails, which happens when there are conflicts between the union
// types, e.g. { foo: string; bar?: undefined } | { foo?: undefined; bar: string };
export type ValidAggregationKeysOf<
T extends Record<string, any>
> = keyof (UnionToIntersection<T> extends never ? T : UnionToIntersection<T>);
export type AggregationResultOf<
TAggregationOptionsMap extends AggregationOptionsMap,
TDocument
> = AggregationResponsePart<TAggregationOptionsMap, TDocument>[AggregationType &
ValidAggregationKeysOf<TAggregationOptionsMap>];
export type AggregationResponseMap<
TAggregationInputMap extends AggregationInputMap | undefined,
TDocument
> = TAggregationInputMap extends AggregationInputMap
? {
[TName in keyof TAggregationInputMap]: AggregationResponsePart<
TAggregationInputMap[TName],
TDocument
>[AggregationType & ValidAggregationKeysOf<TAggregationInputMap[TName]>];
}
: undefined;

View file

@ -5,136 +5,28 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { estypes } from '@elastic/elasticsearch';
import { InferSearchResponseOf, AggregateOf as AggregationResultOf, SearchHit } from './search';
import { ValuesType } from 'utility-types';
import { Explanation, SearchParams, SearchResponse } from 'elasticsearch';
import { RequestParams } from '@elastic/elasticsearch';
import { AggregationResponseMap, AggregationInputMap, SortOptions } from './aggregations';
export {
AggregationInputMap,
AggregationOptionsByType,
AggregationResponseMap,
AggregationResultOf,
SortOptions,
ValidAggregationKeysOf,
} from './aggregations';
export type ESFilter = estypes.QueryContainer;
export type ESSearchRequest = estypes.SearchRequest;
export type AggregationOptionsByType = Required<estypes.AggregationContainer>;
// Typings for Elasticsearch queries and aggregations. These are intended to be
// moved to the Elasticsearch JS client at some point (see #77720.)
export type MaybeReadonlyArray<T> = T[] | readonly T[];
interface CollapseQuery {
field: string;
inner_hits?: {
name: string;
size?: number;
sort?: SortOptions;
_source?:
| string
| string[]
| {
includes?: string | string[];
excludes?: string | string[];
};
collapse?: {
field: string;
};
};
max_concurrent_group_searches?: number;
}
export type ESSourceOptions = boolean | string | string[];
export type ESHitsOf<
TOptions extends
| {
size?: number;
_source?: ESSourceOptions;
docvalue_fields?: MaybeReadonlyArray<string>;
fields?: MaybeReadonlyArray<string>;
}
| undefined,
TDocument extends unknown
> = Array<
ESSearchHit<
TOptions extends { _source: false } ? undefined : TDocument,
TOptions extends { fields: MaybeReadonlyArray<string> } ? TOptions['fields'] : undefined,
TOptions extends { docvalue_fields: MaybeReadonlyArray<string> }
? TOptions['docvalue_fields']
: undefined
>
>;
export interface ESSearchBody {
query?: any;
size?: number;
from?: number;
aggs?: AggregationInputMap;
track_total_hits?: boolean | number;
collapse?: CollapseQuery;
search_after?: Array<string | number>;
_source?: ESSourceOptions;
}
export type ESSearchRequest = RequestParams.Search<ESSearchBody>;
export interface ESSearchOptions {
restTotalHitsAsInt: boolean;
}
export type ESSearchHit<
TSource extends any = unknown,
TFields extends MaybeReadonlyArray<string> | undefined = undefined,
TDocValueFields extends MaybeReadonlyArray<string> | undefined = undefined
> = {
_index: string;
_type: string;
_id: string;
_score: number;
_version?: number;
_explanation?: Explanation;
highlight?: any;
inner_hits?: any;
matched_queries?: string[];
sort?: string[];
} & (TSource extends false ? {} : { _source: TSource }) &
(TFields extends MaybeReadonlyArray<string>
? {
fields: Partial<Record<ValuesType<TFields>, unknown[]>>;
}
: {}) &
(TDocValueFields extends MaybeReadonlyArray<string>
? {
fields: Partial<Record<ValuesType<TDocValueFields>, unknown[]>>;
}
: {});
export type ESSearchResponse<
TDocument,
TSearchRequest extends ESSearchRequest,
TOptions extends ESSearchOptions = { restTotalHitsAsInt: false }
> = Omit<SearchResponse<TDocument>, 'aggregations' | 'hits'> &
(TSearchRequest extends { body: { aggs: AggregationInputMap } }
? {
aggregations?: AggregationResponseMap<TSearchRequest['body']['aggs'], TDocument>;
}
: {}) & {
hits: Omit<SearchResponse<TDocument>['hits'], 'total' | 'hits'> &
(TOptions['restTotalHitsAsInt'] extends true
? {
total: number;
}
: {
total: {
value: number;
relation: 'eq' | 'gte';
};
}) & { hits: ESHitsOf<TSearchRequest['body'], TDocument> };
};
TDocument = unknown,
TSearchRequest extends ESSearchRequest = ESSearchRequest,
TOptions extends { restTotalHitsAsInt: boolean } = { restTotalHitsAsInt: false }
> = InferSearchResponseOf<TDocument, TSearchRequest, TOptions>;
export interface ESFilter {
[key: string]: {
[key: string]: string | string[] | number | boolean | Record<string, unknown> | ESFilter[];
};
}
export { InferSearchResponseOf, AggregationResultOf, SearchHit };

577
typings/elasticsearch/search.d.ts vendored Normal file
View file

@ -0,0 +1,577 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { ValuesType } from 'utility-types';
import { estypes } from '@elastic/elasticsearch';
type InvalidAggregationRequest = unknown;
// ensures aggregations work with requests where aggregation options are a union type,
// e.g. { transaction_groups: { composite: any } | { terms: any } }.
// Union keys are not included in keyof, but extends iterates over the types in a union.
type ValidAggregationKeysOf<T extends Record<string, any>> = T extends T ? keyof T : never;
type KeyOfSource<T> = Record<
keyof T,
(T extends Record<string, { terms: { missing_bucket: true } }> ? null : never) | string | number
>;
type KeysOfSources<T extends any[]> = T extends [infer U, ...infer V]
? KeyOfSource<U> & KeysOfSources<V>
: T extends Array<infer U>
? KeyOfSource<U>
: {};
type CompositeKeysOf<
TAggregationContainer extends estypes.AggregationContainer
> = TAggregationContainer extends {
composite: { sources: [...infer TSource] };
}
? KeysOfSources<TSource>
: unknown;
type Source = estypes.SourceFilter | boolean | estypes.Fields;
type ValueTypeOfField<T> = T extends Record<string, string | number>
? ValuesType<T>
: T extends string[] | number[]
? ValueTypeOfField<ValuesType<T>>
: T extends { field: estypes.Field }
? T['field']
: T extends string | number
? T
: never;
type MaybeArray<T> = T | T[];
type Fields = MaybeArray<string | estypes.DateField>;
type DocValueFields = MaybeArray<string | estypes.DocValueField>;
export type SearchHit<
TSource extends any = unknown,
TFields extends Fields | undefined = undefined,
TDocValueFields extends DocValueFields | undefined = undefined
> = Omit<estypes.Hit, '_source' | 'fields'> &
(TSource extends false ? {} : { _source: TSource }) &
(TFields extends estypes.Fields
? {
fields: Partial<Record<ValueTypeOfField<TFields>, unknown[]>>;
}
: {}) &
(TDocValueFields extends DocValueFields
? {
fields: Partial<Record<ValueTypeOfField<TDocValueFields>, unknown[]>>;
}
: {});
type HitsOf<
TOptions extends
| { _source?: Source; fields?: Fields; docvalue_fields?: DocValueFields }
| undefined,
TDocument extends unknown
> = Array<
SearchHit<
TOptions extends { _source: false } ? undefined : TDocument,
TOptions extends { fields: estypes.Fields } ? TOptions['fields'] : undefined,
TOptions extends { docvalue_fields: DocValueFields } ? TOptions['docvalue_fields'] : undefined
>
>;
type AggregationTypeName = Exclude<keyof estypes.AggregationContainer, 'aggs' | 'aggregations'>;
type AggregationMap = Partial<Record<string, estypes.AggregationContainer>>;
type TopLevelAggregationRequest = Pick<estypes.AggregationContainer, 'aggs' | 'aggregations'>;
type MaybeKeyed<
TAggregationContainer,
TBucket,
TKeys extends string = string
> = TAggregationContainer extends Record<string, { keyed: true }>
? Record<TKeys, TBucket>
: { buckets: TBucket[] };
export type AggregateOf<
TAggregationContainer extends estypes.AggregationContainer,
TDocument
> = (Record<AggregationTypeName, unknown> & {
adjacency_matrix: {
buckets: Array<
{
key: string;
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
};
auto_date_histogram: {
interval: string;
buckets: Array<
{
key: number;
key_as_string: string;
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
};
avg: {
value: number | null;
value_as_string?: string;
};
avg_bucket: {
value: number | null;
};
boxplot: {
min: number | null;
max: number | null;
q1: number | null;
q2: number | null;
q3: number | null;
};
bucket_script: {
value: unknown;
};
cardinality: {
value: number;
};
children: {
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>;
composite: {
after_key: CompositeKeysOf<TAggregationContainer>;
buckets: Array<
{
doc_count: number;
key: CompositeKeysOf<TAggregationContainer>;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
};
cumulative_cardinality: {
value: number;
};
cumulative_sum: {
value: number;
};
date_histogram: MaybeKeyed<
TAggregationContainer,
{
key: number;
key_as_string: string;
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
date_range: MaybeKeyed<
TAggregationContainer,
Partial<{ from: string | number; from_as_string: string }> &
Partial<{ to: string | number; to_as_string: string }> & {
doc_count: number;
key: string;
}
>;
derivative:
| {
value: number | null;
}
| undefined;
extended_stats: {
count: number;
min: number | null;
max: number | null;
avg: number | null;
sum: number;
sum_of_squares: number | null;
variance: number | null;
variance_population: number | null;
variance_sampling: number | null;
std_deviation: number | null;
std_deviation_population: number | null;
std_deviation_sampling: number | null;
std_deviation_bounds: {
upper: number | null;
lower: number | null;
upper_population: number | null;
lower_population: number | null;
upper_sampling: number | null;
lower_sampling: number | null;
};
} & (
| {
min_as_string: string;
max_as_string: string;
avg_as_string: string;
sum_of_squares_as_string: string;
variance_population_as_string: string;
variance_sampling_as_string: string;
std_deviation_as_string: string;
std_deviation_population_as_string: string;
std_deviation_sampling_as_string: string;
std_deviation_bounds_as_string: {
upper: string;
lower: string;
upper_population: string;
lower_population: string;
upper_sampling: string;
lower_sampling: string;
};
}
| {}
);
extended_stats_bucket: {
count: number;
min: number | null;
max: number | null;
avg: number | null;
sum: number | null;
sum_of_squares: number | null;
variance: number | null;
variance_population: number | null;
variance_sampling: number | null;
std_deviation: number | null;
std_deviation_population: number | null;
std_deviation_sampling: number | null;
std_deviation_bounds: {
upper: number | null;
lower: number | null;
upper_population: number | null;
lower_population: number | null;
upper_sampling: number | null;
lower_sampling: number | null;
};
};
filter: {
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>;
filters: {
buckets: TAggregationContainer extends { filters: { filters: any[] } }
? Array<
{
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>
>
: TAggregationContainer extends { filters: { filters: Record<string, any> } }
? {
[key in keyof TAggregationContainer['filters']['filters']]: {
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>;
} &
(TAggregationContainer extends { filters: { other_bucket_key: infer TOtherBucketKey } }
? Record<
TOtherBucketKey & string,
{ doc_count: number } & SubAggregateOf<TAggregationContainer, TDocument>
>
: unknown) &
(TAggregationContainer extends { filters: { other_bucket: true } }
? { _other: { doc_count: number } & SubAggregateOf<TAggregationContainer, TDocument> }
: unknown)
: unknown;
};
geo_bounds: {
top_left: {
lat: number | null;
lon: number | null;
};
bottom_right: {
lat: number | null;
lon: number | null;
};
};
geo_centroid: {
count: number;
location: {
lat: number;
lon: number;
};
};
geo_distance: MaybeKeyed<
TAggregationContainer,
{
from: number;
to?: number;
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
geo_hash: {
buckets: Array<
{
doc_count: number;
key: string;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
};
geotile_grid: {
buckets: Array<
{
doc_count: number;
key: string;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
};
global: {
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>;
histogram: MaybeKeyed<
TAggregationContainer,
{
key: number;
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
ip_range: MaybeKeyed<
TAggregationContainer,
{
key: string;
from?: string;
to?: string;
doc_count: number;
},
TAggregationContainer extends { ip_range: { ranges: Array<infer TRangeType> } }
? TRangeType extends { key: infer TKeys }
? TKeys
: string
: string
>;
inference: {
value: number;
prediction_probability: number;
prediction_score: number;
};
max: {
value: number | null;
value_as_string?: string;
};
max_bucket: {
value: number | null;
};
min: {
value: number | null;
value_as_string?: string;
};
min_bucket: {
value: number | null;
};
median_absolute_deviation: {
value: number | null;
};
moving_avg:
| {
value: number | null;
}
| undefined;
moving_fn: {
value: number | null;
};
moving_percentiles: TAggregationContainer extends Record<string, { keyed: false }>
? Array<{ key: number; value: number | null }>
: Record<string, number | null> | undefined;
missing: {
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>;
nested: {
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>;
normalize: {
value: number | null;
// TODO: should be perhaps based on input? ie when `format` is specified
value_as_string?: string;
};
parent: {
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>;
percentiles: {
values: TAggregationContainer extends Record<string, { keyed: false }>
? Array<{ key: number; value: number | null }>
: Record<string, number | null>;
};
percentile_ranks: {
values: TAggregationContainer extends Record<string, { keyed: false }>
? Array<{ key: number; value: number | null }>
: Record<string, number | null>;
};
percentiles_bucket: {
values: TAggregationContainer extends Record<string, { keyed: false }>
? Array<{ key: number; value: number | null }>
: Record<string, number | null>;
};
range: MaybeKeyed<
TAggregationContainer,
{
key: string;
from?: number;
to?: number;
doc_count: number;
},
TAggregationContainer extends { range: { ranges: Array<infer TRangeType> } }
? TRangeType extends { key: infer TKeys }
? TKeys
: string
: string
>;
rare_terms: Array<
{
key: string | number;
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
rate: {
value: number | null;
};
reverse_nested: {
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>;
sampler: {
doc_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>;
scripted_metric: {
value: unknown;
};
serial_diff: {
value: number | null;
// TODO: should be perhaps based on input? ie when `format` is specified
value_as_string?: string;
};
significant_terms: {
doc_count: number;
bg_count: number;
buckets: Array<
{
key: string | number;
score: number;
doc_count: number;
bg_count: number;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
};
significant_text: {
doc_count: number;
buckets: Array<{
key: string;
doc_count: number;
score: number;
bg_count: number;
}>;
};
stats: {
count: number;
min: number | null;
max: number | null;
avg: number | null;
sum: number;
} & (
| {
min_as_string: string;
max_as_string: string;
avg_as_string: string;
sum_as_string: string;
}
| {}
);
stats_bucket: {
count: number;
min: number | null;
max: number | null;
avg: number | null;
sum: number;
};
string_stats: {
count: number;
min_length: number | null;
max_length: number | null;
avg_length: number | null;
entropy: number | null;
distribution: Record<string, number>;
};
sum: {
value: number | null;
value_as_string?: string;
};
sum_bucket: {
value: number | null;
};
terms: {
doc_count_error_upper_bound: number;
sum_other_doc_count: number;
buckets: Array<
{
doc_count: number;
key: string | number;
} & SubAggregateOf<TAggregationContainer, TDocument>
>;
};
top_hits: {
hits: {
total: {
value: number;
relation: 'eq' | 'gte';
};
max_score: number | null;
hits: TAggregationContainer extends { top_hits: estypes.TopHitsAggregation }
? HitsOf<TAggregationContainer['top_hits'], TDocument>
: estypes.HitsMetadata<TDocument>;
};
};
top_metrics: {
top: Array<{
sort: number[] | string[];
metrics: Record<
TAggregationContainer extends Record<string, { metrics: Array<{ field: infer TKeys }> }>
? TKeys
: string,
string | number | null
>;
}>;
};
weighted_avg: { value: number | null };
value_count: {
value: number;
};
// t_test: {} not defined
})[ValidAggregationKeysOf<TAggregationContainer> & AggregationTypeName];
type AggregateOfMap<TAggregationMap extends AggregationMap, TDocument> = {
[TAggregationName in keyof TAggregationMap]: TAggregationMap[TAggregationName] extends estypes.AggregationContainer
? AggregateOf<TAggregationMap[TAggregationName], TDocument>
: never; // using never means we effectively ignore optional keys, using {} creates a union type of { ... } | {}
};
type SubAggregateOf<TAggregationRequest, TDocument = unknown> = TAggregationRequest extends {
aggs?: AggregationMap;
}
? AggregateOfMap<TAggregationRequest['aggs'], TDocument>
: TAggregationRequest extends { aggregations?: AggregationMap }
? AggregateOfMap<TAggregationRequest['aggregations'], TDocument>
: {};
type SearchResponseOf<
TAggregationRequest extends TopLevelAggregationRequest,
TDocument
> = SubAggregateOf<TAggregationRequest, TDocument>;
// if aggregation response cannot be inferred, fall back to unknown
type WrapAggregationResponse<T> = keyof T extends never
? { aggregations?: unknown }
: { aggregations?: T };
export type InferSearchResponseOf<
TDocument = unknown,
TSearchRequest extends estypes.SearchRequest = estypes.SearchRequest,
TOptions extends { restTotalHitsAsInt?: boolean } = {}
> = Omit<estypes.SearchResponse<TDocument>, 'aggregations' | 'hits'> &
(TSearchRequest['body'] extends TopLevelAggregationRequest
? WrapAggregationResponse<SearchResponseOf<TSearchRequest['body'], TDocument>>
: { aggregations?: InvalidAggregationRequest }) & {
hits: Omit<estypes.SearchResponse<TDocument>['hits'], 'total' | 'hits'> &
(TOptions['restTotalHitsAsInt'] extends true
? {
total: number;
}
: {
total: {
value: number;
relation: 'eq' | 'gte';
};
}) & { hits: HitsOf<TSearchRequest['body'], TDocument> };
};