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/jest": "^22.1.4",
|
||||||
"@types/lodash": "^4.14.104",
|
"@types/lodash": "^4.14.104",
|
||||||
"@types/node": "^9.4.6",
|
"@types/node": "^9.4.6",
|
||||||
|
"@types/papaparse": "^4.1.34",
|
||||||
"@types/prop-types": "^15.5.2",
|
"@types/prop-types": "^15.5.2",
|
||||||
"@types/react": "^16.0.38",
|
"@types/react": "^16.0.38",
|
||||||
"@types/react-dnd": "^2.0.36",
|
"@types/react-dnd": "^2.0.36",
|
||||||
|
@ -133,6 +134,7 @@
|
||||||
"lodash": "^4.3.0",
|
"lodash": "^4.3.0",
|
||||||
"moment": "^2.13.0",
|
"moment": "^2.13.0",
|
||||||
"nano-date": "^2.0.1",
|
"nano-date": "^2.0.1",
|
||||||
|
"papaparse": "^4.4.0",
|
||||||
"prop-types": "^15.6.1",
|
"prop-types": "^15.6.1",
|
||||||
"query-string": "^5.0.0",
|
"query-string": "^5.0.0",
|
||||||
"react": "^16.3.1",
|
"react": "^16.3.1",
|
||||||
|
@ -157,4 +159,4 @@
|
||||||
"rome": "^2.1.22",
|
"rome": "^2.1.22",
|
||||||
"uuid": "^3.2.1"
|
"uuid": "^3.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,34 @@
|
||||||
export const parseTables = resp => {
|
import Papa from 'papaparse'
|
||||||
return resp.split('\n\n')
|
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
|
// 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
|
#partition,false,false,false,false,false,false,true,true,true,true
|
||||||
#default,_result,,,,,,,,,
|
#default,_result,,,,,,,,,
|
||||||
,result,table,_start,_stop,_time,_value,_field,_measurement,cpu,host
|
,result,table,_start,_stop,_time,_value,_field,_measurement,cpu,host
|
|
@ -1,10 +1,52 @@
|
||||||
import {parseTables} from 'src/shared/parsing/ifql'
|
import {parseResults} from 'src/shared/parsing/ifql'
|
||||||
import {FROM_LAST_RESPONSE} from 'test/shared/parsing/constants'
|
import {
|
||||||
|
RESPONSE_NO_METADATA,
|
||||||
|
RESPONSE_METADATA,
|
||||||
|
RESPONSE_NO_MEASUREMENT,
|
||||||
|
LARGE_RESPONSE,
|
||||||
|
EXPECTED_METADATA,
|
||||||
|
EXPECTED_COLUMNS,
|
||||||
|
} from 'test/shared/parsing/constants'
|
||||||
|
|
||||||
describe('IFQL response parser', () => {
|
describe('IFQL response parser', () => {
|
||||||
it('parseTables', () => {
|
it('parseResults into the right number of tables', () => {
|
||||||
const result = parseTables(FROM_LAST_RESPONSE)
|
const result = parseResults(LARGE_RESPONSE)
|
||||||
|
|
||||||
expect(result).toHaveLength(47)
|
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"
|
version "9.6.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.6.tgz#439b91f9caf3983cad2eef1e11f6bedcbf9431d2"
|
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":
|
"@types/prop-types@*", "@types/prop-types@^15.5.2":
|
||||||
version "15.5.2"
|
version "15.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.2.tgz#3c6b8dceb2906cc87fe4358e809f9d20c8d59be1"
|
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"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
|
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:
|
parallel-transform@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
|
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
|
||||||
|
|
Loading…
Reference in New Issue