import { cloneDeep } from 'lodash' ; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey' ; import type { IScopedClusterClient } from 'kibana/server' ; import type { Field , FieldId , NewJobCaps , RollupFields } from '../../../../common/types/fields' ; import { ES_FIELD_TYPES } from '../../../../../../../src/plugins/data/common' ; import type { DataViewsService } from '../../../../../../../src/plugins/data_views/common' ; import { combineFieldsAndAggs } from '../../../../common/util/fields_utils' ; import { rollupServiceProvider } from './rollup' ; import { aggregations , mlOnlyAggregations } from '../../../../common/constants/aggregation_types' ; const supportedTypes = [ ES_FIELD_TYPES . DATE , ES_FIELD_TYPES . KEYWORD , ES_FIELD_TYPES . TEXT , ES_FIELD_TYPES . DOUBLE , ES_FIELD_TYPES . INTEGER , ES_FIELD_TYPES . FLOAT , ES_FIELD_TYPES . LONG , ES_FIELD_TYPES . UNSIGNED_LONG , ES_FIELD_TYPES . BYTE , ES_FIELD_TYPES . HALF_FLOAT , ES_FIELD_TYPES . SCALED_FLOAT , ES_FIELD_TYPES . SHORT , ES_FIELD_TYPES . IP , ES_FIELD_TYPES . GEO_POINT , ES_FIELD_TYPES . GEO_SHAPE , ES_FIELD_TYPES . BOOLEAN , ] ; export function fieldServiceProvider ( indexPattern , isRollup , client , dataViewsService ) { return new FieldsService ( indexPattern , isRollup , client , dataViewsService ) ; } class FieldsService { private _indexPattern : string ; private _isRollup : boolean ; private _mlClusterClient : IScopedClusterClient ; private _dataViewsService : DataViewsService ; constructor ( indexPattern , isRollup , client , dataViewsService ) { this . _indexPattern = indexPattern ; this . _isRollup = isRollup ; this . _mlClusterClient = client ; this . _dataViewsService = dataViewsService ; } private async loadFieldCaps ( ) { const { body } = await this . _mlClusterClient . asCurrentUser . fieldCaps ( { index : this . _indexPattern , fields : '*' , } ) ; return body ; } private async createFields ( includeNested = false ) { const fieldCaps = await this . loadFieldCaps ( ) ; const fields = [ ] ; if ( fieldCaps && fieldCaps . fields ) { Object . keys ( fieldCaps . fields ) . forEach ( ( k ) => { const fc = fieldCaps . fields [ k ] ; const firstKey = Object . keys ( fc ) [ 0 ] ; if ( firstKey !== undefined ) { const field = fc [ firstKey ] ; if ( ( supportedTypes . includes ( field . type ) === true && field . metadata_field !== true ) || ( includeNested && field . type === ES_FIELD_TYPES . NESTED ) ) { fields . push ( { id : k , name : k , type : field . type , aggregatable : field . aggregatable , aggs : [ ] , } ) ; } } } ) ; } return fields . sort ( ( a , b ) => a . id . localeCompare ( b . id ) ) ; } public async getData ( includeNested = false ) { let rollupFields = { } ; if ( this . _isRollup ) { const rollupService = await rollupServiceProvider ( this . _indexPattern , this . _mlClusterClient , this . _dataViewsService ) ; const rollupConfigs = await rollupService . getRollupJobs ( ) ; if ( rollupConfigs === null ) { return { aggs : [ ] , fields : [ ] , } ; } else { rollupFields = combineAllRollupFields ( rollupConfigs ) ; this . _indexPattern = rollupService . getIndexPattern ( ) ; } } const aggs = cloneDeep ( [ ... aggregations , ... mlOnlyAggregations ] ) ; const fields = await this . createFields ( includeNested ) ; return combineFieldsAndAggs ( fields , aggs , rollupFields ) ; } } function combineAllRollupFields ( rollupConfigs ) { const rollupFields = { } ; rollupConfigs . forEach ( ( conf ) => { Object . keys ( conf . fields ) . forEach ( ( fieldName ) => { if ( rollupFields [ fieldName ] === undefined ) { rollupFields [ fieldName ] = conf . fields [ fieldName ] ; } else { const aggs = conf . fields [ fieldName ] ; aggs . forEach ( ( agg ) => { if ( rollupFields [ fieldName ] . find ( ( f ) => f . agg === agg . agg ) === null ) { rollupFields [ fieldName ] . push ( agg ) ; } } ) ; } } ) ; } ) ; return rollupFields ; }