Skip to content

Commit a57f231

Browse files
authored
Bugfix: Fix $interval variable interpolation (#291)
1 parent 62e2ffb commit a57f231

File tree

5 files changed

+43
-21
lines changed

5 files changed

+43
-21
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ cypress/videos/
99
dist/
1010
provisioning
1111
pkg/__debug_bin
12+
yarn-error.log

src/DataSource.test.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,26 @@ import { mockDatasource, mockQuery } from './__mocks__/datasource';
55

66
describe('DataSource', () => {
77
describe('applyTemplateVariables', () => {
8-
const scopedVars: Record<string, any> = {
9-
$simple: 'foo',
10-
$multiple: ['foo', 'bar'],
8+
const scopedVars: ScopedVars = {
9+
$simple: { value: 'foo' },
10+
$multiple: { value: ['foo', 'bar'] },
11+
__interval_ms: { value: 5000000 },
12+
__interval: { value: 50000 },
1113
};
1214
// simplified version of getTemplateSrv().replace
13-
const replace = jest.fn((target?: string, scopedVars?: ScopedVars, format?: string | Function) => {
14-
let res = target ?? '';
15-
if (scopedVars && typeof format === 'function') {
16-
Object.keys(scopedVars).forEach((v) => (res = res.replace(v, format(scopedVars[v]))));
15+
const replaceMock = jest.fn().mockImplementation(
16+
(target?: string, scopedVars?: ScopedVars, format?: string | Function) => {
17+
let res = target ?? '';
18+
if (scopedVars && typeof format === 'function') {
19+
Object.keys(scopedVars).forEach((v) => (res = res.replace(v, format(scopedVars[v]?.value))));
20+
}
21+
return res;
1722
}
18-
return res;
19-
});
23+
);
2024
beforeEach(() => {
2125
jest.spyOn(runtime, 'getTemplateSrv').mockImplementation(() => ({
2226
getVariables: jest.fn(),
23-
replace: replace,
27+
replace: replaceMock,
2428
containsTemplate: jest.fn(),
2529
updateTimeRange: jest.fn(),
2630
}));
@@ -41,5 +45,18 @@ describe('DataSource', () => {
4145
);
4246
expect(res.rawQuery).toEqual(`select * from foo where var in ('foo','bar')`);
4347
});
48+
49+
it('should replace __interval interpolated variables with their original string', () => {
50+
mockDatasource.applyTemplateVariables(
51+
{ ...mockQuery, rawQuery: 'select $__interval_ms, $__interval' },
52+
{
53+
__interval_ms: { value: 5000000 },
54+
__interval: { value: 50000 },
55+
}
56+
);
57+
// check rawQuery.replace is called with correct interval value
58+
expect(replaceMock.mock.calls[3][1].__interval).toEqual({ value: '$__interval' });
59+
expect(replaceMock.mock.calls[3][1].__interval_ms).toEqual({ value: '$__interval_ms' });
60+
});
4461
});
4562
});

src/DataSource.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,23 @@ export class DataSource extends DataSourceWithBackend<TimestreamQuery, Timestrea
7575
return query;
7676
}
7777

78-
// create a copy of scopedVars without $__interval_ms for using with rawQuery
79-
// ${__interval*} should be escaped by the server, not the frontend
80-
const queryScopedVars = { ...scopedVars };
81-
delete queryScopedVars.__interval_ms;
82-
delete queryScopedVars.__interval;
78+
const variables = { ...scopedVars };
79+
// We want to interpolate these variables on backend.
80+
// The pre-calculated values are replaced with the variable strings.
81+
variables.__interval = {
82+
value: '$__interval',
83+
};
84+
variables.__interval_ms = {
85+
value: '$__interval_ms',
86+
};
8387

8488
const templateSrv = getTemplateSrv();
8589
return {
8690
...query,
8791
database: templateSrv.replace(query.database || '', scopedVars),
8892
table: templateSrv.replace(query.table || '', scopedVars),
8993
measure: templateSrv.replace(query.measure || '', scopedVars),
90-
rawQuery: templateSrv.replace(query.rawQuery, queryScopedVars, this.interpolateVariable),
94+
rawQuery: templateSrv.replace(query.rawQuery, variables, this.interpolateVariable),
9195
};
9296
}
9397

src/components/SQLEditor.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ export default function SQLEditor({ query, datasource, onRunQuery, onChange }: R
4343
const getColumns = useCallback(
4444
async (database?: string, tableName?: string) => {
4545
const interpolatedArgs = {
46-
database: database ? database.replace(DATABASE_MACRO, queryRef.current.database ?? '') : queryRef.current.database,
47-
table: tableName
48-
? tableName.replace(TABLE_MACRO, queryRef.current.table ?? '')
49-
: queryRef.current.table,
46+
database: database
47+
? database.replace(DATABASE_MACRO, queryRef.current.database ?? '')
48+
: queryRef.current.database,
49+
table: tableName ? tableName.replace(TABLE_MACRO, queryRef.current.table ?? '') : queryRef.current.table,
5050
};
5151
const [measures, dimensions] = await Promise.all([
5252
datasource.postResource('measures', interpolatedArgs).catch(() => []),

src/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"updated": "%TODAY%"
3333
},
3434
"dependencies": {
35-
"grafanaDependency": ">=8.0.0",
35+
"grafanaDependency": ">=9.5.13",
3636
"plugins": []
3737
}
3838
}

0 commit comments

Comments
 (0)