From d964c840864bda0c6a093b49a594ad50796e917b Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Fri, 5 Jun 2020 14:23:32 -0700 Subject: [PATCH 01/24] [search] Refactor the way search strategies are registered/retrieved on the server --- .../server/async_demo_search_strategy.ts | 46 ++++---- .../server/demo_search_strategy.ts | 6 +- examples/demo_search/server/plugin.ts | 13 +- src/plugins/data/server/index.ts | 6 +- src/plugins/data/server/plugin.ts | 4 +- .../data/server/search/create_api.test.ts | 71 ----------- src/plugins/data/server/search/create_api.ts | 58 --------- .../search/es_search/es_search_strategy.ts | 24 ++-- .../search/i_route_handler_search_context.ts | 25 ---- src/plugins/data/server/search/i_search.ts | 55 --------- .../data/server/search/i_search_context.ts | 26 ---- .../data/server/search/i_search_setup.ts | 40 ------- .../data/server/search/i_search_strategy.ts | 67 ----------- src/plugins/data/server/search/index.ts | 14 +-- src/plugins/data/server/search/routes.ts | 19 ++- .../data/server/search/search_service.ts | 86 +++++--------- .../data/server/search/strategy_types.ts | 39 ------ src/plugins/data/server/search/types.ts | 111 ++++++++++++++++++ x-pack/plugins/data_enhanced/server/plugin.ts | 5 +- .../server/search/es_search_strategy.ts | 25 ++-- 20 files changed, 227 insertions(+), 513 deletions(-) delete mode 100644 src/plugins/data/server/search/create_api.test.ts delete mode 100644 src/plugins/data/server/search/create_api.ts delete mode 100644 src/plugins/data/server/search/i_route_handler_search_context.ts delete mode 100644 src/plugins/data/server/search/i_search.ts delete mode 100644 src/plugins/data/server/search/i_search_context.ts delete mode 100644 src/plugins/data/server/search/i_search_setup.ts delete mode 100644 src/plugins/data/server/search/i_search_strategy.ts delete mode 100644 src/plugins/data/server/search/strategy_types.ts create mode 100644 src/plugins/data/server/search/types.ts diff --git a/examples/demo_search/server/async_demo_search_strategy.ts b/examples/demo_search/server/async_demo_search_strategy.ts index 7ed5062acba484..dc8490ea983ea8 100644 --- a/examples/demo_search/server/async_demo_search_strategy.ts +++ b/examples/demo_search/server/async_demo_search_strategy.ts @@ -17,30 +17,32 @@ * under the License. */ -import { TSearchStrategyProvider } from '../../../src/plugins/data/server'; +import { ISearchStrategy } from '../../../src/plugins/data/server'; import { ASYNC_DEMO_SEARCH_STRATEGY } from '../common'; -function getFibonacciSequence(n = 0) { - const beginning = [0, 1].slice(0, n); - return Array(Math.max(0, n)) - .fill(null) - .reduce((sequence, value, i) => { - if (i < 2) return sequence; - return [...sequence, sequence[i - 1] + sequence[i - 2]]; - }, beginning); -} - -const generateId = (() => { - let id = 0; - return () => `${id++}`; -})(); - -const loadedMap = new Map(); -const totalMap = new Map(); - -export const asyncDemoSearchStrategyProvider: TSearchStrategyProvider = () => { +export const asyncDemoSearchStrategyProvider = (): ISearchStrategy< + typeof ASYNC_DEMO_SEARCH_STRATEGY +> => { + function getFibonacciSequence(n = 0) { + const beginning = [0, 1].slice(0, n); + return Array(Math.max(0, n)) + .fill(null) + .reduce((sequence, value, i) => { + if (i < 2) return sequence; + return [...sequence, sequence[i - 1] + sequence[i - 2]]; + }, beginning); + } + + const generateId = (() => { + let id = 0; + return () => `${id++}`; + })(); + + const loadedMap = new Map(); + const totalMap = new Map(); + return { - search: async (request) => { + search: async (context, request) => { const id = request.id ?? generateId(); const loaded = (loadedMap.get(id) ?? 0) + 1; @@ -52,7 +54,7 @@ export const asyncDemoSearchStrategyProvider: TSearchStrategyProvider { + cancel: async (context, id) => { loadedMap.delete(id); totalMap.delete(id); }, diff --git a/examples/demo_search/server/demo_search_strategy.ts b/examples/demo_search/server/demo_search_strategy.ts index a1fd0e45dbc8e7..7e307497a98b75 100644 --- a/examples/demo_search/server/demo_search_strategy.ts +++ b/examples/demo_search/server/demo_search_strategy.ts @@ -17,12 +17,12 @@ * under the License. */ -import { TSearchStrategyProvider } from '../../../src/plugins/data/server'; +import { ISearchStrategy } from '../../../src/plugins/data/server'; import { DEMO_SEARCH_STRATEGY } from '../common'; -export const demoSearchStrategyProvider: TSearchStrategyProvider = () => { +export const demoSearchStrategyProvider = (): ISearchStrategy => { return { - search: (request) => { + search: (context, request) => { return Promise.resolve({ greeting: request.mood === 'happy' diff --git a/examples/demo_search/server/plugin.ts b/examples/demo_search/server/plugin.ts index 49fbae43e3aa28..8bf63120c19e65 100644 --- a/examples/demo_search/server/plugin.ts +++ b/examples/demo_search/server/plugin.ts @@ -56,18 +56,13 @@ declare module '../../../src/plugins/data/server' { } export class DemoDataPlugin implements Plugin { - constructor(private initializerContext: PluginInitializerContext) {} + constructor() {} public setup(core: CoreSetup, deps: IDemoSearchExplorerDeps) { - deps.data.search.registerSearchStrategyProvider( - this.initializerContext.opaqueId, - DEMO_SEARCH_STRATEGY, - demoSearchStrategyProvider - ); - deps.data.search.registerSearchStrategyProvider( - this.initializerContext.opaqueId, + deps.data.search.registerSearchStrategy(DEMO_SEARCH_STRATEGY, demoSearchStrategyProvider()); + deps.data.search.registerSearchStrategy( ASYNC_DEMO_SEARCH_STRATEGY, - asyncDemoSearchStrategyProvider + asyncDemoSearchStrategyProvider() ); } diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 831d23864d2287..16ac59e300237d 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -172,8 +172,10 @@ export { ISearchOptions, IRequestTypesMap, IResponseTypesMap, - ISearchContext, - TSearchStrategyProvider, + ISearchSetup, + ISearchStart, + TStrategyTypes, + ISearchStrategy, getDefaultSearchParams, getTotalLoaded, } from './search'; diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index 8c9d0df2ed8947..ecc506ad2f9e25 100644 --- a/src/plugins/data/server/plugin.ts +++ b/src/plugins/data/server/plugin.ts @@ -20,7 +20,7 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/server'; import { ConfigSchema } from '../config'; import { IndexPatternsService } from './index_patterns'; -import { ISearchSetup } from './search'; +import { ISearchSetup, ISearchStart } from './search'; import { SearchService } from './search/search_service'; import { QueryService } from './query/query_service'; import { ScriptsService } from './scripts'; @@ -36,6 +36,7 @@ export interface DataPluginSetup { } export interface DataPluginStart { + search: ISearchStart; fieldFormats: FieldFormatsStart; } @@ -76,6 +77,7 @@ export class DataServerPlugin implements Plugin Promise.resolve({ total: 100, loaded: 0 })); -const mockDefaultSearchStrategyProvider = jest.fn(() => - Promise.resolve({ - search: mockDefaultSearch, - }) -); -const mockStrategies: TSearchStrategiesMap = { - [DEFAULT_SEARCH_STRATEGY]: mockDefaultSearchStrategyProvider, -}; - -describe('createApi', () => { - let api: IRouteHandlerSearchContext; - - beforeEach(() => { - api = createApi({ - caller: jest.fn(), - searchStrategies: mockStrategies, - }); - mockDefaultSearchStrategyProvider.mockClear(); - }); - - it('should default to DEFAULT_SEARCH_STRATEGY if none is provided', async () => { - await api.search({ - params: {}, - }); - expect(mockDefaultSearchStrategyProvider).toBeCalled(); - expect(mockDefaultSearch).toBeCalled(); - }); - - it('should throw if no provider is found for the given name', () => { - expect(api.search({}, {}, 'noneByThisName')).rejects.toThrowErrorMatchingInlineSnapshot( - `"No strategy found for noneByThisName"` - ); - }); - - it('logs the response if `debug` is set to `true`', async () => { - const spy = jest.spyOn(console, 'log'); - await api.search({ params: {} }); - - expect(spy).not.toBeCalled(); - - await api.search({ debug: true, params: {} }); - - expect(spy).toBeCalled(); - }); -}); diff --git a/src/plugins/data/server/search/create_api.ts b/src/plugins/data/server/search/create_api.ts deleted file mode 100644 index 00665b21f2ba75..00000000000000 --- a/src/plugins/data/server/search/create_api.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 { APICaller } from 'kibana/server'; -import { IRouteHandlerSearchContext } from './i_route_handler_search_context'; -import { DEFAULT_SEARCH_STRATEGY } from '../../common/search'; -import { TSearchStrategiesMap } from './i_search_strategy'; - -export function createApi({ - caller, - searchStrategies, -}: { - searchStrategies: TSearchStrategiesMap; - caller: APICaller; -}) { - const api: IRouteHandlerSearchContext = { - search: async (request, options, strategyName) => { - if (request.debug) { - // eslint-disable-next-line - console.log(JSON.stringify(request, null, 2)); - } - const name = strategyName ?? DEFAULT_SEARCH_STRATEGY; - const strategyProvider = searchStrategies[name]; - if (!strategyProvider) { - throw new Error(`No strategy found for ${strategyName}`); - } - // Give providers access to other search strategies by injecting this function - const strategy = await strategyProvider(caller, api.search); - return strategy.search(request, options); - }, - cancel: async (id, strategyName) => { - const name = strategyName ?? DEFAULT_SEARCH_STRATEGY; - const strategyProvider = searchStrategies[name]; - if (!strategyProvider) { - throw new Error(`No strategy found for ${strategyName}`); - } - const strategy = await strategyProvider(caller, api.search); - return strategy.cancel && strategy.cancel(id); - }, - }; - return api; -} diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.ts b/src/plugins/data/server/search/es_search/es_search_strategy.ts index 47cad7aa6b4d75..e8b4d327097378 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.ts @@ -17,19 +17,18 @@ * under the License. */ import { first } from 'rxjs/operators'; -import { APICaller } from 'kibana/server'; +import { RequestHandlerContext, SharedGlobalConfig } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; +import { Observable } from 'rxjs'; import { ES_SEARCH_STRATEGY } from '../../../common/search'; -import { ISearchStrategy, TSearchStrategyProvider } from '../i_search_strategy'; -import { getDefaultSearchParams, getTotalLoaded, ISearchContext } from '..'; +import { ISearchStrategy, getDefaultSearchParams, getTotalLoaded } from '..'; -export const esSearchStrategyProvider: TSearchStrategyProvider = ( - context: ISearchContext, - caller: APICaller -): ISearchStrategy => { +export const esSearchStrategyProvider = async ( + config$: Observable +): Promise> => { + const config = await config$.pipe(first()).toPromise(); return { - search: async (request, options) => { - const config = await context.config$.pipe(first()).toPromise(); + search: async (context: RequestHandlerContext, request, options) => { const defaultParams = getDefaultSearchParams(config); // Only default index pattern type is supported here. @@ -42,7 +41,12 @@ export const esSearchStrategyProvider: TSearchStrategyProvider; + + const rawResponse = (await context.core.elasticsearch.legacy.client.callAsCurrentUser( + 'search', + params, + options + )) as SearchResponse; // The above query will either complete or timeout and throw an error. // There is no progress indication on this api. diff --git a/src/plugins/data/server/search/i_route_handler_search_context.ts b/src/plugins/data/server/search/i_route_handler_search_context.ts deleted file mode 100644 index 9888c774ea104c..00000000000000 --- a/src/plugins/data/server/search/i_route_handler_search_context.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 { ISearchGeneric, ISearchCancelGeneric } from './i_search'; - -export interface IRouteHandlerSearchContext { - search: ISearchGeneric; - cancel: ISearchCancelGeneric; -} diff --git a/src/plugins/data/server/search/i_search.ts b/src/plugins/data/server/search/i_search.ts deleted file mode 100644 index fa4aa72ac7287e..00000000000000 --- a/src/plugins/data/server/search/i_search.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 { IKibanaSearchResponse, IKibanaSearchRequest } from '../../common/search'; -import { TStrategyTypes } from './strategy_types'; -import { ES_SEARCH_STRATEGY, IEsSearchResponse } from '../../common/search/es_search'; -import { IEsSearchRequest } from './es_search'; - -export interface ISearchOptions { - signal?: AbortSignal; -} - -export interface IRequestTypesMap { - [ES_SEARCH_STRATEGY]: IEsSearchRequest; - [key: string]: IKibanaSearchRequest; -} - -export interface IResponseTypesMap { - [ES_SEARCH_STRATEGY]: IEsSearchResponse; - [key: string]: IKibanaSearchResponse; -} - -export type ISearchGeneric = ( - request: IRequestTypesMap[T], - options?: ISearchOptions, - strategy?: T -) => Promise; - -export type ISearchCancelGeneric = ( - id: string, - strategy?: T -) => Promise; - -export type ISearch = ( - request: IRequestTypesMap[T], - options?: ISearchOptions -) => Promise; - -export type ISearchCancel = (id: string) => Promise; diff --git a/src/plugins/data/server/search/i_search_context.ts b/src/plugins/data/server/search/i_search_context.ts deleted file mode 100644 index 9d9de055d994fd..00000000000000 --- a/src/plugins/data/server/search/i_search_context.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 { Observable } from 'rxjs'; -import { CoreSetup, SharedGlobalConfig } from '../../../../core/server'; - -export interface ISearchContext { - core: CoreSetup; - config$: Observable; -} diff --git a/src/plugins/data/server/search/i_search_setup.ts b/src/plugins/data/server/search/i_search_setup.ts deleted file mode 100644 index e4a4d501412018..00000000000000 --- a/src/plugins/data/server/search/i_search_setup.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 { IContextProvider } from 'kibana/server'; -import { ISearchContext } from './i_search_context'; -import { TRegisterSearchStrategyProvider, TSearchStrategyProvider } from './i_search_strategy'; - -/** - * The setup contract exposed by the Search plugin exposes the search strategy extension - * point. - */ -export interface ISearchSetup { - registerSearchStrategyContext: ( - pluginId: symbol, - strategyName: TContextName, - provider: IContextProvider, TContextName> - ) => void; - - /** - * Extension point exposed for other plugins to register their own search - * strategies. - */ - registerSearchStrategyProvider: TRegisterSearchStrategyProvider; -} diff --git a/src/plugins/data/server/search/i_search_strategy.ts b/src/plugins/data/server/search/i_search_strategy.ts deleted file mode 100644 index 9b405034f883f7..00000000000000 --- a/src/plugins/data/server/search/i_search_strategy.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 { APICaller } from 'kibana/server'; -import { ISearch, ISearchCancel, ISearchGeneric } from './i_search'; -import { TStrategyTypes } from './strategy_types'; -import { ISearchContext } from './i_search_context'; - -/** - * Search strategy interface contains a search method that takes in - * a request and returns a promise that resolves to a response. - */ -export interface ISearchStrategy { - search: ISearch; - cancel?: ISearchCancel; -} - -/** - * Search strategy provider creates an instance of a search strategy with the request - * handler context bound to it. This way every search strategy can use - * whatever information they require from the request context. - */ -export type TSearchStrategyProviderEnhanced = ( - caller: APICaller, - search: ISearchGeneric -) => Promise>; - -/** - * Search strategy provider creates an instance of a search strategy with the request - * handler context bound to it. This way every search strategy can use - * whatever information they require from the request context. - */ -export type TSearchStrategyProvider = ( - context: ISearchContext, - caller: APICaller, - search: ISearchGeneric -) => ISearchStrategy; - -/** - * Extension point exposed for other plugins to register their own search - * strategies. - */ -export type TRegisterSearchStrategyProvider = ( - opaqueId: symbol, - name: T, - searchStrategyProvider: TSearchStrategyProvider -) => void; - -export type TSearchStrategiesMap = { - [K in TStrategyTypes]?: TSearchStrategyProviderEnhanced; -}; diff --git a/src/plugins/data/server/search/index.ts b/src/plugins/data/server/search/index.ts index e08eba1cad8318..882f56e83d4ca2 100644 --- a/src/plugins/data/server/search/index.ts +++ b/src/plugins/data/server/search/index.ts @@ -17,20 +17,16 @@ * under the License. */ -export { ISearchSetup } from './i_search_setup'; - -export { ISearchContext } from './i_search_context'; - export { ISearch, ISearchCancel, ISearchOptions, IRequestTypesMap, IResponseTypesMap, -} from './i_search'; - -export { TStrategyTypes } from './strategy_types'; - -export { TSearchStrategyProvider } from './i_search_strategy'; + ISearchSetup, + ISearchStart, + TStrategyTypes, + ISearchStrategy, +} from './types'; export { getDefaultSearchParams, getTotalLoaded } from './es_search'; diff --git a/src/plugins/data/server/search/routes.ts b/src/plugins/data/server/search/routes.ts index b90d7d4ff80cea..a1bdf966f3b020 100644 --- a/src/plugins/data/server/search/routes.ts +++ b/src/plugins/data/server/search/routes.ts @@ -18,10 +18,13 @@ */ import { schema } from '@kbn/config-schema'; -import { IRouter } from '../../../../core/server'; +import { CoreSetup } from '../../../../core/server'; import { getRequestAbortedSignal } from '../lib'; +import { DataPluginStart } from '../plugin'; + +export function registerSearchRoute(core: CoreSetup): void { + const router = core.http.createRouter(); -export function registerSearchRoute(router: IRouter): void { router.post( { path: '/internal/search/{strategy}', @@ -38,8 +41,11 @@ export function registerSearchRoute(router: IRouter): void { const { strategy } = request.params; const signal = getRequestAbortedSignal(request.events.aborted$); + const [, , selfStart] = await core.getStartServices(); + const searchStrategy = selfStart.search.getSearchStrategy(strategy); + try { - const response = await context.search!.search(searchRequest, { signal }, strategy); + const response = await searchStrategy.search(context, searchRequest, { signal }); return res.ok({ body: response }); } catch (err) { return res.customError({ @@ -69,8 +75,13 @@ export function registerSearchRoute(router: IRouter): void { }, async (context, request, res) => { const { strategy, id } = request.params; + + const [, , selfStart] = await core.getStartServices(); + const searchStrategy = selfStart.getSearchStrategy(strategy); + if (!searchStrategy.cancel) return res.ok(); + try { - await context.search!.cancel(id, strategy); + await searchStrategy.cancel(context, id); return res.ok(); } catch (err) { return res.customError({ diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 1c267c32ebc37b..12eba0b76b262c 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -17,82 +17,50 @@ * under the License. */ +import { Plugin, PluginInitializerContext, CoreSetup } from '../../../../core/server'; import { - PluginInitializerContext, - Plugin, - CoreSetup, - IContextContainer, -} from '../../../../core/server'; -import { registerSearchRoute } from './routes'; -import { ISearchSetup } from './i_search_setup'; -import { createApi } from './create_api'; -import { + ISearchSetup, + ISearchStart, TSearchStrategiesMap, - TSearchStrategyProvider, - TRegisterSearchStrategyProvider, -} from './i_search_strategy'; -import { IRouteHandlerSearchContext } from './i_route_handler_search_context'; + TRegisterSearchStrategy, + TGetSearchStrategy, +} from './types'; +import { registerSearchRoute } from './routes'; import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './es_search'; - import { searchSavedObjectType } from '../saved_objects'; +import { DataPluginStart } from '../plugin'; -declare module 'kibana/server' { - interface RequestHandlerContext { - search?: IRouteHandlerSearchContext; - } -} - -export class SearchService implements Plugin { +export class SearchService implements Plugin { private searchStrategies: TSearchStrategiesMap = {}; - private contextContainer?: IContextContainer>; - constructor(private initializerContext: PluginInitializerContext) {} - public setup(core: CoreSetup): ISearchSetup { - const router = core.http.createRouter(); - registerSearchRoute(router); - - this.contextContainer = core.context.createContextContainer(); - + public setup(core: CoreSetup): ISearchSetup { core.savedObjects.registerType(searchSavedObjectType); - core.http.registerRouteHandlerContext<'search'>('search', (context) => { - return createApi({ - caller: context.core.elasticsearch.legacy.client.callAsCurrentUser, - searchStrategies: this.searchStrategies, - }); - }); - - const registerSearchStrategyProvider: TRegisterSearchStrategyProvider = ( - plugin, - name, - strategyProvider - ) => { - this.searchStrategies[name] = this.contextContainer!.createHandler(plugin, strategyProvider); - }; - - const api: ISearchSetup = { - registerSearchStrategyContext: this.contextContainer!.registerContext, - registerSearchStrategyProvider, + const registerSearchStrategy: TRegisterSearchStrategy = async (name, strategy) => { + this.searchStrategies[name] = await strategy; }; - api.registerSearchStrategyContext(this.initializerContext.opaqueId, 'core', () => core); - api.registerSearchStrategyContext( - this.initializerContext.opaqueId, - 'config$', - () => this.initializerContext.config.legacy.globalConfig$ - ); - - api.registerSearchStrategyProvider( - this.initializerContext.opaqueId, + registerSearchStrategy( ES_SEARCH_STRATEGY, - esSearchStrategyProvider + esSearchStrategyProvider(this.initializerContext.config.legacy.globalConfig$) ); - return api; + registerSearchRoute(core); + + return { registerSearchStrategy }; } - public start() {} + public start(): ISearchStart { + const getSearchStrategy: TGetSearchStrategy = (name) => { + if (!this.searchStrategies.hasOwnProperty(name)) { + throw new Error('No strategy registered for `${name}`.'); + } + return this.searchStrategies[name]; + }; + + return { getSearchStrategy }; + } public stop() {} } diff --git a/src/plugins/data/server/search/strategy_types.ts b/src/plugins/data/server/search/strategy_types.ts deleted file mode 100644 index 252e0c8f9e6c9d..00000000000000 --- a/src/plugins/data/server/search/strategy_types.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 { ES_SEARCH_STRATEGY } from '../../common/search/es_search'; - -/** - * Contains all known strategy type identifiers that will be used to map to - * request and response shapes. Plugins that wish to add their own custom search - * strategies should extend this type via: - * - * const MY_STRATEGY = 'MY_STRATEGY'; - * - * declare module 'src/plugins/search/server' { - * export interface IRequestTypesMap { - * [MY_STRATEGY]: IMySearchRequest; - * } - * - * export interface IResponseTypesMap { - * [MY_STRATEGY]: IMySearchResponse - * } - * } - */ -export type TStrategyTypes = typeof ES_SEARCH_STRATEGY | string; diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts new file mode 100644 index 00000000000000..a95c707cfb07eb --- /dev/null +++ b/src/plugins/data/server/search/types.ts @@ -0,0 +1,111 @@ +/* + * 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 { RequestHandlerContext } from '../../../../core/server'; +import { IKibanaSearchResponse, IKibanaSearchRequest } from '../../common/search'; +import { ES_SEARCH_STRATEGY, IEsSearchRequest, IEsSearchResponse } from './es_search'; + +export interface ISearchSetup { + /** + * Extension point exposed for other plugins to register their own search + * strategies. + */ + registerSearchStrategy: TRegisterSearchStrategy; +} + +export interface ISearchStart { + /** + * Get other registered search strategies. For example, if a new strategy needs to use the + * already-registered ES search strategy, it can use this function to accomplish that. + */ + getSearchStrategy: TGetSearchStrategy; +} + +export interface ISearchOptions { + /** + * An `AbortSignal` that allows the caller of `search` to abort a search request. + */ + signal?: AbortSignal; +} + +/** + * Contains all known strategy type identifiers that will be used to map to + * request and response shapes. Plugins that wish to add their own custom search + * strategies should extend this type via: + * + * const MY_STRATEGY = 'MY_STRATEGY'; + * + * declare module 'src/plugins/search/server' { + * export interface IRequestTypesMap { + * [MY_STRATEGY]: IMySearchRequest; + * } + * + * export interface IResponseTypesMap { + * [MY_STRATEGY]: IMySearchResponse + * } + * } + */ +export type TStrategyTypes = typeof ES_SEARCH_STRATEGY | string; + +/** + * The map of search strategy IDs to the corresponding request type definitions. + */ +export interface IRequestTypesMap { + [ES_SEARCH_STRATEGY]: IEsSearchRequest; + [key: string]: IKibanaSearchRequest; +} + +/** + * The map of search strategy IDs to the corresponding response type definitions. + */ +export interface IResponseTypesMap { + [ES_SEARCH_STRATEGY]: IEsSearchResponse; + [key: string]: IKibanaSearchResponse; +} + +export type ISearch = ( + context: RequestHandlerContext, + request: IRequestTypesMap[T], + options?: ISearchOptions +) => Promise; + +export type ISearchCancel = ( + context: RequestHandlerContext, + id: string +) => Promise; + +/** + * Search strategy interface contains a search method that takes in a request and returns a promise + * that resolves to a response. + */ +export interface ISearchStrategy { + search: ISearch; + cancel?: ISearchCancel; +} + +export type TRegisterSearchStrategy = ( + name: T, + searchStrategy: Promise> +) => void; + +export type TGetSearchStrategy = (name: T) => ISearchStrategy; + +export type TSearchStrategiesMap = { + [K in TStrategyTypes]?: ISearchStrategy; +}; diff --git a/x-pack/plugins/data_enhanced/server/plugin.ts b/x-pack/plugins/data_enhanced/server/plugin.ts index a27a73431574b5..4f6756231912cc 100644 --- a/x-pack/plugins/data_enhanced/server/plugin.ts +++ b/x-pack/plugins/data_enhanced/server/plugin.ts @@ -22,10 +22,9 @@ export class EnhancedDataServerPlugin implements Plugin { response: SearchResponse; } -export const enhancedEsSearchStrategyProvider: TSearchStrategyProvider = ( - context: ISearchContext, - caller: APICaller -) => { +export const enhancedEsSearchStrategyProvider = async ( + config$: Observable +): Promise> => { + const config = await config$.pipe(first()).toPromise(); + const search: ISearch = async ( + context, request: IEnhancedEsSearchRequest, options ) => { - const config = await context.config$.pipe(first()).toPromise(); + const caller = context.core.elasticsearch.legacy.client.callAsCurrentUser; const defaultParams = getDefaultSearchParams(config); const params = { ...defaultParams, ...request.params }; @@ -45,10 +47,13 @@ export const enhancedEsSearchStrategyProvider: TSearchStrategyProvider = async (id) => { + const cancel: ISearchCancel = async (context, id) => { const method = 'DELETE'; const path = encodeURI(`/_async_search/${id}`); - await caller('transport.request', { method, path }); + await context.core.elasticsearch.legacy.client.callAsCurrentUser('transport.request', { + method, + path, + }); }; return { search, cancel }; From 1452ed547651375f4acba96bf5abdad6993f797a Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Mon, 8 Jun 2020 17:06:10 -0700 Subject: [PATCH 02/24] Fix types and tests and update docs --- ...in-plugins-data-server.irequesttypesmap.md | 2 + ...n-plugins-data-server.iresponsetypesmap.md | 2 + ...bana-plugin-plugins-data-server.isearch.md | 2 +- ...lugin-plugins-data-server.isearchcancel.md | 2 +- ...gins-data-server.isearchcontext.config_.md | 11 --- ...plugins-data-server.isearchcontext.core.md | 11 --- ...ugin-plugins-data-server.isearchcontext.md | 19 ----- ...ugin-plugins-data-server.isearchoptions.md | 2 +- ...ugins-data-server.isearchoptions.signal.md | 2 + ...plugin-plugins-data-server.isearchsetup.md | 18 +++++ ...ver.isearchsetup.registersearchstrategy.md | 13 ++++ ...a-server.isearchstart.getsearchstrategy.md | 13 ++++ ...plugin-plugins-data-server.isearchstart.md | 18 +++++ ...gins-data-server.isearchstrategy.cancel.md | 11 +++ ...gin-plugins-data-server.isearchstrategy.md | 21 ++++++ ...gins-data-server.isearchstrategy.search.md | 11 +++ .../kibana-plugin-plugins-data-server.md | 10 ++- ...plugin-plugins-data-server.plugin.setup.md | 8 +- ...plugin-plugins-data-server.plugin.start.md | 6 +- ...-plugin-plugins-data-server.pluginstart.md | 1 + ...-plugins-data-server.pluginstart.search.md | 11 +++ ...ins-data-server.tsearchstrategyprovider.md | 13 ---- ...ugin-plugins-data-server.tstrategytypes.md | 19 +++++ .../server/async_demo_search_strategy.ts | 8 +- .../server/demo_search_strategy.ts | 8 +- examples/demo_search/server/index.ts | 5 +- examples/demo_search/server/plugin.ts | 2 +- .../data/server/field_formats/mocks.ts | 30 ++++++++ src/plugins/data/server/mocks.ts | 40 ++++++++++ src/plugins/data/server/plugin.ts | 7 +- .../es_search/es_search_strategy.test.ts | 55 ++++---------- src/plugins/data/server/search/mocks.ts | 18 +++-- src/plugins/data/server/search/routes.test.ts | 67 +++++++---------- src/plugins/data/server/search/routes.ts | 2 +- .../data/server/search/search_service.test.ts | 13 +++- .../data/server/search/search_service.ts | 30 ++++---- src/plugins/data/server/search/types.ts | 2 +- src/plugins/data/server/server.api.md | 75 +++++++++++-------- .../server/search/es_search_strategy.test.ts | 69 +++++------------ 39 files changed, 388 insertions(+), 269 deletions(-) delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.config_.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.core.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.cancel.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.search.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tsearchstrategyprovider.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tstrategytypes.md create mode 100644 src/plugins/data/server/field_formats/mocks.ts create mode 100644 src/plugins/data/server/mocks.ts diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.irequesttypesmap.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.irequesttypesmap.md index a9bb8f1eb9d6df..3f5e4ba0f77999 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.irequesttypesmap.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.irequesttypesmap.md @@ -4,6 +4,8 @@ ## IRequestTypesMap interface +The map of search strategy IDs to the corresponding request type definitions. + Signature: ```typescript diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iresponsetypesmap.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iresponsetypesmap.md index fe5fa0a5d3a331..629ab4347eda80 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iresponsetypesmap.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iresponsetypesmap.md @@ -4,6 +4,8 @@ ## IResponseTypesMap interface +The map of search strategy IDs to the corresponding response type definitions. + Signature: ```typescript diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearch.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearch.md index 6e037f5161b532..96991579c17169 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearch.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearch.md @@ -7,5 +7,5 @@ Signature: ```typescript -export declare type ISearch = (request: IRequestTypesMap[T], options?: ISearchOptions) => Promise; +export declare type ISearch = (context: RequestHandlerContext, request: IRequestTypesMap[T], options?: ISearchOptions) => Promise; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md index 99c30515e8da6a..b5a687d1b19d84 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md @@ -7,5 +7,5 @@ Signature: ```typescript -export declare type ISearchCancel = (id: string) => Promise; +export declare type ISearchCancel = (context: RequestHandlerContext, id: string) => Promise; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.config_.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.config_.md deleted file mode 100644 index 364d44dba758af..00000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.config_.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchContext](./kibana-plugin-plugins-data-server.isearchcontext.md) > [config$](./kibana-plugin-plugins-data-server.isearchcontext.config_.md) - -## ISearchContext.config$ property - -Signature: - -```typescript -config$: Observable; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.core.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.core.md deleted file mode 100644 index 9d571c25d94bd5..00000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.core.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchContext](./kibana-plugin-plugins-data-server.isearchcontext.md) > [core](./kibana-plugin-plugins-data-server.isearchcontext.core.md) - -## ISearchContext.core property - -Signature: - -```typescript -core: CoreSetup; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.md deleted file mode 100644 index 1c3c5ec78f894e..00000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchContext](./kibana-plugin-plugins-data-server.isearchcontext.md) - -## ISearchContext interface - -Signature: - -```typescript -export interface ISearchContext -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [config$](./kibana-plugin-plugins-data-server.isearchcontext.config_.md) | Observable<SharedGlobalConfig> | | -| [core](./kibana-plugin-plugins-data-server.isearchcontext.core.md) | CoreSetup | | - diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.md index 0319048f4418bc..49412fc42d3b5f 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.md @@ -14,5 +14,5 @@ export interface ISearchOptions | Property | Type | Description | | --- | --- | --- | -| [signal](./kibana-plugin-plugins-data-server.isearchoptions.signal.md) | AbortSignal | | +| [signal](./kibana-plugin-plugins-data-server.isearchoptions.signal.md) | AbortSignal | An AbortSignal that allows the caller of search to abort a search request. | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.signal.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.signal.md index 7da5c182b2e0f7..948dfd66da7a03 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.signal.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.signal.md @@ -4,6 +4,8 @@ ## ISearchOptions.signal property +An `AbortSignal` that allows the caller of `search` to abort a search request. + Signature: ```typescript diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md new file mode 100644 index 00000000000000..93e253b2e98a3f --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) + +## ISearchSetup interface + +Signature: + +```typescript +export interface ISearchSetup +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) | TRegisterSearchStrategy | Extension point exposed for other plugins to register their own search strategies. | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md new file mode 100644 index 00000000000000..c06b8b00806bfe --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) > [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) + +## ISearchSetup.registerSearchStrategy property + +Extension point exposed for other plugins to register their own search strategies. + +Signature: + +```typescript +registerSearchStrategy: TRegisterSearchStrategy; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md new file mode 100644 index 00000000000000..0ba4bf578d6cc9 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) > [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) + +## ISearchStart.getSearchStrategy property + +Get other registered search strategies. For example, if a new strategy needs to use the already-registered ES search strategy, it can use this function to accomplish that. + +Signature: + +```typescript +getSearchStrategy: TGetSearchStrategy; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md new file mode 100644 index 00000000000000..abe72396f61e18 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) + +## ISearchStart interface + +Signature: + +```typescript +export interface ISearchStart +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | TGetSearchStrategy | Get other registered search strategies. For example, if a new strategy needs to use the already-registered ES search strategy, it can use this function to accomplish that. | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.cancel.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.cancel.md new file mode 100644 index 00000000000000..c1e0c3d9f23300 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.cancel.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) > [cancel](./kibana-plugin-plugins-data-server.isearchstrategy.cancel.md) + +## ISearchStrategy.cancel property + +Signature: + +```typescript +cancel?: ISearchCancel; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md new file mode 100644 index 00000000000000..167c6ab6e5a16f --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) + +## ISearchStrategy interface + +Search strategy interface contains a search method that takes in a request and returns a promise that resolves to a response. + +Signature: + +```typescript +export interface ISearchStrategy +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [cancel](./kibana-plugin-plugins-data-server.isearchstrategy.cancel.md) | ISearchCancel<T> | | +| [search](./kibana-plugin-plugins-data-server.isearchstrategy.search.md) | ISearch<T> | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md new file mode 100644 index 00000000000000..34a17ca87807a4 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) > [search](./kibana-plugin-plugins-data-server.isearchstrategy.search.md) + +## ISearchStrategy.search property + +Signature: + +```typescript +search: ISearch; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 0efbe8ed4ed643..f492ba2843a697 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -39,10 +39,12 @@ | [IIndexPattern](./kibana-plugin-plugins-data-server.iindexpattern.md) | | | [IndexPatternAttributes](./kibana-plugin-plugins-data-server.indexpatternattributes.md) | Use data plugin interface instead | | [IndexPatternFieldDescriptor](./kibana-plugin-plugins-data-server.indexpatternfielddescriptor.md) | | -| [IRequestTypesMap](./kibana-plugin-plugins-data-server.irequesttypesmap.md) | | -| [IResponseTypesMap](./kibana-plugin-plugins-data-server.iresponsetypesmap.md) | | -| [ISearchContext](./kibana-plugin-plugins-data-server.isearchcontext.md) | | +| [IRequestTypesMap](./kibana-plugin-plugins-data-server.irequesttypesmap.md) | The map of search strategy IDs to the corresponding request type definitions. | +| [IResponseTypesMap](./kibana-plugin-plugins-data-server.iresponsetypesmap.md) | The map of search strategy IDs to the corresponding response type definitions. | | [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) | | +| [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) | | +| [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) | | +| [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) | Search strategy interface contains a search method that takes in a request and returns a promise that resolves to a response. | | [KueryNode](./kibana-plugin-plugins-data-server.kuerynode.md) | | | [PluginSetup](./kibana-plugin-plugins-data-server.pluginsetup.md) | | | [PluginStart](./kibana-plugin-plugins-data-server.pluginstart.md) | | @@ -73,5 +75,5 @@ | [ISearch](./kibana-plugin-plugins-data-server.isearch.md) | | | [ISearchCancel](./kibana-plugin-plugins-data-server.isearchcancel.md) | | | [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | | -| [TSearchStrategyProvider](./kibana-plugin-plugins-data-server.tsearchstrategyprovider.md) | Search strategy provider creates an instance of a search strategy with the request handler context bound to it. This way every search strategy can use whatever information they require from the request context. | +| [TStrategyTypes](./kibana-plugin-plugins-data-server.tstrategytypes.md) | Contains all known strategy type identifiers that will be used to map to request and response shapes. Plugins that wish to add their own custom search strategies should extend this type via:const MY\_STRATEGY = 'MY\_STRATEGY';declare module 'src/plugins/search/server' { export interface IRequestTypesMap { \[MY\_STRATEGY\]: IMySearchRequest; }export interface IResponseTypesMap { \[MY\_STRATEGY\]: IMySearchResponse } } | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md index bd617990a00a2f..13c69d6bf7548e 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md @@ -7,11 +7,11 @@ Signature: ```typescript -setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { +setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { + search: ISearchSetup; fieldFormats: { register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; - search: ISearchSetup; }; ``` @@ -19,15 +19,15 @@ setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { | Parameter | Type | Description | | --- | --- | --- | -| core | CoreSetup | | +| core | CoreSetup<object, DataPluginStart> | | | { usageCollection } | DataPluginSetupDependencies | | Returns: `{ + search: ISearchSetup; fieldFormats: { register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; - search: ISearchSetup; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md index 2a30cd3e68158c..2c7a833ab641bc 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md @@ -8,8 +8,9 @@ ```typescript start(core: CoreStart): { + search: ISearchStart; fieldFormats: { - fieldFormatServiceFactory: (uiSettings: import("kibana/server").IUiSettingsClient) => Promise; + fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; }; ``` @@ -23,8 +24,9 @@ start(core: CoreStart): { Returns: `{ + search: ISearchStart; fieldFormats: { - fieldFormatServiceFactory: (uiSettings: import("kibana/server").IUiSettingsClient) => Promise; + fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.md index b7d6a7e8a83fd2..1377d82123d412 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.md @@ -15,4 +15,5 @@ export interface DataPluginStart | Property | Type | Description | | --- | --- | --- | | [fieldFormats](./kibana-plugin-plugins-data-server.pluginstart.fieldformats.md) | FieldFormatsStart | | +| [search](./kibana-plugin-plugins-data-server.pluginstart.search.md) | ISearchStart | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.search.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.search.md new file mode 100644 index 00000000000000..3144d8c40b780e --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.search.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [PluginStart](./kibana-plugin-plugins-data-server.pluginstart.md) > [search](./kibana-plugin-plugins-data-server.pluginstart.search.md) + +## PluginStart.search property + +Signature: + +```typescript +search: ISearchStart; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tsearchstrategyprovider.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tsearchstrategyprovider.md deleted file mode 100644 index f528f48a68f727..00000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tsearchstrategyprovider.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TSearchStrategyProvider](./kibana-plugin-plugins-data-server.tsearchstrategyprovider.md) - -## TSearchStrategyProvider type - -Search strategy provider creates an instance of a search strategy with the request handler context bound to it. This way every search strategy can use whatever information they require from the request context. - -Signature: - -```typescript -export declare type TSearchStrategyProvider = (context: ISearchContext, caller: APICaller, search: ISearchGeneric) => ISearchStrategy; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tstrategytypes.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tstrategytypes.md new file mode 100644 index 00000000000000..443d8d1b424d0b --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tstrategytypes.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TStrategyTypes](./kibana-plugin-plugins-data-server.tstrategytypes.md) + +## TStrategyTypes type + +Contains all known strategy type identifiers that will be used to map to request and response shapes. Plugins that wish to add their own custom search strategies should extend this type via: + +const MY\_STRATEGY = 'MY\_STRATEGY'; + +declare module 'src/plugins/search/server' { export interface IRequestTypesMap { \[MY\_STRATEGY\]: IMySearchRequest; } + +export interface IResponseTypesMap { \[MY\_STRATEGY\]: IMySearchResponse } } + +Signature: + +```typescript +export declare type TStrategyTypes = typeof ES_SEARCH_STRATEGY | string; +``` diff --git a/examples/demo_search/server/async_demo_search_strategy.ts b/examples/demo_search/server/async_demo_search_strategy.ts index dc8490ea983ea8..d869425b3f1955 100644 --- a/examples/demo_search/server/async_demo_search_strategy.ts +++ b/examples/demo_search/server/async_demo_search_strategy.ts @@ -18,10 +18,10 @@ */ import { ISearchStrategy } from '../../../src/plugins/data/server'; -import { ASYNC_DEMO_SEARCH_STRATEGY } from '../common'; +import { ASYNC_DEMO_SEARCH_STRATEGY, IAsyncDemoRequest } from '../common'; -export const asyncDemoSearchStrategyProvider = (): ISearchStrategy< - typeof ASYNC_DEMO_SEARCH_STRATEGY +export const asyncDemoSearchStrategyProvider = async (): Promise< + ISearchStrategy > => { function getFibonacciSequence(n = 0) { const beginning = [0, 1].slice(0, n); @@ -42,7 +42,7 @@ export const asyncDemoSearchStrategyProvider = (): ISearchStrategy< const totalMap = new Map(); return { - search: async (context, request) => { + search: async (context, request: IAsyncDemoRequest) => { const id = request.id ?? generateId(); const loaded = (loadedMap.get(id) ?? 0) + 1; diff --git a/examples/demo_search/server/demo_search_strategy.ts b/examples/demo_search/server/demo_search_strategy.ts index 7e307497a98b75..2976df22044bb7 100644 --- a/examples/demo_search/server/demo_search_strategy.ts +++ b/examples/demo_search/server/demo_search_strategy.ts @@ -18,11 +18,13 @@ */ import { ISearchStrategy } from '../../../src/plugins/data/server'; -import { DEMO_SEARCH_STRATEGY } from '../common'; +import { DEMO_SEARCH_STRATEGY, IDemoRequest } from '../common'; -export const demoSearchStrategyProvider = (): ISearchStrategy => { +export const demoSearchStrategyProvider = async (): Promise< + ISearchStrategy +> => { return { - search: (context, request) => { + search: (context, request: IDemoRequest) => { return Promise.resolve({ greeting: request.mood === 'happy' diff --git a/examples/demo_search/server/index.ts b/examples/demo_search/server/index.ts index 6289b684b2b1e7..368575b705c90a 100644 --- a/examples/demo_search/server/index.ts +++ b/examples/demo_search/server/index.ts @@ -17,9 +17,6 @@ * under the License. */ -import { PluginInitializerContext, PluginInitializer } from 'kibana/server'; import { DemoDataPlugin } from './plugin'; -export const plugin: PluginInitializer = ( - initializerContext: PluginInitializerContext -) => new DemoDataPlugin(initializerContext); +export const plugin = () => new DemoDataPlugin(); diff --git a/examples/demo_search/server/plugin.ts b/examples/demo_search/server/plugin.ts index 8bf63120c19e65..8a72b5007f988c 100644 --- a/examples/demo_search/server/plugin.ts +++ b/examples/demo_search/server/plugin.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Plugin, CoreSetup, PluginInitializerContext } from 'kibana/server'; +import { Plugin, CoreSetup } from 'kibana/server'; import { PluginSetup as DataPluginSetup } from 'src/plugins/data/server'; import { demoSearchStrategyProvider } from './demo_search_strategy'; import { diff --git a/src/plugins/data/server/field_formats/mocks.ts b/src/plugins/data/server/field_formats/mocks.ts new file mode 100644 index 00000000000000..ecfa33c86cf162 --- /dev/null +++ b/src/plugins/data/server/field_formats/mocks.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +export function createFieldFormatsSetupMock() { + return { + register: jest.fn(), + }; +} + +export function createFieldFormatsStartMock() { + return { + fieldFormatServiceFactory: jest.fn(), + }; +} diff --git a/src/plugins/data/server/mocks.ts b/src/plugins/data/server/mocks.ts new file mode 100644 index 00000000000000..e2f2298234054b --- /dev/null +++ b/src/plugins/data/server/mocks.ts @@ -0,0 +1,40 @@ +/* + * 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 { createSearchSetupMock, createSearchStartMock } from './search/mocks'; +import { createFieldFormatsSetupMock, createFieldFormatsStartMock } from './field_formats/mocks'; + +function createSetupContract() { + return { + search: createSearchSetupMock(), + fieldFormats: createFieldFormatsSetupMock(), + }; +} + +function createStartContract() { + return { + search: createSearchStartMock(), + fieldFormats: createFieldFormatsStartMock(), + }; +} + +export const dataPluginMock = { + createSetupContract, + createStartContract, +}; diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index ecc506ad2f9e25..0edce458f1c6b3 100644 --- a/src/plugins/data/server/plugin.ts +++ b/src/plugins/data/server/plugin.ts @@ -60,7 +60,10 @@ export class DataServerPlugin implements Plugin, + { usageCollection }: DataPluginSetupDependencies + ) { this.indexPatterns.setup(core); this.scriptsService.setup(core); this.queryService.setup(core); @@ -70,8 +73,8 @@ export class DataServerPlugin implements Plugin { - const mockCoreSetup = coreMock.createSetup(); const mockApiCaller = jest.fn().mockResolvedValue({ _shards: { total: 10, @@ -30,39 +30,26 @@ describe('ES search strategy', () => { successful: 7, }, }); - const mockSearch = jest.fn(); + const mockContext = { + core: { elasticsearch: { legacy: { client: { callAsCurrentUser: mockApiCaller } } } }, + }; const mockConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; beforeEach(() => { mockApiCaller.mockClear(); - mockSearch.mockClear(); }); - it('returns a strategy with `search`', () => { - const esSearch = esSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + it('returns a strategy with `search`', async () => { + const esSearch = await esSearchStrategyProvider(mockConfig$); expect(typeof esSearch.search).toBe('function'); }); it('calls the API caller with the params with defaults', async () => { const params = { index: 'logstash-*' }; - const esSearch = esSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await esSearchStrategyProvider(mockConfig$); - await esSearch.search({ params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('search'); @@ -76,16 +63,9 @@ describe('ES search strategy', () => { it('calls the API caller with overridden defaults', async () => { const params = { index: 'logstash-*', ignoreUnavailable: false, timeout: '1000ms' }; - const esSearch = esSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await esSearchStrategyProvider(mockConfig$); - await esSearch.search({ params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('search'); @@ -97,16 +77,11 @@ describe('ES search strategy', () => { it('returns total, loaded, and raw response', async () => { const params = { index: 'logstash-*' }; - const esSearch = esSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await esSearchStrategyProvider(mockConfig$); - const response = await esSearch.search({ params }); + const response = await esSearch.search((mockContext as unknown) as RequestHandlerContext, { + params, + }); expect(response).toHaveProperty('total'); expect(response).toHaveProperty('loaded'); diff --git a/src/plugins/data/server/search/mocks.ts b/src/plugins/data/server/search/mocks.ts index 136e7a1d580c9d..0aab466a9a0d9e 100644 --- a/src/plugins/data/server/search/mocks.ts +++ b/src/plugins/data/server/search/mocks.ts @@ -17,10 +17,14 @@ * under the License. */ -export const searchSetupMock = { - registerSearchStrategyContext: jest.fn(), - registerSearchStrategyProvider: jest.fn(), - __LEGACY: { - search: jest.fn(), - }, -}; +export function createSearchSetupMock() { + return { + registerSearchStrategy: jest.fn(), + }; +} + +export function createSearchStartMock() { + return { + getSearchStrategy: jest.fn(), + }; +} diff --git a/src/plugins/data/server/search/routes.test.ts b/src/plugins/data/server/search/routes.test.ts index f5e6507d977cd8..4ef67de93e4549 100644 --- a/src/plugins/data/server/search/routes.test.ts +++ b/src/plugins/data/server/search/routes.test.ts @@ -17,36 +17,26 @@ * under the License. */ -import { httpServiceMock, httpServerMock } from '../../../../../src/core/server/mocks'; +import { CoreSetup, RequestHandlerContext } from '../../../../../src/core/server'; +import { coreMock, httpServerMock } from '../../../../../src/core/server/mocks'; import { registerSearchRoute } from './routes'; -import { IRouter, ScopedClusterClient, RequestHandlerContext } from 'kibana/server'; +import { DataPluginStart } from '../plugin'; +import { dataPluginMock } from '../mocks'; describe('Search service', () => { - let routerMock: jest.Mocked; + let mockDataStart: MockedKeys; + let mockCoreSetup: MockedKeys>; beforeEach(() => { - routerMock = httpServiceMock.createRouter(); - }); - - it('registers a post route', async () => { - registerSearchRoute(routerMock); - expect(routerMock.post).toBeCalled(); + mockDataStart = dataPluginMock.createStartContract(); + mockCoreSetup = coreMock.createSetup({ pluginStartContract: mockDataStart }); }); it('handler calls context.search.search with the given request and strategy', async () => { const mockSearch = jest.fn().mockResolvedValue('yay'); - const mockContext = { - core: { - elasticsearch: { - legacy: { - client: {} as ScopedClusterClient, - }, - }, - }, - search: { - search: mockSearch, - }, - }; + mockDataStart.search.getSearchStrategy.mockReturnValueOnce({ search: mockSearch }); + + const mockContext = {}; const mockBody = { params: {} }; const mockParams = { strategy: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ @@ -55,13 +45,15 @@ describe('Search service', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerSearchRoute(routerMock); - const handler = routerMock.post.mock.calls[0][1]; + registerSearchRoute(mockCoreSetup); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.post.mock.calls[0][1]; await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + expect(mockDataStart.search.getSearchStrategy.mock.calls[0][0]).toBe(mockParams.strategy); expect(mockSearch).toBeCalled(); - expect(mockSearch.mock.calls[0][0]).toStrictEqual(mockBody); - expect(mockSearch.mock.calls[0][2]).toBe(mockParams.strategy); + expect(mockSearch.mock.calls[0][1]).toStrictEqual(mockBody); expect(mockResponse.ok).toBeCalled(); expect(mockResponse.ok.mock.calls[0][0]).toEqual({ body: 'yay' }); }); @@ -73,18 +65,9 @@ describe('Search service', () => { error: 'oops', }, }); - const mockContext = { - core: { - elasticsearch: { - legacy: { - client: {} as ScopedClusterClient, - }, - }, - }, - search: { - search: mockSearch, - }, - }; + mockDataStart.search.getSearchStrategy.mockReturnValueOnce({ search: mockSearch }); + + const mockContext = {}; const mockBody = { params: {} }; const mockParams = { strategy: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ @@ -93,13 +76,15 @@ describe('Search service', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerSearchRoute(routerMock); - const handler = routerMock.post.mock.calls[0][1]; + registerSearchRoute(mockCoreSetup); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.post.mock.calls[0][1]; await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + expect(mockDataStart.search.getSearchStrategy.mock.calls[0][0]).toBe(mockParams.strategy); expect(mockSearch).toBeCalled(); - expect(mockSearch.mock.calls[0][0]).toStrictEqual(mockBody); - expect(mockSearch.mock.calls[0][2]).toBe(mockParams.strategy); + expect(mockSearch.mock.calls[0][1]).toStrictEqual(mockBody); expect(mockResponse.customError).toBeCalled(); const error: any = mockResponse.customError.mock.calls[0][0]; expect(error.body.message).toBe('oh no'); diff --git a/src/plugins/data/server/search/routes.ts b/src/plugins/data/server/search/routes.ts index a1bdf966f3b020..7b6c045b0908c4 100644 --- a/src/plugins/data/server/search/routes.ts +++ b/src/plugins/data/server/search/routes.ts @@ -77,7 +77,7 @@ export function registerSearchRoute(core: CoreSetup): v const { strategy, id } = request.params; const [, , selfStart] = await core.getStartServices(); - const searchStrategy = selfStart.getSearchStrategy(strategy); + const searchStrategy = selfStart.search.getSearchStrategy(strategy); if (!searchStrategy.cancel) return res.ok(); try { diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index fa659756c12732..e672f50dc86aa4 100644 --- a/src/plugins/data/server/search/search_service.test.ts +++ b/src/plugins/data/server/search/search_service.test.ts @@ -21,6 +21,7 @@ import { coreMock } from '../../../../core/server/mocks'; import { SearchService } from './search_service'; import { CoreSetup } from '../../../../core/server'; +import { DataPluginStart } from '../plugin'; const mockSearchApi = { search: jest.fn() }; jest.mock('./create_api', () => ({ @@ -29,7 +30,7 @@ jest.mock('./create_api', () => ({ describe('Search service', () => { let plugin: SearchService; - let mockCoreSetup: MockedKeys; + let mockCoreSetup: MockedKeys>; beforeEach(() => { plugin = new SearchService(coreMock.createPluginInitializerContext({})); @@ -40,8 +41,14 @@ describe('Search service', () => { describe('setup()', () => { it('exposes proper contract', async () => { const setup = plugin.setup(mockCoreSetup); - expect(setup).toHaveProperty('registerSearchStrategyContext'); - expect(setup).toHaveProperty('registerSearchStrategyProvider'); + expect(setup).toHaveProperty('registerSearchStrategy'); + }); + }); + + describe('start()', () => { + it('exposes proper contract', async () => { + const setup = plugin.start(); + expect(setup).toHaveProperty('getSearchStrategy'); }); }); }); diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 12eba0b76b262c..0ab9abf4e44a2b 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -38,29 +38,31 @@ export class SearchService implements Plugin { public setup(core: CoreSetup): ISearchSetup { core.savedObjects.registerType(searchSavedObjectType); - const registerSearchStrategy: TRegisterSearchStrategy = async (name, strategy) => { - this.searchStrategies[name] = await strategy; - }; - - registerSearchStrategy( + this.registerSearchStrategy( ES_SEARCH_STRATEGY, esSearchStrategyProvider(this.initializerContext.config.legacy.globalConfig$) ); registerSearchRoute(core); - return { registerSearchStrategy }; + return { registerSearchStrategy: this.registerSearchStrategy }; } public start(): ISearchStart { - const getSearchStrategy: TGetSearchStrategy = (name) => { - if (!this.searchStrategies.hasOwnProperty(name)) { - throw new Error('No strategy registered for `${name}`.'); - } - return this.searchStrategies[name]; - }; - - return { getSearchStrategy }; + return { getSearchStrategy: this.getSearchStrategy }; } + public stop() {} + + private registerSearchStrategy: TRegisterSearchStrategy = async (name, strategy) => { + this.searchStrategies[name] = await strategy; + }; + + private getSearchStrategy: TGetSearchStrategy = (name) => { + const strategy = this.searchStrategies[name]; + if (!strategy) { + throw new Error(`Search strategy ${name} not found`); + } + return strategy; + }; } diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index a95c707cfb07eb..7227dc095411ae 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -107,5 +107,5 @@ export type TRegisterSearchStrategy = ( export type TGetSearchStrategy = (name: T) => ISearchStrategy; export type TSearchStrategiesMap = { - [K in TStrategyTypes]?: ISearchStrategy; + [K in TStrategyTypes]?: ISearchStrategy; }; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index ab8903f8c67901..e2a197e75c2251 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -48,7 +48,6 @@ import { GetResponse } from 'elasticsearch'; import { GetScriptParams } from 'elasticsearch'; import { GetSourceParams } from 'elasticsearch'; import { GetTemplateParams } from 'elasticsearch'; -import { IContextProvider as IContextProvider_2 } from 'kibana/server'; import { IncomingHttpHeaders } from 'http'; import { IndexDocumentParams } from 'elasticsearch'; import { IndicesAnalyzeParams } from 'elasticsearch'; @@ -490,7 +489,7 @@ export class IndexPatternsFetcher { // Warning: (ae-missing-release-tag) "IRequestTypesMap" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) +// @public export interface IRequestTypesMap { // Warning: (ae-forgotten-export) The symbol "IKibanaSearchRequest" needs to be exported by the entry point index.d.ts // @@ -505,7 +504,7 @@ export interface IRequestTypesMap { // Warning: (ae-missing-release-tag) "IResponseTypesMap" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) +// @public export interface IResponseTypesMap { // Warning: (ae-forgotten-export) The symbol "IKibanaSearchResponse" needs to be exported by the entry point index.d.ts // @@ -517,35 +516,48 @@ export interface IResponseTypesMap { [ES_SEARCH_STRATEGY]: IEsSearchResponse; } -// Warning: (ae-forgotten-export) The symbol "TStrategyTypes" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RequestHandlerContext" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ISearch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type ISearch = (request: IRequestTypesMap[T], options?: ISearchOptions) => Promise; +export type ISearch = (context: RequestHandlerContext, request: IRequestTypesMap[T], options?: ISearchOptions) => Promise; // Warning: (ae-missing-release-tag) "ISearchCancel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type ISearchCancel = (id: string) => Promise; +export type ISearchCancel = (context: RequestHandlerContext, id: string) => Promise; -// Warning: (ae-missing-release-tag) "ISearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "ISearchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export interface ISearchContext { - // (undocumented) - config$: Observable; - // Warning: (ae-forgotten-export) The symbol "CoreSetup" needs to be exported by the entry point index.d.ts - // - // (undocumented) - core: CoreSetup; +export interface ISearchOptions { + signal?: AbortSignal; } -// Warning: (ae-missing-release-tag) "ISearchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "ISearchSetup" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export interface ISearchOptions { +export interface ISearchSetup { + // Warning: (ae-forgotten-export) The symbol "TRegisterSearchStrategy" needs to be exported by the entry point index.d.ts + registerSearchStrategy: TRegisterSearchStrategy; +} + +// Warning: (ae-missing-release-tag) "ISearchStart" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface ISearchStart { + // Warning: (ae-forgotten-export) The symbol "TGetSearchStrategy" needs to be exported by the entry point index.d.ts + getSearchStrategy: TGetSearchStrategy; +} + +// Warning: (ae-missing-release-tag) "ISearchStrategy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface ISearchStrategy { // (undocumented) - signal?: AbortSignal; + cancel?: ISearchCancel; + // (undocumented) + search: ISearch; } // @public (undocumented) @@ -612,21 +624,23 @@ export function parseInterval(interval: string): moment.Duration | null; export class Plugin implements Plugin_2 { // Warning: (ae-forgotten-export) The symbol "PluginInitializerContext" needs to be exported by the entry point index.d.ts constructor(initializerContext: PluginInitializerContext); + // Warning: (ae-forgotten-export) The symbol "CoreSetup" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataPluginSetupDependencies" needs to be exported by the entry point index.d.ts // // (undocumented) - setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { + setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { + search: ISearchSetup; fieldFormats: { register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; - search: ISearchSetup; }; // Warning: (ae-forgotten-export) The symbol "CoreStart" needs to be exported by the entry point index.d.ts // // (undocumented) start(core: CoreStart): { + search: ISearchStart; fieldFormats: { - fieldFormatServiceFactory: (uiSettings: import("kibana/server").IUiSettingsClient) => Promise; + fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; }; // (undocumented) @@ -656,6 +670,8 @@ export interface PluginStart { // // (undocumented) fieldFormats: FieldFormatsStart; + // (undocumented) + search: ISearchStart; } // Warning: (ae-missing-release-tag) "Query" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -713,12 +729,10 @@ export interface TimeRange { to: string; } -// Warning: (ae-forgotten-export) The symbol "ISearchGeneric" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "ISearchStrategy" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "TSearchStrategyProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "TStrategyTypes" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type TSearchStrategyProvider = (context: ISearchContext, caller: APICaller_2, search: ISearchGeneric) => ISearchStrategy; +export type TStrategyTypes = typeof ES_SEARCH_STRATEGY | string; // Warning: (ae-missing-release-tag) "UI_SETTINGS" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -778,13 +792,12 @@ export const UI_SETTINGS: { // src/plugins/data/server/index.ts:103:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:131:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:131:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:184:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:185:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:186:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:187:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:191:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/plugin.ts:66:14 - (ae-forgotten-export) The symbol "ISearchSetup" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:186:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:187:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:189:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:190:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:193:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.test.ts b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.test.ts index a8a42fe11e7ceb..1eec941466b737 100644 --- a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.test.ts +++ b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.test.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { coreMock, pluginInitializerContextConfigMock } from '../../../../../src/core/server/mocks'; +import { RequestHandlerContext } from '../../../../../src/core/server'; +import { pluginInitializerContextConfigMock } from '../../../../../src/core/server/mocks'; import { enhancedEsSearchStrategyProvider } from './es_search_strategy'; const mockAsyncResponse = { @@ -29,25 +30,18 @@ const mockRollupResponse = { }; describe('ES search strategy', () => { - const mockCoreSetup = coreMock.createSetup(); const mockApiCaller = jest.fn(); - const mockSearch = jest.fn(); + const mockContext = { + core: { elasticsearch: { legacy: { client: { callAsCurrentUser: mockApiCaller } } } }, + }; const mockConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; beforeEach(() => { mockApiCaller.mockClear(); - mockSearch.mockClear(); }); - it('returns a strategy with `search`', () => { - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + it('returns a strategy with `search`', async () => { + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); expect(typeof esSearch.search).toBe('function'); }); @@ -56,16 +50,9 @@ describe('ES search strategy', () => { mockApiCaller.mockResolvedValueOnce(mockAsyncResponse); const params = { index: 'logstash-*', body: { query: {} } }; - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); - await esSearch.search({ params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('transport.request'); @@ -79,16 +66,9 @@ describe('ES search strategy', () => { mockApiCaller.mockResolvedValueOnce(mockAsyncResponse); const params = { index: 'logstash-*', body: { query: {} } }; - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); - await esSearch.search({ id: 'foo', params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { id: 'foo', params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('transport.request'); @@ -102,16 +82,9 @@ describe('ES search strategy', () => { mockApiCaller.mockResolvedValueOnce(mockAsyncResponse); const params = { index: 'foo-程', body: {} }; - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); - await esSearch.search({ params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('transport.request'); @@ -124,16 +97,12 @@ describe('ES search strategy', () => { mockApiCaller.mockResolvedValueOnce(mockRollupResponse); const params = { index: 'foo-程', body: {} }; - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); - - await esSearch.search({ indexType: 'rollup', params }); + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); + + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { + indexType: 'rollup', + params, + }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('transport.request'); From c7d6b61d910175df2072ac5e752666f98abcd407 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 9 Jun 2020 15:56:44 -0700 Subject: [PATCH 03/24] Fix failing test --- src/plugins/data/server/search/search_service.test.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index e672f50dc86aa4..25143fa09e6bff 100644 --- a/src/plugins/data/server/search/search_service.test.ts +++ b/src/plugins/data/server/search/search_service.test.ts @@ -23,11 +23,6 @@ import { SearchService } from './search_service'; import { CoreSetup } from '../../../../core/server'; import { DataPluginStart } from '../plugin'; -const mockSearchApi = { search: jest.fn() }; -jest.mock('./create_api', () => ({ - createApi: () => mockSearchApi, -})); - describe('Search service', () => { let plugin: SearchService; let mockCoreSetup: MockedKeys>; @@ -35,7 +30,6 @@ describe('Search service', () => { beforeEach(() => { plugin = new SearchService(coreMock.createPluginInitializerContext({})); mockCoreSetup = coreMock.createSetup(); - mockSearchApi.search.mockClear(); }); describe('setup()', () => { From 955bd8819cda745a32155dc1744cbd2b78270b66 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 9 Jun 2020 22:09:03 -0700 Subject: [PATCH 04/24] Fix build of example plugin --- examples/search_explorer/public/search_api.tsx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/examples/search_explorer/public/search_api.tsx b/examples/search_explorer/public/search_api.tsx index c77ec725c6890d..4a0e9afd20c85d 100644 --- a/examples/search_explorer/public/search_api.tsx +++ b/examples/search_explorer/public/search_api.tsx @@ -23,11 +23,6 @@ import { GuideSection } from './guide_section'; import publicSearch from '!!raw-loader!./../../../src/plugins/data/public/search/i_search'; // @ts-ignore import publicPlugin from '!!raw-loader!./../../../src/plugins/data/public/search/search_service'; - -// @ts-ignore -import serverSetupContract from '!!raw-loader!./../../../src/plugins/data/server/search/i_search_setup'; -// @ts-ignore -import serverSearch from '!!raw-loader!./../../../src/plugins/data/server/search/i_search'; // @ts-ignore import serverPlugin from '!!raw-loader!./../../../src/plugins/data/server/search/search_service'; @@ -54,14 +49,6 @@ export const SearchApiPage = () => ( description: 'search_service.ts', snippet: serverPlugin, }, - { - description: `i_search_setup.ts`, - snippet: serverSetupContract, - }, - { - description: 'i_search', - snippet: serverSearch, - }, ], }, ]} From b0be2dfa1ef5da2ab8a0797c4f6828d6910474d1 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Wed, 10 Jun 2020 11:38:43 -0700 Subject: [PATCH 05/24] Fix functional test --- .../test_suites/core_plugins/legacy_plugins.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts b/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts index cb3a24375607e2..c9274c867df837 100644 --- a/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts +++ b/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts @@ -39,7 +39,7 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide await supertest .get('/api/np-context-in-legacy') .expect(200) - .expect(JSON.stringify({ contexts: ['core', 'search', 'pluginA'] })); + .expect(JSON.stringify({ contexts: ['core', 'pluginA'] })); }); }); From b536e74e2ce37d6dda2ce6be8155a1d2795cf5f6 Mon Sep 17 00:00:00 2001 From: Liza K Date: Tue, 16 Jun 2020 14:20:45 +0300 Subject: [PATCH 06/24] Make server strategies sync --- examples/demo_search/server/async_demo_search_strategy.ts | 4 ++-- examples/demo_search/server/demo_search_strategy.ts | 4 +--- .../data/server/search/es_search/es_search_strategy.ts | 6 +++--- src/plugins/data/server/search/search_service.ts | 4 ++-- src/plugins/data/server/search/types.ts | 2 +- .../data_enhanced/server/search/es_search_strategy.ts | 7 +++---- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/examples/demo_search/server/async_demo_search_strategy.ts b/examples/demo_search/server/async_demo_search_strategy.ts index d869425b3f1955..2eda0f4d09e11b 100644 --- a/examples/demo_search/server/async_demo_search_strategy.ts +++ b/examples/demo_search/server/async_demo_search_strategy.ts @@ -20,8 +20,8 @@ import { ISearchStrategy } from '../../../src/plugins/data/server'; import { ASYNC_DEMO_SEARCH_STRATEGY, IAsyncDemoRequest } from '../common'; -export const asyncDemoSearchStrategyProvider = async (): Promise< - ISearchStrategy +export const asyncDemoSearchStrategyProvider = (): ISearchStrategy< + typeof ASYNC_DEMO_SEARCH_STRATEGY > => { function getFibonacciSequence(n = 0) { const beginning = [0, 1].slice(0, n); diff --git a/examples/demo_search/server/demo_search_strategy.ts b/examples/demo_search/server/demo_search_strategy.ts index 2976df22044bb7..36280ad22e83ca 100644 --- a/examples/demo_search/server/demo_search_strategy.ts +++ b/examples/demo_search/server/demo_search_strategy.ts @@ -20,9 +20,7 @@ import { ISearchStrategy } from '../../../src/plugins/data/server'; import { DEMO_SEARCH_STRATEGY, IDemoRequest } from '../common'; -export const demoSearchStrategyProvider = async (): Promise< - ISearchStrategy -> => { +export const demoSearchStrategyProvider = (): ISearchStrategy => { return { search: (context, request: IDemoRequest) => { return Promise.resolve({ diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.ts b/src/plugins/data/server/search/es_search/es_search_strategy.ts index e8b4d327097378..db08ddf9208185 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.ts @@ -23,12 +23,12 @@ import { Observable } from 'rxjs'; import { ES_SEARCH_STRATEGY } from '../../../common/search'; import { ISearchStrategy, getDefaultSearchParams, getTotalLoaded } from '..'; -export const esSearchStrategyProvider = async ( +export const esSearchStrategyProvider = ( config$: Observable -): Promise> => { - const config = await config$.pipe(first()).toPromise(); +): ISearchStrategy => { return { search: async (context: RequestHandlerContext, request, options) => { + const config = await config$.pipe(first()).toPromise(); const defaultParams = getDefaultSearchParams(config); // Only default index pattern type is supported here. diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 0ab9abf4e44a2b..df809b425eb9ee 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -54,8 +54,8 @@ export class SearchService implements Plugin { public stop() {} - private registerSearchStrategy: TRegisterSearchStrategy = async (name, strategy) => { - this.searchStrategies[name] = await strategy; + private registerSearchStrategy: TRegisterSearchStrategy = (name, strategy) => { + this.searchStrategies[name] = strategy; }; private getSearchStrategy: TGetSearchStrategy = (name) => { diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index 7227dc095411ae..dea325cc063bbf 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -101,7 +101,7 @@ export interface ISearchStrategy { export type TRegisterSearchStrategy = ( name: T, - searchStrategy: Promise> + searchStrategy: ISearchStrategy ) => void; export type TGetSearchStrategy = (name: T) => ISearchStrategy; diff --git a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts index 6e12a353185e7c..9083ab24a4521a 100644 --- a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts +++ b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts @@ -28,16 +28,15 @@ export interface AsyncSearchResponse { response: SearchResponse; } -export const enhancedEsSearchStrategyProvider = async ( +export const enhancedEsSearchStrategyProvider = ( config$: Observable -): Promise> => { - const config = await config$.pipe(first()).toPromise(); - +): ISearchStrategy => { const search: ISearch = async ( context, request: IEnhancedEsSearchRequest, options ) => { + const config = await config$.pipe(first()).toPromise(); const caller = context.core.elasticsearch.legacy.client.callAsCurrentUser; const defaultParams = getDefaultSearchParams(config); const params = { ...defaultParams, ...request.params }; From 97c456e46183b9c9b5612cc82a75f6595cd5749d Mon Sep 17 00:00:00 2001 From: Liza K Date: Tue, 16 Jun 2020 23:25:47 +0300 Subject: [PATCH 07/24] Move strategy name into options --- .../public/async_demo_strategy.tsx | 2 +- .../search_explorer/public/demo_strategy.tsx | 2 +- src/plugins/data/public/search/i_search.ts | 16 ++++++++++------ .../data/public/search/search_interceptor.ts | 9 +++++---- src/plugins/data/public/search/search_service.ts | 6 +++--- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/examples/search_explorer/public/async_demo_strategy.tsx b/examples/search_explorer/public/async_demo_strategy.tsx index 9cea556c32d54f..40be50a8f5bb59 100644 --- a/examples/search_explorer/public/async_demo_strategy.tsx +++ b/examples/search_explorer/public/async_demo_strategy.tsx @@ -82,7 +82,7 @@ export class AsyncDemoStrategy extends React.Component { request={request} strategy={ASYNC_DEMO_SEARCH_STRATEGY} search={(signal: AbortSignal) => - this.props.search(request, { signal }, ASYNC_DEMO_SEARCH_STRATEGY) + this.props.search(request, { signal, strategy: ASYNC_DEMO_SEARCH_STRATEGY }) } /> diff --git a/examples/search_explorer/public/demo_strategy.tsx b/examples/search_explorer/public/demo_strategy.tsx index 3de6827818e14b..f2fbcfefe02696 100644 --- a/examples/search_explorer/public/demo_strategy.tsx +++ b/examples/search_explorer/public/demo_strategy.tsx @@ -99,7 +99,7 @@ export class DemoStrategy extends React.Component { request={request} strategy={DEMO_SEARCH_STRATEGY} search={(signal: AbortSignal) => - this.props.search(request, { signal }, DEMO_SEARCH_STRATEGY) + this.props.search(request, { signal, strategy: DEMO_SEARCH_STRATEGY }) } /> diff --git a/src/plugins/data/public/search/i_search.ts b/src/plugins/data/public/search/i_search.ts index a39ef3e3e75719..e474135288149a 100644 --- a/src/plugins/data/public/search/i_search.ts +++ b/src/plugins/data/public/search/i_search.ts @@ -20,9 +20,9 @@ import { Observable } from 'rxjs'; import { TStrategyTypes } from './strategy_types'; import { - DEFAULT_SEARCH_STRATEGY, IKibanaSearchRequest, IKibanaSearchResponse, + DEFAULT_SEARCH_STRATEGY, } from '../../common/search'; import { SYNC_SEARCH_STRATEGY, ISyncSearchRequest } from './sync_search_strategy'; import { @@ -47,13 +47,17 @@ export interface IResponseTypesMap { [key: string]: IKibanaSearchResponse; } -export type ISearchGeneric = ( +export type ISearch = ( request: IRequestTypesMap[T], - options?: ISearchOptions, - strategy?: T + options?: ISearchOptions ) => Observable; -export type ISearch = ( +// Service API types +export interface IStrategyOptions extends ISearchOptions { + strategy?: TStrategyTypes; +} + +export type ISearchGeneric = ( request: IRequestTypesMap[T], - options?: ISearchOptions + options?: IStrategyOptions ) => Observable; diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index 90acf5b89ab924..7cf6dac34ddaee 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -22,9 +22,10 @@ import { takeUntil, finalize, mergeMapTo, filter } from 'rxjs/operators'; import { ApplicationStart, Toast, ToastsStart } from 'kibana/public'; import { getCombinedSignal, AbortError } from '../../common/utils'; import { IKibanaSearchRequest } from '../../common/search'; -import { ISearchGeneric, ISearchOptions } from './i_search'; +import { ISearch, ISearchOptions } from './i_search'; import { RequestTimeoutError } from './request_timeout_error'; import { getLongQueryNotification } from './long_query_notification'; +import { TStrategyTypes } from './strategy_types'; const LONG_QUERY_NOTIFICATION_DELAY = 10000; @@ -86,8 +87,8 @@ export class SearchInterceptor { * either when `cancelPending` is called, when the request times out, or when the original * `AbortSignal` is aborted. Updates the `pendingCount` when the request is started/finalized. */ - public search = ( - search: ISearchGeneric, + public search = ( + search: ISearch, request: IKibanaSearchRequest, options?: ISearchOptions ) => { @@ -127,7 +128,7 @@ export class SearchInterceptor { ]; const combinedSignal = getCombinedSignal(signals); - return search(request as any, { ...options, signal: combinedSignal }).pipe( + return search(request, { ...options, signal: combinedSignal }).pipe( takeUntil(timeoutError$), takeUntil(userAbort$), finalize(() => { diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index d5997c15817f69..a6037bc181f4f2 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -135,11 +135,11 @@ export class SearchService implements Plugin { const aggTypesStart = this.aggTypesRegistry.start(); - const search: ISearchGeneric = (request, options, strategyName) => { + const search: ISearchGeneric = (request, options) => { const { search: defaultSearch } = this.getSearchStrategy( - strategyName || DEFAULT_SEARCH_STRATEGY + options?.strategy || DEFAULT_SEARCH_STRATEGY ); - return this.searchInterceptor.search(defaultSearch as any, request, options); + return this.searchInterceptor.search(defaultSearch, request, options); }; const legacySearch = { From 239e3a5bde5845428f2fba173f9502d9c5dea96f Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 17 Jun 2020 11:12:04 +0300 Subject: [PATCH 08/24] docs --- .../kibana-plugin-plugins-data-public.isearchgeneric.md | 2 +- .../kibana-plugin-plugins-data-public.searchinterceptor.md | 2 +- ...na-plugin-plugins-data-public.searchinterceptor.search.md | 2 +- src/plugins/data/public/public.api.md | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isearchgeneric.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isearchgeneric.md index e118dac31c2962..39bb371bec8aef 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isearchgeneric.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isearchgeneric.md @@ -7,5 +7,5 @@ Signature: ```typescript -export declare type ISearchGeneric = (request: IRequestTypesMap[T], options?: ISearchOptions, strategy?: T) => Observable; +export declare type ISearchGeneric = (request: IRequestTypesMap[T], options?: IStrategyOptions) => Observable; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md index 0c7b123be72af3..f0daf97aae2f62 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md @@ -26,7 +26,7 @@ export declare class SearchInterceptor | [hideToast](./kibana-plugin-plugins-data-public.searchinterceptor.hidetoast.md) | | () => void | | | [longRunningToast](./kibana-plugin-plugins-data-public.searchinterceptor.longrunningtoast.md) | | Toast | The current long-running toast (if there is one). | | [requestTimeout](./kibana-plugin-plugins-data-public.searchinterceptor.requesttimeout.md) | | number | undefined | | -| [search](./kibana-plugin-plugins-data-public.searchinterceptor.search.md) | | (search: ISearchGeneric, request: IKibanaSearchRequest, options?: ISearchOptions | undefined) => import("rxjs").Observable<import("../../common/search").IEsSearchResponse<unknown>> | Searches using the given search method. Overrides the AbortSignal with one that will abort either when cancelPending is called, when the request times out, or when the original AbortSignal is aborted. Updates the pendingCount when the request is started/finalized. | +| [search](./kibana-plugin-plugins-data-public.searchinterceptor.search.md) | | <T extends string>(search: ISearch<T>, request: IKibanaSearchRequest, options?: ISearchOptions | undefined) => import("rxjs").Observable<import("./i_search").IResponseTypesMap[T]> | Searches using the given search method. Overrides the AbortSignal with one that will abort either when cancelPending is called, when the request times out, or when the original AbortSignal is aborted. Updates the pendingCount when the request is started/finalized. | | [showToast](./kibana-plugin-plugins-data-public.searchinterceptor.showtoast.md) | | () => void | | | [timeoutSubscriptions](./kibana-plugin-plugins-data-public.searchinterceptor.timeoutsubscriptions.md) | | Set<Subscription> | The subscriptions from scheduling the automatic timeout for each request. | | [toasts](./kibana-plugin-plugins-data-public.searchinterceptor.toasts.md) | | ToastsStart | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.search.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.search.md index 80c98ab84fb40d..c14008c3860bfc 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.search.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.search.md @@ -9,5 +9,5 @@ Searches using the given `search` method. Overrides the `AbortSignal` with one t Signature: ```typescript -search: (search: ISearchGeneric, request: IKibanaSearchRequest, options?: ISearchOptions | undefined) => import("rxjs").Observable>; +search: (search: ISearch, request: IKibanaSearchRequest, options?: ISearchOptions | undefined) => import("rxjs").Observable; ``` diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 23213d4d1165a6..e6f06902ecdf95 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1252,10 +1252,11 @@ export interface IResponseTypesMap { // @public (undocumented) export type ISearch = (request: IRequestTypesMap[T], options?: ISearchOptions) => Observable; +// Warning: (ae-forgotten-export) The symbol "IStrategyOptions" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ISearchGeneric" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type ISearchGeneric = (request: IRequestTypesMap[T], options?: ISearchOptions, strategy?: T) => Observable; +export type ISearchGeneric = (request: IRequestTypesMap[T], options?: IStrategyOptions) => Observable; // Warning: (ae-missing-release-tag) "ISearchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1755,7 +1756,7 @@ export class SearchInterceptor { protected longRunningToast?: Toast; // (undocumented) protected readonly requestTimeout?: number | undefined; - search: (search: ISearchGeneric, request: IKibanaSearchRequest, options?: ISearchOptions | undefined) => import("rxjs").Observable>; + search: (search: ISearch, request: IKibanaSearchRequest, options?: ISearchOptions | undefined) => import("rxjs").Observable; // (undocumented) protected showToast: () => void; protected timeoutSubscriptions: Set; From b918556bc85f90a44d417437f1492eb1dfaffc52 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 18 Jun 2020 21:39:55 +0300 Subject: [PATCH 09/24] Remove FE strategies --- examples/demo_search/public/plugin.ts | 11 -- .../search_explorer/public/search_api.tsx | 6 - src/plugins/data/public/index.ts | 6 +- .../es_search/es_search_strategy.test.ts | 47 ------ .../search/es_search/es_search_strategy.ts | 43 ------ .../data/public/search/es_search/index.ts | 1 - src/plugins/data/public/search/i_search.ts | 63 -------- src/plugins/data/public/search/index.ts | 15 +- src/plugins/data/public/search/mocks.ts | 2 - .../public/search/search_interceptor.test.ts | 20 ++- .../data/public/search/search_interceptor.ts | 128 ++++++++++------ .../data/public/search/search_service.ts | 49 ++---- .../data/public/search/strategy_types.ts | 40 ----- .../search/sync_search_strategy.test.ts | 84 ----------- .../public/search/sync_search_strategy.ts | 50 ------- src/plugins/data/public/search/types.ts | 51 +++---- x-pack/plugins/data_enhanced/public/plugin.ts | 24 +-- .../search/async_search_strategy.test.ts | 141 ------------------ .../public/search/async_search_strategy.ts | 83 ----------- .../public/search/es_search_strategy.test.ts | 35 ----- .../public/search/es_search_strategy.ts | 44 ------ .../data_enhanced/public/search/index.ts | 1 - .../public/search/search_interceptor.ts | 71 ++++++++- 23 files changed, 197 insertions(+), 818 deletions(-) delete mode 100644 src/plugins/data/public/search/es_search/es_search_strategy.test.ts delete mode 100644 src/plugins/data/public/search/es_search/es_search_strategy.ts delete mode 100644 src/plugins/data/public/search/i_search.ts delete mode 100644 src/plugins/data/public/search/strategy_types.ts delete mode 100644 src/plugins/data/public/search/sync_search_strategy.test.ts delete mode 100644 src/plugins/data/public/search/sync_search_strategy.ts delete mode 100644 x-pack/plugins/data_enhanced/public/search/async_search_strategy.test.ts delete mode 100644 x-pack/plugins/data_enhanced/public/search/async_search_strategy.ts delete mode 100644 x-pack/plugins/data_enhanced/public/search/es_search_strategy.test.ts delete mode 100644 x-pack/plugins/data_enhanced/public/search/es_search_strategy.ts diff --git a/examples/demo_search/public/plugin.ts b/examples/demo_search/public/plugin.ts index 5d074c19903e21..543ea0a91909fc 100644 --- a/examples/demo_search/public/plugin.ts +++ b/examples/demo_search/public/plugin.ts @@ -39,17 +39,6 @@ import { DemoDataSearchSetupDependencies, DemoDataSearchStartDependencies } from * If the caller does not pass in the right `request` shape, typescript will * complain. The caller will also get a typed response. */ -declare module '../../../src/plugins/data/public' { - export interface IRequestTypesMap { - [DEMO_SEARCH_STRATEGY]: IDemoRequest; - [ASYNC_DEMO_SEARCH_STRATEGY]: IAsyncDemoRequest; - } - - export interface IResponseTypesMap { - [DEMO_SEARCH_STRATEGY]: IDemoResponse; - [ASYNC_DEMO_SEARCH_STRATEGY]: IAsyncDemoResponse; - } -} export class DemoDataPlugin implements Plugin { diff --git a/examples/search_explorer/public/search_api.tsx b/examples/search_explorer/public/search_api.tsx index 4a0e9afd20c85d..afe3cd6a93f93a 100644 --- a/examples/search_explorer/public/search_api.tsx +++ b/examples/search_explorer/public/search_api.tsx @@ -19,8 +19,6 @@ import React from 'react'; import { GuideSection } from './guide_section'; -// @ts-ignore -import publicSearch from '!!raw-loader!./../../../src/plugins/data/public/search/i_search'; // @ts-ignore import publicPlugin from '!!raw-loader!./../../../src/plugins/data/public/search/search_service'; // @ts-ignore @@ -36,10 +34,6 @@ export const SearchApiPage = () => ( description: 'search_service.ts', snippet: publicPlugin, }, - { - description: 'i_search', - snippet: publicSearch, - }, ], }, { diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 1554ac71f8c552..228b6654125eb8 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -338,18 +338,13 @@ export { OptionedValueProp, // search ES_SEARCH_STRATEGY, - SYNC_SEARCH_STRATEGY, getEsPreference, getSearchErrorType, - ISearchStrategy, ISearch, ISearchOptions, - IRequestTypesMap, - IResponseTypesMap, ISearchGeneric, IEsSearchResponse, IEsSearchRequest, - ISyncSearchRequest, IKibanaSearchResponse, IKibanaSearchRequest, SearchRequest, @@ -369,6 +364,7 @@ export { TabbedAggRow, TabbedTable, SearchInterceptor, + SearchInterceptorDeps, RequestTimeoutError, } from './search'; diff --git a/src/plugins/data/public/search/es_search/es_search_strategy.test.ts b/src/plugins/data/public/search/es_search/es_search_strategy.test.ts deleted file mode 100644 index b580c5170aad72..00000000000000 --- a/src/plugins/data/public/search/es_search/es_search_strategy.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 { CoreSetup } from '../../../../../core/public'; -import { coreMock } from '../../../../../core/public/mocks'; -import { esSearchStrategyProvider } from './es_search_strategy'; -import { ES_SEARCH_STRATEGY } from '../../../common/search/es_search'; - -describe('ES search strategy', () => { - let mockCoreSetup: MockedKeys; - const mockSearch = { search: jest.fn() }; - - beforeEach(() => { - mockCoreSetup = coreMock.createSetup(); - mockSearch.search.mockClear(); - }); - - it('returns a strategy with `search` that calls the sync search `search`', () => { - const request = { params: {} }; - const options = {}; - - const esSearch = esSearchStrategyProvider(mockCoreSetup, mockSearch); - esSearch.search(request, options); - - expect(mockSearch.search.mock.calls[0][0]).toEqual({ - ...request, - serverStrategy: ES_SEARCH_STRATEGY, - }); - expect(mockSearch.search.mock.calls[0][1]).toBe(options); - }); -}); diff --git a/src/plugins/data/public/search/es_search/es_search_strategy.ts b/src/plugins/data/public/search/es_search/es_search_strategy.ts deleted file mode 100644 index 82f8bf21ee57ba..00000000000000 --- a/src/plugins/data/public/search/es_search/es_search_strategy.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 { Observable } from 'rxjs'; -import { CoreSetup } from '../../../../../core/public'; -import { ES_SEARCH_STRATEGY, IEsSearchResponse } from '../../../common/search'; -import { ISearch } from '../i_search'; -import { ISearchStrategy } from '../types'; -import { SYNC_SEARCH_STRATEGY } from '../sync_search_strategy'; -import { getEsPreference } from './get_es_preference'; - -export function esSearchStrategyProvider( - core: CoreSetup, - syncStrategy: ISearchStrategy -) { - const search: ISearch = (request, options) => { - request.params = { - preference: getEsPreference(core.uiSettings), - ...request.params, - }; - return syncStrategy.search( - { ...request, serverStrategy: ES_SEARCH_STRATEGY }, - options - ) as Observable; - }; - return { search }; -} diff --git a/src/plugins/data/public/search/es_search/index.ts b/src/plugins/data/public/search/es_search/index.ts index 41c6ec388bfafe..f9bb7cd725eacd 100644 --- a/src/plugins/data/public/search/es_search/index.ts +++ b/src/plugins/data/public/search/es_search/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export { esSearchStrategyProvider } from './es_search_strategy'; export { getEsPreference } from './get_es_preference'; diff --git a/src/plugins/data/public/search/i_search.ts b/src/plugins/data/public/search/i_search.ts deleted file mode 100644 index e474135288149a..00000000000000 --- a/src/plugins/data/public/search/i_search.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 { Observable } from 'rxjs'; -import { TStrategyTypes } from './strategy_types'; -import { - IKibanaSearchRequest, - IKibanaSearchResponse, - DEFAULT_SEARCH_STRATEGY, -} from '../../common/search'; -import { SYNC_SEARCH_STRATEGY, ISyncSearchRequest } from './sync_search_strategy'; -import { - ES_SEARCH_STRATEGY, - IEsSearchRequest, - IEsSearchResponse, -} from '../../common/search/es_search'; - -export interface ISearchOptions { - signal?: AbortSignal; -} - -export interface IRequestTypesMap { - [SYNC_SEARCH_STRATEGY]: ISyncSearchRequest; - [ES_SEARCH_STRATEGY]: IEsSearchRequest; - [key: string]: IKibanaSearchRequest; -} - -export interface IResponseTypesMap { - [SYNC_SEARCH_STRATEGY]: IKibanaSearchResponse; - [ES_SEARCH_STRATEGY]: IEsSearchResponse; - [key: string]: IKibanaSearchResponse; -} - -export type ISearch = ( - request: IRequestTypesMap[T], - options?: ISearchOptions -) => Observable; - -// Service API types -export interface IStrategyOptions extends ISearchOptions { - strategy?: TStrategyTypes; -} - -export type ISearchGeneric = ( - request: IRequestTypesMap[T], - options?: IStrategyOptions -) => Observable; diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index 1b5395e1071c50..40d45ab88ea9f9 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -21,20 +21,11 @@ export * from './aggs'; export * from './expressions'; export * from './tabify'; -export { ISearchSetup, ISearchStart, ISearchStrategy } from './types'; - -export { - ISearch, - ISearchOptions, - IRequestTypesMap, - IResponseTypesMap, - ISearchGeneric, -} from './i_search'; +export { ISearch, ISearchOptions, ISearchGeneric, ISearchSetup, ISearchStart } from './types'; export { IEsSearchResponse, IEsSearchRequest, ES_SEARCH_STRATEGY } from '../../common/search'; -export { ISyncSearchRequest, SYNC_SEARCH_STRATEGY } from './sync_search_strategy'; -export { esSearchStrategyProvider, getEsPreference } from './es_search'; +export { getEsPreference } from './es_search'; export { IKibanaSearchResponse, IKibanaSearchRequest } from '../../common/search'; @@ -59,5 +50,5 @@ export { parseSearchSourceJSON, } from './search_source'; -export { SearchInterceptor } from './search_interceptor'; +export { SearchInterceptor, SearchInterceptorDeps } from './search_interceptor'; export { RequestTimeoutError } from './request_timeout_error'; diff --git a/src/plugins/data/public/search/mocks.ts b/src/plugins/data/public/search/mocks.ts index 45f4416859640b..c56331baffed2e 100644 --- a/src/plugins/data/public/search/mocks.ts +++ b/src/plugins/data/public/search/mocks.ts @@ -26,7 +26,6 @@ export * from './search_source/mocks'; function createSetupContract(): jest.Mocked { return { aggs: searchAggsSetupMock(), - registerSearchStrategy: jest.fn(), }; } @@ -34,7 +33,6 @@ function createStartContract(): jest.Mocked { return { aggs: searchAggsStartMock(), setInterceptor: jest.fn(), - getSearchStrategy: jest.fn(), search: jest.fn(), searchSource: searchSourceMock, __LEGACY: { diff --git a/src/plugins/data/public/search/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor.test.ts index bd056271688c1c..0f77f993165b0c 100644 --- a/src/plugins/data/public/search/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor.test.ts @@ -35,8 +35,12 @@ describe('SearchInterceptor', () => { mockCoreStart = coreMock.createStart(); mockSearch.mockClear(); searchInterceptor = new SearchInterceptor( - mockCoreStart.notifications.toasts, - mockCoreStart.application, + { + toasts: mockCoreStart.notifications.toasts, + application: mockCoreStart.application, + uiSettings: mockCoreStart.uiSettings, + http: mockCoreStart.http, + }, 1000 ); }); @@ -46,7 +50,7 @@ describe('SearchInterceptor', () => { const mockResponse = new Subject(); mockSearch.mockReturnValue(mockResponse.asObservable()); const mockRequest: IKibanaSearchRequest = {}; - const response = searchInterceptor.search(mockSearch, mockRequest); + const response = searchInterceptor.search(mockRequest); mockResponse.complete(); response.subscribe(); @@ -56,7 +60,7 @@ describe('SearchInterceptor', () => { test('should mirror the observable to completion if the request does not time out', () => { const mockResponse = new Subject(); mockSearch.mockReturnValue(mockResponse.asObservable()); - const response = searchInterceptor.search(mockSearch, {}); + const response = searchInterceptor.search({}); setTimeout(() => mockResponse.next('hi'), 250); setTimeout(() => mockResponse.complete(), 500); @@ -74,7 +78,7 @@ describe('SearchInterceptor', () => { test('should mirror the observable to error if the request does not time out', () => { const mockResponse = new Subject(); mockSearch.mockReturnValue(mockResponse.asObservable()); - const response = searchInterceptor.search(mockSearch, {}); + const response = searchInterceptor.search({}); setTimeout(() => mockResponse.next('hi'), 250); setTimeout(() => mockResponse.error('error'), 500); @@ -91,7 +95,7 @@ describe('SearchInterceptor', () => { test('should return a `RequestTimeoutError` if the request times out', () => { mockSearch.mockReturnValue(new Observable()); - const response = searchInterceptor.search(mockSearch, {}); + const response = searchInterceptor.search({}); const error = jest.fn(); response.subscribe({ error }); @@ -115,8 +119,8 @@ describe('SearchInterceptor', () => { pendingCount$.subscribe(next); const error = jest.fn(); - searchInterceptor.search(mockSearch, {}).subscribe({ error }); - searchInterceptor.search(mockSearch, {}).subscribe({ error }); + searchInterceptor.search({}).subscribe({ error }); + searchInterceptor.search({}).subscribe({ error }); setTimeout(() => mockResponses[0].complete(), 250); setTimeout(() => mockResponses[1].error('error'), 500); diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index 7cf6dac34ddaee..c7db04f291f148 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -17,18 +17,33 @@ * under the License. */ -import { BehaviorSubject, throwError, timer, Subscription, defer, fromEvent } from 'rxjs'; +import { + BehaviorSubject, + throwError, + timer, + Subscription, + defer, + fromEvent, + from, + Observable, +} from 'rxjs'; import { takeUntil, finalize, mergeMapTo, filter } from 'rxjs/operators'; -import { ApplicationStart, Toast, ToastsStart } from 'kibana/public'; +import { ApplicationStart, Toast, ToastsStart, CoreStart } from 'kibana/public'; import { getCombinedSignal, AbortError } from '../../common/utils'; -import { IKibanaSearchRequest } from '../../common/search'; -import { ISearch, ISearchOptions } from './i_search'; +import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../common/search'; +import { ISearchOptions } from './types'; import { RequestTimeoutError } from './request_timeout_error'; import { getLongQueryNotification } from './long_query_notification'; -import { TStrategyTypes } from './strategy_types'; const LONG_QUERY_NOTIFICATION_DELAY = 10000; +export interface SearchInterceptorDeps { + toasts: ToastsStart; + application: ApplicationStart; + http: CoreStart['http']; + uiSettings: CoreStart['uiSettings']; +} + export class SearchInterceptor { /** * `abortController` used to signal all searches to abort. @@ -63,10 +78,11 @@ export class SearchInterceptor { * @param requestTimeout Usually config value `elasticsearch.requestTimeout` */ constructor( - protected readonly toasts: ToastsStart, - protected readonly application: ApplicationStart, + protected readonly deps: SearchInterceptorDeps, protected readonly requestTimeout?: number ) { + this.deps.http.addLoadingCountSource(this.pendingCount$); + // When search requests go out, a notification is scheduled allowing users to continue the // request past the timeout. When all search requests complete, we remove the notification. this.getPendingCount$() @@ -87,66 +103,84 @@ export class SearchInterceptor { * either when `cancelPending` is called, when the request times out, or when the original * `AbortSignal` is aborted. Updates the `pendingCount` when the request is started/finalized. */ - public search = ( - search: ISearch, + public search( request: IKibanaSearchRequest, options?: ISearchOptions - ) => { + ): Observable { // Defer the following logic until `subscribe` is actually called return defer(() => { - this.pendingCount$.next(++this.pendingCount); - - // Schedule this request to automatically timeout after some interval - const timeoutController = new AbortController(); - const { signal: timeoutSignal } = timeoutController; - const timeout$ = timer(this.requestTimeout); - const subscription = timeout$.subscribe(() => timeoutController.abort()); - this.timeoutSubscriptions.add(subscription); + const { combinedSignal, cleanup } = this.getCombinedSignal(options); // If the request timed out, throw a `RequestTimeoutError` - const timeoutError$ = fromEvent(timeoutSignal, 'abort').pipe( - mergeMapTo(throwError(new RequestTimeoutError())) - ); - - const userAbort$ = fromEvent(this.abortController.signal, 'abort').pipe( - mergeMapTo(throwError(new AbortError())) + const timeoutError$ = fromEvent(combinedSignal, 'abort').pipe( + mergeMapTo( + throwError( + this.abortController.signal.aborted ? new AbortError() : new RequestTimeoutError() + ) + ) ); - // Schedule the notification to allow users to cancel or wait beyond the timeout - const notificationSubscription = timer(LONG_QUERY_NOTIFICATION_DELAY).subscribe( - this.showToast - ); + this.pendingCount$.next(++this.pendingCount); - // Get a combined `AbortSignal` that will be aborted whenever the first of the following occurs: - // 1. The user manually aborts (via `cancelPending`) - // 2. The request times out - // 3. The passed-in signal aborts (e.g. when re-fetching, or whenever the app determines) - const signals = [ - this.abortController.signal, - timeoutSignal, - ...(options?.signal ? [options.signal] : []), - ]; - const combinedSignal = getCombinedSignal(signals); - - return search(request, { ...options, signal: combinedSignal }).pipe( + return from( + this.deps.http.fetch({ + path: `/internal/search/es`, + method: 'POST', + body: JSON.stringify(request), + signal: combinedSignal, + }) + ).pipe( takeUntil(timeoutError$), - takeUntil(userAbort$), finalize(() => { this.pendingCount$.next(--this.pendingCount); - this.timeoutSubscriptions.delete(subscription); - notificationSubscription.unsubscribe(); + cleanup(); }) ); }); - }; + } + + protected getCombinedSignal(options?: ISearchOptions) { + // Schedule this request to automatically timeout after some interval + const timeoutController = new AbortController(); + const { signal: timeoutSignal } = timeoutController; + const timeout$ = timer(this.requestTimeout); + const subscription = timeout$.subscribe(() => timeoutController.abort()); + this.timeoutSubscriptions.add(subscription); + + // Schedule the notification to allow users to cancel or wait beyond the timeout + const notificationSubscription = timer(LONG_QUERY_NOTIFICATION_DELAY).subscribe(this.showToast); + + // Get a combined `AbortSignal` that will be aborted whenever the first of the following occurs: + // 1. The user manually aborts (via `cancelPending`) + // 2. The request times out + // 3. The passed-in signal aborts (e.g. when re-fetching, or whenever the app determines) + const signals = [ + this.abortController.signal, + timeoutSignal, + ...(options?.signal ? [options.signal] : []), + ]; + + const combinedSignal = getCombinedSignal(signals); + const cleanup = () => { + this.timeoutSubscriptions.delete(subscription); + notificationSubscription.unsubscribe(); + }; + + combinedSignal.addEventListener('abort', cleanup); + + return { + combinedSignal, + cleanup, + }; + } protected showToast = () => { if (this.longRunningToast) return; - this.longRunningToast = this.toasts.addInfo( + this.longRunningToast = this.deps.toasts.addInfo( { title: 'Your query is taking awhile', text: getLongQueryNotification({ - application: this.application, + application: this.deps.application, }), }, { @@ -157,7 +191,7 @@ export class SearchInterceptor { protected hideToast = () => { if (this.longRunningToast) { - this.toasts.remove(this.longRunningToast); + this.deps.toasts.remove(this.longRunningToast); delete this.longRunningToast; } }; diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index a6037bc181f4f2..9cc7327916eb18 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -18,15 +18,11 @@ */ import { Plugin, CoreSetup, CoreStart, PackageInfo } from '../../../../core/public'; -import { SYNC_SEARCH_STRATEGY, syncSearchStrategyProvider } from './sync_search_strategy'; -import { ISearchSetup, ISearchStart, TSearchStrategiesMap, ISearchStrategy } from './types'; +import { ISearchSetup, ISearchStart } from './types'; import { ExpressionsSetup } from '../../../../plugins/expressions/public'; import { createSearchSource, SearchSource, SearchSourceDependencies } from './search_source'; -import { TStrategyTypes } from './strategy_types'; import { getEsClient, LegacyApiCaller } from './legacy'; -import { ES_SEARCH_STRATEGY, DEFAULT_SEARCH_STRATEGY } from '../../common/search'; -import { esSearchStrategyProvider } from './es_search'; import { IndexPatternsContract } from '../index_patterns/index_patterns'; import { QuerySetup } from '../query'; import { GetInternalStartServicesFn } from '../types'; @@ -39,7 +35,7 @@ import { getCalculateAutoTimeExpression, } from './aggs'; import { FieldFormatsStart } from '../field_formats'; -import { ISearchGeneric } from './i_search'; +import { ISearchGeneric } from './types'; interface SearchServiceSetupDependencies { expressions: ExpressionsSetup; @@ -60,42 +56,16 @@ interface SearchServiceStartDependencies { * It also comes with two search strategy implementations - SYNC_SEARCH_STRATEGY and ES_SEARCH_STRATEGY. */ export class SearchService implements Plugin { - /** - * A mapping of search strategies keyed by a unique identifier. Plugins can use this unique identifier - * to override certain strategy implementations. - */ - private searchStrategies: TSearchStrategiesMap = {}; - private esClient?: LegacyApiCaller; private readonly aggTypesRegistry = new AggTypesRegistry(); private searchInterceptor!: SearchInterceptor; - private registerSearchStrategy = ( - name: T, - strategy: ISearchStrategy - ) => { - this.searchStrategies[name] = strategy; - }; - - private getSearchStrategy = (name: T): ISearchStrategy => { - const strategy = this.searchStrategies[name]; - if (!strategy) { - throw new Error(`Search strategy ${name} not found`); - } - return strategy; - }; - public setup( core: CoreSetup, { expressions, packageInfo, query, getInternalStartServices }: SearchServiceSetupDependencies ): ISearchSetup { this.esClient = getEsClient(core.injectedMetadata, core.http, packageInfo); - const syncSearchStrategy = syncSearchStrategyProvider(core); - const esSearchStrategy = esSearchStrategyProvider(core, syncSearchStrategy); - this.registerSearchStrategy(SYNC_SEARCH_STRATEGY, syncSearchStrategy); - this.registerSearchStrategy(ES_SEARCH_STRATEGY, esSearchStrategy); - const aggTypesSetup = this.aggTypesRegistry.setup(); // register each agg type @@ -116,7 +86,6 @@ export class SearchService implements Plugin { calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), types: aggTypesSetup, }, - registerSearchStrategy: this.registerSearchStrategy, }; } @@ -128,18 +97,19 @@ export class SearchService implements Plugin { * their own search collector instances */ this.searchInterceptor = new SearchInterceptor( - core.notifications.toasts, - core.application, + { + toasts: core.notifications.toasts, + application: core.application, + http: core.http, + uiSettings: core.uiSettings, + }, core.injectedMetadata.getInjectedVar('esRequestTimeout') as number ); const aggTypesStart = this.aggTypesRegistry.start(); const search: ISearchGeneric = (request, options) => { - const { search: defaultSearch } = this.getSearchStrategy( - options?.strategy || DEFAULT_SEARCH_STRATEGY - ); - return this.searchInterceptor.search(defaultSearch, request, options); + return this.searchInterceptor.search(request, options); }; const legacySearch = { @@ -164,7 +134,6 @@ export class SearchService implements Plugin { }, types: aggTypesStart, }, - getSearchStrategy: this.getSearchStrategy, search, searchSource: { create: createSearchSource(dependencies.indexPatterns, searchSourceDependencies), diff --git a/src/plugins/data/public/search/strategy_types.ts b/src/plugins/data/public/search/strategy_types.ts deleted file mode 100644 index 9afac9b5463620..00000000000000 --- a/src/plugins/data/public/search/strategy_types.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 { ES_SEARCH_STRATEGY } from '../../common/search/es_search'; -import { SYNC_SEARCH_STRATEGY } from './sync_search_strategy'; - -/** - * Contains all known strategy type identifiers that will be used to map to - * request and response shapes. Plugins that wish to add their own custom search - * strategies should extend this type via: - * - * const MY_STRATEGY = 'MY_STRATEGY'; - * - * declare module 'src/plugins/data/public' { - * export interface IRequestTypesMap { - * [MY_STRATEGY]: IMySearchRequest; - * } - * - * export interface IResponseTypesMap { - * [MY_STRATEGY]: IMySearchResponse - * } - * } - */ -export type TStrategyTypes = typeof SYNC_SEARCH_STRATEGY | typeof ES_SEARCH_STRATEGY | string; diff --git a/src/plugins/data/public/search/sync_search_strategy.test.ts b/src/plugins/data/public/search/sync_search_strategy.test.ts deleted file mode 100644 index 383a312fffad9d..00000000000000 --- a/src/plugins/data/public/search/sync_search_strategy.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 { coreMock } from '../../../../core/public/mocks'; -import { SYNC_SEARCH_STRATEGY, syncSearchStrategyProvider } from './sync_search_strategy'; -import { CoreSetup } from 'kibana/public'; - -describe('Sync search strategy', () => { - let mockCoreSetup: MockedKeys; - - beforeEach(() => { - mockCoreSetup = coreMock.createSetup(); - }); - - it('returns a strategy with `search` that calls the backend API', () => { - mockCoreSetup.http.fetch.mockImplementationOnce(() => Promise.resolve()); - - const syncSearch = syncSearchStrategyProvider(mockCoreSetup); - const request = { serverStrategy: SYNC_SEARCH_STRATEGY }; - syncSearch.search(request, {}); - - expect(mockCoreSetup.http.fetch.mock.calls[0][0]).toEqual({ - path: `/internal/search/${SYNC_SEARCH_STRATEGY}`, - body: JSON.stringify({ - serverStrategy: 'SYNC_SEARCH_STRATEGY', - }), - method: 'POST', - signal: undefined, - }); - }); - - it('increments and decrements loading count on success', async () => { - const expectedLoadingCountValues = [0, 1, 0]; - const receivedLoadingCountValues: number[] = []; - - mockCoreSetup.http.fetch.mockResolvedValueOnce('response'); - - const syncSearch = syncSearchStrategyProvider(mockCoreSetup); - const request = { serverStrategy: SYNC_SEARCH_STRATEGY }; - - const loadingCount$ = mockCoreSetup.http.addLoadingCountSource.mock.calls[0][0]; - loadingCount$.subscribe((value) => receivedLoadingCountValues.push(value)); - - await syncSearch.search(request, {}).toPromise(); - - expect(receivedLoadingCountValues).toEqual(expectedLoadingCountValues); - }); - - it('increments and decrements loading count on failure', async () => { - expect.assertions(1); - const expectedLoadingCountValues = [0, 1, 0]; - const receivedLoadingCountValues: number[] = []; - - mockCoreSetup.http.fetch.mockRejectedValueOnce('error'); - - const syncSearch = syncSearchStrategyProvider(mockCoreSetup); - const request = { serverStrategy: SYNC_SEARCH_STRATEGY }; - - const loadingCount$ = mockCoreSetup.http.addLoadingCountSource.mock.calls[0][0]; - loadingCount$.subscribe((value) => receivedLoadingCountValues.push(value)); - - try { - await syncSearch.search(request, {}).toPromise(); - } catch (e) { - expect(receivedLoadingCountValues).toEqual(expectedLoadingCountValues); - } - }); -}); diff --git a/src/plugins/data/public/search/sync_search_strategy.ts b/src/plugins/data/public/search/sync_search_strategy.ts deleted file mode 100644 index 25d2731df7d5ca..00000000000000 --- a/src/plugins/data/public/search/sync_search_strategy.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 { BehaviorSubject, from } from 'rxjs'; -import { finalize } from 'rxjs/operators'; -import { CoreSetup } from '../../../../core/public'; -import { IKibanaSearchRequest } from '../../common/search'; -import { ISearch } from './i_search'; - -export const SYNC_SEARCH_STRATEGY = 'SYNC_SEARCH_STRATEGY'; - -export interface ISyncSearchRequest extends IKibanaSearchRequest { - serverStrategy: string; -} - -export function syncSearchStrategyProvider(core: CoreSetup) { - const loadingCount$ = new BehaviorSubject(0); - core.http.addLoadingCountSource(loadingCount$); - - const search: ISearch = (request, options) => { - loadingCount$.next(loadingCount$.getValue() + 1); - - return from( - core.http.fetch({ - path: `/internal/search/${request.serverStrategy}`, - method: 'POST', - body: JSON.stringify(request), - signal: options?.signal, - }) - ).pipe(finalize(() => loadingCount$.next(loadingCount$.getValue() - 1))); - }; - - return { search }; -} diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index 135974b6977397..0c931e2beae09b 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -17,38 +17,32 @@ * under the License. */ +import { Observable } from 'rxjs'; import { SearchAggsSetup, SearchAggsStart } from './aggs'; -import { ISearch, ISearchGeneric } from './i_search'; -import { TStrategyTypes } from './strategy_types'; import { LegacyApiCaller } from './legacy/es_client'; import { SearchInterceptor } from './search_interceptor'; import { ISearchSource, SearchSourceFields } from './search_source'; -/** - * Search strategy interface contains a search method that takes in - * a request and returns a promise that resolves to a response. - */ -export interface ISearchStrategy { - search: ISearch; +import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../common/search'; + +export interface ISearchOptions { + signal?: AbortSignal; } -export type TSearchStrategiesMap = { - [K in TStrategyTypes]?: ISearchStrategy; -}; +export type ISearch = ( + request: IKibanaSearchRequest, + options?: ISearchOptions +) => Observable; -/** - * Extension point exposed for other plugins to register their own search - * strategies. - */ -export type TRegisterSearchStrategy = ( - name: T, - searchStrategy: ISearchStrategy -) => void; +// Service API types +export interface IStrategyOptions extends ISearchOptions { + strategy?: string; +} -/** - * Used if a plugin needs access to an already registered search strategy. - */ -export type TGetSearchStrategy = (name: T) => ISearchStrategy; +export type ISearchGeneric = ( + request: IKibanaSearchRequest, + options?: IStrategyOptions +) => Observable; export interface ISearchStartLegacy { esClient: LegacyApiCaller; @@ -60,22 +54,11 @@ export interface ISearchStartLegacy { */ export interface ISearchSetup { aggs: SearchAggsSetup; - /** - * Extension point exposed for other plugins to register their own search - * strategies. - */ - registerSearchStrategy: TRegisterSearchStrategy; } export interface ISearchStart { aggs: SearchAggsStart; setInterceptor: (searchInterceptor: SearchInterceptor) => void; - - /** - * Used if a plugin needs access to an already registered search strategy. - */ - getSearchStrategy: TGetSearchStrategy; - search: ISearchGeneric; searchSource: { create: (fields?: SearchSourceFields) => Promise; diff --git a/x-pack/plugins/data_enhanced/public/plugin.ts b/x-pack/plugins/data_enhanced/public/plugin.ts index 879c73587ed965..231f1d434b8922 100644 --- a/x-pack/plugins/data_enhanced/public/plugin.ts +++ b/x-pack/plugins/data_enhanced/public/plugin.ts @@ -5,18 +5,10 @@ */ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; -import { - DataPublicPluginSetup, - DataPublicPluginStart, - ES_SEARCH_STRATEGY, -} from '../../../../src/plugins/data/public'; +import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; import { setAutocompleteService } from './services'; import { setupKqlQuerySuggestionProvider, KUERY_LANGUAGE_NAME } from './autocomplete'; -import { - ASYNC_SEARCH_STRATEGY, - asyncSearchStrategyProvider, - enhancedEsSearchStrategyProvider, -} from './search'; + import { EnhancedSearchInterceptor } from './search/search_interceptor'; export interface DataEnhancedSetupDependencies { @@ -39,17 +31,17 @@ export class DataEnhancedPlugin KUERY_LANGUAGE_NAME, setupKqlQuerySuggestionProvider(core) ); - const asyncSearchStrategy = asyncSearchStrategyProvider(core); - const esSearchStrategy = enhancedEsSearchStrategyProvider(core, asyncSearchStrategy); - data.search.registerSearchStrategy(ASYNC_SEARCH_STRATEGY, asyncSearchStrategy); - data.search.registerSearchStrategy(ES_SEARCH_STRATEGY, esSearchStrategy); } public start(core: CoreStart, plugins: DataEnhancedStartDependencies) { setAutocompleteService(plugins.data.autocomplete); const enhancedSearchInterceptor = new EnhancedSearchInterceptor( - core.notifications.toasts, - core.application, + { + toasts: core.notifications.toasts, + application: core.application, + http: core.http, + uiSettings: core.uiSettings, + }, core.injectedMetadata.getInjectedVar('esRequestTimeout') as number ); plugins.data.search.setInterceptor(enhancedSearchInterceptor); diff --git a/x-pack/plugins/data_enhanced/public/search/async_search_strategy.test.ts b/x-pack/plugins/data_enhanced/public/search/async_search_strategy.test.ts deleted file mode 100644 index 6b8820b92ba84f..00000000000000 --- a/x-pack/plugins/data_enhanced/public/search/async_search_strategy.test.ts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { of } from 'rxjs'; -import { AbortController } from 'abort-controller'; -import { CoreSetup } from '../../../../../src/core/public'; -import { coreMock } from '../../../../../src/core/public/mocks'; -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; -import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; -import { asyncSearchStrategyProvider } from './async_search_strategy'; -import { IAsyncSearchOptions } from '.'; -import { DataEnhancedStartDependencies } from '../plugin'; - -describe('Async search strategy', () => { - let mockCoreSetup: jest.Mocked>; - let mockDataStart: jest.Mocked; - const mockSearch = jest.fn(); - const mockRequest = { params: {}, serverStrategy: 'foo' }; - const mockOptions: IAsyncSearchOptions = { pollInterval: 0 }; - - beforeEach(() => { - mockCoreSetup = coreMock.createSetup(); - mockDataStart = dataPluginMock.createStartContract(); - (mockDataStart.search.getSearchStrategy as jest.Mock).mockReturnValue({ search: mockSearch }); - - mockCoreSetup.getStartServices.mockResolvedValue([ - undefined as any, - { data: mockDataStart }, - undefined, - ]); - mockSearch.mockReset(); - }); - - it('only sends one request if the first response is complete', async () => { - mockSearch.mockReturnValueOnce(of({ id: 1, total: 1, loaded: 1 })); - - const asyncSearch = asyncSearchStrategyProvider(mockCoreSetup); - - await asyncSearch.search(mockRequest, mockOptions).toPromise(); - - expect(mockSearch.mock.calls[0][0]).toEqual(mockRequest); - expect(mockSearch.mock.calls[0][1]).toEqual({}); - expect(mockSearch).toBeCalledTimes(1); - }); - - it('stops polling when the response is complete', async () => { - mockSearch - .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 1, is_running: true, is_partial: true })) - .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2, is_running: false, is_partial: false })) - .mockReturnValueOnce( - of({ id: 1, total: 2, loaded: 2, is_running: false, is_partial: false }) - ); - - const asyncSearch = asyncSearchStrategyProvider(mockCoreSetup); - expect(mockSearch).toBeCalledTimes(0); - - await asyncSearch.search(mockRequest, mockOptions).toPromise(); - - expect(mockSearch).toBeCalledTimes(2); - }); - - it('stops polling when the response is an error', async () => { - mockSearch - .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 1, is_running: true, is_partial: true })) - .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2, is_running: false, is_partial: true })) - .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2, is_running: false, is_partial: true })); - - const asyncSearch = asyncSearchStrategyProvider(mockCoreSetup); - expect(mockSearch).toBeCalledTimes(0); - - await asyncSearch - .search(mockRequest, mockOptions) - .toPromise() - .catch(() => { - expect(mockSearch).toBeCalledTimes(2); - }); - }); - - // For bug fixed in https://github.com/elastic/kibana/pull/64155 - it('Continues polling if no records are returned on first async request', async () => { - mockSearch - .mockReturnValueOnce(of({ id: 1, total: 0, loaded: 0, is_running: true, is_partial: true })) - .mockReturnValueOnce( - of({ id: 1, total: 2, loaded: 2, is_running: false, is_partial: false }) - ); - - const asyncSearch = asyncSearchStrategyProvider(mockCoreSetup); - - expect(mockSearch).toBeCalledTimes(0); - - await asyncSearch.search(mockRequest, mockOptions).toPromise(); - - expect(mockDataStart.search.getSearchStrategy).toBeCalledTimes(1); - expect(mockSearch).toBeCalledTimes(2); - expect(mockSearch.mock.calls[0][0]).toEqual(mockRequest); - expect(mockSearch.mock.calls[1][0]).toEqual({ id: 1, serverStrategy: 'foo' }); - }); - - it('only sends the ID and server strategy after the first request', async () => { - mockSearch - .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 1, is_running: true, is_partial: true })) - .mockReturnValueOnce( - of({ id: 1, total: 2, loaded: 2, is_running: false, is_partial: false }) - ); - - const asyncSearch = asyncSearchStrategyProvider(mockCoreSetup); - - expect(mockSearch).toBeCalledTimes(0); - - await asyncSearch.search(mockRequest, mockOptions).toPromise(); - - expect(mockSearch).toBeCalledTimes(2); - expect(mockSearch.mock.calls[0][0]).toEqual(mockRequest); - expect(mockSearch.mock.calls[1][0]).toEqual({ id: 1, serverStrategy: 'foo' }); - }); - - it('sends a DELETE request and stops polling when the signal is aborted', async () => { - mockSearch - .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 1 })) - .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2 })) - .mockReturnValueOnce(of({ id: 1, total: 2, loaded: 2 })); - - const asyncSearch = asyncSearchStrategyProvider(mockCoreSetup); - const abortController = new AbortController(); - const options = { ...mockOptions, signal: abortController.signal }; - - const promise = asyncSearch.search(mockRequest, options).toPromise(); - abortController.abort(); - - try { - await promise; - } catch (e) { - expect(e.name).toBe('AbortError'); - expect(mockSearch).toBeCalledTimes(1); - expect(mockCoreSetup.http.delete).toBeCalled(); - } - }); -}); diff --git a/x-pack/plugins/data_enhanced/public/search/async_search_strategy.ts b/x-pack/plugins/data_enhanced/public/search/async_search_strategy.ts deleted file mode 100644 index 49b27bba33a608..00000000000000 --- a/x-pack/plugins/data_enhanced/public/search/async_search_strategy.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { EMPTY, fromEvent, NEVER, throwError, timer, Observable, from } from 'rxjs'; -import { mergeMap, expand, takeUntil, share, flatMap } from 'rxjs/operators'; -import { CoreSetup } from '../../../../../src/core/public'; -import { AbortError } from '../../../../../src/plugins/data/common'; -import { - ISearch, - ISearchStrategy, - ISyncSearchRequest, - SYNC_SEARCH_STRATEGY, -} from '../../../../../src/plugins/data/public'; -import { IAsyncSearchOptions, IAsyncSearchResponse, IAsyncSearchRequest } from './types'; -import { DataEnhancedStartDependencies } from '../plugin'; - -export const ASYNC_SEARCH_STRATEGY = 'ASYNC_SEARCH_STRATEGY'; - -declare module '../../../../../src/plugins/data/public' { - export interface IRequestTypesMap { - [ASYNC_SEARCH_STRATEGY]: IAsyncSearchRequest; - } -} - -export function asyncSearchStrategyProvider( - core: CoreSetup -): ISearchStrategy { - const startServices$ = from(core.getStartServices()).pipe(share()); - - const search: ISearch = ( - request: ISyncSearchRequest, - { pollInterval = 1000, ...options }: IAsyncSearchOptions = {} - ) => { - const { serverStrategy } = request; - let { id } = request; - - const aborted$ = options.signal - ? fromEvent(options.signal, 'abort').pipe( - mergeMap(() => { - // If we haven't received the response to the initial request, including the ID, then - // we don't need to send a follow-up request to delete this search. Otherwise, we - // send the follow-up request to delete this search, then throw an abort error. - if (id !== undefined) { - core.http.delete(`/internal/search/${request.serverStrategy}/${id}`); - } - return throwError(new AbortError()); - }) - ) - : NEVER; - - return startServices$.pipe( - flatMap((startServices) => { - const syncSearch = startServices[1].data.search.getSearchStrategy(SYNC_SEARCH_STRATEGY); - return (syncSearch.search(request, options) as Observable).pipe( - expand((response) => { - // If the response indicates of an error, stop polling and complete the observable - if (!response || (response.is_partial && !response.is_running)) { - return throwError(new AbortError()); - } - - // If the response indicates it is complete, stop polling and complete the observable - if (!response.is_running) return EMPTY; - - id = response.id; - - // Delay by the given poll interval - return timer(pollInterval).pipe( - // Send future requests using just the ID from the response - mergeMap(() => { - return syncSearch.search({ id, serverStrategy }, options); - }) - ); - }), - takeUntil(aborted$) - ); - }) - ); - }; - return { search }; -} diff --git a/x-pack/plugins/data_enhanced/public/search/es_search_strategy.test.ts b/x-pack/plugins/data_enhanced/public/search/es_search_strategy.test.ts deleted file mode 100644 index 5d6bd53e2c9453..00000000000000 --- a/x-pack/plugins/data_enhanced/public/search/es_search_strategy.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { CoreSetup } from '../../../../../src/core/public'; -import { coreMock } from '../../../../../src/core/public/mocks'; -import { ES_SEARCH_STRATEGY } from '../../../../../src/plugins/data/common'; -import { enhancedEsSearchStrategyProvider } from './es_search_strategy'; -import { IAsyncSearchOptions } from '.'; - -describe('Enhanced ES search strategy', () => { - let mockCoreSetup: jest.Mocked; - const mockSearch = { search: jest.fn() }; - - beforeEach(() => { - mockCoreSetup = coreMock.createSetup(); - mockSearch.search.mockClear(); - }); - - it('returns a strategy with `search` that calls the async search `search`', () => { - const request = { params: {} }; - const options: IAsyncSearchOptions = { pollInterval: 0 }; - - const esSearch = enhancedEsSearchStrategyProvider(mockCoreSetup, mockSearch); - esSearch.search(request, options); - - expect(mockSearch.search.mock.calls[0][0]).toEqual({ - ...request, - serverStrategy: ES_SEARCH_STRATEGY, - }); - expect(mockSearch.search.mock.calls[0][1]).toEqual(options); - }); -}); diff --git a/x-pack/plugins/data_enhanced/public/search/es_search_strategy.ts b/x-pack/plugins/data_enhanced/public/search/es_search_strategy.ts deleted file mode 100644 index c4b293a52a1043..00000000000000 --- a/x-pack/plugins/data_enhanced/public/search/es_search_strategy.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Observable } from 'rxjs'; -import { CoreSetup } from '../../../../../src/core/public'; -import { ES_SEARCH_STRATEGY, IEsSearchResponse } from '../../../../../src/plugins/data/common'; -import { - ISearch, - getEsPreference, - ISearchStrategy, - UI_SETTINGS, -} from '../../../../../src/plugins/data/public'; -import { IEnhancedEsSearchRequest, EnhancedSearchParams } from '../../common'; -import { ASYNC_SEARCH_STRATEGY } from './async_search_strategy'; -import { IAsyncSearchOptions } from './types'; - -export function enhancedEsSearchStrategyProvider( - core: CoreSetup, - asyncStrategy: ISearchStrategy -) { - const search: ISearch = ( - request: IEnhancedEsSearchRequest, - options - ) => { - const params: EnhancedSearchParams = { - ignoreThrottled: !core.uiSettings.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN), - preference: getEsPreference(core.uiSettings), - ...request.params, - }; - request.params = params; - - const asyncOptions: IAsyncSearchOptions = { pollInterval: 0, ...options }; - - return asyncStrategy.search( - { ...request, serverStrategy: ES_SEARCH_STRATEGY }, - asyncOptions - ) as Observable; - }; - - return { search }; -} diff --git a/x-pack/plugins/data_enhanced/public/search/index.ts b/x-pack/plugins/data_enhanced/public/search/index.ts index e39c1b6a1dd618..a7729aeea56478 100644 --- a/x-pack/plugins/data_enhanced/public/search/index.ts +++ b/x-pack/plugins/data_enhanced/public/search/index.ts @@ -5,5 +5,4 @@ */ export { ASYNC_SEARCH_STRATEGY, asyncSearchStrategyProvider } from './async_search_strategy'; -export { enhancedEsSearchStrategyProvider } from './es_search_strategy'; export { IAsyncSearchRequest, IAsyncSearchOptions } from './types'; diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts index a4cf324f9d475c..c9ecbe004780af 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts @@ -4,9 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ApplicationStart, ToastsStart } from 'kibana/public'; +import { fromEvent, Observable, throwError, NEVER, EMPTY, timer } from 'rxjs'; +import { mergeMap, expand, takeUntil } from 'rxjs/operators'; import { getLongQueryNotification } from './long_query_notification'; -import { SearchInterceptor } from '../../../../../src/plugins/data/public'; +import { + SearchInterceptor, + SearchInterceptorDeps, + IKibanaSearchRequest, + IKibanaSearchResponse, + UI_SETTINGS, +} from '../../../../../src/plugins/data/public'; +import { AbortError } from '../../../../../src/plugins/data/common'; +import { IAsyncSearchOptions } from '.'; +import { IAsyncSearchResponse } from './types'; +import { EnhancedSearchParams } from '../../common'; export class EnhancedSearchInterceptor extends SearchInterceptor { /** @@ -16,8 +27,8 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { * @param application The `core.application` service * @param requestTimeout Usually config value `elasticsearch.requestTimeout` */ - constructor(toasts: ToastsStart, application: ApplicationStart, requestTimeout?: number) { - super(toasts, application, requestTimeout); + constructor(deps: SearchInterceptorDeps, requestTimeout?: number) { + super(deps, requestTimeout); } /** @@ -40,7 +51,7 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { protected showToast = () => { if (this.longRunningToast) return; - this.longRunningToast = this.toasts.addInfo( + this.longRunningToast = this.deps.toasts.addInfo( { title: 'Your query is taking awhile', text: getLongQueryNotification({ @@ -53,4 +64,54 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { } ); }; + + public search( + request: IKibanaSearchRequest, + { pollInterval = 1000, ...options }: IAsyncSearchOptions = {} + ): Observable { + let { id } = request; + const syncSearch = super.search; + + const params: EnhancedSearchParams = { + ignoreThrottled: !this.deps.uiSettings.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN), + ...request.params, + }; + + const aborted$ = options?.signal + ? fromEvent(options.signal, 'abort').pipe( + mergeMap(() => { + // If we haven't received the response to the initial request, including the ID, then + // we don't need to send a follow-up request to delete this search. Otherwise, we + // send the follow-up request to delete this search, then throw an abort error. + if (id !== undefined) { + this.deps.http.delete(`/internal/search/es/${id}`); + } + return throwError(new AbortError()); + }) + ) + : NEVER; + + return syncSearch.call(this, request, options).pipe( + expand((response: IAsyncSearchResponse) => { + // If the response indicates of an error, stop polling and complete the observable + if (!response || (response.is_partial && !response.is_running)) { + return throwError(new AbortError()); + } + + // If the response indicates it is complete, stop polling and complete the observable + if (!response.is_running) return EMPTY; + + id = response.id; + + // Delay by the given poll interval + return timer(pollInterval).pipe( + // Send future requests using just the ID from the response + mergeMap(() => { + return syncSearch.call(this, { id }, options); + }) + ); + }), + takeUntil(aborted$) + ); + } } From ddd0d0e5e310f0e57e5b846e52e114f8a28b13ca Mon Sep 17 00:00:00 2001 From: Liza K Date: Sun, 28 Jun 2020 23:57:45 +0300 Subject: [PATCH 10/24] TypeScript of hell delete search explorer --- examples/search_explorer/README.md | 8 - examples/search_explorer/kibana.json | 9 -- .../search_explorer/public/application.tsx | 133 ----------------- .../public/async_demo_strategy.tsx | 123 ---------------- .../search_explorer/public/demo_strategy.tsx | 134 ----------------- examples/search_explorer/public/do_search.tsx | 138 ------------------ .../search_explorer/public/documentation.tsx | 102 ------------- .../search_explorer/public/es_strategy.tsx | 136 ----------------- .../search_explorer/public/guide_section.tsx | 137 ----------------- examples/search_explorer/public/index.ts | 22 --- examples/search_explorer/public/page.tsx | 51 ------- examples/search_explorer/public/plugin.tsx | 65 --------- .../search_explorer/public/search_api.tsx | 50 ------- examples/search_explorer/public/types.ts | 31 ---- examples/search_explorer/tsconfig.json | 15 -- .../data/common/search/es_search/index.ts | 7 +- .../data/common/search/es_search/types.ts | 12 +- src/plugins/data/common/search/index.ts | 7 +- .../public/search/fetch/get_search_params.ts | 4 +- .../public/search/search_interceptor.test.ts | 129 +++++++++++----- .../data/public/search/search_interceptor.ts | 10 +- .../data/public/search/search_service.test.ts | 2 +- .../data/public/search/search_service.ts | 2 +- src/plugins/data/public/search/types.ts | 11 +- x-pack/plugins/data_enhanced/common/index.ts | 7 +- .../data_enhanced/common/search/index.ts | 7 +- .../data_enhanced/common/search/types.ts | 29 +++- x-pack/plugins/data_enhanced/public/index.ts | 2 - .../data_enhanced/public/search/index.ts | 3 +- .../public/search/search_interceptor.test.ts | 15 +- .../public/search/search_interceptor.ts | 22 ++- .../data_enhanced/public/search/types.ts | 24 +-- .../server/search/es_search_strategy.ts | 7 +- 33 files changed, 192 insertions(+), 1262 deletions(-) delete mode 100644 examples/search_explorer/README.md delete mode 100644 examples/search_explorer/kibana.json delete mode 100644 examples/search_explorer/public/application.tsx delete mode 100644 examples/search_explorer/public/async_demo_strategy.tsx delete mode 100644 examples/search_explorer/public/demo_strategy.tsx delete mode 100644 examples/search_explorer/public/do_search.tsx delete mode 100644 examples/search_explorer/public/documentation.tsx delete mode 100644 examples/search_explorer/public/es_strategy.tsx delete mode 100644 examples/search_explorer/public/guide_section.tsx delete mode 100644 examples/search_explorer/public/index.ts delete mode 100644 examples/search_explorer/public/page.tsx delete mode 100644 examples/search_explorer/public/plugin.tsx delete mode 100644 examples/search_explorer/public/search_api.tsx delete mode 100644 examples/search_explorer/public/types.ts delete mode 100644 examples/search_explorer/tsconfig.json diff --git a/examples/search_explorer/README.md b/examples/search_explorer/README.md deleted file mode 100644 index 0e5a48cf22dc1a..00000000000000 --- a/examples/search_explorer/README.md +++ /dev/null @@ -1,8 +0,0 @@ -## Search explorer - -This example search explorer app shows how to use different search strategies in order to retrieve data. - -One demo uses the built in elasticsearch search strategy, and runs a search against data in elasticsearch. The -other demo uses the custom demo search strategy, a custom search strategy registerd inside the [demo_search plugin](../demo_search). - -To run this example, use the command `yarn start --run-examples`. \ No newline at end of file diff --git a/examples/search_explorer/kibana.json b/examples/search_explorer/kibana.json deleted file mode 100644 index e22d4e2756d11b..00000000000000 --- a/examples/search_explorer/kibana.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "id": "searchExplorer", - "version": "0.0.1", - "kibanaVersion": "kibana", - "server": false, - "ui": true, - "requiredPlugins": ["data", "demoSearch", "developerExamples"], - "optionalPlugins": [] -} diff --git a/examples/search_explorer/public/application.tsx b/examples/search_explorer/public/application.tsx deleted file mode 100644 index a7072936f268d3..00000000000000 --- a/examples/search_explorer/public/application.tsx +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 React from 'react'; -import ReactDOM from 'react-dom'; -import { BrowserRouter as Router, Route, withRouter, RouteComponentProps } from 'react-router-dom'; - -import { - EuiPage, - EuiPageSideBar, - // @ts-ignore - EuiSideNav, -} from '@elastic/eui'; - -import { AppMountParameters, CoreStart } from '../../../src/core/public'; -import { EsSearchTest } from './es_strategy'; -import { Page } from './page'; -import { DemoStrategy } from './demo_strategy'; -import { AsyncDemoStrategy } from './async_demo_strategy'; -import { DocumentationPage } from './documentation'; -import { SearchApiPage } from './search_api'; -import { AppPluginStartDependencies, SearchBarComponentParams } from './types'; - -const Home = () => ; - -interface PageDef { - title: string; - id: string; - component: React.ReactNode; -} - -type NavProps = RouteComponentProps & { - navigateToApp: CoreStart['application']['navigateToApp']; - pages: PageDef[]; -}; - -const Nav = withRouter(({ history, navigateToApp, pages }: NavProps) => { - const navItems = pages.map((page) => ({ - id: page.id, - name: page.title, - onClick: () => history.push(`/${page.id}`), - 'data-test-subj': page.id, - })); - - return ( - - ); -}); - -const buildPage = (page: PageDef) => {page.component}; - -const SearchApp = ({ basename, data, application }: SearchBarComponentParams) => { - const pages: PageDef[] = [ - { - id: 'home', - title: 'Home', - component: , - }, - { - title: 'Search API', - id: 'searchAPI', - component: , - }, - { - title: 'ES search strategy', - id: 'esSearch', - component: , - }, - { - title: 'Demo search strategy', - id: 'demoSearch', - component: , - }, - { - title: 'Async demo search strategy', - id: 'asyncDemoSearch', - component: , - }, - ]; - - const routes = pages.map((page, i) => ( - buildPage(page)} /> - )); - - return ( - - - -