mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
SQL Datasources: Fix variable throwing error if query returns no data (#65937)
* Fix SQL query variable throwing error if query returns no data * Tests to verify that metricFindQuery returns properly and doesn't throw error * Fix all codepaths that might throw errors because of undefined backendSrv response
This commit is contained in:
parent
0aa301e251
commit
02a8bc76d2
@ -164,7 +164,7 @@ export abstract class SqlDatasource extends DataSourceWithBackend<SQLQuery, SQLO
|
||||
.pipe(
|
||||
map((res: FetchResponse<BackendDataSourceResponse>) => {
|
||||
const rsp = toDataQueryResponse(res, queries);
|
||||
return rsp.data[0];
|
||||
return rsp.data[0] ?? { fields: [] };
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
dataFrameToJSON,
|
||||
DataSourceInstanceSettings,
|
||||
dateTime,
|
||||
FieldType,
|
||||
MetricFindValue,
|
||||
MutableDataFrame,
|
||||
TimeRange,
|
||||
@ -80,6 +81,133 @@ describe('MSSQLDatasource', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('When runSql returns an empty dataframe', () => {
|
||||
const response = {
|
||||
results: {
|
||||
tempvar: {
|
||||
refId: 'tempvar',
|
||||
frames: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
fetchMock.mockImplementation(() => of(createFetchResponse(response)));
|
||||
});
|
||||
|
||||
it('should return an empty array when metricFindQuery is called', async () => {
|
||||
const query = 'select * from atable';
|
||||
const results = await ctx.ds.metricFindQuery(query);
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should return an empty array when fetchDatasets is called', async () => {
|
||||
const results = await ctx.ds.fetchDatasets();
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should return an empty array when fetchTables is called', async () => {
|
||||
const results = await ctx.ds.fetchTables();
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should return an empty array when fetchFields is called', async () => {
|
||||
const query: SQLQuery = {
|
||||
refId: 'refId',
|
||||
table: 'schema.table',
|
||||
dataset: 'dataset',
|
||||
};
|
||||
const results = await ctx.ds.fetchFields(query);
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('When runSql returns a populated dataframe', () => {
|
||||
it('should return a list of datasets when fetchDatasets is called', async () => {
|
||||
const fetchDatasetsResponse = {
|
||||
results: {
|
||||
datasets: {
|
||||
refId: 'datasets',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [{ name: 'name', type: FieldType.string, values: ['test1', 'test2', 'test3'] }],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
fetchMock.mockImplementation(() => of(createFetchResponse(fetchDatasetsResponse)));
|
||||
|
||||
const results = await ctx.ds.fetchDatasets();
|
||||
expect(results.length).toBe(3);
|
||||
expect(results).toEqual(['test1', 'test2', 'test3']);
|
||||
});
|
||||
|
||||
it('should return a list of tables when fetchTables is called', async () => {
|
||||
const fetchTableResponse = {
|
||||
results: {
|
||||
tables: {
|
||||
refId: 'tables',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [{ name: 'schemaAndName', type: FieldType.string, values: ['test1', 'test2', 'test3'] }],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
fetchMock.mockImplementation(() => of(createFetchResponse(fetchTableResponse)));
|
||||
|
||||
const results = await ctx.ds.fetchTables();
|
||||
expect(results.length).toBe(3);
|
||||
expect(results).toEqual(['test1', 'test2', 'test3']);
|
||||
});
|
||||
|
||||
it('should return a list of fields when fetchFields is called', async () => {
|
||||
const fetchFieldsResponse = {
|
||||
results: {
|
||||
columns: {
|
||||
refId: 'columns',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [
|
||||
{ name: 'column', type: FieldType.string, values: ['test1', 'test2', 'test3'] },
|
||||
{ name: 'type', type: FieldType.string, values: ['int', 'char', 'bool'] },
|
||||
],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
fetchMock.mockImplementation(() => of(createFetchResponse(fetchFieldsResponse)));
|
||||
|
||||
const sqlQuery: SQLQuery = {
|
||||
refId: 'fields',
|
||||
table: 'table',
|
||||
dataset: 'dataset',
|
||||
};
|
||||
const results = await ctx.ds.fetchFields(sqlQuery);
|
||||
expect(results.length).toBe(3);
|
||||
expect(results[0].label).toBe('test1');
|
||||
expect(results[0].value).toBe('test1');
|
||||
expect(results[0].type).toBe('int');
|
||||
expect(results[1].label).toBe('test2');
|
||||
expect(results[1].value).toBe('test2');
|
||||
expect(results[1].type).toBe('char');
|
||||
expect(results[2].label).toBe('test3');
|
||||
expect(results[2].value).toBe('test3');
|
||||
expect(results[2].type).toBe('bool');
|
||||
});
|
||||
});
|
||||
|
||||
describe('When performing metricFindQuery with key, value columns', () => {
|
||||
let results: MetricFindValue[];
|
||||
const query = 'select * from atable';
|
||||
|
@ -23,13 +23,13 @@ export class MssqlDatasource extends SqlDatasource {
|
||||
|
||||
async fetchDatasets(): Promise<string[]> {
|
||||
const datasets = await this.runSql<{ name: string[] }>(showDatabases(), { refId: 'datasets' });
|
||||
return datasets.fields.name.values.toArray().flat();
|
||||
return datasets.fields.name?.values.toArray().flat() ?? [];
|
||||
}
|
||||
|
||||
async fetchTables(dataset?: string): Promise<string[]> {
|
||||
// We get back the table name with the schema as well. like dbo.table
|
||||
const tables = await this.runSql<{ schemaAndName: string[] }>(getSchemaAndName(dataset), { refId: 'tables' });
|
||||
return tables.fields.schemaAndName.values.toArray().flat();
|
||||
return tables.fields.schemaAndName?.values.toArray().flat() ?? [];
|
||||
}
|
||||
|
||||
async fetchFields(query: SQLQuery): Promise<SQLSelectableValue[]> {
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
DataQueryRequest,
|
||||
DataSourceInstanceSettings,
|
||||
dateTime,
|
||||
FieldType,
|
||||
MutableDataFrame,
|
||||
} from '@grafana/data';
|
||||
import { FetchResponse, setBackendSrv } from '@grafana/runtime';
|
||||
@ -17,7 +18,7 @@ import { MySqlDatasource } from '../MySqlDatasource';
|
||||
import { MySQLOptions } from '../types';
|
||||
|
||||
describe('MySQLDatasource', () => {
|
||||
const setupTextContext = (response: unknown) => {
|
||||
const setupTestContext = (response: unknown) => {
|
||||
jest.clearAllMocks();
|
||||
setBackendSrv(backendSrv);
|
||||
const fetchMock = jest.spyOn(backendSrv, 'fetch');
|
||||
@ -55,7 +56,7 @@ describe('MySQLDatasource', () => {
|
||||
],
|
||||
} as unknown as DataQueryRequest<SQLQuery>;
|
||||
|
||||
const { ds, fetchMock } = setupTextContext({});
|
||||
const { ds, fetchMock } = setupTestContext({});
|
||||
|
||||
await expect(ds.query(options)).toEmitValuesWith((received) => {
|
||||
expect(received[0]).toEqual({ data: [] });
|
||||
@ -64,6 +65,132 @@ describe('MySQLDatasource', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('When runSql returns an empty dataframe', () => {
|
||||
let ds: MySqlDatasource;
|
||||
const response = {
|
||||
results: {
|
||||
tempvar: {
|
||||
refId: 'tempvar',
|
||||
frames: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
ds = setupTestContext(response).ds;
|
||||
});
|
||||
|
||||
it('should return an empty array when metricFindQuery is called', async () => {
|
||||
const query = 'select * from atable';
|
||||
const results = await ds.metricFindQuery(query);
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should return an empty array when fetchDatasets is called', async () => {
|
||||
const results = await ds.fetchDatasets();
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should return an empty array when fetchTables is called', async () => {
|
||||
const results = await ds.fetchTables();
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should return an empty array when fetchFields is called', async () => {
|
||||
const query: SQLQuery = {
|
||||
refId: 'refId',
|
||||
table: 'schema.table',
|
||||
dataset: 'dataset',
|
||||
};
|
||||
const results = await ds.fetchFields(query);
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('When runSql returns a populated dataframe', () => {
|
||||
it('should return a list of datasets when fetchDatasets is called', async () => {
|
||||
const fetchDatasetsResponse = {
|
||||
results: {
|
||||
datasets: {
|
||||
refId: 'datasets',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [{ name: 'name', type: FieldType.string, values: ['test1', 'test2', 'test3'] }],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const { ds } = setupTestContext(fetchDatasetsResponse);
|
||||
|
||||
const results = await ds.fetchDatasets();
|
||||
expect(results.length).toBe(3);
|
||||
expect(results).toEqual(['test1', 'test2', 'test3']);
|
||||
});
|
||||
|
||||
it('should return a list of tables when fetchTables is called', async () => {
|
||||
const fetchTableResponse = {
|
||||
results: {
|
||||
tables: {
|
||||
refId: 'tables',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [{ name: 'table_name', type: FieldType.string, values: ['test1', 'test2', 'test3'] }],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const { ds } = setupTestContext(fetchTableResponse);
|
||||
|
||||
const results = await ds.fetchTables();
|
||||
expect(results.length).toBe(3);
|
||||
expect(results).toEqual(['test1', 'test2', 'test3']);
|
||||
});
|
||||
|
||||
it('should return a list of fields when fetchFields is called', async () => {
|
||||
const fetchFieldsResponse = {
|
||||
results: {
|
||||
fields: {
|
||||
refId: 'fields',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [
|
||||
{ name: 'column_name', type: FieldType.string, values: ['test1', 'test2', 'test3'] },
|
||||
{ name: 'data_type', type: FieldType.string, values: ['int', 'char', 'bool'] },
|
||||
],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
const { ds } = setupTestContext(fetchFieldsResponse);
|
||||
|
||||
const sqlQuery: SQLQuery = {
|
||||
refId: 'fields',
|
||||
table: 'table',
|
||||
dataset: 'dataset',
|
||||
};
|
||||
const results = await ds.fetchFields(sqlQuery);
|
||||
expect(results.length).toBe(3);
|
||||
expect(results[0].label).toBe('test1');
|
||||
expect(results[0].value).toBe('test1');
|
||||
expect(results[0].type).toBe('int');
|
||||
expect(results[1].label).toBe('test2');
|
||||
expect(results[1].value).toBe('test2');
|
||||
expect(results[1].type).toBe('char');
|
||||
expect(results[2].label).toBe('test3');
|
||||
expect(results[2].value).toBe('test3');
|
||||
expect(results[2].type).toBe('bool');
|
||||
});
|
||||
});
|
||||
|
||||
describe('When performing metricFindQuery that returns multiple string fields', () => {
|
||||
const query = 'select * from atable';
|
||||
const response = {
|
||||
@ -88,7 +215,7 @@ describe('MySQLDatasource', () => {
|
||||
};
|
||||
|
||||
it('should return list of all string field values', async () => {
|
||||
const { ds } = setupTextContext(response);
|
||||
const { ds } = setupTestContext(response);
|
||||
const results = await ds.metricFindQuery(query, {});
|
||||
|
||||
expect(results.length).toBe(6);
|
||||
@ -121,7 +248,7 @@ describe('MySQLDatasource', () => {
|
||||
};
|
||||
|
||||
it('should return list of all column values', async () => {
|
||||
const { ds, fetchMock } = setupTextContext(response);
|
||||
const { ds, fetchMock } = setupTestContext(response);
|
||||
const results = await ds.metricFindQuery(query, { searchFilter: 'aTit' });
|
||||
|
||||
expect(fetchMock).toBeCalledTimes(1);
|
||||
@ -156,7 +283,7 @@ describe('MySQLDatasource', () => {
|
||||
};
|
||||
|
||||
it('should return list of all column values', async () => {
|
||||
const { ds, fetchMock } = setupTextContext(response);
|
||||
const { ds, fetchMock } = setupTestContext(response);
|
||||
const results = await ds.metricFindQuery(query, {});
|
||||
|
||||
expect(fetchMock).toBeCalledTimes(1);
|
||||
@ -189,7 +316,7 @@ describe('MySQLDatasource', () => {
|
||||
};
|
||||
|
||||
it('should return list of as text, value', async () => {
|
||||
const { ds } = setupTextContext(response);
|
||||
const { ds } = setupTestContext(response);
|
||||
const results = await ds.metricFindQuery(query, {});
|
||||
|
||||
expect(results.length).toBe(3);
|
||||
@ -224,7 +351,7 @@ describe('MySQLDatasource', () => {
|
||||
};
|
||||
|
||||
it('should return list of all field values as text', async () => {
|
||||
const { ds } = setupTextContext(response);
|
||||
const { ds } = setupTestContext(response);
|
||||
const results = await ds.metricFindQuery(query, {});
|
||||
|
||||
expect(results).toEqual([
|
||||
@ -262,7 +389,7 @@ describe('MySQLDatasource', () => {
|
||||
};
|
||||
|
||||
it('should return list of unique keys', async () => {
|
||||
const { ds } = setupTextContext(response);
|
||||
const { ds } = setupTestContext(response);
|
||||
const results = await ds.metricFindQuery(query, {});
|
||||
|
||||
expect(results.length).toBe(1);
|
||||
@ -274,28 +401,28 @@ describe('MySQLDatasource', () => {
|
||||
describe('When interpolating variables', () => {
|
||||
describe('and value is a string', () => {
|
||||
it('should return an unquoted value', () => {
|
||||
const { ds, variable } = setupTextContext({});
|
||||
const { ds, variable } = setupTestContext({});
|
||||
expect(ds.interpolateVariable('abc', variable)).toEqual('abc');
|
||||
});
|
||||
});
|
||||
|
||||
describe('and value is a number', () => {
|
||||
it('should return an unquoted value', () => {
|
||||
const { ds, variable } = setupTextContext({});
|
||||
const { ds, variable } = setupTestContext({});
|
||||
expect(ds.interpolateVariable(1000, variable)).toEqual(1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('and value is an array of strings', () => {
|
||||
it('should return comma separated quoted values', () => {
|
||||
const { ds, variable } = setupTextContext({});
|
||||
const { ds, variable } = setupTestContext({});
|
||||
expect(ds.interpolateVariable(['a', 'b', 'c'], variable)).toEqual("'a','b','c'");
|
||||
});
|
||||
});
|
||||
|
||||
describe('and variable allows multi-value and value is a string', () => {
|
||||
it('should return a quoted value', () => {
|
||||
const { ds, variable } = setupTextContext({});
|
||||
const { ds, variable } = setupTestContext({});
|
||||
variable.multi = true;
|
||||
expect(ds.interpolateVariable('abc', variable)).toEqual("'abc'");
|
||||
});
|
||||
@ -303,7 +430,7 @@ describe('MySQLDatasource', () => {
|
||||
|
||||
describe('and variable contains single quote', () => {
|
||||
it('should return a quoted value', () => {
|
||||
const { ds, variable } = setupTextContext({});
|
||||
const { ds, variable } = setupTestContext({});
|
||||
variable.multi = true;
|
||||
expect(ds.interpolateVariable("a'bc", variable)).toEqual("'a''bc'");
|
||||
});
|
||||
@ -311,7 +438,7 @@ describe('MySQLDatasource', () => {
|
||||
|
||||
describe('and variable allows all and value is a string', () => {
|
||||
it('should return a quoted value', () => {
|
||||
const { ds, variable } = setupTextContext({});
|
||||
const { ds, variable } = setupTestContext({});
|
||||
variable.includeAll = true;
|
||||
expect(ds.interpolateVariable('abc', variable)).toEqual("'abc'");
|
||||
});
|
||||
@ -320,7 +447,7 @@ describe('MySQLDatasource', () => {
|
||||
|
||||
describe('targetContainsTemplate', () => {
|
||||
it('given query that contains template variable it should return true', () => {
|
||||
const { ds, templateSrv } = setupTextContext({});
|
||||
const { ds, templateSrv } = setupTestContext({});
|
||||
const rawSql = `SELECT
|
||||
$__timeGroup(createdAt,'$summarize') as time_sec,
|
||||
avg(value) as value,
|
||||
@ -347,7 +474,7 @@ describe('MySQLDatasource', () => {
|
||||
});
|
||||
|
||||
it('given query that only contains global template variable it should return false', () => {
|
||||
const { ds, templateSrv } = setupTextContext({});
|
||||
const { ds, templateSrv } = setupTestContext({});
|
||||
const rawSql = `SELECT
|
||||
$__timeGroup(createdAt,'$__interval') as time_sec,
|
||||
avg(value) as value,
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
DataQueryResponse,
|
||||
DataSourceInstanceSettings,
|
||||
dateTime,
|
||||
FieldType,
|
||||
LoadingState,
|
||||
MutableDataFrame,
|
||||
} from '@grafana/data';
|
||||
@ -303,6 +304,161 @@ describe('PostgreSQLDatasource', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('When runSql returns an empty dataframe', () => {
|
||||
let ds: PostgresDatasource;
|
||||
const response = {
|
||||
results: {
|
||||
tempvar: {
|
||||
refId: 'tempvar',
|
||||
frames: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
ds = setupTestContext(response).ds;
|
||||
});
|
||||
|
||||
it('should return an empty array when metricFindQuery is called', async () => {
|
||||
const query = 'select * from atable';
|
||||
const results = await ds.metricFindQuery(query);
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should return an empty array when fetchTables is called', async () => {
|
||||
const results = await ds.fetchTables();
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should return empty string when getVersion is called', async () => {
|
||||
const results = await ds.getVersion();
|
||||
expect(results).toBe('');
|
||||
});
|
||||
|
||||
it('should return undefined when getTimescaleDBVersion is called', async () => {
|
||||
const results = await ds.getTimescaleDBVersion();
|
||||
expect(results).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should return an empty array when fetchFields is called', async () => {
|
||||
const query: SQLQuery = {
|
||||
refId: 'refId',
|
||||
table: 'schema.table',
|
||||
dataset: 'dataset',
|
||||
};
|
||||
const results = await ds.fetchFields(query);
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('When runSql returns a populated dataframe', () => {
|
||||
it('should return a list of tables when fetchTables is called', async () => {
|
||||
const fetchTableResponse = {
|
||||
results: {
|
||||
tables: {
|
||||
refId: 'tables',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [{ name: 'table', type: FieldType.string, values: ['test1', 'test2', 'test3'] }],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { ds } = setupTestContext(fetchTableResponse);
|
||||
|
||||
const results = await ds.fetchTables();
|
||||
expect(results.length).toBe(3);
|
||||
expect(results).toEqual(['test1', 'test2', 'test3']);
|
||||
});
|
||||
|
||||
it('should return a version string when getVersion is called', async () => {
|
||||
const fetchVersionResponse = {
|
||||
results: {
|
||||
meta: {
|
||||
refId: 'meta',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [{ name: 'version', type: FieldType.string, values: ['test1'] }],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { ds } = setupTestContext(fetchVersionResponse);
|
||||
|
||||
const version = await ds.getVersion();
|
||||
expect(version).toBe('test1');
|
||||
});
|
||||
|
||||
it('should return a version string when getTimescaleDBVersion is called', async () => {
|
||||
const fetchVersionResponse = {
|
||||
results: {
|
||||
meta: {
|
||||
refId: 'meta',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [{ name: 'extversion', type: FieldType.string, values: ['test1'] }],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { ds } = setupTestContext(fetchVersionResponse);
|
||||
|
||||
const version = await ds.getTimescaleDBVersion();
|
||||
expect(version).toBe('test1');
|
||||
});
|
||||
|
||||
it('should return a list of fields when fetchFields is called', async () => {
|
||||
const fetchFieldsResponse = {
|
||||
results: {
|
||||
columns: {
|
||||
refId: 'columns',
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [
|
||||
{ name: 'column', type: FieldType.string, values: ['test1', 'test2', 'test3'] },
|
||||
{ name: 'type', type: FieldType.string, values: ['int', 'char', 'bool'] },
|
||||
],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { ds } = setupTestContext(fetchFieldsResponse);
|
||||
|
||||
const sqlQuery: SQLQuery = {
|
||||
refId: 'fields',
|
||||
table: 'table',
|
||||
dataset: 'dataset',
|
||||
};
|
||||
const results = await ds.fetchFields(sqlQuery);
|
||||
expect(results.length).toBe(3);
|
||||
expect(results[0].label).toBe('test1');
|
||||
expect(results[0].value).toBe('test1');
|
||||
expect(results[0].type).toBe('int');
|
||||
expect(results[1].label).toBe('test2');
|
||||
expect(results[1].value).toBe('test2');
|
||||
expect(results[1].type).toBe('char');
|
||||
expect(results[2].label).toBe('test3');
|
||||
expect(results[2].value).toBe('test3');
|
||||
expect(results[2].type).toBe('bool');
|
||||
});
|
||||
});
|
||||
|
||||
describe('When performing metricFindQuery that returns multiple string fields', () => {
|
||||
it('should return list of all string field values', async () => {
|
||||
const query = 'select * from atable';
|
||||
|
@ -24,19 +24,29 @@ export class PostgresDatasource extends SqlDatasource {
|
||||
|
||||
async getVersion(): Promise<string> {
|
||||
const value = await this.runSql<{ version: number }>(getVersion());
|
||||
const results = value.fields.version.values.toArray();
|
||||
const results = value.fields.version?.values.toArray();
|
||||
|
||||
if (!results) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return results[0].toString();
|
||||
}
|
||||
|
||||
async getTimescaleDBVersion(): Promise<string | undefined> {
|
||||
const value = await this.runSql<{ extversion: string }>(getTimescaleDBVersion());
|
||||
const results = value.fields.extversion.values.toArray();
|
||||
const results = value.fields.extversion?.values.toArray();
|
||||
|
||||
if (!results) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return results[0];
|
||||
}
|
||||
|
||||
async fetchTables(): Promise<string[]> {
|
||||
const tables = await this.runSql<{ table: string[] }>(showTables(), { refId: 'tables' });
|
||||
return tables.fields.table.values.toArray().flat();
|
||||
return tables.fields.table?.values.toArray().flat() ?? [];
|
||||
}
|
||||
|
||||
getSqlLanguageDefinition(db: DB): LanguageDefinition {
|
||||
|
Loading…
Reference in New Issue
Block a user