sql: do not use the getTimeSrv call (#74800)

* sql: eliminate the getTimeSrv call

* adjusted tests
This commit is contained in:
Gábor Farkas 2023-09-18 10:39:05 +02:00 committed by GitHub
parent 942c4779b9
commit 1f6f866a36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 26 deletions

View File

@ -2,6 +2,7 @@ import { lastValueFrom, Observable, throwError } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { import {
getDefaultTimeRange,
DataFrame, DataFrame,
DataFrameView, DataFrameView,
DataQuery, DataQuery,
@ -15,6 +16,7 @@ import {
getSearchFilterScopedVar, getSearchFilterScopedVar,
LegacyMetricFindQueryOptions, LegacyMetricFindQueryOptions,
VariableWithMultiSupport, VariableWithMultiSupport,
TimeRange,
} from '@grafana/data'; } from '@grafana/data';
import { EditorMode } from '@grafana/experimental'; import { EditorMode } from '@grafana/experimental';
import { import {
@ -27,7 +29,6 @@ import {
TemplateSrv, TemplateSrv,
reportInteraction, reportInteraction,
} from '@grafana/runtime'; } from '@grafana/runtime';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { ResponseParser } from '../ResponseParser'; import { ResponseParser } from '../ResponseParser';
import { SqlQueryEditor } from '../components/QueryEditor'; import { SqlQueryEditor } from '../components/QueryEditor';
@ -182,6 +183,12 @@ export abstract class SqlDatasource extends DataSourceWithBackend<SQLQuery, SQLO
} }
async metricFindQuery(query: string, options?: LegacyMetricFindQueryOptions): Promise<MetricFindValue[]> { async metricFindQuery(query: string, options?: LegacyMetricFindQueryOptions): Promise<MetricFindValue[]> {
const range = options?.range;
if (range == null) {
// i cannot create a scenario where this happens, we handle it just to be sure.
return [];
}
let refId = 'tempvar'; let refId = 'tempvar';
if (options && options.variable && options.variable.name) { if (options && options.variable && options.variable.name) {
refId = options.variable.name; refId = options.variable.name;
@ -201,17 +208,18 @@ export abstract class SqlDatasource extends DataSourceWithBackend<SQLQuery, SQLO
format: QueryFormat.Table, format: QueryFormat.Table,
}; };
const response = await this.runMetaQuery(interpolatedQuery, options); const response = await this.runMetaQuery(interpolatedQuery, range);
return this.getResponseParser().transformMetricFindResponse(response); return this.getResponseParser().transformMetricFindResponse(response);
} }
// NOTE: this always runs with the `@grafana/data/getDefaultTimeRange` time range
async runSql<T>(query: string, options?: RunSQLOptions) { async runSql<T>(query: string, options?: RunSQLOptions) {
const frame = await this.runMetaQuery({ rawSql: query, format: QueryFormat.Table, refId: options?.refId }, options); const range = getDefaultTimeRange();
const frame = await this.runMetaQuery({ rawSql: query, format: QueryFormat.Table, refId: options?.refId }, range);
return new DataFrameView<T>(frame); return new DataFrameView<T>(frame);
} }
private runMetaQuery(request: Partial<SQLQuery>, options?: LegacyMetricFindQueryOptions): Promise<DataFrame> { private runMetaQuery(request: Partial<SQLQuery>, range: TimeRange): Promise<DataFrame> {
const range = getTimeSrv().timeRange();
const refId = request.refId || 'meta'; const refId = request.refId || 'meta';
const queries: DataQuery[] = [{ ...request, datasource: request.datasource || this.getRef(), refId }]; const queries: DataQuery[] = [{ ...request, datasource: request.datasource || this.getRef(), refId }];
@ -222,8 +230,8 @@ export abstract class SqlDatasource extends DataSourceWithBackend<SQLQuery, SQLO
method: 'POST', method: 'POST',
headers: this.getRequestHeaders(), headers: this.getRequestHeaders(),
data: { data: {
from: options?.range?.from.valueOf().toString() || range.from.valueOf().toString(), from: range.from.valueOf().toString(),
to: options?.range?.to.valueOf().toString() || range.to.valueOf().toString(), to: range.to.valueOf().toString(),
queries, queries,
}, },
requestId: refId, requestId: refId,

View File

@ -3,6 +3,7 @@ import { createFetchResponse } from 'test/helpers/createFetchResponse';
import { import {
dataFrameToJSON, dataFrameToJSON,
getDefaultTimeRange,
DataSourceInstanceSettings, DataSourceInstanceSettings,
dateTime, dateTime,
FieldType, FieldType,
@ -33,6 +34,7 @@ const instanceSettings = {
} as DataSourceInstanceSettings<MssqlOptions>; } as DataSourceInstanceSettings<MssqlOptions>;
describe('MSSQLDatasource', () => { describe('MSSQLDatasource', () => {
const defaultRange = getDefaultTimeRange(); // it does not matter what value this has
const fetchMock = jest.spyOn(backendSrv, 'fetch'); const fetchMock = jest.spyOn(backendSrv, 'fetch');
const ctx = { const ctx = {
@ -69,7 +71,7 @@ describe('MSSQLDatasource', () => {
beforeEach(() => { beforeEach(() => {
fetchMock.mockImplementation(() => of(createFetchResponse(response))); fetchMock.mockImplementation(() => of(createFetchResponse(response)));
return ctx.ds.metricFindQuery(query).then((data: MetricFindValue[]) => { return ctx.ds.metricFindQuery(query, { range: defaultRange }).then((data: MetricFindValue[]) => {
results = data; results = data;
}); });
}); });
@ -97,7 +99,7 @@ describe('MSSQLDatasource', () => {
it('should return an empty array when metricFindQuery is called', async () => { it('should return an empty array when metricFindQuery is called', async () => {
const query = 'select * from atable'; const query = 'select * from atable';
const results = await ctx.ds.metricFindQuery(query); const results = await ctx.ds.metricFindQuery(query, { range: defaultRange });
expect(results.length).toBe(0); expect(results.length).toBe(0);
}); });
@ -231,7 +233,7 @@ describe('MSSQLDatasource', () => {
beforeEach(() => { beforeEach(() => {
fetchMock.mockImplementation(() => of(createFetchResponse(response))); fetchMock.mockImplementation(() => of(createFetchResponse(response)));
return ctx.ds.metricFindQuery(query).then((data) => { return ctx.ds.metricFindQuery(query, { range: defaultRange }).then((data) => {
results = data; results = data;
}); });
}); });
@ -272,7 +274,7 @@ describe('MSSQLDatasource', () => {
beforeEach(() => { beforeEach(() => {
fetchMock.mockImplementation(() => of(createFetchResponse(response))); fetchMock.mockImplementation(() => of(createFetchResponse(response)));
return ctx.ds.metricFindQuery(query).then((data) => { return ctx.ds.metricFindQuery(query, { range: defaultRange }).then((data) => {
results = data; results = data;
}); });
}); });
@ -311,7 +313,7 @@ describe('MSSQLDatasource', () => {
beforeEach(() => { beforeEach(() => {
fetchMock.mockImplementation(() => of(createFetchResponse(response))); fetchMock.mockImplementation(() => of(createFetchResponse(response)));
return ctx.ds.metricFindQuery(query).then((data) => { return ctx.ds.metricFindQuery(query, { range: defaultRange }).then((data) => {
results = data; results = data;
}); });
}); });

View File

@ -2,6 +2,7 @@ import { of } from 'rxjs';
import { import {
dataFrameToJSON, dataFrameToJSON,
getDefaultTimeRange,
DataQueryRequest, DataQueryRequest,
DataSourceInstanceSettings, DataSourceInstanceSettings,
dateTime, dateTime,
@ -18,6 +19,7 @@ import { MySqlDatasource } from '../MySqlDatasource';
import { MySQLOptions } from '../types'; import { MySQLOptions } from '../types';
describe('MySQLDatasource', () => { describe('MySQLDatasource', () => {
const defaultRange = getDefaultTimeRange(); // it does not matter what value this has
const setupTestContext = (response: unknown) => { const setupTestContext = (response: unknown) => {
jest.clearAllMocks(); jest.clearAllMocks();
setBackendSrv(backendSrv); setBackendSrv(backendSrv);
@ -82,7 +84,7 @@ describe('MySQLDatasource', () => {
it('should return an empty array when metricFindQuery is called', async () => { it('should return an empty array when metricFindQuery is called', async () => {
const query = 'select * from atable'; const query = 'select * from atable';
const results = await ds.metricFindQuery(query); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results.length).toBe(0); expect(results.length).toBe(0);
}); });
@ -216,7 +218,7 @@ describe('MySQLDatasource', () => {
it('should return list of all string field values', async () => { it('should return list of all string field values', async () => {
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results.length).toBe(6); expect(results.length).toBe(6);
expect(results[0].text).toBe('aTitle'); expect(results[0].text).toBe('aTitle');
@ -249,7 +251,7 @@ describe('MySQLDatasource', () => {
it('should return list of all column values', async () => { it('should return list of all column values', async () => {
const { ds, fetchMock } = setupTestContext(response); const { ds, fetchMock } = setupTestContext(response);
const results = await ds.metricFindQuery(query, { searchFilter: 'aTit' }); const results = await ds.metricFindQuery(query, { range: defaultRange, searchFilter: 'aTit' });
expect(fetchMock).toBeCalledTimes(1); expect(fetchMock).toBeCalledTimes(1);
expect(fetchMock.mock.calls[0][0].data.queries[0].rawSql).toBe( expect(fetchMock.mock.calls[0][0].data.queries[0].rawSql).toBe(
@ -284,7 +286,7 @@ describe('MySQLDatasource', () => {
it('should return list of all column values', async () => { it('should return list of all column values', async () => {
const { ds, fetchMock } = setupTestContext(response); const { ds, fetchMock } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(fetchMock).toBeCalledTimes(1); expect(fetchMock).toBeCalledTimes(1);
expect(fetchMock.mock.calls[0][0].data.queries[0].rawSql).toBe("select title from atable where title LIKE '%'"); expect(fetchMock.mock.calls[0][0].data.queries[0].rawSql).toBe("select title from atable where title LIKE '%'");
@ -317,7 +319,7 @@ describe('MySQLDatasource', () => {
it('should return list of as text, value', async () => { it('should return list of as text, value', async () => {
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results.length).toBe(3); expect(results.length).toBe(3);
expect(results[0].text).toBe('aTitle'); expect(results[0].text).toBe('aTitle');
@ -352,7 +354,7 @@ describe('MySQLDatasource', () => {
it('should return list of all field values as text', async () => { it('should return list of all field values as text', async () => {
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results).toEqual([ expect(results).toEqual([
{ text: 1 }, { text: 1 },
@ -390,7 +392,7 @@ describe('MySQLDatasource', () => {
it('should return list of unique keys', async () => { it('should return list of unique keys', async () => {
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results.length).toBe(1); expect(results.length).toBe(1);
expect(results[0].text).toBe('aTitle'); expect(results[0].text).toBe('aTitle');

View File

@ -2,6 +2,7 @@ import { Observable, of } from 'rxjs';
import { TestScheduler } from 'rxjs/testing'; import { TestScheduler } from 'rxjs/testing';
import { import {
getDefaultTimeRange,
dataFrameToJSON, dataFrameToJSON,
DataQueryRequest, DataQueryRequest,
DataQueryResponse, DataQueryResponse,
@ -37,6 +38,7 @@ jest.mock('@grafana/runtime/src/services', () => ({
})); }));
describe('PostgreSQLDatasource', () => { describe('PostgreSQLDatasource', () => {
const defaultRange = getDefaultTimeRange(); // it does not matter what value this has
const fetchMock = jest.spyOn(backendSrv, 'fetch'); const fetchMock = jest.spyOn(backendSrv, 'fetch');
const setupTestContext = (data: unknown, mock?: Observable<FetchResponse<unknown>>) => { const setupTestContext = (data: unknown, mock?: Observable<FetchResponse<unknown>>) => {
jest.clearAllMocks(); jest.clearAllMocks();
@ -311,7 +313,7 @@ describe('PostgreSQLDatasource', () => {
it('should return an empty array when metricFindQuery is called', async () => { it('should return an empty array when metricFindQuery is called', async () => {
const query = 'select * from atable'; const query = 'select * from atable';
const results = await ds.metricFindQuery(query); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results.length).toBe(0); expect(results.length).toBe(0);
}); });
@ -474,7 +476,7 @@ describe('PostgreSQLDatasource', () => {
}; };
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results.length).toBe(6); expect(results.length).toBe(6);
expect(results[0].text).toBe('aTitle'); expect(results[0].text).toBe('aTitle');
@ -507,7 +509,7 @@ describe('PostgreSQLDatasource', () => {
}; };
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, { searchFilter: 'aTit' }); const results = await ds.metricFindQuery(query, { range: defaultRange, searchFilter: 'aTit' });
expect(fetchMock).toBeCalledTimes(1); expect(fetchMock).toBeCalledTimes(1);
expect(fetchMock.mock.calls[0][0].data.queries[0].rawSql).toBe( expect(fetchMock.mock.calls[0][0].data.queries[0].rawSql).toBe(
@ -549,7 +551,7 @@ describe('PostgreSQLDatasource', () => {
}; };
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(fetchMock).toBeCalledTimes(1); expect(fetchMock).toBeCalledTimes(1);
expect(fetchMock.mock.calls[0][0].data.queries[0].rawSql).toBe("select title from atable where title LIKE '%'"); expect(fetchMock.mock.calls[0][0].data.queries[0].rawSql).toBe("select title from atable where title LIKE '%'");
@ -588,7 +590,7 @@ describe('PostgreSQLDatasource', () => {
}, },
}; };
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results).toEqual([ expect(results).toEqual([
{ text: 'aTitle', value: 'value1' }, { text: 'aTitle', value: 'value1' },
@ -622,7 +624,7 @@ describe('PostgreSQLDatasource', () => {
}, },
}; };
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results).toEqual([ expect(results).toEqual([
{ text: 1 }, { text: 1 },
@ -659,7 +661,7 @@ describe('PostgreSQLDatasource', () => {
}, },
}; };
const { ds } = setupTestContext(response); const { ds } = setupTestContext(response);
const results = await ds.metricFindQuery(query, {}); const results = await ds.metricFindQuery(query, { range: defaultRange });
expect(results).toEqual([{ text: 'aTitle', value: 'same' }]); expect(results).toEqual([{ text: 'aTitle', value: 'same' }]);
}); });