Skip to content

Commit b880774

Browse files
committed
Support variable interpolation
1 parent ea65674 commit b880774

File tree

3 files changed

+84
-3
lines changed

3 files changed

+84
-3
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,38 @@ Plugin supports the following marcos:
4343

4444
A description of macros is available by typing their names in Raw Editor
4545

46+
## Templating
47+
48+
### Using Variables in Queries
49+
50+
Template variable values are only quoted when the template variable is a `multi-value`.
51+
52+
If the variable is a multi-value variable then use the `IN` comparison operator
53+
rather than `=` to match against multiple values.
54+
55+
Example with a template variable named hostname:
56+
57+
```sql
58+
SELECT
59+
atimestamp as time,
60+
aint as value
61+
FROM table
62+
WHERE $__timeFilter(atimestamp) and hostname in($hostname)
63+
ORDER BY atimestamp ASC
64+
```
65+
66+
### Disabling quoting for multi-value variables
67+
68+
Grafana automatically creates a quoted, comma-separated string for multi-value variables.
69+
For example: if `server01` and `server02` are selected then it will be formatted as:
70+
`'server01', 'server02'`. To disable quoting, use the `csv` formatting option for variables:
71+
72+
```
73+
${servers:csv}
74+
```
75+
76+
Read more about variable formatting options in the [Variables](https://grafana.com/docs/grafana/latest/variables/#advanced-formatting-options) documentation.
77+
4678
# Contributing
4779

4880
If you have any idea for an improvement or found a bug do not hesitate to open an issue or submit a pull request.

src/datasource.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import { DataSourceInstanceSettings } from '@grafana/data';
2-
import { DataSourceWithBackend, getBackendSrv, toDataQueryError } from '@grafana/runtime';
1+
import { DataSourceInstanceSettings, ScopedVars } from '@grafana/data';
2+
import { DataSourceWithBackend, getBackendSrv, getTemplateSrv, toDataQueryError } from '@grafana/runtime';
33
import { TrinoDataSourceOptions, TrinoQuery } from './types';
44
import { lastValueFrom, of } from 'rxjs';
55
import { catchError, mapTo } from 'rxjs/operators';
6+
import { map } from 'lodash';
67

78
export class DataSource extends DataSourceWithBackend<TrinoQuery, TrinoDataSourceOptions> {
89
constructor(instanceSettings: DataSourceInstanceSettings<TrinoDataSourceOptions>) {
910
super(instanceSettings);
11+
// give interpolateQueryStr access to this
12+
this.interpolateQueryStr = this.interpolateQueryStr.bind(this);
1013
}
1114

1215
testDatasource(): Promise<any> {
@@ -40,4 +43,35 @@ export class DataSource extends DataSourceWithBackend<TrinoQuery, TrinoDataSourc
4043
)
4144
);
4245
}
46+
47+
applyTemplateVariables(query: TrinoQuery, scopedVars: ScopedVars): Record<string, any> {
48+
query.rawSQL = getTemplateSrv().replace(query.rawSQL, scopedVars, this.interpolateQueryStr);
49+
return query;
50+
}
51+
52+
interpolateQueryStr(value: any, variable: { multi: any; includeAll: any }, defaultFormatFn: any) {
53+
// if no multi or include all do not regexEscape
54+
if (!variable.multi && !variable.includeAll) {
55+
return this.escapeLiteral(value);
56+
}
57+
58+
if (typeof value === 'string') {
59+
return this.quoteLiteral(value);
60+
}
61+
62+
const escapedValues = map(value, this.quoteLiteral);
63+
return escapedValues.join(',');
64+
}
65+
66+
quoteIdentifier(value: any) {
67+
return '"' + String(value).replace(/"/g, '""') + '"';
68+
}
69+
70+
quoteLiteral(value: any) {
71+
return "'" + String(value).replace(/'/g, "''") + "'";
72+
}
73+
74+
escapeLiteral(value: any) {
75+
return String(value).replace(/'/g, "''");
76+
}
4377
}

src/specs/datasource.test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,27 @@ import { of } from 'rxjs';
22
import { TestScheduler } from 'rxjs/testing';
33

44
import { dataFrameToJSON, DataSourceInstanceSettings, dateTime, MutableDataFrame } from '@grafana/data';
5-
import { BackendSrv, DataSourceSrv, FetchResponse, setBackendSrv, setDataSourceSrv } from '@grafana/runtime';
5+
import {
6+
BackendSrv,
7+
DataSourceSrv,
8+
FetchResponse,
9+
setBackendSrv,
10+
setDataSourceSrv,
11+
TemplateSrv,
12+
setTemplateSrv,
13+
} from '@grafana/runtime';
614

715
import { DataSource } from '../datasource';
816
import { TrinoDataSourceOptions } from '../types';
917

1018
const mockBackend = { fetch: () => {} };
1119
setBackendSrv(mockBackend as unknown as BackendSrv);
20+
const mockTemplate = {
21+
replace: (target: any) => {
22+
return target;
23+
},
24+
};
25+
setTemplateSrv(mockTemplate as unknown as TemplateSrv);
1226
const mockDataSource = {
1327
getInstanceSettings: () => ({ id: 8674 }),
1428
};
@@ -17,6 +31,7 @@ setDataSourceSrv(mockDataSource as unknown as DataSourceSrv);
1731
jest.mock('@grafana/runtime', () => ({
1832
...(jest.requireActual('@grafana/runtime') as unknown as object),
1933
getBackendSrv: () => mockBackend,
34+
getTemplateSrv: () => mockTemplate,
2035
getDataSourceSrv: () => mockDataSource,
2136
}));
2237

0 commit comments

Comments
 (0)