import { some , chain , isEmpty , values , pick } from 'lodash' ; import { parseLine } from './parseLine' ; import { filterByDate } from './filter' ; import { ParserOptions , ColumnName , ColumnValue } from '../types/library' ; function splice ( lines , newLine , sortBy ) { if ( newLine . some ( ( val ) => ! val ) ) { return lines ; } let len = lines . length ; let compare ; while ( len -- ) { if ( typeof lines [ len ] [ sortBy ] === 'number' && typeof newLine [ sortBy ] === 'number' ) { compare = lines [ len ] [ sortBy ] < newLine [ sortBy ] ? - 1 : 1 ; } else { compare = String ( lines [ len ] [ sortBy ] ) . localeCompare ( newLine [ sortBy ] . toString ( ) ) ; } if ( compare < 0 ) { break ; } } lines . splice ( len + 1 , 0 , newLine ) ; return lines ; } interface ProcessorType { process ( filterFunc , line ) : void ; getResults ( ) : ColumnValue [ ] [ ] ; } export function generateProcessor ( { requestedColumns , sortBy , ascending , limit , prefixes , start , end , } ) { const indexOfCountColumn = requestedColumns . indexOf ( 'count' ) ; if ( indexOfCountColumn > - 1 ) { const counts = { } ; const tempCols = requestedColumns . slice ( 0 ) ; tempCols . splice ( indexOfCountColumn , 1 ) ; return { process ( filterFunc , line ) { if ( isEmpty ( line ) ) { return ; } const parsedLineAsObject = parseLine ( line ) ; if ( ! parsedLineAsObject ) { return ; } if ( ( start || end ) && filterByDate ( parsedLineAsObject , start , end ) ) { return ; } const parsedLineWithRequestedColumns = values ( pick ( parsedLineAsObject , tempCols ) ) ; if ( some ( parsedLineWithRequestedColumns , ( column ) => ! column && column !== 'null' ) ) { return ; } if ( filterFunc && ! filterFunc ( parsedLineWithRequestedColumns ) ) { return ; } const LINESTRING = JSON . stringify ( parsedLineWithRequestedColumns ) ; counts [ LINESTRING ] = counts [ LINESTRING ] ? counts [ LINESTRING ] + 1 : 1 ; } , getResults ( ) { let q = chain ( counts ) . map ( function ( countNumber , key ) { const line = JSON . parse ( key ) ; line . splice ( indexOfCountColumn , 0 , countNumber ) ; return line ; } ) ; if ( prefixes && prefixes [ indexOfCountColumn ] ) { q = q . filter ( ( line ) => line [ indexOfCountColumn ] . toString ( ) . startsWith ( prefixes [ indexOfCountColumn ] ) ) ; } return q . sortBy ( sortBy . toString ( ) ) . value ( ) ; } , } ; } else { let outputLines = [ ] ; return { process ( filterFunc , line ) { const lineObj = parseLine ( line ) ; if ( ! lineObj ) { return ; } if ( ( start || end ) && filterByDate ( lineObj , start , end ) ) { return ; } const mappedLine = values ( pick ( lineObj , ... requestedColumns ) ) ; if ( some ( mappedLine , ( columnValue ) => typeof columnValue === 'undefined' ) ) { return ; } if ( filterFunc && ! filterFunc ( lineObj ) ) { return ; } if ( outputLines . length < limit ) { outputLines = splice ( outputLines , mappedLine , sortBy ) ; return ; } let compare ; const firstLine = outputLines [ 0 ] ; if ( firstLine ) { if ( typeof firstLine [ sortBy ] === 'number' && typeof mappedLine [ sortBy ] === 'number' ) { compare = firstLine [ sortBy ] < mappedLine [ sortBy ] ? - 1 : 1 ; } else { compare = String ( firstLine [ sortBy ] ) . localeCompare ( mappedLine [ sortBy ] . toString ( ) ) ; } } if ( ( ! ascending && compare === 1 ) || ( ascending && compare === - 1 ) ) { return ; } outputLines = splice ( outputLines , mappedLine , sortBy ) ; outputLines . shift ( ) ; } , getResults ( ) { return outputLines ; } , } ; } }