From 0f9a80752a81190c8e0a5315ff346bd84212b2b5 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 17 Sep 2020 12:24:19 +0200 Subject: [PATCH] =?UTF-8?q?improve=20=E2=80=9Cnull=E2=80=9D=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../url_drilldown/url_drilldown_scope.test.ts | 29 ++++++++++++++++++- .../url_drilldown/url_drilldown_scope.ts | 14 +++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/embeddable_enhanced/public/drilldowns/url_drilldown/url_drilldown_scope.test.ts b/x-pack/plugins/embeddable_enhanced/public/drilldowns/url_drilldown/url_drilldown_scope.test.ts index 503367741fa8a..bb1baf5b96428 100644 --- a/x-pack/plugins/embeddable_enhanced/public/drilldowns/url_drilldown/url_drilldown_scope.test.ts +++ b/x-pack/plugins/embeddable_enhanced/public/drilldowns/url_drilldown/url_drilldown_scope.test.ts @@ -10,7 +10,13 @@ import { ValueClickTriggerEventScope, } from './url_drilldown_scope'; -const createPoint = ({ field, value }: { field: string; value: string }) => ({ +const createPoint = ({ + field, + value, +}: { + field: string; + value: string | null | number | boolean; +}) => ({ table: { columns: [ { @@ -99,4 +105,25 @@ describe('VALUE_CLICK_TRIGGER', () => { `); }); }); + + describe('handles undefined, null or missing values', () => { + test('undefined or missing values are removed from the result scope', () => { + const point = createPoint({ field: undefined } as any); + const eventScope = getEventScope({ + data: { data: [point] }, + }) as ValueClickTriggerEventScope; + + expect('key' in eventScope).toBeFalsy(); + expect('value' in eventScope).toBeFalsy(); + }); + + test('null value stays in the result scope', () => { + const point = createPoint({ field: 'field', value: null }); + const eventScope = getEventScope({ + data: { data: [point] }, + }) as ValueClickTriggerEventScope; + + expect(eventScope.value).toBeNull(); + }); + }); }); diff --git a/x-pack/plugins/embeddable_enhanced/public/drilldowns/url_drilldown/url_drilldown_scope.ts b/x-pack/plugins/embeddable_enhanced/public/drilldowns/url_drilldown/url_drilldown_scope.ts index 0b82d2edb9501..15a9a3ba77d88 100644 --- a/x-pack/plugins/embeddable_enhanced/public/drilldowns/url_drilldown/url_drilldown_scope.ts +++ b/x-pack/plugins/embeddable_enhanced/public/drilldowns/url_drilldown/url_drilldown_scope.ts @@ -105,9 +105,9 @@ export type UrlDrilldownEventScope = ValueClickTriggerEventScope | RangeSelectTr export type EventScopeInput = ActionContext; export interface ValueClickTriggerEventScope { key?: string; - value: string | number | boolean; + value: Primitive; negate: boolean; - points: Array<{ key?: string; value: string | number | boolean }>; + points: Array<{ key?: string; value: Primitive }>; } export interface RangeSelectTriggerEventScope { key: string; @@ -144,7 +144,7 @@ function getEventScopeFromValueClickTriggerContext( const points = eventScopeInput.data.data.map(({ table, value, column: columnIndex }) => { const column = table.columns[columnIndex]; return { - value: toPrimitiveOrUndefined(value) as string | number | boolean, + value: toPrimitiveOrUndefined(value) as Primitive, key: toPrimitiveOrUndefined(column?.meta?.aggConfigParams?.field) as string | undefined, }; }); @@ -186,10 +186,12 @@ export function getMockEventScope([trigger]: UrlTrigger[]): UrlDrilldownEventSco } } -function toPrimitiveOrUndefined(v: unknown): string | number | boolean | undefined { - if (typeof v === 'number' || typeof v === 'boolean' || typeof v === 'string') return v; +type Primitive = string | number | boolean | null; +function toPrimitiveOrUndefined(v: unknown): Primitive | undefined { + if (typeof v === 'number' || typeof v === 'boolean' || typeof v === 'string' || v === null) + return v; if (typeof v === 'object' && v instanceof Date) return v.toISOString(); - if (typeof v === 'undefined' || v === null) return undefined; + if (typeof v === 'undefined') return undefined; return String(v); }