Merge pull request #4607 from influxdata/flux/multi-column-metaquery
Fix metaquery parsing for tablespull/4612/head
commit
db9b32e775
|
@ -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}]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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'],
|
||||
|
|
Loading…
Reference in New Issue