import _ from 'lodash' ; import moment from 'moment' ; export interface DataTarget { target : string ; datapoints : any [ ] ; refId : string ; query : any ; } export interface TableResult { columns : TableColumn [ ] ; rows : any [ ] ; type : string ; refId : string ; query : string ; } export interface TableColumn { text : string ; type : string ; } export interface KustoSchema { Databases : { [ key ] : KustoDatabase ; } ; Plugins : any [ ] ; } export interface KustoDatabase { Name : string ; Tables : { [ key ] : KustoTable ; } ; Functions : { [ key ] : KustoFunction ; } ; } export interface KustoTable { Name : string ; OrderedColumns : KustoColumn [ ] ; } export interface KustoColumn { Name : string ; Type : string ; } export interface KustoFunction { Name : string ; DocString : string ; Body : string ; Folder : string ; FunctionKind : string ; InputParameters : any [ ] ; OutputColumns : any [ ] ; } export interface Variable { text : string ; value : string ; } export interface AnnotationItem { annotation : any ; time : number ; text : string ; tags : string [ ] ; } export default class ResponseParser { columns : Array < string > ; constructor ( private results ) { } parseQueryResult ( ) { let data = [ ] ; let columns = [ ] ; for ( let i = 0 ; i < this . results . length ; i ++ ) { if ( this . results [ i ] . result . data . tables . length === 0 ) { continue ; } columns = this . results [ i ] . result . data . tables [ 0 ] . columns ; const rows = this . results [ i ] . result . data . tables [ 0 ] . rows ; if ( this . results [ i ] . query . resultFormat === 'time_series' ) { data = _ . concat ( data , this . parseTimeSeriesResult ( this . results [ i ] . query , columns , rows ) ) ; } else { data = _ . concat ( data , this . parseTableResult ( this . results [ i ] . query , columns , rows ) ) ; } } return data ; } parseTimeSeriesResult ( query , columns , rows ) { const data = [ ] ; let timeIndex = - 1 ; let metricIndex = - 1 ; let valueIndex = - 1 ; for ( let i = 0 ; i < columns . length ; i ++ ) { if ( timeIndex === - 1 && columns [ i ] . type === 'datetime' ) { timeIndex = i ; } if ( metricIndex === - 1 && columns [ i ] . type === 'string' ) { metricIndex = i ; } if ( valueIndex === - 1 && [ 'int' , 'long' , 'real' , 'double' ] . includes ( columns [ i ] . type ) ) { valueIndex = i ; } } if ( timeIndex === - 1 ) { throw new Error ( 'No datetime column found in the result. The Time Series format requires a time column.' ) ; } _ . forEach ( rows , function ( row ) { const epoch = ResponseParser . dateTimeToEpoch ( row [ timeIndex ] ) ; const metricName = metricIndex > - 1 ? row [ metricIndex ] : columns [ valueIndex ] . name ; const bucket = ResponseParser . findOrCreateBucket ( data , metricName ) ; bucket . datapoints . push ( [ row [ valueIndex ] , epoch ] ) ; bucket . refId = query . refId ; bucket . query = query . query ; } ) ; return data ; } parseTableResult ( query , columns , rows ) { const tableResult = { type : 'table' , columns : _ . map ( columns , col => { return { text : col . name , type : col . type } ; } ) , rows : rows , refId : query . refId , query : query . query , } ; return tableResult ; } parseToVariables ( ) { const queryResult = this . parseQueryResult ( ) ; const variables = [ ] ; _ . forEach ( queryResult , result => { _ . forEach ( _ . flattenDeep ( result . rows ) , row => { variables . push ( < Variable > { text : row , value : row , } ) ; } ) ; } ) ; return variables ; } transformToAnnotations ( options ) { const queryResult = this . parseQueryResult ( ) ; const list = [ ] ; _ . forEach ( queryResult , result => { let timeIndex = - 1 ; let textIndex = - 1 ; let tagsIndex = - 1 ; for ( let i = 0 ; i < result . columns . length ; i ++ ) { if ( timeIndex === - 1 && result . columns [ i ] . type === 'datetime' ) { timeIndex = i ; } if ( textIndex === - 1 && result . columns [ i ] . text . toLowerCase ( ) === 'text' ) { textIndex = i ; } if ( tagsIndex === - 1 && result . columns [ i ] . text . toLowerCase ( ) === 'tags' ) { tagsIndex = i ; } } _ . forEach ( result . rows , row => { list . push ( { annotation : options . annotation , time : Math . floor ( ResponseParser . dateTimeToEpoch ( row [ timeIndex ] ) ) , text : row [ textIndex ] ? row [ textIndex ] . toString ( ) : '' , tags : row [ tagsIndex ] ? row [ tagsIndex ] . trim ( ) . split ( /\s*,\s*/ ) : [ ] , } ) ; } ) ; } ) ; return list ; } parseSchemaResult ( ) { return { Plugins : [ { Name : 'pivot' , } , ] , Databases : this . createSchemaDatabaseWithTables ( ) , } ; } createSchemaDatabaseWithTables ( ) { const databases = { Default : { Name : 'Default' , Tables : this . createSchemaTables ( ) , Functions : this . createSchemaFunctions ( ) , } , } ; return databases ; } createSchemaTables ( ) { const tables = { } ; for ( let table of this . results . tables ) { tables [ table . name ] = { Name : table . name , OrderedColumns : [ ] , } ; for ( let col of table . columns ) { tables [ table . name ] . OrderedColumns . push ( this . convertToKustoColumn ( col ) ) ; } } return tables ; } convertToKustoColumn ( col ) { return { Name : col . name , Type : col . type , } ; } createSchemaFunctions ( ) { const functions = { } ; for ( let func of this . results . functions ) { functions [ func . name ] = { Name : func . name , Body : func . body , DocString : func . displayName , Folder : func . category , FunctionKind : 'Unknown' , InputParameters : [ ] , OutputColumns : [ ] , } ; } return functions ; } static findOrCreateBucket ( data , target ) { let dataTarget = _ . find ( data , [ 'target' , target ] ) ; if ( ! dataTarget ) { dataTarget = { target : target , datapoints : [ ] , refId : '' , query : '' } ; data . push ( dataTarget ) ; } return dataTarget ; } static dateTimeToEpoch ( dateTime ) { return moment ( dateTime ) . valueOf ( ) ; } }