Expressions: Add support for variables (#41778)

pull/45548/head
Todd Treece 4 years ago committed by GitHub
parent 42e547d27f
commit c8bb01d1ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      docs/sources/panels/query-a-data-source/use-expressions-to-manipulate-data/about-expressions.md
  2. 37
      public/app/features/expressions/ExpressionDatasource.test.ts
  3. 36
      public/app/features/expressions/ExpressionDatasource.ts

@ -16,8 +16,6 @@ Expressions are primarily used by the new [Grafana 8 alerts]({{< relref "../../.
> **Note:** Expressions do not work with legacy dashboard alerts.
> **Note:** Expressions do not work with dashboard variables.
Expressions are meant to augment data sources by enabling queries from different data sources to be combined or by providing operations unavailable in a data source.
> **Note:** When possible, you should do data processing inside the data source. Copying data from storage to the Grafana server for processing is inefficient, so expressions are targeted at lightweight data processing.

@ -0,0 +1,37 @@
import { DataSourceInstanceSettings } from '@grafana/data';
import { backendSrv } from 'app/core/services/backend_srv';
import { ExpressionDatasourceApi } from './ExpressionDatasource';
import { ExpressionQueryType } from './types';
jest.mock('@grafana/runtime', () => ({
...(jest.requireActual('@grafana/runtime') as unknown as object),
getBackendSrv: () => backendSrv,
getTemplateSrv: () => ({
replace: (val: string) => (val ? val.replace('$input', '10').replace('$window', '10s') : val),
}),
}));
describe('ExpressionDatasourceApi', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('expression queries with template variables', () => {
it('should interpolate template variables in expression query', () => {
const ds = new ExpressionDatasourceApi({} as DataSourceInstanceSettings);
const query = ds.applyTemplateVariables(
{ type: ExpressionQueryType.math, refId: 'B', expression: '$input + 5 + $A' },
{}
);
expect(query.expression).toBe('10 + 5 + $A');
});
it('should interpolate template variables in expression query', () => {
const ds = new ExpressionDatasourceApi({} as DataSourceInstanceSettings);
const query = ds.applyTemplateVariables(
{ type: ExpressionQueryType.resample, refId: 'B', window: '$window' },
{}
);
expect(query.window).toBe('10s');
});
});
});

@ -1,8 +1,16 @@
import { DataSourceInstanceSettings, DataSourcePluginMeta, PluginType } from '@grafana/data';
import {
DataQueryRequest,
DataQueryResponse,
DataSourceInstanceSettings,
DataSourcePluginMeta,
PluginType,
ScopedVars,
} from '@grafana/data';
import { ExpressionQuery, ExpressionQueryType } from './types';
import { ExpressionQueryEditor } from './ExpressionQueryEditor';
import { DataSourceWithBackend } from '@grafana/runtime';
import { DataSourceWithBackend, getDataSourceSrv, getTemplateSrv } from '@grafana/runtime';
import { ExpressionDatasourceRef } from '@grafana/runtime/src/utils/DataSourceWithBackend';
import { Observable, from, mergeMap } from 'rxjs';
/**
* This is a singleton instance that just pretends to be a DataSource
@ -12,10 +20,34 @@ export class ExpressionDatasourceApi extends DataSourceWithBackend<ExpressionQue
super(instanceSettings);
}
applyTemplateVariables(query: ExpressionQuery, scopedVars: ScopedVars): Record<string, any> {
const templateSrv = getTemplateSrv();
return {
...query,
expression: templateSrv.replace(query.expression, scopedVars),
window: templateSrv.replace(query.window, scopedVars),
};
}
getCollapsedText(query: ExpressionQuery) {
return `Expression: ${query.type}`;
}
query(request: DataQueryRequest<ExpressionQuery>): Observable<DataQueryResponse> {
let targets = request.targets.map(async (query: ExpressionQuery): Promise<ExpressionQuery> => {
const ds = await getDataSourceSrv().get(query.datasource);
if (!ds.interpolateVariablesInQueries) {
return query;
}
return ds?.interpolateVariablesInQueries([query], {})[0] as ExpressionQuery;
});
let sub = from(Promise.all(targets));
return sub.pipe(mergeMap((t) => super.query({ ...request, targets: t })));
}
newQuery(query?: Partial<ExpressionQuery>): ExpressionQuery {
return {
refId: '--', // Replaced with query

Loading…
Cancel
Save