mirror of
https://github.com/grafana/grafana.git
synced 2025-09-22 20:19:05 +08:00
SQL data sources: Convert to return data frames (#32257)
Convert SQL data sources to return data frames. Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> Co-authored-by: Will Browne <will.browne@grafana.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
This commit is contained in:
@ -1,36 +1,37 @@
|
||||
import { map as _map, filter } from 'lodash';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map as _map } from 'lodash';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { DataQueryResponse, ScopedVars } from '@grafana/data';
|
||||
import { BackendDataSourceResponse, DataSourceWithBackend, FetchResponse, getBackendSrv } from '@grafana/runtime';
|
||||
import { AnnotationEvent, DataSourceInstanceSettings, MetricFindValue, ScopedVars } from '@grafana/data';
|
||||
|
||||
import ResponseParser from './response_parser';
|
||||
import PostgresQuery from 'app/plugins/datasource/postgres/postgres_query';
|
||||
import PostgresQueryModel from 'app/plugins/datasource/postgres/postgres_query_model';
|
||||
import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
//Types
|
||||
import { PostgresMetricFindValue, PostgresQueryForInterpolation } from './types';
|
||||
import { PostgresOptions, PostgresQuery, PostgresQueryForInterpolation } from './types';
|
||||
import { getSearchFilterScopedVar } from '../../../features/variables/utils';
|
||||
|
||||
export class PostgresDatasource {
|
||||
export class PostgresDatasource extends DataSourceWithBackend<PostgresQuery, PostgresOptions> {
|
||||
id: any;
|
||||
name: any;
|
||||
jsonData: any;
|
||||
responseParser: ResponseParser;
|
||||
queryModel: PostgresQuery;
|
||||
queryModel: PostgresQueryModel;
|
||||
interval: string;
|
||||
|
||||
constructor(
|
||||
instanceSettings: { name: any; id?: any; jsonData?: any },
|
||||
instanceSettings: DataSourceInstanceSettings<PostgresOptions>,
|
||||
private readonly templateSrv: TemplateSrv = getTemplateSrv(),
|
||||
private readonly timeSrv: TimeSrv = getTimeSrv()
|
||||
) {
|
||||
super(instanceSettings);
|
||||
this.name = instanceSettings.name;
|
||||
this.id = instanceSettings.id;
|
||||
this.jsonData = instanceSettings.jsonData;
|
||||
this.responseParser = new ResponseParser();
|
||||
this.queryModel = new PostgresQuery({});
|
||||
this.interval = (instanceSettings.jsonData || {}).timeInterval || '1m';
|
||||
this.queryModel = new PostgresQueryModel({});
|
||||
const settingsData = instanceSettings.jsonData || ({} as PostgresOptions);
|
||||
this.interval = settingsData.timeInterval || '1m';
|
||||
}
|
||||
|
||||
interpolateVariable = (value: string | string[], variable: { multi: any; includeAll: any }) => {
|
||||
@ -71,40 +72,21 @@ export class PostgresDatasource {
|
||||
return expandedQueries;
|
||||
}
|
||||
|
||||
query(options: any): Observable<DataQueryResponse> {
|
||||
const queries = filter(options.targets, (target) => {
|
||||
return target.hide !== true;
|
||||
}).map((target) => {
|
||||
const queryModel = new PostgresQuery(target, this.templateSrv, options.scopedVars);
|
||||
|
||||
return {
|
||||
refId: target.refId,
|
||||
intervalMs: options.intervalMs,
|
||||
maxDataPoints: options.maxDataPoints,
|
||||
datasourceId: this.id,
|
||||
rawSql: queryModel.render(this.interpolateVariable),
|
||||
format: target.format,
|
||||
};
|
||||
});
|
||||
|
||||
if (queries.length === 0) {
|
||||
return of({ data: [] });
|
||||
}
|
||||
|
||||
return getBackendSrv()
|
||||
.fetch({
|
||||
url: '/api/tsdb/query',
|
||||
method: 'POST',
|
||||
data: {
|
||||
from: options.range.from.valueOf().toString(),
|
||||
to: options.range.to.valueOf().toString(),
|
||||
queries: queries,
|
||||
},
|
||||
})
|
||||
.pipe(map(this.responseParser.processQueryResult));
|
||||
filterQuery(query: PostgresQuery): boolean {
|
||||
return !query.hide;
|
||||
}
|
||||
|
||||
annotationQuery(options: any) {
|
||||
applyTemplateVariables(target: PostgresQuery, scopedVars: ScopedVars): Record<string, any> {
|
||||
const queryModel = new PostgresQueryModel(target, this.templateSrv, scopedVars);
|
||||
return {
|
||||
refId: target.refId,
|
||||
datasourceId: this.id,
|
||||
rawSql: queryModel.render(this.interpolateVariable as any),
|
||||
format: target.format,
|
||||
};
|
||||
}
|
||||
|
||||
async annotationQuery(options: any): Promise<AnnotationEvent[]> {
|
||||
if (!options.annotation.rawQuery) {
|
||||
return Promise.reject({
|
||||
message: 'Query missing in annotation definition',
|
||||
@ -119,23 +101,26 @@ export class PostgresDatasource {
|
||||
};
|
||||
|
||||
return getBackendSrv()
|
||||
.fetch({
|
||||
url: '/api/tsdb/query',
|
||||
.fetch<BackendDataSourceResponse>({
|
||||
url: '/api/ds/query',
|
||||
method: 'POST',
|
||||
data: {
|
||||
from: options.range.from.valueOf().toString(),
|
||||
to: options.range.to.valueOf().toString(),
|
||||
queries: [query],
|
||||
},
|
||||
requestId: options.annotation.name,
|
||||
})
|
||||
.pipe(map((data: any) => this.responseParser.transformAnnotationResponse(options, data)))
|
||||
.pipe(
|
||||
map(
|
||||
async (res: FetchResponse<BackendDataSourceResponse>) =>
|
||||
await this.responseParser.transformAnnotationResponse(options, res.data)
|
||||
)
|
||||
)
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
metricFindQuery(
|
||||
query: string,
|
||||
optionalOptions: { variable?: any; searchFilter?: string }
|
||||
): Promise<PostgresMetricFindValue[]> {
|
||||
metricFindQuery(query: string, optionalOptions: any): Promise<MetricFindValue[]> {
|
||||
let refId = 'tempvar';
|
||||
if (optionalOptions && optionalOptions.variable && optionalOptions.variable.name) {
|
||||
refId = optionalOptions.variable.name;
|
||||
@ -155,33 +140,37 @@ export class PostgresDatasource {
|
||||
};
|
||||
|
||||
const range = this.timeSrv.timeRange();
|
||||
const data = {
|
||||
queries: [interpolatedQuery],
|
||||
from: range.from.valueOf().toString(),
|
||||
to: range.to.valueOf().toString(),
|
||||
};
|
||||
|
||||
return getBackendSrv()
|
||||
.fetch({
|
||||
url: '/api/tsdb/query',
|
||||
.fetch<BackendDataSourceResponse>({
|
||||
url: '/api/ds/query',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
data: {
|
||||
from: range.from.valueOf().toString(),
|
||||
to: range.to.valueOf().toString(),
|
||||
queries: [interpolatedQuery],
|
||||
},
|
||||
requestId: refId,
|
||||
})
|
||||
.pipe(map((data: any) => this.responseParser.parseMetricFindQueryResult(refId, data)))
|
||||
.pipe(
|
||||
map((rsp) => {
|
||||
return this.responseParser.transformMetricFindResponse(rsp);
|
||||
})
|
||||
)
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
getVersion() {
|
||||
getVersion(): Promise<any> {
|
||||
return this.metricFindQuery("SELECT current_setting('server_version_num')::int/100", {});
|
||||
}
|
||||
|
||||
getTimescaleDBVersion() {
|
||||
getTimescaleDBVersion(): Promise<any> {
|
||||
return this.metricFindQuery("SELECT extversion FROM pg_extension WHERE extname = 'timescaledb'", {});
|
||||
}
|
||||
|
||||
testDatasource() {
|
||||
testDatasource(): Promise<any> {
|
||||
return this.metricFindQuery('SELECT 1', {})
|
||||
.then((res: any) => {
|
||||
.then(() => {
|
||||
return { status: 'success', message: 'Database Connection OK' };
|
||||
})
|
||||
.catch((err: any) => {
|
||||
@ -200,7 +189,7 @@ export class PostgresDatasource {
|
||||
if (target.rawQuery) {
|
||||
rawSql = target.rawSql;
|
||||
} else {
|
||||
const query = new PostgresQuery(target);
|
||||
const query = new PostgresQueryModel(target);
|
||||
rawSql = query.buildQuery();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user