Files
grafana/public/app/features/scenes/variables/variants/query/createQueryVariableRunner.ts
Dominik Prokop 1758ddd457 Scenes: Add query variable support (#59553)
* WIP first attempt to query variable

* regex issue repro demo

* Refresh variable on time range change if refresh specified

* Instantiate variable runner when updating query variable options

* Simplify runners getTarget interface

* Fix issue with variable ot being updated correctly after other variable changed

* Add templateSrv.replace compatibility with query variable

* QueryVariable: use datasource variable as source

* use proper format

* Make sure variables set is correctly updated when query variable errors

* Do not destruct scopedVars when using sceneGraph.interpolate in templateSrv

* Add support for Legacy variables (metricFindQuery)

* Review

* Fix lint

* Test: Add unit for datasource by variable

* test: Add unit for datasource as var

* query: delegate interpolation to datasourceSrv

* Cleanup

Co-authored-by: Ivan Ortega <ivanortegaalba@gmail.com>
2022-12-12 04:01:27 -08:00

116 lines
3.4 KiB
TypeScript

import { from, mergeMap, Observable, of } from 'rxjs';
import {
DataQuery,
DataQueryRequest,
DataSourceApi,
getDefaultTimeRange,
LoadingState,
PanelData,
} from '@grafana/data';
import { runRequest } from 'app/features/query/state/runRequest';
import { hasLegacyVariableSupport, hasStandardVariableSupport } from 'app/features/variables/guard';
import { QueryVariable } from './QueryVariable';
export interface RunnerArgs {
searchFilter?: string;
variable: QueryVariable;
}
export interface QueryRunner {
getTarget: (variable: QueryVariable) => DataQuery;
runRequest: (args: RunnerArgs, request: DataQueryRequest) => Observable<PanelData>;
}
class StandardQueryRunner implements QueryRunner {
public constructor(private datasource: DataSourceApi, private _runRequest = runRequest) {}
public getTarget(variable: QueryVariable) {
if (hasStandardVariableSupport(this.datasource)) {
return this.datasource.variables.toDataQuery(variable.state.query);
}
throw new Error("Couldn't create a target with supplied arguments.");
}
public runRequest(_: RunnerArgs, request: DataQueryRequest) {
if (!hasStandardVariableSupport(this.datasource)) {
return getEmptyMetricFindValueObservable();
}
if (!this.datasource.variables.query) {
return this._runRequest(this.datasource, request);
}
return this._runRequest(this.datasource, request, this.datasource.variables.query);
}
}
class LegacyQueryRunner implements QueryRunner {
public constructor(private datasource: DataSourceApi) {}
public getTarget(variable: QueryVariable) {
if (hasLegacyVariableSupport(this.datasource)) {
return variable.state.query;
}
throw new Error("Couldn't create a target with supplied arguments.");
}
public runRequest({ variable }: RunnerArgs, request: DataQueryRequest) {
if (!hasLegacyVariableSupport(this.datasource)) {
return getEmptyMetricFindValueObservable();
}
return from(
this.datasource.metricFindQuery(variable.state.query, {
...request,
// variable is used by SQL common data source
variable: {
name: variable.state.name,
type: variable.state.type,
},
// TODO: add support for search filter
// searchFilter
})
).pipe(
mergeMap((values) => {
if (!values || !values.length) {
return getEmptyMetricFindValueObservable();
}
const series: any = values;
return of({ series, state: LoadingState.Done, timeRange: request.range });
})
);
}
}
function getEmptyMetricFindValueObservable(): Observable<PanelData> {
return of({ state: LoadingState.Done, series: [], timeRange: getDefaultTimeRange() });
}
function createQueryVariableRunnerFactory(datasource: DataSourceApi): QueryRunner {
if (hasStandardVariableSupport(datasource)) {
return new StandardQueryRunner(datasource, runRequest);
}
if (hasLegacyVariableSupport(datasource)) {
return new LegacyQueryRunner(datasource);
}
// TODO: add support for legacy, cutom and datasource query runners
throw new Error(`Couldn't create a query runner for datasource ${datasource.type}`);
}
export let createQueryVariableRunner = createQueryVariableRunnerFactory;
/**
* Use only in tests
*/
export function setCreateQueryVariableRunnerFactory(fn: (datasource: DataSourceApi) => QueryRunner) {
createQueryVariableRunner = fn;
}