import { groupBy , sumBy , maxBy , minBy , meanBy , flatten } from 'lodash' ; export type AggregateMethod = 'SUM' | 'COUNT' | 'MAX' | 'MIN' | 'MEAN' ; export type Aggregator = ( data : any , measure : string ) => number ; const sum = ( data , measure ) => { return sumBy ( data , measure ) ; } ; const count = ( data , measure ) => { return data . filter ( ( item ) => measure in item ) . length ; } ; const max = ( data , measure ) => { return maxBy ( data , measure ) ?. [ measure ] as number ; } ; const min = ( data , measure ) => { return minBy ( data , measure ) ?. [ measure ] as number ; } ; const mean = ( data , measure ) => { return meanBy ( data , measure ) ; } ; const AggregatorMap = { SUM : sum , COUNT : count , MAX : max , MIN : min , MEAN : mean , } ; param data param dimensionField param measure param seriesField returns export const aggregate = ( data , dimensionField , measure , seriesField ? , aggMethod = 'SUM' ) => { const grouped = groupBy ( data , dimensionField ) ; const aggregator = AggregatorMap [ aggMethod ] ; if ( ! seriesField ) { return Object . entries ( grouped ) . map ( ( [ value , dataGroup ] ) => { return { [ dimensionField ] : value , [ measure ] : aggregator ( dataGroup , measure ) , } ; } ) ; } return flatten ( Object . entries ( grouped ) . map ( ( [ value , dataGroup ] ) => { const childGrouped = groupBy ( dataGroup , seriesField ) ; const part = Object . entries ( childGrouped ) . map ( ( [ childValue , childDataGroup ] ) => { return { [ seriesField ] : childValue , [ measure ] : sum ( childDataGroup , measure ) , } ; } ) ; return part . map ( ( item ) => { return { ... item , [ dimensionField ] : value , } ; } ) ; } ) ) ; } ;