import { get , isPlainObject , keys , findKey } from 'lodash' ; import moment from 'moment' ; import { IAggConfig } from '../aggs' ; import { AggResponseBucket , TabbedRangeFilterParams , TimeRangeInformation } from './types' ; type AggParams = IAggConfig [ 'params' ] & { drop_partials : boolean ; ranges : TabbedRangeFilterParams [ ] ; } ; const isRangeEqual = ( range1 , range2 ) => range1 ?. from === range2 ?. from && range1 ?. to === range2 ?. to ; export class TabifyBuckets { length : number ; objectMode : boolean ; buckets : any ; _keys : any [ ] = [ ] ; constructor ( aggResp , aggParams ? , timeRange ? ) { if ( aggResp && aggResp . buckets ) { this . buckets = aggResp . buckets ; } else if ( aggResp ) { this . buckets = [ aggResp ] ; } else { this . buckets = [ ] ; } this . objectMode = isPlainObject ( this . buckets ) ; if ( this . objectMode ) { this . _keys = keys ( this . buckets ) ; this . length = this . _keys . length ; } else { this . length = this . buckets . length ; } if ( this . length && aggParams ) { this . orderBucketsAccordingToParams ( aggParams ) ; if ( aggParams . drop_partials ) { this . dropPartials ( aggParams , timeRange ) ; } } } forEach ( fn ) { const buckets = this . buckets ; if ( this . objectMode ) { this . _keys . forEach ( ( key ) => { fn ( buckets [ key ] , key ) ; } ) ; } else { buckets . forEach ( ( bucket ) => { fn ( bucket , bucket . key ) ; } ) ; } } private orderBucketsAccordingToParams ( params ) { if ( params . filters && this . objectMode ) { this . _keys = params . filters . map ( ( filter ) => { const query = get ( filter , 'input.query.query_string.query' , filter . input . query ) ; const queryString = typeof query === 'string' ? query : JSON . stringify ( query ) ; return filter . label || queryString || '*' ; } ) ; } else if ( params . ranges && this . objectMode ) { this . _keys = params . ranges . map ( ( range ) => findKey ( this . buckets , ( el ) => isRangeEqual ( el , range ) ) ) ; } else if ( params . ranges && params . field . type !== 'date' ) { let ranges = params . ranges ; if ( params . ipRangeType ) { ranges = params . ipRangeType === 'mask' ? ranges . mask : ranges . fromTo ; } this . buckets = ranges . map ( ( range ) => { if ( range . mask ) { return this . buckets . find ( ( el ) => el . key === range . mask ) ; } return this . buckets . find ( ( el ) => isRangeEqual ( el , range ) ) ; } ) ; } } private dropPartials ( params , timeRange ? ) { if ( ! timeRange || this . buckets . length <= 1 || this . objectMode || ! timeRange . timeFields . includes ( params . field . name ) ) { return ; } const interval = this . buckets [ 1 ] . key - this . buckets [ 0 ] . key ; this . buckets = this . buckets . filter ( ( bucket ) => { if ( moment ( bucket . key ) . isBefore ( timeRange . from ) ) { return false ; } if ( moment ( bucket . key + interval ) . isAfter ( timeRange . to ) ) { return false ; } return true ; } ) ; this . length = this . buckets . length ; } }