From 97677aadf771623c112b133b74ca4c3d5e8db2da Mon Sep 17 00:00:00 2001 From: ppisljar Date: Tue, 14 Jan 2020 14:03:04 -0500 Subject: [PATCH 1/3] variable support for interpreter --- src/plugins/expressions/public/execute.ts | 1 + .../expressions/public/functions/var.ts | 53 +++++++++++++++++ .../expressions/public/functions/var_set.ts | 58 +++++++++++++++++++ src/plugins/expressions/public/loader.ts | 3 + src/plugins/expressions/public/plugin.ts | 4 ++ src/plugins/expressions/public/types/index.ts | 1 + 6 files changed, 120 insertions(+) create mode 100644 src/plugins/expressions/public/functions/var.ts create mode 100644 src/plugins/expressions/public/functions/var_set.ts diff --git a/src/plugins/expressions/public/execute.ts b/src/plugins/expressions/public/execute.ts index 12e84f677ce3e..89ef272a0d023 100644 --- a/src/plugins/expressions/public/execute.ts +++ b/src/plugins/expressions/public/execute.ts @@ -65,6 +65,7 @@ export class ExpressionDataHandler { getInitialContext, inspectorAdapters: this.inspectorAdapters, abortSignal: this.abortController.signal, + variables: params.variables, }) .then( (v: IInterpreterResult) => { diff --git a/src/plugins/expressions/public/functions/var.ts b/src/plugins/expressions/public/functions/var.ts new file mode 100644 index 0000000000000..796534a08bc0d --- /dev/null +++ b/src/plugins/expressions/public/functions/var.ts @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { ExpressionFunction } from '../../common/types'; + +interface Arguments { + name: string; +} + +type Context = any; +type ExpressionFunctionVar = ExpressionFunction<'var', Context, Arguments, any>; + +export const variable = (): ExpressionFunctionVar => ({ + name: 'var', + help: i18n.translate('expressions.functions.var.help', { + defaultMessage: 'Updates kibana global context', + }), + args: { + name: { + types: ['string'], + aliases: ['_'], + required: true, + help: i18n.translate('expressions.functions.var.name.help', { + defaultMessage: 'Specify name of the variable', + }), + }, + }, + async fn(context, args, handlers) { + const variables: Record = handlers.variables; + if (!variables[args.name]) { + throw new Error(`Variable "${args.name}" does not exist`); + } + + return variables[args.name]; + }, +}); diff --git a/src/plugins/expressions/public/functions/var_set.ts b/src/plugins/expressions/public/functions/var_set.ts new file mode 100644 index 0000000000000..0b78bb40d0bb4 --- /dev/null +++ b/src/plugins/expressions/public/functions/var_set.ts @@ -0,0 +1,58 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { ExpressionFunction } from '../../common/types'; + +interface Arguments { + name: string; + value?: any; +} + +type Context = any; +type ExpressionFunctionVarSet = ExpressionFunction<'var_set', Context, Arguments, Context>; + +export const variableSet = (): ExpressionFunctionVarSet => ({ + name: 'var_set', + help: i18n.translate('expressions.functions.varset.help', { + defaultMessage: 'Updates kibana global context', + }), + args: { + name: { + types: ['string'], + aliases: ['_'], + required: true, + help: i18n.translate('expressions.functions.varset.name.help', { + defaultMessage: 'Specify name of the variable', + }), + }, + value: { + aliases: ['val'], + help: i18n.translate('expressions.functions.varset.val.help', { + defaultMessage: + 'Specify value for the variable. If not provided input context will be used', + }), + }, + }, + async fn(context, args, handlers) { + const variables: Record = handlers.variables; + variables[args.name] = args.value === undefined ? context : args.value; + return context; + }, +}); diff --git a/src/plugins/expressions/public/loader.ts b/src/plugins/expressions/public/loader.ts index 0342713f7627b..d714282360f71 100644 --- a/src/plugins/expressions/public/loader.ts +++ b/src/plugins/expressions/public/loader.ts @@ -178,6 +178,9 @@ export class ExpressionLoader { if (params.extraHandlers && this.params) { this.params.extraHandlers = params.extraHandlers; } + if (params.variables && this.params) { + this.params.variables = params.variables; + } } } diff --git a/src/plugins/expressions/public/plugin.ts b/src/plugins/expressions/public/plugin.ts index 7471326cdd749..11f804464704e 100644 --- a/src/plugins/expressions/public/plugin.ts +++ b/src/plugins/expressions/public/plugin.ts @@ -32,6 +32,8 @@ import { clog as clogFunction } from './functions/clog'; import { font as fontFunction } from './functions/font'; import { kibana as kibanaFunction } from './functions/kibana'; import { kibanaContext as kibanaContextFunction } from './functions/kibana_context'; +import { variable } from './functions/var'; +import { variableSet } from './functions/var_set'; import { boolean as booleanType, datatable as datatableType, @@ -109,6 +111,8 @@ export class ExpressionsPublicPlugin registerFunction(fontFunction); registerFunction(kibanaFunction); registerFunction(kibanaContextFunction); + registerFunction(variable); + registerFunction(variableSet); types.register(booleanType); types.register(datatableType); diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index 66a3da48dbee9..e094e5e91d006 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -65,6 +65,7 @@ export interface IExpressionLoaderParams { export interface IInterpreterHandlers { getInitialContext: IGetInitialContext; inspectorAdapters?: Adapters; + variables?: Record; abortSignal?: AbortSignal; } From d83ab8e0f6cf9fcc1b88aeb2feee8d43f83d906b Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 15 Jan 2020 10:54:58 -0500 Subject: [PATCH 2/3] updating based on review --- src/plugins/expressions/public/functions/var.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/plugins/expressions/public/functions/var.ts b/src/plugins/expressions/public/functions/var.ts index 796534a08bc0d..935b3c3f7a258 100644 --- a/src/plugins/expressions/public/functions/var.ts +++ b/src/plugins/expressions/public/functions/var.ts @@ -44,10 +44,6 @@ export const variable = (): ExpressionFunctionVar => ({ }, async fn(context, args, handlers) { const variables: Record = handlers.variables; - if (!variables[args.name]) { - throw new Error(`Variable "${args.name}" does not exist`); - } - return variables[args.name]; }, }); From 2e7e4192953befd3c18cf99c375cd78e33c268a9 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 15 Jan 2020 11:12:48 -0500 Subject: [PATCH 3/3] adding unit tests --- .../public/functions/tests/var.test.ts | 63 ++++++++++++++++ .../public/functions/tests/var_set.test.ts | 74 +++++++++++++++++++ .../expressions/public/functions/var.ts | 2 +- .../expressions/public/functions/var_set.ts | 2 +- 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/plugins/expressions/public/functions/tests/var.test.ts create mode 100644 src/plugins/expressions/public/functions/tests/var_set.test.ts diff --git a/src/plugins/expressions/public/functions/tests/var.test.ts b/src/plugins/expressions/public/functions/tests/var.test.ts new file mode 100644 index 0000000000000..fe5963ec8c509 --- /dev/null +++ b/src/plugins/expressions/public/functions/tests/var.test.ts @@ -0,0 +1,63 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from './utils'; +import { variable } from '../var'; +import { FunctionHandlers } from '../../../common/types'; +import { KibanaContext } from '../../../common/expression_types/kibana_context'; + +describe('interpreter/functions#var', () => { + const fn = functionWrapper(variable); + let context: Partial; + let initialContext: KibanaContext; + let handlers: FunctionHandlers; + + beforeEach(() => { + context = { timeRange: { from: '0', to: '1' } }; + initialContext = { + type: 'kibana_context', + query: { language: 'lucene', query: 'geo.src:US' }, + filters: [ + { + meta: { + disabled: false, + negate: false, + alias: null, + }, + query: { match: {} }, + }, + ], + timeRange: { from: '2', to: '3' }, + }; + handlers = { + getInitialContext: () => initialContext, + variables: { test: 1 } as any, + }; + }); + + it('returns the selected variable', () => { + const actual = fn(context, { name: 'test' }, handlers); + expect(actual).toEqual(1); + }); + + it('returns undefined if variable does not exist', () => { + const actual = fn(context, { name: 'unknown' }, handlers); + expect(actual).toEqual(undefined); + }); +}); diff --git a/src/plugins/expressions/public/functions/tests/var_set.test.ts b/src/plugins/expressions/public/functions/tests/var_set.test.ts new file mode 100644 index 0000000000000..7efa8ebc0dd3f --- /dev/null +++ b/src/plugins/expressions/public/functions/tests/var_set.test.ts @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from './utils'; +import { variableSet } from '../var_set'; +import { FunctionHandlers } from '../../../common/types'; +import { KibanaContext } from '../../../common/expression_types/kibana_context'; + +describe('interpreter/functions#varset', () => { + const fn = functionWrapper(variableSet); + let context: Partial; + let initialContext: KibanaContext; + let handlers: FunctionHandlers; + let variables: Record; + + beforeEach(() => { + context = { timeRange: { from: '0', to: '1' } }; + initialContext = { + type: 'kibana_context', + query: { language: 'lucene', query: 'geo.src:US' }, + filters: [ + { + meta: { + disabled: false, + negate: false, + alias: null, + }, + query: { match: {} }, + }, + ], + timeRange: { from: '2', to: '3' }, + }; + handlers = { + getInitialContext: () => initialContext, + variables: { test: 1 } as any, + }; + + variables = handlers.variables; + }); + + it('updates a variable', () => { + const actual = fn(context, { name: 'test', value: 2 }, handlers); + expect(variables.test).toEqual(2); + expect(actual).toEqual(context); + }); + + it('sets a new variable', () => { + const actual = fn(context, { name: 'new', value: 3 }, handlers); + expect(variables.new).toEqual(3); + expect(actual).toEqual(context); + }); + + it('stores context if value is not set', () => { + const actual = fn(context, { name: 'test' }, handlers); + expect(variables.test).toEqual(context); + expect(actual).toEqual(context); + }); +}); diff --git a/src/plugins/expressions/public/functions/var.ts b/src/plugins/expressions/public/functions/var.ts index 935b3c3f7a258..9410149060216 100644 --- a/src/plugins/expressions/public/functions/var.ts +++ b/src/plugins/expressions/public/functions/var.ts @@ -42,7 +42,7 @@ export const variable = (): ExpressionFunctionVar => ({ }), }, }, - async fn(context, args, handlers) { + fn(context, args, handlers) { const variables: Record = handlers.variables; return variables[args.name]; }, diff --git a/src/plugins/expressions/public/functions/var_set.ts b/src/plugins/expressions/public/functions/var_set.ts index 0b78bb40d0bb4..a10ee7a00814f 100644 --- a/src/plugins/expressions/public/functions/var_set.ts +++ b/src/plugins/expressions/public/functions/var_set.ts @@ -50,7 +50,7 @@ export const variableSet = (): ExpressionFunctionVarSet => ({ }), }, }, - async fn(context, args, handlers) { + fn(context, args, handlers) { const variables: Record = handlers.variables; variables[args.name] = args.value === undefined ? context : args.value; return context;