Add IFQL script response parser
Co-authored-by: Andrew Watkins <andrew.watkinz@gmail.com> Co-authored-by: Chris Henn <chris.henn@influxdata.com>pull/3519/head
parent
df94bf30d4
commit
2b37494dcb
|
@ -41,6 +41,7 @@
|
|||
"@types/jest": "^22.1.4",
|
||||
"@types/lodash": "^4.14.104",
|
||||
"@types/node": "^9.4.6",
|
||||
"@types/papaparse": "^4.1.34",
|
||||
"@types/prop-types": "^15.5.2",
|
||||
"@types/react": "^16.0.38",
|
||||
"@types/react-dnd": "^2.0.36",
|
||||
|
@ -133,6 +134,7 @@
|
|||
"lodash": "^4.3.0",
|
||||
"moment": "^2.13.0",
|
||||
"nano-date": "^2.0.1",
|
||||
"papaparse": "^4.4.0",
|
||||
"prop-types": "^15.6.1",
|
||||
"query-string": "^5.0.0",
|
||||
"react": "^16.3.1",
|
||||
|
@ -157,4 +159,4 @@
|
|||
"rome": "^2.1.22",
|
||||
"uuid": "^3.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,34 @@
|
|||
export const parseTables = resp => {
|
||||
return resp.split('\n\n')
|
||||
import Papa from 'papaparse'
|
||||
import _ from 'lodash'
|
||||
|
||||
interface ScriptResult {
|
||||
name: string
|
||||
data: string[][]
|
||||
metadata: string[][]
|
||||
}
|
||||
|
||||
export const parseResults = (resp: string): ScriptResult[] => {
|
||||
return resp.split('\n\n').map(parseResult)
|
||||
}
|
||||
|
||||
export const parseResult = (raw: string, index: number): ScriptResult => {
|
||||
const lines = raw.split('\n')
|
||||
const rawMetadata: string = lines
|
||||
.filter(line => line.startsWith('#'))
|
||||
.map(line => line.slice(1))
|
||||
.join('\n')
|
||||
const rawData: string = lines.filter(line => !line.startsWith('#')).join('\n')
|
||||
|
||||
const metadata = Papa.parse(rawMetadata).data
|
||||
const data = Papa.parse(rawData).data
|
||||
|
||||
const headerRow = _.get(data, '0', [])
|
||||
const measurementHeaderIndex = headerRow.findIndex(v => v === '_measurement')
|
||||
const name = _.get(data, `1.${measurementHeaderIndex}`, `Result ${index}`)
|
||||
|
||||
return {
|
||||
name,
|
||||
data,
|
||||
metadata,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1358,7 +1358,66 @@ export const rule = {
|
|||
}
|
||||
|
||||
// prettier-ignore
|
||||
export const FROM_LAST_RESPONSE = `#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string
|
||||
export const RESPONSE_METADATA = `#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string
|
||||
#partition,false,false,false,false,false,false,true,true,true,true
|
||||
#default,_result,,,,,,,,,
|
||||
,result,table,_start,_stop,_time,_value,_field,_measurement,cpu,host
|
||||
,,0,2018-05-23T17:42:29.536834648Z,2018-05-23T17:43:29.536834648Z,2018-05-23T17:42:29.654Z,0,usage_guest,cpu,cpu-total,WattsInfluxDB
|
||||
`
|
||||
|
||||
export const RESPONSE_NO_METADATA = `,result,table,_start,_stop,_time,_value,_field,_measurement,cpu,host
|
||||
,,0,2018-05-23T17:42:29.536834648Z,2018-05-23T17:43:29.536834648Z,2018-05-23T17:42:29.654Z,0,usage_guest,cpu,cpu-total,WattsInfluxDB
|
||||
`
|
||||
|
||||
export const RESPONSE_NO_MEASUREMENT = `,result,table,_start,_stop,_time,_value,_field,cpu,host
|
||||
,,0,2018-05-23T17:42:29.536834648Z,2018-05-23T17:43:29.536834648Z,2018-05-23T17:42:29.654Z,0,usage_guest,cpu-total,WattsInfluxDB`
|
||||
|
||||
export const EXPECTED_COLUMNS = [
|
||||
'',
|
||||
'result',
|
||||
'table',
|
||||
'_start',
|
||||
'_stop',
|
||||
'_time',
|
||||
'_value',
|
||||
'_field',
|
||||
'_measurement',
|
||||
'cpu',
|
||||
'host',
|
||||
]
|
||||
|
||||
export const EXPECTED_METADATA = [
|
||||
[
|
||||
'datatype',
|
||||
'string',
|
||||
'long',
|
||||
'dateTime:RFC3339',
|
||||
'dateTime:RFC3339',
|
||||
'dateTime:RFC3339',
|
||||
'double',
|
||||
'string',
|
||||
'string',
|
||||
'string',
|
||||
'string',
|
||||
],
|
||||
[
|
||||
'partition',
|
||||
'false',
|
||||
'false',
|
||||
'false',
|
||||
'false',
|
||||
'false',
|
||||
'false',
|
||||
'true',
|
||||
'true',
|
||||
'true',
|
||||
'true',
|
||||
],
|
||||
['default', '_result', '', '', '', '', '', '', '', '', ''],
|
||||
]
|
||||
|
||||
// prettier-ignore
|
||||
export const LARGE_RESPONSE = `#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string
|
||||
#partition,false,false,false,false,false,false,true,true,true,true
|
||||
#default,_result,,,,,,,,,
|
||||
,result,table,_start,_stop,_time,_value,_field,_measurement,cpu,host
|
|
@ -1,10 +1,52 @@
|
|||
import {parseTables} from 'src/shared/parsing/ifql'
|
||||
import {FROM_LAST_RESPONSE} from 'test/shared/parsing/constants'
|
||||
import {parseResults} from 'src/shared/parsing/ifql'
|
||||
import {
|
||||
RESPONSE_NO_METADATA,
|
||||
RESPONSE_METADATA,
|
||||
RESPONSE_NO_MEASUREMENT,
|
||||
LARGE_RESPONSE,
|
||||
EXPECTED_METADATA,
|
||||
EXPECTED_COLUMNS,
|
||||
} from 'test/shared/parsing/constants'
|
||||
|
||||
describe('IFQL response parser', () => {
|
||||
it('parseTables', () => {
|
||||
const result = parseTables(FROM_LAST_RESPONSE)
|
||||
|
||||
it('parseResults into the right number of tables', () => {
|
||||
const result = parseResults(LARGE_RESPONSE)
|
||||
expect(result).toHaveLength(47)
|
||||
})
|
||||
|
||||
describe('headers', () => {
|
||||
it('can parse headers when no metadata is present', () => {
|
||||
const actual = parseResults(RESPONSE_NO_METADATA)[0].data[0]
|
||||
|
||||
expect(actual).toEqual(EXPECTED_COLUMNS)
|
||||
})
|
||||
|
||||
it('can parse headers when metadata is present', () => {
|
||||
const actual = parseResults(RESPONSE_METADATA)[0].data[0]
|
||||
|
||||
expect(actual).toEqual(EXPECTED_COLUMNS)
|
||||
})
|
||||
|
||||
it('returns the approriate metadata', () => {
|
||||
const actual = parseResults(RESPONSE_METADATA)[0].metadata
|
||||
|
||||
expect(actual).toEqual(EXPECTED_METADATA)
|
||||
})
|
||||
})
|
||||
|
||||
describe('name', () => {
|
||||
it('uses the measurement as a name when present', () => {
|
||||
const actual = parseResults(RESPONSE_METADATA)[0].name
|
||||
const expected = 'cpu'
|
||||
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
|
||||
it('uses the index as a name if a measurement column is not present', () => {
|
||||
const actual = parseResults(RESPONSE_NO_MEASUREMENT)[0].name
|
||||
const expected = 'Result 0'
|
||||
|
||||
expect(actual).toBe(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -65,6 +65,10 @@
|
|||
version "9.6.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.6.tgz#439b91f9caf3983cad2eef1e11f6bedcbf9431d2"
|
||||
|
||||
"@types/papaparse@^4.1.34":
|
||||
version "4.1.34"
|
||||
resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-4.1.34.tgz#893628fbb70243313e46d1b962989c023184783b"
|
||||
|
||||
"@types/prop-types@*", "@types/prop-types@^15.5.2":
|
||||
version "15.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.2.tgz#3c6b8dceb2906cc87fe4358e809f9d20c8d59be1"
|
||||
|
@ -6297,6 +6301,10 @@ pako@~1.0.5:
|
|||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
|
||||
|
||||
papaparse@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-4.4.0.tgz#6bcdbda80873e00cfb0bdcd7a4571c72a9a40168"
|
||||
|
||||
parallel-transform@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
|
||||
|
|
Loading…
Reference in New Issue