mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* WIP: Initial hardcoded version * Feature: Introduces SearchFiltering to Graphite * Feature: Adds searchFiltering to MySql * Tests: Adds tests to Graphite and MySql * Feature: Adds $__searchFilter to TestData * Refactor: Adds searchFilter to Postgres and extracts function * Tests: Adds tests to variable * Refactor: Adds debounce and lodash import optimization * Docs: Adds documentation * Refactor: Removes unused function and fixes typo * Docs: Updates docs * Fixed issue with UI not updating when no was used due to async func and no .apply in the non lazy path
219 lines
6.1 KiB
TypeScript
219 lines
6.1 KiB
TypeScript
import _ from 'lodash';
|
|
import ResponseParser from './response_parser';
|
|
import MysqlQuery from 'app/plugins/datasource/mysql/mysql_query';
|
|
import { BackendSrv } from 'app/core/services/backend_srv';
|
|
import { IQService } from 'angular';
|
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
|
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
|
//Types
|
|
import { MysqlQueryForInterpolation } from './types';
|
|
import { interpolateSearchFilter } from '../../../features/templating/variable';
|
|
|
|
export class MysqlDatasource {
|
|
id: any;
|
|
name: any;
|
|
responseParser: ResponseParser;
|
|
queryModel: MysqlQuery;
|
|
interval: string;
|
|
|
|
/** @ngInject */
|
|
constructor(
|
|
instanceSettings: any,
|
|
private backendSrv: BackendSrv,
|
|
private $q: IQService,
|
|
private templateSrv: TemplateSrv,
|
|
private timeSrv: TimeSrv
|
|
) {
|
|
this.name = instanceSettings.name;
|
|
this.id = instanceSettings.id;
|
|
this.responseParser = new ResponseParser(this.$q);
|
|
this.queryModel = new MysqlQuery({});
|
|
this.interval = (instanceSettings.jsonData || {}).timeInterval || '1m';
|
|
}
|
|
|
|
interpolateVariable = (value: string, variable: any) => {
|
|
if (typeof value === 'string') {
|
|
if (variable.multi || variable.includeAll) {
|
|
return this.queryModel.quoteLiteral(value);
|
|
} else {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
if (typeof value === 'number') {
|
|
return value;
|
|
}
|
|
|
|
const quotedValues = _.map(value, (v: any) => {
|
|
return this.queryModel.quoteLiteral(v);
|
|
});
|
|
return quotedValues.join(',');
|
|
};
|
|
|
|
interpolateVariablesInQueries(queries: MysqlQueryForInterpolation[]): MysqlQueryForInterpolation[] {
|
|
let expandedQueries = queries;
|
|
if (queries && queries.length > 0) {
|
|
expandedQueries = queries.map(query => {
|
|
const expandedQuery = {
|
|
...query,
|
|
datasource: this.name,
|
|
rawSql: this.templateSrv.replace(query.rawSql, {}, this.interpolateVariable),
|
|
};
|
|
return expandedQuery;
|
|
});
|
|
}
|
|
return expandedQueries;
|
|
}
|
|
|
|
query(options: any) {
|
|
const queries = _.filter(options.targets, target => {
|
|
return target.hide !== true;
|
|
}).map(target => {
|
|
const queryModel = new MysqlQuery(target, this.templateSrv, options.scopedVars);
|
|
|
|
return {
|
|
refId: target.refId,
|
|
intervalMs: options.intervalMs,
|
|
maxDataPoints: options.maxDataPoints,
|
|
datasourceId: this.id,
|
|
rawSql: queryModel.render(this.interpolateVariable as any),
|
|
format: target.format,
|
|
};
|
|
});
|
|
|
|
if (queries.length === 0) {
|
|
return this.$q.when({ data: [] });
|
|
}
|
|
|
|
return this.backendSrv
|
|
.datasourceRequest({
|
|
url: '/api/tsdb/query',
|
|
method: 'POST',
|
|
data: {
|
|
from: options.range.from.valueOf().toString(),
|
|
to: options.range.to.valueOf().toString(),
|
|
queries: queries,
|
|
},
|
|
})
|
|
.then(this.responseParser.processQueryResult);
|
|
}
|
|
|
|
annotationQuery(options: any) {
|
|
if (!options.annotation.rawQuery) {
|
|
return this.$q.reject({
|
|
message: 'Query missing in annotation definition',
|
|
});
|
|
}
|
|
|
|
const query = {
|
|
refId: options.annotation.name,
|
|
datasourceId: this.id,
|
|
rawSql: this.templateSrv.replace(options.annotation.rawQuery, options.scopedVars, this.interpolateVariable),
|
|
format: 'table',
|
|
};
|
|
|
|
return this.backendSrv
|
|
.datasourceRequest({
|
|
url: '/api/tsdb/query',
|
|
method: 'POST',
|
|
data: {
|
|
from: options.range.from.valueOf().toString(),
|
|
to: options.range.to.valueOf().toString(),
|
|
queries: [query],
|
|
},
|
|
})
|
|
.then((data: any) => this.responseParser.transformAnnotationResponse(options, data));
|
|
}
|
|
|
|
metricFindQuery(query: string, optionalOptions: any) {
|
|
let refId = 'tempvar';
|
|
if (optionalOptions && optionalOptions.variable && optionalOptions.variable.name) {
|
|
refId = optionalOptions.variable.name;
|
|
}
|
|
|
|
const rawSql = interpolateSearchFilter({
|
|
query: this.templateSrv.replace(query, {}, this.interpolateVariable),
|
|
options: optionalOptions,
|
|
wildcardChar: '%',
|
|
quoteLiteral: true,
|
|
});
|
|
|
|
const interpolatedQuery = {
|
|
refId: refId,
|
|
datasourceId: this.id,
|
|
rawSql,
|
|
format: 'table',
|
|
};
|
|
|
|
const range = this.timeSrv.timeRange();
|
|
const data = {
|
|
queries: [interpolatedQuery],
|
|
from: range.from.valueOf().toString(),
|
|
to: range.to.valueOf().toString(),
|
|
};
|
|
|
|
if (optionalOptions && optionalOptions.range && optionalOptions.range.from) {
|
|
data['from'] = optionalOptions.range.from.valueOf().toString();
|
|
}
|
|
if (optionalOptions && optionalOptions.range && optionalOptions.range.to) {
|
|
data['to'] = optionalOptions.range.to.valueOf().toString();
|
|
}
|
|
|
|
return this.backendSrv
|
|
.datasourceRequest({
|
|
url: '/api/tsdb/query',
|
|
method: 'POST',
|
|
data: data,
|
|
})
|
|
.then((data: any) => this.responseParser.parseMetricFindQueryResult(refId, data));
|
|
}
|
|
|
|
testDatasource() {
|
|
return this.backendSrv
|
|
.datasourceRequest({
|
|
url: '/api/tsdb/query',
|
|
method: 'POST',
|
|
data: {
|
|
from: '5m',
|
|
to: 'now',
|
|
queries: [
|
|
{
|
|
refId: 'A',
|
|
intervalMs: 1,
|
|
maxDataPoints: 1,
|
|
datasourceId: this.id,
|
|
rawSql: 'SELECT 1',
|
|
format: 'table',
|
|
},
|
|
],
|
|
},
|
|
})
|
|
.then((res: any) => {
|
|
return { status: 'success', message: 'Database Connection OK' };
|
|
})
|
|
.catch((err: any) => {
|
|
console.log(err);
|
|
if (err.data && err.data.message) {
|
|
return { status: 'error', message: err.data.message };
|
|
} else {
|
|
return { status: 'error', message: err.status };
|
|
}
|
|
});
|
|
}
|
|
|
|
targetContainsTemplate(target: any) {
|
|
let rawSql = '';
|
|
|
|
if (target.rawQuery) {
|
|
rawSql = target.rawSql;
|
|
} else {
|
|
const query = new MysqlQuery(target);
|
|
rawSql = query.buildQuery();
|
|
}
|
|
|
|
rawSql = rawSql.replace('$__', '');
|
|
|
|
return this.templateSrv.variableExists(rawSql);
|
|
}
|
|
}
|