import _ , { each , reject } from 'lodash' ; import { SavedObjectsClientCommon } from '../..' ; import { DuplicateField } from '../../../../opensearch_dashboards_utils/common' ; import { OPENSEARCH_FIELD_TYPES , OSD_FIELD_TYPES , IIndexPattern , FieldFormatNotFoundError , IFieldType , } from '../../../common' ; import { IndexPatternField , IIndexPatternFieldList , fieldList } from '../fields' ; import { formatHitProvider } from './format_hit' ; import { flattenHitWrapper } from './flatten_hit' ; import { FieldFormatsStartCommon , FieldFormat } from '../../field_formats' ; import { IndexPatternSpec , TypeMeta , SourceFilter , IndexPatternFieldMap } from '../types' ; import { SerializedFieldFormat } from '../../../../expressions/common' ; interface IndexPatternDeps { spec ? : IndexPatternSpec ; savedObjectsClient : SavedObjectsClientCommon ; fieldFormats : FieldFormatsStartCommon ; shortDotsEnable : boolean ; metaFields : string [ ] ; } interface SavedObjectBody { title ? : string ; timeFieldName ? : string ; intervalName ? : string ; fields ? : string ; sourceFilters ? : string ; fieldFormatMap ? : string ; typeMeta ? : string ; type ? : string ; } type FormatFieldFn = ( hit : Record < string , any > , fieldName : string ) => any ; export class IndexPattern implements IIndexPattern { public id ? : string ; public title : string = '' ; public fieldFormatMap : Record < string , any > ; public typeMeta ? : TypeMeta ; public fields : IIndexPatternFieldList & { toSpec : ( ) => IndexPatternFieldMap ; } ; public timeFieldName : string | undefined ; public intervalName : string | undefined ; public type : string | undefined ; public formatHit : { ( hit , type ? ) : any ; formatField : FormatFieldFn ; } ; public formatField : FormatFieldFn ; public flattenHit : ( hit : Record < string , any > , deep ? : boolean ) => Record < string , any > ; public metaFields : string [ ] ; public version : string | undefined ; public sourceFilters ? : SourceFilter [ ] ; private originalSavedObjectBody : SavedObjectBody = { } ; private shortDotsEnable : boolean = false ; private fieldFormats : FieldFormatsStartCommon ; constructor ( { spec = { } , fieldFormats , shortDotsEnable = false , metaFields = [ ] , } ) { this . fieldFormats = fieldFormats ; this . shortDotsEnable = shortDotsEnable ; this . metaFields = metaFields ; this . fields = fieldList ( [ ] , this . shortDotsEnable ) ; this . flattenHit = flattenHitWrapper ( this , metaFields ) ; this . formatHit = formatHitProvider ( this , fieldFormats . getDefaultInstance ( OSD_FIELD_TYPES . STRING ) ) ; this . formatField = this . formatHit . formatField ; this . id = spec . id ; const fieldFormatMap = this . fieldSpecsToFieldFormatMap ( spec . fields ) ; this . version = spec . version ; this . title = spec . title || '' ; this . timeFieldName = spec . timeFieldName ; this . sourceFilters = spec . sourceFilters ; this . fields . replaceAll ( Object . values ( spec . fields || { } ) ) ; this . type = spec . type ; this . typeMeta = spec . typeMeta ; this . fieldFormatMap = _ . mapValues ( fieldFormatMap , ( mapping ) => { return this . deserializeFieldFormatMap ( mapping ) ; } ) ; } /**
     * Get last saved saved object fields
     */ getOriginalSavedObjectBody = ( ) => ( { ... this . originalSavedObjectBody } ) ; /**
     * Reset last saved saved object fields. used after saving
     */ resetOriginalSavedObjectBody = ( ) => { this . originalSavedObjectBody = this . getAsSavedObjectBody ( ) ; } ; param mapping private deserializeFieldFormatMap ( mapping ) { try { return this . fieldFormats . getInstance ( mapping . id as string , mapping . params ) ; } catch ( err ) { if ( err instanceof FieldFormatNotFoundError ) { return undefined ; } else { throw err ; } } } param fldList private fieldSpecsToFieldFormatMap = ( fldList = { } ) => Object . values ( fldList ) . reduce < Record < string , SerializedFieldFormat > > ( ( col , fieldSpec ) => { if ( fieldSpec . format ) { col [ fieldSpec . name ] = { ... fieldSpec . format } ; } return col ; } , { } ) ; getComputedFields ( ) { const scriptFields = { } ; if ( ! this . fields ) { return { storedFields : [ '*' ] , scriptFields , docvalueFields : [ ] , } ; } const docvalueFields = reject ( this . fields . getByType ( 'date' ) , 'scripted' ) . map ( ( dateField ) => { return { field : dateField . name , format : dateField . esTypes && dateField . esTypes . indexOf ( 'date_nanos' ) !== - 1 ? 'strict_date_time' : 'date_time' , } ; } ) ; each ( this . getScriptedFields ( ) , function ( field ) { scriptFields [ field . name ] = { script : { source : field . script , lang : field . lang , } , } ; } ) ; return { storedFields : [ '*' ] , scriptFields , docvalueFields , } ; } public toSpec ( ) { return { id : this . id , version : this . version , title : this . title , timeFieldName : this . timeFieldName , sourceFilters : this . sourceFilters , fields : this . fields . toSpec ( { getFormatterForField : this . getFormatterForField . bind ( this ) } ) , typeMeta : this . typeMeta , type : this . type , } ; } /**
     * Get the source filtering configuration for that index.
     */ getSourceFiltering ( ) { return { excludes : ( this . sourceFilters && this . sourceFilters . map ( ( filter ) => filter . value ) ) || [ ] , } ; } param name param script param fieldType param lang async addScriptedField ( name , script , fieldType = 'string' ) { const scriptedFields = this . getScriptedFields ( ) ; const names = _ . map ( scriptedFields , 'name' ) ; if ( _ . includes ( names , name ) ) { throw new DuplicateField ( name ) ; } this . fields . add ( { name , script , type : fieldType , scripted : true , lang : 'painless' , aggregatable : true , searchable : true , count : 0 , readFromDocValues : false , } ) ; } param fieldName removeScriptedField ( fieldName ) { const field = this . fields . getByName ( fieldName ) ; if ( field ) { this . fields . remove ( field ) ; } } getNonScriptedFields ( ) { return [ ... this . fields . getAll ( ) . filter ( ( field ) => ! field . scripted ) ] ; } getScriptedFields ( ) { return [ ... this . fields . getAll ( ) . filter ( ( field ) => field . scripted ) ] ; } getIndex ( ) { if ( ! this . isUnsupportedTimePattern ( ) ) { return this . title ; } const regex = /\[[^\]]*]/g ; const splits = this . title . split ( regex ) ; const matches = this . title . match ( regex ) || [ ] ; return splits . map ( ( split , i ) => { const match = i >= matches . length ? '' : matches [ i ] . replace ( /[\[\]]/g , '' ) ; return `${ split . length ? '*' : '' }${ match }` ; } ) . join ( '' ) ; } isUnsupportedTimePattern ( ) { return ! ! this . intervalName ; } isTimeBased ( ) { return ! ! this . timeFieldName && ( ! this . fields || ! ! this . getTimeField ( ) ) ; } isTimeNanosBased ( ) { const timeField = this . getTimeField ( ) ; return timeField && timeField . esTypes && timeField . esTypes . indexOf ( 'date_nanos' ) !== - 1 ; } getTimeField ( ) { if ( ! this . timeFieldName || ! this . fields || ! this . fields . getByName ) return undefined ; return this . fields . getByName ( this . timeFieldName ) ; } getFieldByName ( name ) { if ( ! this . fields || ! this . fields . getByName ) return undefined ; return this . fields . getByName ( name ) ; } getAggregationRestrictions ( ) { return this . typeMeta ?. aggs ; } /**
     * Returns index pattern as saved object body for saving
     */ getAsSavedObjectBody ( ) { const serializeFieldFormatMap = ( flat , format , field ) => { if ( format && field ) { flat [ field ] = format ; } } ; const serialized = _ . transform ( this . fieldFormatMap , serializeFieldFormatMap ) ; const fieldFormatMap = _ . isEmpty ( serialized ) ? undefined : JSON . stringify ( serialized ) ; return { title : this . title , timeFieldName : this . timeFieldName , intervalName : this . intervalName , sourceFilters : this . sourceFilters ? JSON . stringify ( this . sourceFilters ) : undefined , fields : this . fields ? JSON . stringify ( this . fields ) : undefined , fieldFormatMap , type : this . type , typeMeta : this . typeMeta ? JSON . stringify ( this . typeMeta ) : undefined , } ; } param field getFormatterForField ( field ) { return ( this . fieldFormatMap [ field . name ] || this . fieldFormats . getDefaultInstance ( field . type as OSD_FIELD_TYPES , field . esTypes as OPENSEARCH_FIELD_TYPES [ ] ) ) ; } }