Datasource: making sure we are having the same data field order when using mixed data sources. (#22718)

* changed so data query response always it returned in the correct order when using mixed data sources.

* refactored the code to make it a bit simpler and not failing the tests.

* changed to simple array type.
This commit is contained in:
Marcus Andersson 2020-03-12 18:16:32 +01:00 committed by GitHub
parent d813204546
commit f44c0f0643
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,7 +1,7 @@
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import groupBy from 'lodash/groupBy'; import groupBy from 'lodash/groupBy';
import { from, of, Observable, merge } from 'rxjs'; import { from, of, Observable, forkJoin } from 'rxjs';
import { tap } from 'rxjs/operators'; import { map, mergeMap, mergeAll } from 'rxjs/operators';
import { import {
LoadingState, LoadingState,
@ -12,7 +12,6 @@ import {
DataSourceInstanceSettings, DataSourceInstanceSettings,
} from '@grafana/data'; } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime'; import { getDataSourceSrv } from '@grafana/runtime';
import { mergeMap, map } from 'rxjs/operators';
export const MIXED_DATASOURCE_NAME = '-- Mixed --'; export const MIXED_DATASOURCE_NAME = '-- Mixed --';
@ -51,64 +50,46 @@ export class MixedDatasource extends DataSourceApi<DataQuery> {
} }
batchQueries(mixed: BatchedQueries[], request: DataQueryRequest<DataQuery>): Observable<DataQueryResponse> { batchQueries(mixed: BatchedQueries[], request: DataQueryRequest<DataQuery>): Observable<DataQueryResponse> {
const observables: Array<Observable<DataQueryResponse>> = []; const runningQueries = mixed.filter(this.isQueryable).map((query, i) =>
let runningSubRequests = 0; from(query.datasource).pipe(
mergeMap((api: DataSourceApi) => {
const dsRequest = cloneDeep(request);
dsRequest.requestId = `mixed-${i}-${dsRequest.requestId || ''}`;
dsRequest.targets = query.targets;
for (let i = 0; i < mixed.length; i++) { return from(api.query(dsRequest)).pipe(
const query = mixed[i]; map(response => {
if (!query.targets || !query.targets.length) {
continue;
}
const observable = from(query.datasource).pipe(
mergeMap((dataSourceApi: DataSourceApi) => {
const datasourceRequest = cloneDeep(request);
datasourceRequest.requestId = `mixed-${i}-${datasourceRequest.requestId || ''}`;
datasourceRequest.targets = query.targets;
runningSubRequests++;
let hasCountedAsDone = false;
return from(dataSourceApi.query(datasourceRequest)).pipe(
tap(
(response: DataQueryResponse) => {
if (
hasCountedAsDone ||
response.state === LoadingState.Streaming ||
response.state === LoadingState.Loading
) {
return;
}
runningSubRequests--;
hasCountedAsDone = true;
},
() => {
if (hasCountedAsDone) {
return;
}
hasCountedAsDone = true;
runningSubRequests--;
}
),
map((response: DataQueryResponse) => {
return { return {
...response, ...response,
data: response.data || [], data: response.data || [],
state: runningSubRequests === 0 ? LoadingState.Done : LoadingState.Loading, state: LoadingState.Loading,
key: `mixed-${i}-${response.key || ''}`, key: `mixed-${i}-${response.key || ''}`,
} as DataQueryResponse; } as DataQueryResponse;
}) })
); );
}) })
); )
);
observables.push(observable); return forkJoin(runningQueries).pipe(map(this.markAsDone), mergeAll());
}
return merge(...observables);
} }
testDatasource() { testDatasource() {
return Promise.resolve({}); return Promise.resolve({});
} }
private isQueryable(query: BatchedQueries): boolean {
return query && Array.isArray(query.targets) && query.targets.length > 0;
}
private markAsDone(responses: DataQueryResponse[]): DataQueryResponse[] {
const { length } = responses;
if (length === 0) {
return responses;
}
responses[length - 1].state = LoadingState.Done;
return responses;
}
} }