diff --git a/public/app/plugins/datasource/graphite/graphite_query.ts b/public/app/plugins/datasource/graphite/graphite_query.ts index 94e2d7db4ef..d9202c335a5 100644 --- a/public/app/plugins/datasource/graphite/graphite_query.ts +++ b/public/app/plugins/datasource/graphite/graphite_query.ts @@ -210,17 +210,20 @@ export default class GraphiteQuery { // render nested query const targetsByRefId = keyBy(targets, 'refId'); - // no references to self - delete targetsByRefId[target.refId]; - const nestedSeriesRefRegex = /\#([A-Z])/g; let targetWithNestedQueries = target.target; // Use ref count to track circular references each(targetsByRefId, (t, id) => { const regex = RegExp(`\#(${id})`, 'g'); - const refMatches = targetWithNestedQueries.match(regex); - t.refCount = refMatches?.length ?? 0; + let refCount = 0; + each(targetsByRefId, (t2, id2) => { + if (id2 !== id) { + const refMatches = t2.target.match(regex); + refCount += refMatches?.length ?? 0; + } + }); + t.refCount = refCount; }); // Keep interpolating until there are no query references diff --git a/public/app/plugins/datasource/graphite/specs/graphite_query.test.ts b/public/app/plugins/datasource/graphite/specs/graphite_query.test.ts index a02456b64a9..5d5035c5dd6 100644 --- a/public/app/plugins/datasource/graphite/specs/graphite_query.test.ts +++ b/public/app/plugins/datasource/graphite/specs/graphite_query.test.ts @@ -53,6 +53,21 @@ describe('Graphite query model', () => { expect(ctx.queryModel.target.targetFull).toBe(targetFullExpected); }); + it('targetFull should include nested queries at any level with repeated subqueries', () => { + ctx.target = { refId: 'C', target: 'aggregateSeriesLists(#B, #C, "sum")' }; + ctx.targets = [ + { refId: 'A', target: 'first.query.count' }, + { refId: 'B', target: "alias(timeShift(#A, '-1min', true), '-1min')" }, + { refId: 'C', target: "alias(timeShift(#A, '-2min', true), '-2min')" }, + { refId: 'D', target: 'aggregateSeriesLists(#B, #C, "sum")' }, + ]; + ctx.queryModel = new GraphiteQuery(ctx.datasource, ctx.target, ctx.templateSrv); + ctx.queryModel.updateRenderedTarget(ctx.target, ctx.targets); + const targetFullExpected = + "aggregateSeriesLists(alias(timeShift(first.query.count, '-1min', true), '-1min'), alias(timeShift(first.query.count, '-2min', true), '-2min'), \"sum\")"; + expect(ctx.queryModel.target.targetFull).toBe(targetFullExpected); + }); + it('should not hang on circular references', () => { ctx.target.target = 'asPercent(#A, #B)'; ctx.targets = [