Browse Source

Merge pull request 'SQL: support Grafana 9' (#12) from update-sql-exporter-to-work-with-grafana-9 into master

Reviewed-on: #12
cli-sql-testing^2
rozetko 1 year ago
parent
commit
f8367d9e58
  1. 48
      spec/sql.jest.ts
  2. 17
      src/connectors/sql.ts
  3. 2
      src/connectors/utils.ts
  4. 20
      src/services/query_service/grafana.ts

48
spec/sql.jest.ts

@ -37,22 +37,40 @@ describe('Test result parsing', function() {
data: { data: {
results: { results: {
A: { A: {
refId: 'A', frames: [
meta: {
rowCount:0,
sql: 'SELECT "time" AS "time", val FROM local ORDER BY 1'
},
series: [
{ {
name:"val", schema: {
points: [ refId: 'A',
[622, timestamps[0]], meta: {
[844, timestamps[1]], 'executedQueryString': 'SELECT\n \"time\" AS \"time\",\n eur\nFROM rate_test\nWHERE\n \"time\" >= 1669648679 AND \"time\" <= 1672240679\nORDER BY 1'
[648, timestamps[2]] },
] fields: [
{
name: 'Time',
type: 'time',
typeInfo: {
frame: 'time.Time',
nullable: true
}
},
{
name: 'eur',
type: 'number',
typeInfo: {
frame: 'float64',
nullable: true
}
}
]
},
data: {
values: [
[ timestamps[0], timestamps[1], timestamps[2] ],
[ 1.53, 1.17, 1.17 ],
]
}
} }
], ]
tables: 'null'
} }
} }
} }
@ -61,7 +79,7 @@ describe('Test result parsing', function() {
let result = connector.parseResponse(response); let result = connector.parseResponse(response);
it('check results columns order', function() { it('check results columns order', function() {
let timestampColumnNumber = result.columns.indexOf('timestamp'); let timestampColumnNumber = result.columns.indexOf('Time');
expect(result.values.map(v => v[timestampColumnNumber])).toEqual(timestamps); expect(result.values.map(v => v[timestampColumnNumber])).toEqual(timestamps);
}); });
}); });

17
src/connectors/sql.ts

@ -6,11 +6,13 @@ import * as _ from 'lodash';
// as of 26.09.2020, it works for all SQL datasources // as of 26.09.2020, it works for all SQL datasources
export class SqlConnector extends DatasourceConnector { export class SqlConnector extends DatasourceConnector {
private _targetName: string; //save first target name, while multi metric not implemented private _targetName: string; //save first target name, while multi metric not implemented
private url: string = 'api/tsdb/query'; private url: string;
constructor(datasource: Datasource, targets: any[]) { constructor(datasource: Datasource, targets: any[]) {
super(datasource, targets); super(datasource, targets);
this.url = datasource.url;
if(targets.length === 0) { if(targets.length === 0) {
throw Error('got empty targets list'); throw Error('got empty targets list');
} }
@ -34,7 +36,7 @@ export class SqlConnector extends DatasourceConnector {
data: { data: {
from: String(from), from: String(from),
to: String(to), to: String(to),
queries: queries queries: queries,
} }
} }
}; };
@ -53,16 +55,15 @@ export class SqlConnector extends DatasourceConnector {
// TODO: support more than 1 metric (each res.data.results item is a metric) // TODO: support more than 1 metric (each res.data.results item is a metric)
let results = res.data.results[this._targetName]; let results = res.data.results[this._targetName];
if (!results.series) { if (_.isEmpty(results.frames)) {
return emptyResult; return emptyResult;
} }
let points = results.series[0].points; const frame = results.frames[0];
points.forEach(p => p.reverse());
return { return {
columns: ['timestamp', results.series[0].name], columns: frame.schema.fields.map(field => field.name),
values: points // @ts-ignore
values: _.zip(...frame.data.values),
}; };
} }
} }

2
src/connectors/utils.ts

@ -32,7 +32,7 @@ export function processSQLLimitOffset(sql: string, limit: number, offset: number
} }
function ensureParentheses(regex: RegExp, str: string): { index: number, length: number } { function ensureParentheses(regex: RegExp, str: string): { index: number, length: number } {
let occurence: RegExpExecArray; let occurence: RegExpExecArray | null;
while((occurence = regex.exec(str)) !== null) { while((occurence = regex.exec(str)) !== null) {
let leftPart = str.slice(0, occurence.index) let leftPart = str.slice(0, occurence.index)
let rightPart = str.slice(occurence.index + occurence[0].length); let rightPart = str.slice(occurence.index + occurence[0].length);

20
src/services/query_service/grafana.ts

@ -16,9 +16,6 @@ export class GrafanaQueryService extends QueryService {
async query(query: DatasourceQuery, apiKey: string): Promise<AxiosResponse<any>> { async query(query: DatasourceQuery, apiKey: string): Promise<AxiosResponse<any>> {
let headers = { Authorization: `Bearer ${apiKey}` }; let headers = { Authorization: `Bearer ${apiKey}` };
const grafanaUrl = getGrafanaUrl(query.url);
query.url = `${grafanaUrl}/${query.url}`;
if(query.headers !== undefined) { if(query.headers !== undefined) {
_.merge(headers, query.headers); _.merge(headers, query.headers);
} }
@ -64,20 +61,3 @@ export class GrafanaQueryService extends QueryService {
} }
} }
} }
export function getGrafanaUrl(url: string): string {
const parsedUrl = new URL(url);
const path = parsedUrl.pathname;
const panelUrl = path.match(/^\/*([^\/]*)\/d\//);
if(panelUrl === null) {
return url;
}
const origin = parsedUrl.origin;
const grafanaSubPath = panelUrl[1];
if(grafanaSubPath.length > 0) {
return `${origin}/${grafanaSubPath}`;
}
return origin;
}

Loading…
Cancel
Save