From 0754cd7c3d65abdf05f2004df90e56adf27d6483 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Thu, 15 Oct 2020 05:20:16 -0700 Subject: [PATCH] cleaning up expression service types --- .../expressions/common/execution/execution.ts | 58 ++++++++----------- .../common/execution/execution_contract.ts | 9 +-- .../expressions/common/execution/types.ts | 2 + .../expressions/common/executor/executor.ts | 36 ++++-------- .../common/service/expressions_services.ts | 43 +++++++++----- src/plugins/expressions/public/loader.ts | 4 ++ src/plugins/expressions/public/types/index.ts | 2 + 7 files changed, 74 insertions(+), 80 deletions(-) diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index d4c9b0a25d45b78..560f28114c9b71c 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -18,7 +18,7 @@ */ import { keys, last, mapValues, reduce, zipObject } from 'lodash'; -import { Executor, ExpressionExecOptions } from '../executor'; +import { Executor } from '../executor'; import { createExecutionContainer, ExecutionContainer } from './container'; import { createError } from '../util'; import { Defer, now } from '../../../kibana_utils/common'; @@ -38,6 +38,7 @@ import { getType, ExpressionValue } from '../expression_types'; import { ArgumentType, ExpressionFunction } from '../expression_functions'; import { getByAlias } from '../util/get_by_alias'; import { ExecutionContract } from './execution_contract'; +import { ExpressionExecutionParams } from '../service'; const createAbortErrorValue = () => createError({ @@ -45,20 +46,11 @@ const createAbortErrorValue = () => name: 'AbortError', }); -export interface ExecutionParams< - ExtraContext extends Record = Record -> { +export interface ExecutionParams { executor: Executor; ast?: ExpressionAstExpression; expression?: string; - context?: ExtraContext; - - /** - * Whether to execute expression in *debug mode*. In *debug mode* inputs and - * outputs as well as all resolved arguments and time it took to execute each - * function are saved and are available for introspection. - */ - debug?: boolean; + params?: ExpressionExecutionParams; } const createDefaultInspectorAdapters = (): DefaultInspectorAdapters => ({ @@ -67,11 +59,10 @@ const createDefaultInspectorAdapters = (): DefaultInspectorAdapters => ({ }); export class Execution< - ExtraContext extends Record = Record, Input = unknown, Output = unknown, - InspectorAdapters extends Adapters = ExtraContext['inspectorAdapters'] extends object - ? ExtraContext['inspectorAdapters'] + InspectorAdapters extends Adapters = ExpressionExecutionParams['inspectorAdapters'] extends object + ? ExpressionExecutionParams['inspectorAdapters'] : DefaultInspectorAdapters > { /** @@ -91,7 +82,7 @@ export class Execution< * Execution context - object that allows to do side-effects. Context is passed * to every function. */ - public readonly context: ExecutionContext & ExtraContext; + public readonly context: ExecutionContext; /** * AbortController to cancel this Execution. @@ -125,11 +116,10 @@ export class Execution< * can return to other plugins for their consumption. */ public readonly contract: ExecutionContract< - ExtraContext, Input, Output, InspectorAdapters - > = new ExecutionContract(this); + > = new ExecutionContract(this); public readonly expression: string; @@ -141,17 +131,17 @@ export class Execution< return this.context.inspectorAdapters; } - constructor(public readonly params: ExecutionParams) { - const { executor } = params; + constructor(public readonly execution: ExecutionParams) { + const { executor } = execution; - if (!params.ast && !params.expression) { + if (!execution.ast && !execution.expression) { throw new TypeError('Execution params should contain at least .ast or .expression key.'); - } else if (params.ast && params.expression) { + } else if (execution.ast && execution.expression) { throw new TypeError('Execution params cannot contain both .ast and .expression key.'); } - this.expression = params.expression || formatExpression(params.ast!); - const ast = params.ast || parseExpression(this.expression); + this.expression = execution.expression || formatExpression(execution.ast!); + const ast = execution.ast || parseExpression(this.expression); this.state = createExecutionContainer({ ...executor.state.get(), @@ -161,12 +151,12 @@ export class Execution< this.context = { getInitialInput: () => this.input, + getSessionId: () => execution.params?.sessionId, variables: {}, types: executor.getTypes(), abortSignal: this.abortController.signal, - ...(params.context || ({} as ExtraContext)), - inspectorAdapters: (params.context && params.context.inspectorAdapters - ? params.context.inspectorAdapters + inspectorAdapters: (execution.params?.inspectorAdapters + ? execution.params.inspectorAdapters : createDefaultInspectorAdapters()) as InspectorAdapters, }; } @@ -228,10 +218,10 @@ export class Execution< // actually have a `then` function which would be treated as a `Promise`. const { resolvedArgs } = await this.race(this.resolveArgs(fn, input, fnArgs)); args = resolvedArgs; - timeStart = this.params.debug ? now() : 0; + timeStart = this.execution.params.debug ? now() : 0; const output = await this.race(this.invokeFunction(fn, input, resolvedArgs)); - if (this.params.debug) { + if (this.execution.params.debug) { const timeEnd: number = now(); (link as ExpressionAstFunction).debug = { success: true, @@ -246,11 +236,11 @@ export class Execution< if (getType(output) === 'error') return output; input = output; } catch (rawError) { - const timeEnd: number = this.params.debug ? now() : 0; + const timeEnd: number = this.execution.params.debug ? now() : 0; const error = createError(rawError) as ExpressionValueError; error.error.message = `[${fnName}] > ${error.error.message}`; - if (this.params.debug) { + if (this.execution.params.debug) { (link as ExpressionAstFunction).debug = { success: false, fn: fn.name, @@ -384,7 +374,7 @@ export class Execution< return asts.map((item: ExpressionAstExpression) => { return async (subInput = input) => { const output = await this.interpret(item, subInput, { - debug: this.params.debug, + debug: this.execution.params.debug, }); if (isExpressionValueError(output)) throw output.error; const casted = this.cast(output, argDefs[argName as any].types); @@ -420,11 +410,11 @@ export class Execution< public async interpret( ast: ExpressionAstNode, input: T, - options?: ExpressionExecOptions + options?: ExpressionExecutionParams ): Promise { switch (getType(ast)) { case 'expression': - const execution = this.params.executor.createExecution( + const execution = this.execution.executor.createExecution( ast as ExpressionAstExpression, this.context, options diff --git a/src/plugins/expressions/common/execution/execution_contract.ts b/src/plugins/expressions/common/execution/execution_contract.ts index 20c5b2dd434b509..42e250a435d1576 100644 --- a/src/plugins/expressions/common/execution/execution_contract.ts +++ b/src/plugins/expressions/common/execution/execution_contract.ts @@ -25,12 +25,7 @@ import { ExpressionAstExpression } from '../ast'; * `ExecutionContract` is a wrapper around `Execution` class. It provides the * same functionality but does not expose Expressions plugin internals. */ -export class ExecutionContract< - ExtraContext extends Record = Record, - Input = unknown, - Output = unknown, - InspectorAdapters = unknown -> { +export class ExecutionContract { public get isPending(): boolean { const state = this.execution.state.get().state; const finished = state === 'error' || state === 'result'; @@ -38,7 +33,7 @@ export class ExecutionContract< } constructor( - protected readonly execution: Execution + protected readonly execution: Execution ) {} /** diff --git a/src/plugins/expressions/common/execution/types.ts b/src/plugins/expressions/common/execution/types.ts index 7c26e586fb790a5..a5b10c0c170b10d 100644 --- a/src/plugins/expressions/common/execution/types.ts +++ b/src/plugins/expressions/common/execution/types.ts @@ -57,6 +57,8 @@ export interface ExecutionContext string | undefined; + /** * Allows to fetch saved objects from ElasticSearch. In browser `getSavedObject` * function is provided automatically by the Expressions plugin. On the server diff --git a/src/plugins/expressions/common/executor/executor.ts b/src/plugins/expressions/common/executor/executor.ts index 2b5f9f2556d89a1..f8b5652546ea969 100644 --- a/src/plugins/expressions/common/executor/executor.ts +++ b/src/plugins/expressions/common/executor/executor.ts @@ -29,15 +29,7 @@ import { AnyExpressionTypeDefinition } from '../expression_types/types'; import { ExpressionAstExpression } from '../ast'; import { typeSpecs } from '../expression_types/specs'; import { functionSpecs } from '../expression_functions/specs'; - -export interface ExpressionExecOptions { - /** - * Whether to execute expression in *debug mode*. In *debug mode* inputs and - * outputs as well as all resolved arguments and time it took to execute each - * function are saved and are available for introspection. - */ - debug?: boolean; -} +import { ExpressionExecutionParams } from '../service'; export class TypesRegistry implements IRegistry { constructor(private readonly executor: Executor) {} @@ -171,28 +163,22 @@ export class Executor = Record = Record, - Input = unknown, - Output = unknown - >( + public createExecution( ast: string | ExpressionAstExpression, - context: ExtraContext = {} as ExtraContext, - { debug }: ExpressionExecOptions = {} as ExpressionExecOptions - ): Execution { - const params: ExecutionParams = { + params: ExpressionExecutionParams = {} + ): Execution { + const executionParams: ExecutionParams = { executor: this, - context: { + params: { + ...params, ...this.context, - ...context, - } as Context & ExtraContext, - debug, + }, }; - if (typeof ast === 'string') params.expression = ast; - else params.ast = ast; + if (typeof ast === 'string') executionParams.expression = ast; + else executionParams.ast = ast; - const execution = new Execution(params); + const execution = new Execution(executionParams); return execution; } diff --git a/src/plugins/expressions/common/service/expressions_services.ts b/src/plugins/expressions/common/service/expressions_services.ts index b5c98fada07c468..89ddcb5d6ca7d86 100644 --- a/src/plugins/expressions/common/service/expressions_services.ts +++ b/src/plugins/expressions/common/service/expressions_services.ts @@ -21,8 +21,10 @@ import { Executor } from '../executor'; import { AnyExpressionRenderDefinition, ExpressionRendererRegistry } from '../expression_renderers'; import { ExpressionAstExpression } from '../ast'; import { ExecutionContract } from '../execution/execution_contract'; -import { AnyExpressionTypeDefinition } from '../expression_types'; +import { AnyExpressionTypeDefinition, ExpressionValue } from '../expression_types'; import { AnyExpressionFunctionDefinition } from '../expression_functions'; +import { Adapters } from '../../../inspector/common/adapters'; +import { ExecutionContextSearch } from '../execution'; /** * The public contract that `ExpressionsService` provides to other plugins @@ -43,6 +45,23 @@ export type ExpressionsServiceSetup = Pick< | 'fork' >; +export interface ExpressionExecutionParams { + searchContext?: ExecutionContextSearch; + + variables?: Record; + + /** + * Whether to execute expression in *debug mode*. In *debug mode* inputs and + * outputs as well as all resolved arguments and time it took to execute each + * function are saved and are available for introspection. + */ + debug?: boolean; + + sessionId?: string; + + inspectorAdapters?: Adapters; +} + /** * The public contract that `ExpressionsService` provides to other plugins * in Kibana Platform in *start* life-cycle. @@ -96,10 +115,10 @@ export interface ExpressionsServiceStart { * expressions.run('...', null, { elasticsearchClient }); * ``` */ - run: = Record>( + run: ( ast: string | ExpressionAstExpression, input: Input, - context?: ExtraContext + params?: ExpressionExecutionParams ) => Promise; /** @@ -107,16 +126,12 @@ export interface ExpressionsServiceStart { * instance that tracks the progress of the execution and can be used to * interact with the execution. */ - execute: < - Input = unknown, - Output = unknown, - ExtraContext extends Record = Record - >( + execute: ( ast: string | ExpressionAstExpression, // This any is for legacy reasons. input: Input, - context?: ExtraContext - ) => ExecutionContract; + params?: ExpressionExecutionParams + ) => ExecutionContract; /** * Create a new instance of `ExpressionsService`. The new instance inherits @@ -210,8 +225,8 @@ export class ExpressionsService { definition: AnyExpressionRenderDefinition | (() => AnyExpressionRenderDefinition) ): void => this.renderers.register(definition); - public readonly run: ExpressionsServiceStart['run'] = (ast, input, context) => - this.executor.run(ast, input, context); + public readonly run: ExpressionsServiceStart['run'] = (ast, input, params) => + this.executor.run(ast, input, params); public readonly getFunction: ExpressionsServiceStart['getFunction'] = (name) => this.executor.getFunction(name); @@ -242,8 +257,8 @@ export class ExpressionsService { */ public readonly getTypes = (): ReturnType => this.executor.getTypes(); - public readonly execute: ExpressionsServiceStart['execute'] = ((ast, input, context) => { - const execution = this.executor.createExecution(ast, context); + public readonly execute: ExpressionsServiceStart['execute'] = ((ast, input, params) => { + const execution = this.executor.createExecution(ast, params); execution.start(input); return execution.contract; }) as ExpressionsServiceStart['execute']; diff --git a/src/plugins/expressions/public/loader.ts b/src/plugins/expressions/public/loader.ts index c4c40e0812e48f5..b889f73e567ceb5 100644 --- a/src/plugins/expressions/public/loader.ts +++ b/src/plugins/expressions/public/loader.ts @@ -149,6 +149,7 @@ export class ExpressionLoader { search: params.searchContext, variables: params.variables || {}, inspectorAdapters: params.inspectorAdapters, + sessionId: params.sessionId, }); const prevDataHandler = this.execution; @@ -181,6 +182,9 @@ export class ExpressionLoader { if (params.variables && this.params) { this.params.variables = params.variables; } + if (params.sessionId && this.params) { + this.params.sessionId = params.sessionId; + } this.params.inspectorAdapters = (params.inspectorAdapters || this.execution?.inspect()) as Adapters; diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index 5e349c95d255546..d4e309a480bd8e8 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -51,6 +51,8 @@ export interface IExpressionLoaderParams { uiState?: unknown; inspectorAdapters?: Adapters; onRenderError?: RenderErrorHandlerFnType; + sessionId?: string; + debug: boolean; } export interface ExpressionRenderError extends Error {