queryRunners.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import { from, Observable, of } from 'rxjs';
  2. import { mergeMap } from 'rxjs/operators';
  3. import {
  4. DataQuery,
  5. DataQueryRequest,
  6. DataSourceApi,
  7. getDefaultTimeRange,
  8. LoadingState,
  9. PanelData,
  10. VariableSupportType,
  11. } from '@grafana/data';
  12. import { TimeSrv } from '../../dashboard/services/TimeSrv';
  13. import {
  14. hasCustomVariableSupport,
  15. hasDatasourceVariableSupport,
  16. hasLegacyVariableSupport,
  17. hasStandardVariableSupport,
  18. } from '../guard';
  19. import { QueryVariableModel } from '../types';
  20. import { getLegacyQueryOptions } from '../utils';
  21. export interface RunnerArgs {
  22. variable: QueryVariableModel;
  23. datasource: DataSourceApi;
  24. timeSrv: TimeSrv;
  25. runRequest: (
  26. datasource: DataSourceApi,
  27. request: DataQueryRequest,
  28. queryFunction?: typeof datasource.query
  29. ) => Observable<PanelData>;
  30. searchFilter?: string;
  31. }
  32. type GetTargetArgs = { datasource: DataSourceApi; variable: QueryVariableModel };
  33. export interface QueryRunner {
  34. type: VariableSupportType;
  35. canRun: (dataSource: DataSourceApi) => boolean;
  36. getTarget: (args: GetTargetArgs) => DataQuery;
  37. runRequest: (args: RunnerArgs, request: DataQueryRequest) => Observable<PanelData>;
  38. }
  39. export class QueryRunners {
  40. private readonly runners: QueryRunner[];
  41. constructor() {
  42. this.runners = [
  43. new LegacyQueryRunner(),
  44. new StandardQueryRunner(),
  45. new CustomQueryRunner(),
  46. new DatasourceQueryRunner(),
  47. ];
  48. }
  49. getRunnerForDatasource(datasource: DataSourceApi): QueryRunner {
  50. const runner = this.runners.find((runner) => runner.canRun(datasource));
  51. if (runner) {
  52. return runner;
  53. }
  54. throw new Error("Couldn't find a query runner that matches supplied arguments.");
  55. }
  56. }
  57. class LegacyQueryRunner implements QueryRunner {
  58. type = VariableSupportType.Legacy;
  59. canRun(dataSource: DataSourceApi) {
  60. return hasLegacyVariableSupport(dataSource);
  61. }
  62. getTarget({ datasource, variable }: GetTargetArgs) {
  63. if (hasLegacyVariableSupport(datasource)) {
  64. return variable.query;
  65. }
  66. throw new Error("Couldn't create a target with supplied arguments.");
  67. }
  68. runRequest({ datasource, variable, searchFilter, timeSrv }: RunnerArgs, request: DataQueryRequest) {
  69. if (!hasLegacyVariableSupport(datasource)) {
  70. return getEmptyMetricFindValueObservable();
  71. }
  72. const queryOptions: any = getLegacyQueryOptions(variable, searchFilter, timeSrv);
  73. return from(datasource.metricFindQuery(variable.query, queryOptions)).pipe(
  74. mergeMap((values) => {
  75. if (!values || !values.length) {
  76. return getEmptyMetricFindValueObservable();
  77. }
  78. const series: any = values;
  79. return of({ series, state: LoadingState.Done, timeRange: queryOptions.range });
  80. })
  81. );
  82. }
  83. }
  84. class StandardQueryRunner implements QueryRunner {
  85. type = VariableSupportType.Standard;
  86. canRun(dataSource: DataSourceApi) {
  87. return hasStandardVariableSupport(dataSource);
  88. }
  89. getTarget({ datasource, variable }: GetTargetArgs) {
  90. if (hasStandardVariableSupport(datasource)) {
  91. return datasource.variables.toDataQuery(variable.query);
  92. }
  93. throw new Error("Couldn't create a target with supplied arguments.");
  94. }
  95. runRequest({ datasource, runRequest }: RunnerArgs, request: DataQueryRequest) {
  96. if (!hasStandardVariableSupport(datasource)) {
  97. return getEmptyMetricFindValueObservable();
  98. }
  99. if (!datasource.variables.query) {
  100. return runRequest(datasource, request);
  101. }
  102. return runRequest(datasource, request, datasource.variables.query);
  103. }
  104. }
  105. class CustomQueryRunner implements QueryRunner {
  106. type = VariableSupportType.Custom;
  107. canRun(dataSource: DataSourceApi) {
  108. return hasCustomVariableSupport(dataSource);
  109. }
  110. getTarget({ datasource, variable }: GetTargetArgs) {
  111. if (hasCustomVariableSupport(datasource)) {
  112. return variable.query;
  113. }
  114. throw new Error("Couldn't create a target with supplied arguments.");
  115. }
  116. runRequest({ datasource, runRequest }: RunnerArgs, request: DataQueryRequest) {
  117. if (!hasCustomVariableSupport(datasource)) {
  118. return getEmptyMetricFindValueObservable();
  119. }
  120. return runRequest(datasource, request, datasource.variables.query);
  121. }
  122. }
  123. export const variableDummyRefId = 'variable-query';
  124. class DatasourceQueryRunner implements QueryRunner {
  125. type = VariableSupportType.Datasource;
  126. canRun(dataSource: DataSourceApi) {
  127. return hasDatasourceVariableSupport(dataSource);
  128. }
  129. getTarget({ datasource, variable }: GetTargetArgs) {
  130. if (hasDatasourceVariableSupport(datasource)) {
  131. return { ...variable.query, refId: variable.query.refId ?? variableDummyRefId };
  132. }
  133. throw new Error("Couldn't create a target with supplied arguments.");
  134. }
  135. runRequest({ datasource, runRequest }: RunnerArgs, request: DataQueryRequest) {
  136. if (!hasDatasourceVariableSupport(datasource)) {
  137. return getEmptyMetricFindValueObservable();
  138. }
  139. return runRequest(datasource, request);
  140. }
  141. }
  142. function getEmptyMetricFindValueObservable(): Observable<PanelData> {
  143. return of({ state: LoadingState.Done, series: [], timeRange: getDefaultTimeRange() });
  144. }