From 91b5398fd07a59deea809eb1899542f29e0b41ec Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Fri, 24 Sep 2021 10:26:09 +0200 Subject: [PATCH] Use rxjs --- package.json | 3 +- spec/DataSource.jest.ts | 50 ++++++++++------- src/DataSource.ts | 121 +++++++++++++++++++++++++++------------- yarn.lock | 12 ++++ 4 files changed, 125 insertions(+), 61 deletions(-) diff --git a/package.json b/package.json index 9a75a3a9..a257cf3b 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ }, "dependencies": { "lodash": "^4.17.21", - "react-virtualized-auto-sizer": "^1.0.5" + "react-virtualized-auto-sizer": "^1.0.5", + "rxjs": "^7.3.0" }, "homepage": "https://github.com/simPod/grafana-json-datasource#readme" } diff --git a/spec/DataSource.jest.ts b/spec/DataSource.jest.ts index 49c82d3f..018b6eeb 100644 --- a/spec/DataSource.jest.ts +++ b/spec/DataSource.jest.ts @@ -1,6 +1,14 @@ import { isDataFrame } from '@grafana/data'; import { DateTime } from '@grafana/data/datetime/moment_wrapper'; -import { BackendSrv, getBackendSrv, getTemplateSrv, setBackendSrv, setTemplateSrv } from '@grafana/runtime'; +import { + BackendSrv, + FetchResponse, + getBackendSrv, + getTemplateSrv, + setBackendSrv, + setTemplateSrv, +} from '@grafana/runtime'; +import { of } from 'rxjs'; import { DataSource } from '../src/DataSource'; import { QueryRequest } from '../src/types'; import TemplateSrvStub from './lib/TemplateSrvStub'; @@ -52,8 +60,8 @@ describe('GenericDatasource', () => { it('should return the server results when a target is set', (done) => { setBackendSrv({ - datasourceRequest: (request) => - Promise.resolve({ + fetch: (request) => + of({ data: [ { target: 'X', @@ -82,14 +90,14 @@ describe('GenericDatasource', () => { }); it('should return the metric target results when a target is set', (done) => { - getBackendSrv().datasourceRequest = (request) => { + getBackendSrv().fetch = (request) => { const target = request.data.target; const result = [target + '_0', target + '_1', target + '_2']; - return Promise.resolve({ + return of({ _request: request, data: result, - }); + } as unknown as FetchResponse); }; const templateSrvStub = new TemplateSrvStub(); @@ -109,11 +117,11 @@ describe('GenericDatasource', () => { }); it('should return the metric results when the target is an empty string', (done) => { - getBackendSrv().datasourceRequest = (request) => - Promise.resolve({ + getBackendSrv().fetch = (request) => + of({ _request: request, data: ['metric_0', 'metric_1', 'metric_2'], - }); + } as unknown as FetchResponse); const templateSrvStub = new TemplateSrvStub(); templateSrvStub.replace = (data) => data ?? ''; @@ -132,11 +140,11 @@ describe('GenericDatasource', () => { }); it('should return the metric results when the args are an empty object', (done) => { - getBackendSrv().datasourceRequest = (request) => - Promise.resolve({ + getBackendSrv().fetch = (request) => + of({ _request: request, data: ['metric_0', 'metric_1', 'metric_2'], - }); + } as unknown as FetchResponse); const templateSrvStub = new TemplateSrvStub(); templateSrvStub.replace = (data) => data ?? ''; @@ -155,14 +163,14 @@ describe('GenericDatasource', () => { }); it('should return the metric target results when the args are a string', (done) => { - getBackendSrv().datasourceRequest = (request) => { + getBackendSrv().fetch = (request) => { const target = request.data.target; const result = [target + '_0', target + '_1', target + '_2']; - return Promise.resolve({ + return of({ _request: request, data: result, - }); + } as unknown as FetchResponse); }; const templateSrvStub = new TemplateSrvStub(); @@ -265,11 +273,11 @@ describe('GenericDatasource', () => { { type: 'string', text: 'two', key: 'Two' }, ]; - getBackendSrv().datasourceRequest = (request) => - Promise.resolve({ + getBackendSrv().fetch = (request) => + of({ data, _request: request, - }); + } as unknown as FetchResponse); ds.getTagKeys().then((result) => { expect(result).toHaveLength(2); @@ -290,11 +298,11 @@ describe('GenericDatasource', () => { { key: 'drei', text: 'Drei!' }, ]; - getBackendSrv().datasourceRequest = (request) => - Promise.resolve({ + getBackendSrv().fetch = (request) => + of({ data, _request: request, - }); + } as unknown as FetchResponse); ds.getTagValues(null).then((result) => { expect(result).toHaveLength(3); diff --git a/src/DataSource.ts b/src/DataSource.ts index 170aeba6..fb06d7de 100644 --- a/src/DataSource.ts +++ b/src/DataSource.ts @@ -1,5 +1,6 @@ import { AnnotationEvent, + DataFrame, DataQueryResponse, DataSourceApi, DataSourceInstanceSettings, @@ -8,7 +9,10 @@ import { } from '@grafana/data'; import { AnnotationQueryRequest } from '@grafana/data/types/datasource'; import { getBackendSrv, getTemplateSrv } from '@grafana/runtime'; +import { BackendSrvRequest } from '@grafana/runtime/services/backendSrv'; import { isEqual, isObject } from 'lodash'; +import { lastValueFrom, of } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; import { GenericOptions, GrafanaQuery, @@ -51,15 +55,24 @@ export class DataSource extends DataSourceApi { options.scopedVars = { ...this.getVariables(), ...options.scopedVars }; - return this.doRequest({ - url: `${this.url}/query`, - data: request, - method: 'POST', - }).then((entry) => { - entry.data = entry.data.map(toDataFrame); - - return entry; - }); + return lastValueFrom( + this.doFetch({ + url: `${this.url}/query`, + data: request, + method: 'POST', + }).pipe( + map((response) => { + response.data = response.data.map(toDataFrame) as DataFrame[]; + + return response; + }), + catchError((err) => { + console.error(err); + + return of({ data: [] }); + }) + ) + ); } annotations = {}; @@ -68,10 +81,12 @@ export class DataSource extends DataSourceApi { const errorMessageBase = 'Data source is not working'; try { - const response = await this.doRequest({ - url: this.url, - method: 'GET', - }); + const response = await lastValueFrom( + this.doFetch({ + url: this.url, + method: 'GET', + }).pipe(map((response) => response)) + ); if (response.status === 200) { return { status: 'success', message: 'Data source is working', title: 'Success' }; @@ -108,35 +123,54 @@ export class DataSource extends DataSourceApi { target: getTemplateSrv().replace(variableQuery.query, undefined, 'regex'), }; - return this.doRequest({ - url: `${this.url}/search`, - data: interpolated, - method: 'POST', - }).then(this.mapToTextValue); + return lastValueFrom( + this.doFetch({ + url: `${this.url}/search`, + data: interpolated, + method: 'POST', + }).pipe( + map((response) => this.mapToTextValue(response)), + catchError((err) => { + console.error(err); + + return of([]); + }) + ) + ); } getTagKeys(options?: any): Promise { - return new Promise((resolve) => { - this.doRequest({ + return lastValueFrom( + this.doFetch({ url: `${this.url}/tag-keys`, method: 'POST', data: options, - }).then((result: any) => { - return resolve(result.data); - }); - }); + }).pipe( + map((result: any) => result.data), + catchError((err) => { + console.error(err); + + return of([]); + }) + ) + ); } getTagValues(options: any): Promise { - return new Promise((resolve) => { - this.doRequest({ + return lastValueFrom( + this.doFetch({ url: `${this.url}/tag-values`, method: 'POST', data: options, - }).then((result: any) => { - return resolve(result.data); - }); - }); + }).pipe( + map((result: any) => result.data), + catchError((err) => { + console.error(err); + + return of([]); + }) + ) + ); } annotationQuery( @@ -157,13 +191,22 @@ export class DataSource extends DataSourceApi { variables: this.getVariables(), }; - return this.doRequest({ - url: `${this.url}/annotations`, - method: 'POST', - data: annotationQuery, - }).then((result: any) => { - return result.data; - }); + return lastValueFrom( + this.doFetch({ + url: `${this.url}/annotations`, + method: 'POST', + data: annotationQuery, + }).pipe( + map((result: any) => { + return result.data; + }), + catchError((err) => { + console.error(err); + + return of([]); + }) + ) + ); } mapToTextValue(result: any) { @@ -179,11 +222,11 @@ export class DataSource extends DataSourceApi { }); } - doRequest(options: any) { + doFetch(options: BackendSrvRequest) { options.withCredentials = this.withCredentials; options.headers = this.headers; - return getBackendSrv().datasourceRequest(options); + return getBackendSrv().fetch(options); } processTargets(options: QueryRequest) { diff --git a/yarn.lock b/yarn.lock index 3b39f4fb..911a39b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10599,6 +10599,13 @@ rxjs@^6.3.3, rxjs@^6.4.0: dependencies: tslib "^1.9.0" +rxjs@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.3.0.tgz#39fe4f3461dc1e50be1475b2b85a0a88c1e938c6" + integrity sha512-p2yuGIg9S1epc3vrjKf6iVb3RCaAYjYskkO+jHIaV0IjOPlJop4UnodOoFb2xeNwlguqLYvGw1b1McillYb5Gw== + dependencies: + tslib "~2.1.0" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -11703,6 +11710,11 @@ tslib@^2.0.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"