diff --git a/public/app/plugins/datasource/loki/querybuilder/parsing.test.ts b/public/app/plugins/datasource/loki/querybuilder/parsing.test.ts index fe1a50185a0..27801581f05 100644 --- a/public/app/plugins/datasource/loki/querybuilder/parsing.test.ts +++ b/public/app/plugins/datasource/loki/querybuilder/parsing.test.ts @@ -235,6 +235,22 @@ describe('buildVisualQueryFromString', () => { ); }); + it('returns error when parsing ambiguous query', () => { + //becomes topk(5, count_over_time({app="aggregator"} [1m])) / count_over_time({cluster="dev-eu-west-2"} [1m]) + const context = buildVisualQueryFromString( + 'topk(5,count_over_time({app="aggregator"}[1m])/count_over_time({cluster="dev-eu-west-2"}[1m]))' + ); + expect(context).toMatchObject({ + errors: [ + { + from: 7, + text: 'Query parsing is ambiguous.', + to: 93, + }, + ], + }); + }); + it('parses query with matcher label filter', () => { expect(buildVisualQueryFromString('{app="frontend"} | bar="baz"')).toEqual( noErrors({ @@ -535,7 +551,8 @@ describe('buildVisualQueryFromString', () => { }); it('parses metrics query with function and aggregation with grouping at the end', () => { - expect(buildVisualQueryFromString('sum(rate({app="frontend"} | json [5m])) without(job,name)')).toEqual( + const expression = 'sum(rate({app="frontend"} | json [5m])) without(job,name)'; + expect(buildVisualQueryFromString(expression)).toEqual( noErrors({ labels: [ { @@ -667,7 +684,9 @@ describe('buildVisualQueryFromString', () => { }); it('parses query with multiple label format', () => { - expect(buildVisualQueryFromString('{app="frontend"} | label_format renameTo=original, bar=baz')).toEqual( + // Converted to {app="frontend"} | label_format renameTo=original | label_format bar=baz by visual query builder + const expression = '{app="frontend"} | label_format renameTo=original, bar=baz'; + expect(buildVisualQueryFromString(expression)).toEqual( noErrors({ labels: [ { @@ -715,9 +734,10 @@ describe('buildVisualQueryFromString', () => { }); it('parses chained binary query', () => { - expect( - buildVisualQueryFromString('rate({project="bar"}[5m]) * 2 / rate({project="foo"}[5m]) + rate({app="test"}[1m])') - ).toEqual( + const expression = 'rate({project="bar"}[5m]) * 2 / rate({project="foo"}[5m]) + rate({app="test"}[1m])'; + // is converted to (rate({project="bar"} [5m]) * 2) / (rate({project="foo"} [5m]) + rate({app="test"} [1m])) by visual query builder + // Note the extra parenthesis around the first binary operation expression: (rate({project="bar"} [5m]) * 2) + expect(buildVisualQueryFromString(expression)).toEqual( noErrors({ labels: [{ op: '=', value: 'bar', label: 'project' }], operations: [ @@ -777,7 +797,9 @@ describe('buildVisualQueryFromString', () => { }); it('parses a regexp with no param', () => { - expect(buildVisualQueryFromString('{app="frontend"} | regexp ')).toEqual( + const expression = '{app="frontend"} | regexp '; + // Converted to {app="frontend"} | regexp `` by visual query builder + expect(buildVisualQueryFromString(expression)).toEqual( noErrors({ labels: [ { diff --git a/public/app/plugins/datasource/loki/querybuilder/parsing.ts b/public/app/plugins/datasource/loki/querybuilder/parsing.ts index 63cb300cb03..b78146a2dda 100644 --- a/public/app/plugins/datasource/loki/querybuilder/parsing.ts +++ b/public/app/plugins/datasource/loki/querybuilder/parsing.ts @@ -541,6 +541,15 @@ function handleVectorAggregation(expr: string, node: SyntaxNode, context: Contex const op: QueryBuilderOperation = { id: funcName, params }; if (metricExpr) { + // A vector aggregation expression with a child of metric expression with a child of binary expression is ambiguous after being parsed into a visual query + if (metricExpr.firstChild?.type.id === BinOpExpr) { + context.errors.push({ + text: 'Query parsing is ambiguous.', + from: metricExpr.firstChild.from, + to: metricExpr.firstChild?.to, + }); + } + handleExpression(expr, metricExpr, context); }