Skip to content

Commit 3c4b5c7

Browse files
committed
[ML] Improve runtime mappings validation.
1 parent 18d936b commit 3c4b5c7

File tree

4 files changed

+75
-6
lines changed

4 files changed

+75
-6
lines changed

x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor/advanced_runtime_mappings_editor.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { EuiCodeEditor } from '@elastic/eui';
1313
import { i18n } from '@kbn/i18n';
1414

1515
import { StepDefineFormHook } from '../step_define';
16+
import { isRuntimeMappings } from '../step_define/common/types';
1617

1718
export const AdvancedRuntimeMappingsEditor: FC<StepDefineFormHook['runtimeMappingsEditor']> = memo(
1819
({
@@ -43,8 +44,8 @@ export const AdvancedRuntimeMappingsEditor: FC<StepDefineFormHook['runtimeMappin
4344
// Try to parse the string passed on from the editor.
4445
// If parsing fails, the "Apply"-Button will be disabled
4546
try {
46-
JSON.parse(convertToJson(d));
47-
setRuntimeMappingsEditorApplyButtonEnabled(true);
47+
const parsedJson = JSON.parse(convertToJson(d));
48+
setRuntimeMappingsEditorApplyButtonEnabled(isRuntimeMappings(parsedJson));
4849
} catch (e) {
4950
setRuntimeMappingsEditorApplyButtonEnabled(false);
5051
}

x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/get_pivot_dropdown_options.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
import { getDefaultAggregationConfig } from './get_default_aggregation_config';
2727
import { getDefaultGroupByConfig } from './get_default_group_by_config';
2828
import type { Field, StepDefineExposedState } from './types';
29-
import { isPopulatedObject } from '../../../../../common/utils/object_utils';
29+
import { isRuntimeMappings } from './types';
3030

3131
const illegalEsAggNameChars = /[[\]>]/g;
3232

@@ -77,7 +77,7 @@ export function getPivotDropdownOptions(
7777

7878
// Support for runtime_mappings that are defined by queries
7979
let runtimeFields: Field[] = [];
80-
if (isPopulatedObject(runtimeMappings)) {
80+
if (isRuntimeMappings(runtimeMappings)) {
8181
runtimeFields = Object.keys(runtimeMappings).map((fieldName) => {
8282
const field = runtimeMappings[fieldName];
8383
return { name: fieldName, type: getKibanaFieldTypeFromEsType(field.type) };
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { isRuntimeField, isRuntimeMappings } from './types';
9+
10+
describe('Transform: step_define type guards', () => {
11+
it('isRuntimeField()', () => {
12+
expect(isRuntimeField(1)).toBe(false);
13+
expect(isRuntimeField(null)).toBe(false);
14+
expect(isRuntimeField([])).toBe(false);
15+
expect(isRuntimeField({})).toBe(false);
16+
expect(isRuntimeField({ someAttribute: 'someValue' })).toBe(false);
17+
expect(isRuntimeField({ type: 'wrong-type' })).toBe(false);
18+
expect(isRuntimeField({ type: 'keyword', someAttribute: 'some value' })).toBe(false);
19+
20+
expect(isRuntimeField({ type: 'keyword' })).toBe(true);
21+
expect(isRuntimeField({ type: 'keyword', script: 'some script' })).toBe(true);
22+
});
23+
24+
it('isRuntimeMappings()', () => {
25+
expect(isRuntimeMappings(1)).toBe(false);
26+
expect(isRuntimeMappings(null)).toBe(false);
27+
expect(isRuntimeMappings([])).toBe(false);
28+
expect(isRuntimeMappings({})).toBe(false);
29+
expect(isRuntimeMappings({ someAttribute: 'someValue' })).toBe(false);
30+
expect(isRuntimeMappings({ fieldName1: { type: 'keyword' }, fieldName2: 'someValue' })).toBe(
31+
false
32+
);
33+
expect(
34+
isRuntimeMappings({
35+
fieldName1: { type: 'keyword' },
36+
fieldName2: { type: 'keyword', someAttribute: 'some value' },
37+
})
38+
).toBe(false);
39+
40+
expect(isRuntimeMappings({ fieldName: { type: 'keyword' } })).toBe(true);
41+
expect(
42+
isRuntimeMappings({ fieldName1: { type: 'keyword' }, fieldName2: { type: 'keyword' } })
43+
).toBe(true);
44+
expect(
45+
isRuntimeMappings({
46+
fieldName1: { type: 'keyword' },
47+
fieldName2: { type: 'keyword', script: 'some script' },
48+
})
49+
).toBe(true);
50+
});
51+
});

x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {
2424
} from '../../../../../../../common/types/transform';
2525
import { LatestFunctionConfig } from '../../../../../../../common/api_schemas/transforms';
2626

27+
import { isPopulatedObject } from '../../../../../common/utils/object_utils';
28+
2729
export interface ErrorMessage {
2830
query: string;
2931
message: string;
@@ -70,10 +72,25 @@ export interface StepDefineExposedState {
7072
isRuntimeMappingsEditorEnabled: boolean;
7173
}
7274

75+
export function isRuntimeField(arg: any): arg is RuntimeField {
76+
return (
77+
isPopulatedObject(arg) &&
78+
((Object.keys(arg).length === 1 && arg.hasOwnProperty('type')) ||
79+
(Object.keys(arg).length === 2 &&
80+
arg.hasOwnProperty('type') &&
81+
arg.hasOwnProperty('script'))) &&
82+
RUNTIME_FIELD_TYPES.includes(arg.type)
83+
);
84+
}
85+
86+
export function isRuntimeMappings(arg: any): arg is RuntimeMappings {
87+
return isPopulatedObject(arg) && Object.values(arg).every((d) => isRuntimeField(d));
88+
}
89+
7390
export function isPivotPartialRequest(arg: any): arg is { pivot: PivotConfigDefinition } {
74-
return typeof arg === 'object' && arg.hasOwnProperty('pivot');
91+
return isPopulatedObject(arg) && arg.hasOwnProperty('pivot');
7592
}
7693

7794
export function isLatestPartialRequest(arg: any): arg is { latest: LatestFunctionConfig } {
78-
return typeof arg === 'object' && arg.hasOwnProperty('latest');
95+
return isPopulatedObject(arg) && arg.hasOwnProperty('latest');
7996
}

0 commit comments

Comments
 (0)