Merge pull request #4607 from influxdata/flux/multi-column-metaquery

Fix metaquery parsing for tables
pull/4612/head
Iris Scholten 2018-10-17 15:54:55 -07:00 committed by GitHub
commit db9b32e775
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 291 additions and 75 deletions

View File

@ -1,7 +1,7 @@
export type TimeSeriesValue = string | number | null
export interface TimeSeriesSeries {
name: string
name?: string
columns: string[]
values: TimeSeriesValue[][]
tags?: [{[x: string]: string}]

View File

@ -26,7 +26,7 @@ interface Result {
}
interface Series {
name: string
name?: string
columns: string[]
values: TimeSeriesValue[][]
responseIndex: number
@ -162,6 +162,7 @@ const constructCells = (
sortedLabels: Label[]
seriesLabels: Label[][]
queryType: InfluxQLQueryType
metaQuerySeries?: TimeSeriesValue[][]
} => {
let cellIndex = 0
let labels: Label[] = []
@ -176,6 +177,7 @@ const constructCells = (
seriesIndex: [],
responseIndex: [],
}
let metaQuerySeries: TimeSeriesValue[][]
fastForEach<Series>(
serieses,
@ -191,76 +193,66 @@ const constructCells = (
},
ind
) => {
let unsortedLabels: Label[]
if (isGroupBy) {
const labelsFromTags = fastMap<string, Label>(_.keys(tags), field => ({
label: `${field}`,
responseIndex,
seriesIndex,
}))
const labelsFromColumns = fastMap<string, Label>(
columns.slice(1),
field => ({
label: `${measurement}.${field}`,
if (columns.find(c => c === 'time')) {
let unsortedLabels: Label[]
if (isGroupBy) {
const labelsFromTags = fastMap<string, Label>(
_.keys(tags),
field => ({
label: `${field}`,
responseIndex,
seriesIndex,
})
)
const labelsFromColumns = fastMap<string, Label>(
columns.slice(1),
field => ({
label: `${measurement}.${field}`,
responseIndex,
seriesIndex,
})
)
unsortedLabels = fastConcat<Label>(labelsFromTags, labelsFromColumns)
seriesLabels[ind] = unsortedLabels
labels = _.concat(labels, unsortedLabels)
} else {
const tagSet = fastMap<string, string>(
_.keys(tags),
tag => `[${tag}=${tags[tag]}]`
)
.sort()
.join('')
unsortedLabels = fastMap<string, Label>(columns.slice(1), field => ({
label: `${measurement}.${field}${tagSet}`,
responseIndex,
seriesIndex,
}))
seriesLabels[ind] = unsortedLabels
labels = _.concat(labels, unsortedLabels)
fastForEach(values, vals => {
const [time, ...rowValues] = vals
fastForEach(rowValues, (value, i) => {
cells.label[cellIndex] = unsortedLabels[i].label
cells.value[cellIndex] = value
cells.time[cellIndex] = time
isDataQuery = true
cells.seriesIndex[cellIndex] = seriesIndex
cells.responseIndex[cellIndex] = responseIndex
cellIndex++ // eslint-disable-line no-plusplus
})
})
)
unsortedLabels = fastConcat<Label>(labelsFromTags, labelsFromColumns)
seriesLabels[ind] = unsortedLabels
labels = _.concat(labels, unsortedLabels)
} else if (columns.length > 1) {
const tagSet = fastMap<string, string>(
_.keys(tags),
tag => `[${tag}=${tags[tag]}]`
)
.sort()
.join('')
unsortedLabels = fastMap<string, Label>(columns.slice(1), field => ({
label: `${measurement}.${field}${tagSet}`,
responseIndex,
seriesIndex,
}))
seriesLabels[ind] = unsortedLabels
labels = _.concat(labels, unsortedLabels)
fastForEach(values, vals => {
const [time, ...rowValues] = vals
fastForEach(rowValues, (value, i) => {
cells.label[cellIndex] = unsortedLabels[i].label
cells.value[cellIndex] = value
cells.time[cellIndex] = time
isDataQuery = true
cells.seriesIndex[cellIndex] = seriesIndex
cells.responseIndex[cellIndex] = responseIndex
cellIndex++ // eslint-disable-line no-plusplus
})
})
}
} else {
const label = `${measurement}.${columns[0]}`
unsortedLabels = [
{
label,
responseIndex,
seriesIndex,
},
]
seriesLabels[ind] = unsortedLabels
labels = _.concat(labels, unsortedLabels)
fastForEach(values, vals => {
const [value] = vals
cells.label[cellIndex] = label
cells.value[cellIndex] = value
cells.time[cellIndex] = null
isMetaQuery = true
cells.seriesIndex[cellIndex] = seriesIndex
cells.responseIndex[cellIndex] = responseIndex
cellIndex++ // eslint-disable-line no-plusplus
})
metaQuerySeries = [columns, ...values]
isMetaQuery = true
labels = columns.map(c => ({
label: c,
responseIndex,
seriesIndex,
}))
}
}
)
@ -275,8 +267,11 @@ const constructCells = (
queryType = InfluxQLQueryType.DataQuery
}
const sortedLabels = _.sortBy(labels, 'label')
return {cells, sortedLabels, seriesLabels, queryType}
const sortedLabels =
queryType === InfluxQLQueryType.MetaQuery
? labels
: _.sortBy(labels, 'label')
return {cells, sortedLabels, seriesLabels, queryType, metaQuerySeries}
}
const insertGroupByValues = (
@ -386,12 +381,26 @@ export const groupByTimeSeriesTransform = (
sortedLabels: Label[]
sortedTimeSeries: TimeSeries[]
queryType: InfluxQLQueryType
metaQuerySeries?: TimeSeriesValue[][]
} => {
const results = constructResults(raw, isTable)
const serieses = constructSerieses(results)
const {cells, sortedLabels, seriesLabels, queryType} = constructCells(
serieses
)
const {
cells,
sortedLabels,
seriesLabels,
queryType,
metaQuerySeries,
} = constructCells(serieses)
if (queryType === InfluxQLQueryType.MetaQuery) {
return {
sortedLabels,
sortedTimeSeries: null,
queryType,
metaQuerySeries,
}
}
const sortedTimeSeries = constructTimeSeries(
serieses,

View File

@ -18,7 +18,12 @@ const timeSeriesToTableData = (
case InfluxQLQueryType.MetaQuery:
return fastMap<TimeSeries, TimeSeriesValue[]>(
timeSeries,
({values}) => values
({time: firstVal, values}) => {
if (firstVal) {
return [firstVal, ...values]
}
return values
}
)
case InfluxQLQueryType.DataQuery:
return fastMap<TimeSeries, TimeSeriesValue[]>(
@ -38,8 +43,13 @@ export const timeSeriesToTableGraphWork = (
sortedLabels,
sortedTimeSeries,
queryType,
metaQuerySeries,
} = groupByTimeSeriesTransform(raw, isTable)
if (queryType === InfluxQLQueryType.MetaQuery) {
return {data: metaQuerySeries, sortedLabels, influxQLQueryType: queryType}
}
let labels = fastMap<Label, string>(sortedLabels, ({label}) => label)
if (queryType === InfluxQLQueryType.DataQuery) {

View File

@ -300,6 +300,203 @@ it('parses a single field influxQL query', () => {
expect(actual.influxQLQueryType).toEqual(InfluxQLQueryType.DataQuery)
})
it('parses a one-column meta query', () => {
const metaQueryResponse = [
{
response: {
results: [
{
statement_id: 0,
series: [
{
name: 'databases',
columns: ['name'],
values: [
['_internal'],
['telegraf'],
['chronograf'],
['hackathon'],
['crypto'],
],
},
],
},
],
uuid: 'd945d2f0-d23d-11e8-ac69-63644ffc39d1',
},
},
]
const expected = {
data: [
['name'],
['_internal'],
['telegraf'],
['chronograf'],
['hackathon'],
['crypto'],
],
sortedLabels: [{label: 'name', responseIndex: 0, seriesIndex: 0}],
influxQLQueryType: 'MetaQuery',
}
const actual = timeSeriesToTableGraph(metaQueryResponse)
expect(actual).toEqual(expected)
})
it('parses a two-column meta query with different first column values', () => {
const metaQueryResponse = [
{
response: {
results: [
{
statement_id: 0,
series: [
{
name: 'syslog',
columns: ['fieldKey', 'fieldType'],
values: [
['facility_code', 'integer'],
['message', 'string'],
['procid', 'string'],
['severity_code', 'integer'],
['timestamp', 'integer'],
['version', 'integer'],
],
},
],
},
],
uuid: 'a43a58e0-d23f-11e8-98ba-639f4bed0e98',
},
},
]
const expected = {
data: [
['fieldKey', 'fieldType'],
['facility_code', 'integer'],
['message', 'string'],
['procid', 'string'],
['severity_code', 'integer'],
['timestamp', 'integer'],
['version', 'integer'],
],
sortedLabels: [
{label: 'fieldKey', responseIndex: 0, seriesIndex: 0},
{label: 'fieldType', responseIndex: 0, seriesIndex: 0},
],
influxQLQueryType: 'MetaQuery',
}
const actual = timeSeriesToTableGraph(metaQueryResponse)
expect(actual).toEqual(expected)
})
it('parses a two-column meta query with same first column values', () => {
const metaQueryResponse = [
{
response: {
results: [
{
statement_id: 0,
series: [
{
name: 'cpu',
columns: ['key', 'value'],
values: [
['cpu', 'cpu-total'],
['cpu', 'cpu0'],
['cpu', 'cpu1'],
['cpu', 'cpu2'],
['cpu', 'cpu3'],
['cpu', 'cpu4'],
['cpu', 'cpu5'],
['cpu', 'cpu6'],
['cpu', 'cpu7'],
],
},
],
},
],
uuid: '7be623a0-d240-11e8-a801-b1de38f10ec1',
},
},
]
const expected = {
data: [
['key', 'value'],
['cpu', 'cpu-total'],
['cpu', 'cpu0'],
['cpu', 'cpu1'],
['cpu', 'cpu2'],
['cpu', 'cpu3'],
['cpu', 'cpu4'],
['cpu', 'cpu5'],
['cpu', 'cpu6'],
['cpu', 'cpu7'],
],
sortedLabels: [
{label: 'key', responseIndex: 0, seriesIndex: 0},
{label: 'value', responseIndex: 0, seriesIndex: 0},
],
influxQLQueryType: 'MetaQuery',
}
const actual = timeSeriesToTableGraph(metaQueryResponse)
expect(actual).toEqual(expected)
})
it('parses meta query with multiple columns', () => {
const metaQueryResponse = [
{
response: {
results: [
{
statement_id: 0,
series: [
{
columns: [
'name',
'duration',
'shardGroupDuration',
'replicaN',
'default',
],
values: [['autogen', '0s', '168h0m0s', 1, true]],
},
],
},
],
uuid: '2f0e3400-d240-11e8-8c53-9748e5c2a80a',
},
},
]
const expected = {
data: [
['name', 'duration', 'shardGroupDuration', 'replicaN', 'default'],
['autogen', '0s', '168h0m0s', 1, true],
],
sortedLabels: [
{label: 'name', responseIndex: 0, seriesIndex: 0},
{label: 'duration', responseIndex: 0, seriesIndex: 0},
{label: 'shardGroupDuration', responseIndex: 0, seriesIndex: 0},
{label: 'replicaN', responseIndex: 0, seriesIndex: 0},
{label: 'default', responseIndex: 0, seriesIndex: 0},
],
influxQLQueryType: 'MetaQuery',
}
const actual = timeSeriesToTableGraph(metaQueryResponse)
expect(actual).toEqual(expected)
})
it('errors when both meta query and data query response', () => {
const influxResponse = [
{
@ -496,7 +693,7 @@ describe('timeSeriesToTableGraph', () => {
const actual = timeSeriesToTableGraph(influxResponse)
const expected = [
['measurements.name'],
['name'],
['cpu'],
['disk'],
['diskio'],