import _ from 'lodash' ; import { Assign } from '@osd/utility-types' ; import { ISearchOptions , ISearchSource } from 'src/plugins/data/public' ; import { AggConfig , AggConfigSerialized , IAggConfig } from './agg_config' ; import { IAggType } from './agg_type' ; import { AggTypesRegistryStart } from './agg_types_registry' ; import { AggGroupNames } from './agg_groups' ; import { IndexPattern } from '../../index_patterns/index_patterns/index_pattern' ; import { TimeRange } from '../../../common' ; function removeParentAggs ( obj ) { for ( const prop in obj ) { if ( prop === 'parentAggs' ) delete obj [ prop ] ; else if ( typeof obj [ prop ] === 'object' ) removeParentAggs ( obj [ prop ] ) ; } } function parseParentAggs ( dslLvlCursor , dsl ) { if ( dsl . parentAggs ) { _ . each ( dsl . parentAggs , ( agg , key ) => { dslLvlCursor [ key as string ] = agg ; parseParentAggs ( dslLvlCursor , agg ) ; } ) ; } } export interface AggConfigsOptions { typesRegistry : AggTypesRegistryStart ; } export type CreateAggConfigParams = Assign < AggConfigSerialized , { type : string | IAggType ; } > ; name description internal export type IAggConfigs = AggConfigs ; export class AggConfigs { public indexPattern : IndexPattern ; public timeRange ? : TimeRange ; private readonly typesRegistry : AggTypesRegistryStart ; aggs : IAggConfig [ ] ; constructor ( indexPattern , configStates = [ ] , opts ) { this . typesRegistry = opts . typesRegistry ; configStates = AggConfig . ensureIds ( configStates ) ; this . aggs = [ ] ; this . indexPattern = indexPattern ; configStates . forEach ( ( params ) => this . createAggConfig ( params ) ) ; } setTimeRange ( timeRange ) { this . timeRange = timeRange ; const updateAggTimeRange = ( agg ) => { _ . each ( agg . params , ( param ) => { if ( param instanceof AggConfig ) { updateAggTimeRange ( param ) ; } } ) ; if ( _ . get ( agg , 'type.name' ) === 'date_histogram' ) { agg . params . timeRange = timeRange ; } } ; this . aggs . forEach ( updateAggTimeRange ) ; } clone ( { enabledOnly = true } = { } ) { const filterAggs = ( agg ) => { if ( ! enabledOnly ) return true ; return agg . enabled ; } ; const aggConfigs = new AggConfigs ( this . indexPattern , this . aggs . filter ( filterAggs ) , { typesRegistry : this . typesRegistry , } ) ; return aggConfigs ; } createAggConfig = < T extends AggConfig = AggConfig > ( params , { addToAggConfigs = true } = { } ) => { const { type } = params ; let aggConfig ; if ( params instanceof AggConfig ) { aggConfig = params ; params . parent = this ; } else { aggConfig = new AggConfig ( this , { ... params , type : typeof type === 'string' ? this . typesRegistry . get ( type ) : type , } ) ; } if ( addToAggConfigs ) { this . aggs . push ( aggConfig ) ; } return aggConfig as T ; } ; param aggConfigs jsonDataEquals ( aggConfigs ) { if ( aggConfigs . length !== this . aggs . length ) { return false ; } for ( let i = 0 ; i < this . aggs . length ; i += 1 ) { if ( ! _ . isEqual ( aggConfigs [ i ] . toJSON ( ) , this . aggs [ i ] . toJSON ( ) ) ) { return false ; } } return true ; } toDsl ( hierarchical = false ) { const dslTopLvl = { } ; let dslLvlCursor ; let nestedMetrics ; if ( hierarchical ) { nestedMetrics = this . aggs . filter ( function ( agg ) { return agg . type . type === 'metrics' && agg . type . name !== 'count' ; } ) . map ( ( agg ) => { return { config : agg , dsl : agg . toDsl ( this ) , } ; } ) ; } this . getRequestAggs ( ) . filter ( ( config ) => ! config . type . hasNoDsl ) . forEach ( ( config , i , list ) => { if ( ! dslLvlCursor ) { dslLvlCursor = dslTopLvl ; } else { const prevConfig = list [ i - 1 ] ; const prevDsl = dslLvlCursor [ prevConfig . id ] ; dslLvlCursor = prevDsl . aggs || dslLvlCursor ; } const dsl = ( dslLvlCursor [ config . id ] = config . toDsl ( this ) ) ; let subAggs ; parseParentAggs ( dslLvlCursor , dsl ) ; if ( config . type . type === AggGroupNames . Buckets && i < list . length - 1 ) { subAggs = dsl . aggs || ( dsl . aggs = { } ) ; } if ( subAggs && nestedMetrics ) { nestedMetrics . forEach ( ( agg ) => { subAggs [ agg . config . id ] = agg . dsl ; if ( agg . dsl . parentAggs ) { Object . entries ( agg . dsl . parentAggs ) . forEach ( ( [ parentAggId , parentAgg ] ) => { subAggs [ parentAggId ] = parentAgg ; } ) ; } } ) ; } } ) ; removeParentAggs ( dslTopLvl ) ; return dslTopLvl ; } getAll ( ) { return [ ... this . aggs ] ; } byIndex ( index ) { return this . aggs [ index ] ; } byId ( id ) { return this . aggs . find ( ( agg ) => agg . id === id ) ; } byName ( name ) { return this . aggs . filter ( ( agg ) => agg . type ?. name === name ) ; } byType ( type ) { return this . aggs . filter ( ( agg ) => agg . type ?. type === type ) ; } byTypeName ( type ) { return this . byName ( type ) ; } bySchemaName ( schema ) { return this . aggs . filter ( ( agg ) => agg . schema === schema ) ; } getRequestAggs ( ) { const aggregations = this . aggs . filter ( ( agg ) => agg . enabled && agg . type ) . reduce ( ( requestValuesAggs , agg ) => { const aggs = agg . getRequestAggs ( ) ; return aggs ? requestValuesAggs . concat ( aggs ) : requestValuesAggs ; } , [ ] as AggConfig [ ] ) ; return _ . sortBy ( aggregations , ( agg ) => agg . type . type === AggGroupNames . Metrics ? 1 : 0 ) ; } getRequestAggById ( id ) { return this . aggs . find ( ( agg ) => agg . id === id ) ; } return { array [ AggConfig ] } getResponseAggs ( ) { return this . getRequestAggs ( ) . reduce ( function ( responseValuesAggs , agg ) { const aggs = agg . getResponseAggs ( ) ; return aggs ? responseValuesAggs . concat ( aggs ) : responseValuesAggs ; } , [ ] as AggConfig [ ] ) ; } param { string } id return { AggConfig } getResponseAggById ( id ) { id = String ( id ) ; const reqAgg = _ . find ( this . getRequestAggs ( ) , function ( agg ) { return id . substr ( 0 , String ( agg . id ) . length ) === agg . id ; } ) ; if ( ! reqAgg ) return ; return _ . find ( reqAgg . getResponseAggs ( ) , { id } ) ; } onSearchRequestStart ( searchSource , options ? ) { return Promise . all ( this . getRequestAggs ( ) . map ( ( agg ) => agg . onSearchRequestStart ( searchSource , options ) ) ) ; } }