Fix template variable replacement within regexes

Template variables used within regexes would not replace when the query
contained a '/' before the regex in the query (see test).

This commit rewrites the logic for replacing template variables within
regexes.
pull/3995/head
Christopher Henn 2018-07-20 15:11:28 -07:00 committed by Chris Henn
parent c1f51530c9
commit 85f222b62e
3 changed files with 69 additions and 11 deletions

View File

@ -5,6 +5,7 @@
1. [#3976](https://github.com/influxdata/chronograf/pull/3976): Ensure text template variables reflect query parameters
1. [#3976](https://github.com/influxdata/chronograf/pull/3976): Enable using a new, blank text template variable in a query
1. [#3976](https://github.com/influxdata/chronograf/pull/3976): Ensure cells with broken queries display “No Data”
1. [#3978](https://github.com/influxdata/chronograf/pull/3978): Fix use of template variables within InfluxQL regexes
## v1.6.0 [2018-06-18]

View File

@ -110,26 +110,51 @@ const renderTemplate = (query: string, template: Template): string => {
}
}
const REGEX_COMPARATORS = ['=~', '!~']
const REGEX_DELIMITER = '/'
const replaceAllRegex = (
query: string,
search: string,
replacement: string
) => {
// check for presence of anything between two forward slashes /[your stuff here]/
const matches = query.match(/\/([^\/]*)\//gm)
let result = query
let i = 0
if (!matches) {
return query
}
while (i < result.length - 1) {
const chars = result[i] + result[i + 1]
const isStartOfRegex = REGEX_COMPARATORS.includes(chars)
return matches.reduce((acc, m) => {
if (m.includes(search)) {
const replaced = m.replace(search, replacement)
return acc.split(m).join(replaced)
if (!isStartOfRegex) {
i += 1
continue
}
return acc
}, query)
const regexStart = findNext(result, REGEX_DELIMITER, i)
const regexEnd = findNext(result, REGEX_DELIMITER, regexStart + 1)
const regexContent = result.slice(regexStart + 1, regexEnd)
const replacedRegexContent = regexContent.replace(search, replacement)
result =
result.slice(0, regexStart + 1) +
replacedRegexContent +
result.slice(regexEnd)
i = findNext(result, REGEX_DELIMITER, regexStart + 1)
}
return result
}
const findNext = (s: string, t: string, startIndex: number) => {
const tail = s.slice(startIndex)
const i = tail.indexOf(t)
if (i === -1) {
throw new Error(`Expected token '${t}' in '${tail}'`)
}
return startIndex + i
}
const replaceAll = (query: string, search: string, replacement: string) => {

View File

@ -221,6 +221,38 @@ describe('templates.utils.replace', () => {
expect(actual).toBe(expected)
})
it('replaces a query with a single / properly', () => {
const templates = [
{
tempVar: ':Cluster_Id:',
values: [
{
value: 'e87a44cb9df65eb0d6fa50730842d926',
type: TemplateValueType.TagValue,
selected: true,
localSelected: true,
},
],
id: 'e4731672-e3d6-4633-b2ed-146ea51cbb7f',
type: TemplateType.TagValues,
label: '',
query: {
influxql:
'SHOW TAG VALUES ON :database: FROM :measurement: WITH KEY=:tagKey:',
db: 'telegraf',
measurement: 'cpu',
tagKey: 'cluster_id',
fieldKey: '',
},
},
]
const query = `SELECT last("max") from (SELECT max("total")/1073741824 FROM "telegraf".."mem" WHERE "cluster_id" = :Cluster_Id: AND (host =~ /.*data.*/ OR host =~ /tot-.*-(3|4)/) GROUP BY time(1s), host)`
const expected = `SELECT last("max") from (SELECT max("total")/1073741824 FROM "telegraf".."mem" WHERE "cluster_id" = 'e87a44cb9df65eb0d6fa50730842d926' AND (host =~ /.*data.*/ OR host =~ /tot-.*-(3|4)/) GROUP BY time(1s), host)`
const actual = templateReplace(query, templates)
expect(actual).toBe(expected)
})
})
describe('with no templates', () => {