Commit 0bb8b328 by Hugo Häggmark Committed by GitHub

Mysql: Support request cancellation properly (Uses new backendSrv.fetch…

Mysql: Support request cancellation properly (Uses new backendSrv.fetch Observable request API) (#27649)
parent 3ae6ba03
import _ from 'lodash'; import _ from 'lodash';
import ResponseParser from './response_parser'; import { Observable, of } from 'rxjs';
import MysqlQuery from 'app/plugins/datasource/mysql/mysql_query'; import { catchError, map, mapTo } from 'rxjs/operators';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
import { ScopedVars } from '@grafana/data'; import { ScopedVars } from '@grafana/data';
import { TemplateSrv } from 'app/features/templating/template_srv'; import { TemplateSrv } from 'app/features/templating/template_srv';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
//Types import MysqlQuery from 'app/plugins/datasource/mysql/mysql_query';
import { MysqlQueryForInterpolation } from './types'; import ResponseParser, { MysqlResponse } from './response_parser';
import { MysqlMetricFindValue, MysqlQueryForInterpolation } from './types';
import { getSearchFilterScopedVar } from '../../../features/variables/utils'; import { getSearchFilterScopedVar } from '../../../features/variables/utils';
export class MysqlDatasource { export class MysqlDatasource {
...@@ -25,7 +27,7 @@ export class MysqlDatasource { ...@@ -25,7 +27,7 @@ export class MysqlDatasource {
this.interval = (instanceSettings.jsonData || {}).timeInterval || '1m'; this.interval = (instanceSettings.jsonData || {}).timeInterval || '1m';
} }
interpolateVariable = (value: string, variable: any) => { interpolateVariable = (value: string | string[] | number, variable: any) => {
if (typeof value === 'string') { if (typeof value === 'string') {
if (variable.multi || variable.includeAll) { if (variable.multi || variable.includeAll) {
const result = this.queryModel.quoteLiteral(value); const result = this.queryModel.quoteLiteral(value);
...@@ -64,7 +66,7 @@ export class MysqlDatasource { ...@@ -64,7 +66,7 @@ export class MysqlDatasource {
return expandedQueries; return expandedQueries;
} }
query(options: any) { query(options: any): Observable<MysqlResponse> {
const queries = _.filter(options.targets, target => { const queries = _.filter(options.targets, target => {
return target.hide !== true; return target.hide !== true;
}).map(target => { }).map(target => {
...@@ -81,11 +83,11 @@ export class MysqlDatasource { ...@@ -81,11 +83,11 @@ export class MysqlDatasource {
}); });
if (queries.length === 0) { if (queries.length === 0) {
return Promise.resolve({ data: [] }); return of({ data: [] });
} }
return getBackendSrv() return getBackendSrv()
.datasourceRequest({ .fetch({
url: '/api/tsdb/query', url: '/api/tsdb/query',
method: 'POST', method: 'POST',
data: { data: {
...@@ -94,7 +96,7 @@ export class MysqlDatasource { ...@@ -94,7 +96,7 @@ export class MysqlDatasource {
queries: queries, queries: queries,
}, },
}) })
.then(this.responseParser.processQueryResult); .pipe(map(this.responseParser.processQueryResult));
} }
annotationQuery(options: any) { annotationQuery(options: any) {
...@@ -112,7 +114,7 @@ export class MysqlDatasource { ...@@ -112,7 +114,7 @@ export class MysqlDatasource {
}; };
return getBackendSrv() return getBackendSrv()
.datasourceRequest({ .fetch({
url: '/api/tsdb/query', url: '/api/tsdb/query',
method: 'POST', method: 'POST',
data: { data: {
...@@ -121,10 +123,11 @@ export class MysqlDatasource { ...@@ -121,10 +123,11 @@ export class MysqlDatasource {
queries: [query], queries: [query],
}, },
}) })
.then((data: any) => this.responseParser.transformAnnotationResponse(options, data)); .pipe(map((data: any) => this.responseParser.transformAnnotationResponse(options, data)))
.toPromise();
} }
metricFindQuery(query: string, optionalOptions: any) { metricFindQuery(query: string, optionalOptions: any): Promise<MysqlMetricFindValue[]> {
let refId = 'tempvar'; let refId = 'tempvar';
if (optionalOptions && optionalOptions.variable && optionalOptions.variable.name) { if (optionalOptions && optionalOptions.variable && optionalOptions.variable.name) {
refId = optionalOptions.variable.name; refId = optionalOptions.variable.name;
...@@ -158,17 +161,18 @@ export class MysqlDatasource { ...@@ -158,17 +161,18 @@ export class MysqlDatasource {
} }
return getBackendSrv() return getBackendSrv()
.datasourceRequest({ .fetch({
url: '/api/tsdb/query', url: '/api/tsdb/query',
method: 'POST', method: 'POST',
data: data, data: data,
}) })
.then((data: any) => this.responseParser.parseMetricFindQueryResult(refId, data)); .pipe(map((data: any) => this.responseParser.parseMetricFindQueryResult(refId, data)))
.toPromise();
} }
testDatasource() { testDatasource() {
return getBackendSrv() return getBackendSrv()
.datasourceRequest({ .fetch({
url: '/api/tsdb/query', url: '/api/tsdb/query',
method: 'POST', method: 'POST',
data: { data: {
...@@ -186,17 +190,18 @@ export class MysqlDatasource { ...@@ -186,17 +190,18 @@ export class MysqlDatasource {
], ],
}, },
}) })
.then((res: any) => { .pipe(
return { status: 'success', message: 'Database Connection OK' }; mapTo({ status: 'success', message: 'Database Connection OK' }),
}) catchError(err => {
.catch((err: any) => { console.error(err);
console.error(err); if (err.data && err.data.message) {
if (err.data && err.data.message) { return of({ status: 'error', message: err.data.message });
return { status: 'error', message: err.data.message }; } else {
} else { return of({ status: 'error', message: err.status });
return { status: 'error', message: err.status }; }
} })
}); )
.toPromise();
} }
targetContainsTemplate(target: any) { targetContainsTemplate(target: any) {
......
import _ from 'lodash'; import _ from 'lodash';
import { MysqlMetricFindValue } from './types';
interface TableResponse extends Record<string, any> {
type: string;
refId: string;
meta: any;
}
interface SeriesResponse extends Record<string, any> {
target: string;
refId: string;
meta: any;
datapoints: [any[]];
}
export interface MysqlResponse {
data: Array<TableResponse | SeriesResponse>;
}
export default class ResponseParser { export default class ResponseParser {
processQueryResult(res: any) { processQueryResult(res: any): MysqlResponse {
const data: any[] = []; const data: any[] = [];
if (!res.data.results) { if (!res.data.results) {
...@@ -35,7 +53,7 @@ export default class ResponseParser { ...@@ -35,7 +53,7 @@ export default class ResponseParser {
return { data: data }; return { data: data };
} }
parseMetricFindQueryResult(refId: string, results: any) { parseMetricFindQueryResult(refId: string, results: any): MysqlMetricFindValue[] {
if (!results || results.data.length === 0 || results.data.results[refId].meta.rowCount === 0) { if (!results || results.data.length === 0 || results.data.results[refId].meta.rowCount === 0) {
return []; return [];
} }
...@@ -117,9 +135,9 @@ export default class ResponseParser { ...@@ -117,9 +135,9 @@ export default class ResponseParser {
} else if (table.columns[i].text === 'timeend') { } else if (table.columns[i].text === 'timeend') {
timeEndColumnIndex = i; timeEndColumnIndex = i;
} else if (table.columns[i].text === 'title') { } else if (table.columns[i].text === 'title') {
return Promise.reject({ throw {
message: 'The title column for annotations is deprecated, now only a column named text is returned', message: 'The title column for annotations is deprecated, now only a column named text is returned',
}); };
} else if (table.columns[i].text === 'text') { } else if (table.columns[i].text === 'text') {
textColumnIndex = i; textColumnIndex = i;
} else if (table.columns[i].text === 'tags') { } else if (table.columns[i].text === 'tags') {
...@@ -128,9 +146,9 @@ export default class ResponseParser { ...@@ -128,9 +146,9 @@ export default class ResponseParser {
} }
if (timeColumnIndex === -1) { if (timeColumnIndex === -1) {
return Promise.reject({ throw {
message: 'Missing mandatory time column (with time_sec column alias) in annotation query.', message: 'Missing mandatory time column (with time_sec column alias) in annotation query.',
}); };
} }
const list = []; const list = [];
......
import { MetricFindValue } from '@grafana/data';
export interface MysqlQueryForInterpolation { export interface MysqlQueryForInterpolation {
alias?: any; alias?: any;
format?: any; format?: any;
...@@ -5,3 +7,7 @@ export interface MysqlQueryForInterpolation { ...@@ -5,3 +7,7 @@ export interface MysqlQueryForInterpolation {
refId?: any; refId?: any;
hide?: any; hide?: any;
} }
export interface MysqlMetricFindValue extends MetricFindValue {
value?: string;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment