Skip to content

Commit

Permalink
[Data] Provide datatable utility functions (#126572)
Browse files Browse the repository at this point in the history
* Extract datatable utilities into a separate service
* Add getField utility function
* Add getFieldFormat utility function
* Add field format setter utility functions
* Add data view field setter utility functions
* Add getInterval utility function
  • Loading branch information
dokmic authored Mar 2, 2022
1 parent f694a2a commit 12f42e0
Show file tree
Hide file tree
Showing 23 changed files with 363 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { createStubDataView } from 'src/plugins/data_views/common/mocks';
import type { DataViewsContract } from 'src/plugins/data_views/common';
import type { DatatableColumn } from 'src/plugins/expressions/common';
import { FieldFormat } from 'src/plugins/field_formats/common';
import { fieldFormatsMock } from 'src/plugins/field_formats/common/mocks';
import type { AggsCommonStart } from '../search';
import { DatatableUtilitiesService } from './datatable_utilities_service';

describe('DatatableUtilitiesService', () => {
let aggs: jest.Mocked<AggsCommonStart>;
let dataViews: jest.Mocked<DataViewsContract>;
let datatableUtilitiesService: DatatableUtilitiesService;

beforeEach(() => {
aggs = {
createAggConfigs: jest.fn(),
types: { get: jest.fn() },
} as unknown as typeof aggs;
dataViews = {
get: jest.fn(),
} as unknown as typeof dataViews;

datatableUtilitiesService = new DatatableUtilitiesService(aggs, dataViews, fieldFormatsMock);
});

describe('clearField', () => {
it('should delete the field reference', () => {
const column = { meta: { field: 'foo' } } as DatatableColumn;

datatableUtilitiesService.clearField(column);

expect(column).not.toHaveProperty('meta.field');
});
});

describe('clearFieldFormat', () => {
it('should remove field format', () => {
const column = { meta: { params: { id: 'number' } } } as DatatableColumn;
datatableUtilitiesService.clearFieldFormat(column);

expect(column).not.toHaveProperty('meta.params');
});
});

describe('getDataView', () => {
it('should return a data view instance', async () => {
const column = { meta: { index: 'index' } } as DatatableColumn;
const dataView = {} as ReturnType<DataViewsContract['get']>;
dataViews.get.mockReturnValue(dataView);

await expect(datatableUtilitiesService.getDataView(column)).resolves.toBe(dataView);
expect(dataViews.get).toHaveBeenCalledWith('index');
});

it('should return undefined when there is no index metadata', async () => {
const column = { meta: {} } as DatatableColumn;

await expect(datatableUtilitiesService.getDataView(column)).resolves.toBeUndefined();
expect(dataViews.get).not.toHaveBeenCalled();
});
});

describe('getField', () => {
it('should return a data view field instance', async () => {
const column = { meta: { field: 'field', index: 'index' } } as DatatableColumn;
const dataView = createStubDataView({ spec: {} });
const field = {};
spyOn(datatableUtilitiesService, 'getDataView').and.returnValue(dataView);
spyOn(dataView, 'getFieldByName').and.returnValue(field);

await expect(datatableUtilitiesService.getField(column)).resolves.toBe(field);
expect(dataView.getFieldByName).toHaveBeenCalledWith('field');
});

it('should return undefined when there is no field metadata', async () => {
const column = { meta: {} } as DatatableColumn;

await expect(datatableUtilitiesService.getField(column)).resolves.toBeUndefined();
});
});

describe('getFieldFormat', () => {
it('should deserialize field format', () => {
const column = { meta: { params: { id: 'number' } } } as DatatableColumn;
const fieldFormat = datatableUtilitiesService.getFieldFormat(column);

expect(fieldFormat).toBeInstanceOf(FieldFormat);
});
});

describe('getInterval', () => {
it('should return a histogram interval', () => {
const column = {
meta: { sourceParams: { params: { interval: '1d' } } },
} as unknown as DatatableColumn;

expect(datatableUtilitiesService.getInterval(column)).toBe('1d');
});
});

describe('setFieldFormat', () => {
it('should set new field format', () => {
const column = { meta: {} } as DatatableColumn;
const fieldFormat = fieldFormatsMock.deserialize({ id: 'number' });
datatableUtilitiesService.setFieldFormat(column, fieldFormat);

expect(column.meta.params).toEqual(
expect.objectContaining({
id: expect.anything(),
params: undefined,
})
);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import type { DataView, DataViewsContract, DataViewField } from 'src/plugins/data_views/common';
import type { DatatableColumn } from 'src/plugins/expressions/common';
import type { FieldFormatsStartCommon, FieldFormat } from 'src/plugins/field_formats/common';
import type { AggsCommonStart, AggConfig, CreateAggConfigParams, IAggType } from '../search';

export class DatatableUtilitiesService {
constructor(
private aggs: AggsCommonStart,
private dataViews: DataViewsContract,
private fieldFormats: FieldFormatsStartCommon
) {
this.getAggConfig = this.getAggConfig.bind(this);
this.getDataView = this.getDataView.bind(this);
this.getField = this.getField.bind(this);
this.isFilterable = this.isFilterable.bind(this);
}

clearField(column: DatatableColumn): void {
delete column.meta.field;
}

clearFieldFormat(column: DatatableColumn): void {
delete column.meta.params;
}

async getAggConfig(column: DatatableColumn): Promise<AggConfig | undefined> {
const dataView = await this.getDataView(column);

if (!dataView) {
return;
}

const { aggs } = await this.aggs.createAggConfigs(
dataView,
column.meta.sourceParams && [column.meta.sourceParams as CreateAggConfigParams]
);

return aggs[0];
}

async getDataView(column: DatatableColumn): Promise<DataView | undefined> {
if (!column.meta.index) {
return;
}

return this.dataViews.get(column.meta.index);
}

async getField(column: DatatableColumn): Promise<DataViewField | undefined> {
if (!column.meta.field) {
return;
}

const dataView = await this.getDataView(column);
if (!dataView) {
return;
}

return dataView.getFieldByName(column.meta.field);
}

getFieldFormat(column: DatatableColumn): FieldFormat | undefined {
return this.fieldFormats.deserialize(column.meta.params);
}

getInterval(column: DatatableColumn): string | undefined {
const params = column.meta.sourceParams?.params as { interval: string } | undefined;

return params?.interval;
}

isFilterable(column: DatatableColumn): boolean {
if (column.meta.source !== 'esaggs') {
return false;
}

const aggType = this.aggs.types.get(column.meta.sourceParams?.type as string) as IAggType;

return Boolean(aggType.createFilter);
}

setFieldFormat(column: DatatableColumn, fieldFormat: FieldFormat): void {
column.meta.params = fieldFormat.toJSON();
}
}
9 changes: 9 additions & 0 deletions src/plugins/data/common/datatable_utilities/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export * from './datatable_utilities_service';
22 changes: 22 additions & 0 deletions src/plugins/data/common/datatable_utilities/mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import type { DatatableUtilitiesService } from './datatable_utilities_service';

export function createDatatableUtilitiesMock(): jest.Mocked<DatatableUtilitiesService> {
return {
clearField: jest.fn(),
clearFieldFormat: jest.fn(),
getAggConfig: jest.fn(),
getDataView: jest.fn(),
getField: jest.fn(),
getFieldFormat: jest.fn(),
isFilterable: jest.fn(),
setFieldFormat: jest.fn(),
} as unknown as jest.Mocked<DatatableUtilitiesService>;
}
1 change: 1 addition & 0 deletions src/plugins/data/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
/* eslint-disable @kbn/eslint/no_export_all */

export * from './constants';
export * from './datatable_utilities';
export * from './es_query';
export * from './kbn_field_types';
export * from './query';
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/common/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
*/

export * from '../../data_views/common/fields/fields.mocks';
export * from './datatable_utilities/mock';
3 changes: 1 addition & 2 deletions src/plugins/data/common/search/aggs/aggs_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,10 @@ describe('Aggs service', () => {
describe('start()', () => {
test('exposes proper contract', () => {
const start = service.start(startDeps);
expect(Object.keys(start).length).toBe(4);
expect(Object.keys(start).length).toBe(3);
expect(start).toHaveProperty('calculateAutoTimeExpression');
expect(start).toHaveProperty('createAggConfigs');
expect(start).toHaveProperty('types');
expect(start).toHaveProperty('datatableUtilities');
});

test('types registry returns uninitialized type providers', () => {
Expand Down
12 changes: 1 addition & 11 deletions src/plugins/data/common/search/aggs/aggs_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
getCalculateAutoTimeExpression,
} from './';
import { AggsCommonSetup, AggsCommonStart } from './types';
import { getDatatableColumnUtilities } from './utils/datatable_column_meta';

/** @internal */
export const aggsRequiredUiSettings = [
Expand Down Expand Up @@ -67,11 +66,7 @@ export class AggsCommonService {
};
}

public start({
getConfig,
getIndexPattern,
isDefaultTimezone,
}: AggsCommonStartDependencies): AggsCommonStart {
public start({ getConfig }: AggsCommonStartDependencies): AggsCommonStart {
const aggTypesStart = this.aggTypesRegistry.start();
const calculateAutoTimeExpression = getCalculateAutoTimeExpression(getConfig);

Expand All @@ -86,11 +81,6 @@ export class AggsCommonService {

return {
calculateAutoTimeExpression,
datatableUtilities: getDatatableColumnUtilities({
getIndexPattern,
createAggConfigs,
aggTypesStart,
}),
createAggConfigs,
types: aggTypesStart,
};
Expand Down
7 changes: 0 additions & 7 deletions src/plugins/data/common/search/aggs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/

import { Assign } from '@kbn/utility-types';
import { DatatableColumn } from 'src/plugins/expressions';
import { IndexPattern } from '../..';
import {
aggAvg,
Expand Down Expand Up @@ -88,7 +87,6 @@ import {
CreateAggConfigParams,
getCalculateAutoTimeExpression,
METRIC_TYPES,
AggConfig,
aggFilteredMetric,
aggSinglePercentile,
} from './';
Expand All @@ -111,11 +109,6 @@ export interface AggsCommonSetup {

export interface AggsCommonStart {
calculateAutoTimeExpression: ReturnType<typeof getCalculateAutoTimeExpression>;
datatableUtilities: {
getIndexPattern: (column: DatatableColumn) => Promise<IndexPattern | undefined>;
getAggConfig: (column: DatatableColumn) => Promise<AggConfig | undefined>;
isFilterable: (column: DatatableColumn) => boolean;
};
createAggConfigs: (
indexPattern: IndexPattern,
configStates?: CreateAggConfigParams[]
Expand Down
57 changes: 0 additions & 57 deletions src/plugins/data/common/search/aggs/utils/datatable_column_meta.ts

This file was deleted.

Loading

0 comments on commit 12f42e0

Please sign in to comment.