Cache ad-hoc data views to avoid repeated field list calls (#144465)

* Cache ad-hoc data views to avoid repeated field list calls

Closes: #144253

* feat: removed await

* update tests

* update tests

Co-authored-by: Nodir Latipov <nodir.latypov@gmail.com>
This commit is contained in:
Alexey Antonov 2022-11-03 22:43:49 +03:00 committed by GitHub
parent e257e8ab68
commit bb67548a2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 15 deletions

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { defaults } from 'lodash';
import { defaults, get, set } from 'lodash';
import { DataViewsService, DataView } from '.';
import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks';
@ -31,6 +31,10 @@ function setDocsourcePayload(id: string | null, providedPayload: any) {
object = defaults(providedPayload || {}, stubbedSavedObjectIndexPattern(id));
}
function doWithTimeout<T = unknown>(fn: () => T, timeout: number = 0): Promise<T> {
return new Promise((resolve) => setTimeout(() => resolve(fn()), timeout));
}
const savedObject = {
id: 'id',
version: 'version',
@ -151,13 +155,45 @@ describe('IndexPatterns', () => {
test('does cache ad-hoc data views', async () => {
const id = '1';
const dataView = await indexPatterns.create({ id });
const gettedDataView = await indexPatterns.get(id);
expect(dataView).toBe(gettedDataView);
const createFromSpecOriginal = get(indexPatterns, 'createFromSpec');
let mockedCreateFromSpec: jest.Mock;
const dataView2 = await indexPatterns.create({ id });
expect(dataView2).toBe(gettedDataView);
set(
indexPatterns,
'createFromSpec',
(mockedCreateFromSpec = jest
.fn()
.mockImplementation((spec: DataViewSpec, skipFetchFields = false, displayErrors = true) =>
doWithTimeout(
() => createFromSpecOriginal.call(indexPatterns, spec, skipFetchFields, displayErrors),
1000
)
))
);
// run creating in parallel
await Promise.all([
indexPatterns.create({ id }),
indexPatterns.create({ id }),
indexPatterns.create({ id }),
doWithTimeout(() => indexPatterns.create({ id }), 1),
doWithTimeout(() => indexPatterns.create({ id }), 10),
doWithTimeout(() => indexPatterns.get(id), 10),
doWithTimeout(() => indexPatterns.get(id), 40),
]).then((results) =>
results.forEach((value) => {
expect(value.id).toBe(id);
})
);
// tests after promise was resolved
expect((await indexPatterns.get(id)).id).toBe(id);
expect((await indexPatterns.create({ id })).id).toBe(id);
expect(mockedCreateFromSpec).toHaveBeenCalledTimes(1);
expect(mockedCreateFromSpec).toHaveBeenCalledWith({ id: '1' }, false, true);
});
test('allowNoIndex flag preserves existing fields when index is missing', async () => {

View file

@ -7,7 +7,7 @@
*/
import { i18n } from '@kbn/i18n';
import { PublicMethodsOf } from '@kbn/utility-types';
import type { PublicMethodsOf } from '@kbn/utility-types';
import { castEsToKbnFieldTypeName } from '@kbn/field-types';
import { FieldFormatsStartCommon, FORMATS_UI_SETTINGS } from '@kbn/field-formats-plugin/common';
import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common';
@ -939,21 +939,20 @@ export class DataViewsService {
skipFetchFields = false,
displayErrors = true
): Promise<DataView> {
const doCreate = () => this.createFromSpec(spec, skipFetchFields, displayErrors);
if (spec.id) {
const cachedDataView = spec.id ? await this.dataViewCache.get(spec.id) : undefined;
const cachedDataView = this.dataViewCache.get(spec.id);
if (cachedDataView) {
return cachedDataView;
}
return this.dataViewCache.set(spec.id, doCreate());
}
const dataView = await this.createFromSpec(spec, skipFetchFields, displayErrors);
if (dataView.id) {
return this.dataViewCache.set(dataView.id, Promise.resolve(dataView));
}
return dataView;
const dataView = await doCreate();
return this.dataViewCache.set(dataView.id!, Promise.resolve(dataView));
}
/**