Influx: Improve variable regex handling (#111853)
This commit is contained in:
@@ -273,6 +273,15 @@ describe('interpolateQueryExpr', () => {
|
|||||||
replace: jest.fn().mockImplementation((...rest: unknown[]) => 'templateVarReplaced'),
|
replace: jest.fn().mockImplementation((...rest: unknown[]) => 'templateVarReplaced'),
|
||||||
} as unknown as TemplateSrv;
|
} as unknown as TemplateSrv;
|
||||||
let ds = getMockInfluxDS(getMockDSInstanceSettings(), templateSrvStub);
|
let ds = getMockInfluxDS(getMockDSInstanceSettings(), templateSrvStub);
|
||||||
|
|
||||||
|
// Mock console.warn as we expect tests to use it
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.spyOn(console, 'warn').mockImplementation();
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
it('should return the value as it is', () => {
|
it('should return the value as it is', () => {
|
||||||
const value = 'normalValue';
|
const value = 'normalValue';
|
||||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||||
@@ -281,6 +290,18 @@ describe('interpolateQueryExpr', () => {
|
|||||||
expect(result).toBe(expectation);
|
expect(result).toBe(expectation);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return the escaped value if the value wrapped in regex without !~ or =~', () => {
|
||||||
|
const value = '/special/path';
|
||||||
|
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||||
|
const result = ds.interpolateQueryExpr(
|
||||||
|
value,
|
||||||
|
variableMock,
|
||||||
|
'select atan(z/sqrt(3.14)), that where path /$tempVar/'
|
||||||
|
);
|
||||||
|
const expectation = `\\/special\\/path`;
|
||||||
|
expect(result).toBe(expectation);
|
||||||
|
});
|
||||||
|
|
||||||
it('should return the escaped value if the value wrapped in regex', () => {
|
it('should return the escaped value if the value wrapped in regex', () => {
|
||||||
const value = '/special/path';
|
const value = '/special/path';
|
||||||
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
const variableMock = queryBuilder().withId('tempVar').withName('tempVar').withMulti(false).build();
|
||||||
|
|||||||
@@ -360,10 +360,7 @@ export default class InfluxDatasource extends DataSourceWithBackend<InfluxQuery,
|
|||||||
// we want to see how it's been used. If it is used in a regex expression
|
// we want to see how it's been used. If it is used in a regex expression
|
||||||
// we escape it. Otherwise, we return it directly.
|
// we escape it. Otherwise, we return it directly.
|
||||||
// The regex below searches for regexes within the query string
|
// The regex below searches for regexes within the query string
|
||||||
const regexMatcher = new RegExp(
|
const regexMatcher = new RegExp(/(?<=\/).+?(?=\/)/, 'gm');
|
||||||
/(\s*(=|!)~\s*)\/((?![*+?])(?:[^\r\n\[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+)\/((?:g(?:im?|mi?)?|i(?:gm?|mg?)?|m(?:gi?|ig?)?)?)/,
|
|
||||||
'gm'
|
|
||||||
);
|
|
||||||
// If matches are found this regex is evaluated to check if the variable is contained in the regex /^...$/ (^ and $ is optional)
|
// If matches are found this regex is evaluated to check if the variable is contained in the regex /^...$/ (^ and $ is optional)
|
||||||
// i.e. /^$myVar$/ or /$myVar/ or /^($myVar)$/
|
// i.e. /^$myVar$/ or /$myVar/ or /^($myVar)$/
|
||||||
const regex = new RegExp(`\\/(?:\\^)?(.*)(\\$${variable.name})(.*)(?:\\$)?\\/`, 'gm');
|
const regex = new RegExp(`\\/(?:\\^)?(.*)(\\$${variable.name})(.*)(?:\\$)?\\/`, 'gm');
|
||||||
@@ -377,14 +374,22 @@ export default class InfluxDatasource extends DataSourceWithBackend<InfluxQuery,
|
|||||||
if (!queryMatches) {
|
if (!queryMatches) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
// Use the variable specific regex against the query
|
||||||
|
if (!query.match(regex)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
for (const match of queryMatches) {
|
for (const match of queryMatches) {
|
||||||
if (!match.match(regex)) {
|
// It is expected that the RegExp should be valid. As our regex matcher matches any text between two '/'
|
||||||
continue;
|
// we also validate that the expression compiles before assuming it is a regular expression.
|
||||||
}
|
try {
|
||||||
|
new RegExp(match);
|
||||||
|
|
||||||
// If the value is a string array first escape them then join them with pipe
|
// If the value is a string array first escape them then join them with pipe
|
||||||
// then put inside parenthesis.
|
// then put inside parenthesis.
|
||||||
return typeof value === 'string' ? escapeRegex(value) : `(${value.map((v) => escapeRegex(v)).join('|')})`;
|
return typeof value === 'string' ? escapeRegex(value) : `(${value.map((v) => escapeRegex(v)).join('|')})`;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`Supplied match is not valid regex: ${match}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|||||||
Reference in New Issue
Block a user