datasource.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import { map as _map } from 'lodash';
  2. import { lastValueFrom, of } from 'rxjs';
  3. import { catchError, map, mapTo } from 'rxjs/operators';
  4. import { AnnotationEvent, DataSourceInstanceSettings, MetricFindValue, ScopedVars, TimeRange } from '@grafana/data';
  5. import { BackendDataSourceResponse, DataSourceWithBackend, FetchResponse, getBackendSrv } from '@grafana/runtime';
  6. import { toTestingStatus } from '@grafana/runtime/src/utils/queryResponse';
  7. import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv';
  8. import ResponseParser from './response_parser';
  9. import { MssqlOptions, MssqlQuery, MssqlQueryForInterpolation } from './types';
  10. export class MssqlDatasource extends DataSourceWithBackend<MssqlQuery, MssqlOptions> {
  11. id: any;
  12. name: any;
  13. responseParser: ResponseParser;
  14. interval: string;
  15. constructor(
  16. instanceSettings: DataSourceInstanceSettings<MssqlOptions>,
  17. private readonly templateSrv: TemplateSrv = getTemplateSrv()
  18. ) {
  19. super(instanceSettings);
  20. this.name = instanceSettings.name;
  21. this.id = instanceSettings.id;
  22. this.responseParser = new ResponseParser();
  23. const settingsData = instanceSettings.jsonData || ({} as MssqlOptions);
  24. this.interval = settingsData.timeInterval || '1m';
  25. }
  26. interpolateVariable(value: any, variable: any) {
  27. if (typeof value === 'string') {
  28. if (variable.multi || variable.includeAll) {
  29. return "'" + value.replace(/'/g, `''`) + "'";
  30. } else {
  31. return value;
  32. }
  33. }
  34. if (typeof value === 'number') {
  35. return value;
  36. }
  37. const quotedValues = _map(value, (val) => {
  38. if (typeof value === 'number') {
  39. return value;
  40. }
  41. return "'" + val.replace(/'/g, `''`) + "'";
  42. });
  43. return quotedValues.join(',');
  44. }
  45. interpolateVariablesInQueries(
  46. queries: MssqlQueryForInterpolation[],
  47. scopedVars: ScopedVars
  48. ): MssqlQueryForInterpolation[] {
  49. let expandedQueries = queries;
  50. if (queries && queries.length > 0) {
  51. expandedQueries = queries.map((query) => {
  52. const expandedQuery = {
  53. ...query,
  54. datasource: this.getRef(),
  55. rawSql: this.templateSrv.replace(query.rawSql, scopedVars, this.interpolateVariable),
  56. rawQuery: true,
  57. };
  58. return expandedQuery;
  59. });
  60. }
  61. return expandedQueries;
  62. }
  63. applyTemplateVariables(target: MssqlQuery, scopedVars: ScopedVars): Record<string, any> {
  64. return {
  65. refId: target.refId,
  66. datasource: this.getRef(),
  67. rawSql: this.templateSrv.replace(target.rawSql, scopedVars, this.interpolateVariable),
  68. format: target.format,
  69. };
  70. }
  71. async annotationQuery(options: any): Promise<AnnotationEvent[]> {
  72. if (!options.annotation.rawQuery) {
  73. return Promise.reject({ message: 'Query missing in annotation definition' });
  74. }
  75. const query = {
  76. refId: options.annotation.name,
  77. datasource: this.getRef(),
  78. rawSql: this.templateSrv.replace(options.annotation.rawQuery, options.scopedVars, this.interpolateVariable),
  79. format: 'table',
  80. };
  81. return lastValueFrom(
  82. getBackendSrv()
  83. .fetch<BackendDataSourceResponse>({
  84. url: '/api/ds/query',
  85. method: 'POST',
  86. data: {
  87. from: options.range.from.valueOf().toString(),
  88. to: options.range.to.valueOf().toString(),
  89. queries: [query],
  90. },
  91. requestId: options.annotation.name,
  92. })
  93. .pipe(
  94. map(
  95. async (res: FetchResponse<BackendDataSourceResponse>) =>
  96. await this.responseParser.transformAnnotationResponse(options, res.data)
  97. )
  98. )
  99. );
  100. }
  101. filterQuery(query: MssqlQuery): boolean {
  102. return !query.hide;
  103. }
  104. metricFindQuery(query: string, optionalOptions: any): Promise<MetricFindValue[]> {
  105. let refId = 'tempvar';
  106. if (optionalOptions && optionalOptions.variable && optionalOptions.variable.name) {
  107. refId = optionalOptions.variable.name;
  108. }
  109. const range = optionalOptions?.range as TimeRange;
  110. const interpolatedQuery = {
  111. refId: refId,
  112. datasource: this.getRef(),
  113. rawSql: this.templateSrv.replace(query, {}, this.interpolateVariable),
  114. format: 'table',
  115. };
  116. return lastValueFrom(
  117. getBackendSrv()
  118. .fetch<BackendDataSourceResponse>({
  119. url: '/api/ds/query',
  120. method: 'POST',
  121. data: {
  122. from: range?.from?.valueOf()?.toString(),
  123. to: range?.to?.valueOf()?.toString(),
  124. queries: [interpolatedQuery],
  125. },
  126. requestId: refId,
  127. })
  128. .pipe(
  129. map((rsp) => {
  130. return this.responseParser.transformMetricFindResponse(rsp);
  131. }),
  132. catchError((err) => {
  133. return of([]);
  134. })
  135. )
  136. );
  137. }
  138. testDatasource(): Promise<any> {
  139. return lastValueFrom(
  140. getBackendSrv()
  141. .fetch({
  142. url: '/api/ds/query',
  143. method: 'POST',
  144. data: {
  145. from: '5m',
  146. to: 'now',
  147. queries: [
  148. {
  149. refId: 'A',
  150. intervalMs: 1,
  151. maxDataPoints: 1,
  152. datasource: this.getRef(),
  153. rawSql: 'SELECT 1',
  154. format: 'table',
  155. },
  156. ],
  157. },
  158. })
  159. .pipe(
  160. mapTo({ status: 'success', message: 'Database Connection OK' }),
  161. catchError((err) => {
  162. return of(toTestingStatus(err));
  163. })
  164. )
  165. );
  166. }
  167. targetContainsTemplate(query: MssqlQuery): boolean {
  168. const rawSql = query.rawSql.replace('$__', '');
  169. return this.templateSrv.containsTemplate(rawSql);
  170. }
  171. }