[Search] Remove msearch from searchsource (#96936)

* Move inspector adapter integration into search source

* docs and ts

* Move other bucket to search source

* test ts + delete unused tabilfy function

* hierarchical param in aggconfig.
ts improvements
more inspector tests

* fix jest

* separate inspect
more tests

* jest

* inspector

* Error handling and more tests

* put the fun in functional tests

* delete client side legacy msearch code

* ts

* override to sync search in search source

* delete more legacy code

* ts

* delete moarrrr
This commit is contained in:
Liza Katz 2021-04-22 13:23:51 +03:00 committed by GitHub
parent 87fa92bf3a
commit b2a9dd12a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 33 additions and 668 deletions

View file

@ -11,7 +11,6 @@ import { SearchSourceDependencies } from './search_source';
import { IIndexPattern } from '../../index_patterns';
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
import { Filter } from '../../es_query/filters';
import { BehaviorSubject } from 'rxjs';
describe('createSearchSource', () => {
const indexPatternMock: IIndexPattern = {} as IIndexPattern;
@ -24,10 +23,6 @@ describe('createSearchSource', () => {
getConfig: jest.fn(),
search: jest.fn(),
onResponse: (req, res) => res,
legacy: {
callMsearch: jest.fn(),
loadingCount$: new BehaviorSubject(0),
},
};
indexPatternContractMock = ({

View file

@ -7,7 +7,6 @@
*/
import type { estypes } from '@elastic/elasticsearch';
import { LegacyFetchHandlers } from '../legacy/types';
import { GetConfigFn } from '../../../types';
/**
@ -29,11 +28,6 @@ export interface FetchHandlers {
request: SearchRequest,
response: estypes.SearchResponse<any>
) => estypes.SearchResponse<any>;
/**
* These handlers are only used by the legacy defaultSearchStrategy and can be removed
* once that strategy has been deprecated.
*/
legacy: LegacyFetchHandlers;
}
export interface SearchError {

View file

@ -1,102 +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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { callClient } from './call_client';
import { SearchStrategySearchParams } from './types';
import { defaultSearchStrategy } from './default_search_strategy';
import { FetchHandlers } from '../fetch';
import { BehaviorSubject } from 'rxjs';
const mockAbortFn = jest.fn();
jest.mock('./default_search_strategy', () => {
return {
defaultSearchStrategy: {
search: jest.fn(({ searchRequests }: SearchStrategySearchParams) => {
return {
searching: Promise.resolve(
searchRequests.map((req) => {
return {
id: req._searchStrategyId,
};
})
),
abort: mockAbortFn,
};
}),
},
};
});
describe('callClient', () => {
const handleResponse = jest.fn().mockImplementation((req, res) => res);
const handlers = {
getConfig: jest.fn(),
onResponse: handleResponse,
legacy: {
callMsearch: jest.fn(),
loadingCount$: new BehaviorSubject(0),
},
} as FetchHandlers;
beforeEach(() => {
handleResponse.mockClear();
});
test('Passes the additional arguments it is given to the search strategy', () => {
const searchRequests = [{ _searchStrategyId: 0 }];
callClient(searchRequests, [], handlers);
expect(defaultSearchStrategy.search).toBeCalled();
expect((defaultSearchStrategy.search as any).mock.calls[0][0]).toEqual({
searchRequests,
...handlers,
});
});
test('Returns the responses in the original order', async () => {
const searchRequests = [{ _searchStrategyId: 1 }, { _searchStrategyId: 0 }];
const responses = await Promise.all(callClient(searchRequests, [], handlers));
expect(responses[0]).toEqual({ id: searchRequests[0]._searchStrategyId });
expect(responses[1]).toEqual({ id: searchRequests[1]._searchStrategyId });
});
test('Calls handleResponse with each request and response', async () => {
const searchRequests = [{ _searchStrategyId: 0 }, { _searchStrategyId: 1 }];
const responses = callClient(searchRequests, [], handlers);
await Promise.all(responses);
expect(handleResponse).toBeCalledTimes(2);
expect(handleResponse).toBeCalledWith(searchRequests[0], {
id: searchRequests[0]._searchStrategyId,
});
expect(handleResponse).toBeCalledWith(searchRequests[1], {
id: searchRequests[1]._searchStrategyId,
});
});
test('If passed an abortSignal, calls abort on the strategy if the signal is aborted', () => {
const searchRequests = [{ _searchStrategyId: 0 }, { _searchStrategyId: 1 }];
const abortController = new AbortController();
const requestOptions = [
{
abortSignal: abortController.signal,
},
];
callClient(searchRequests, requestOptions, handlers);
abortController.abort();
expect(mockAbortFn).toBeCalled();
// expect(mockAbortFns[1]).not.toBeCalled();
});
});

View file

@ -1,38 +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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { estypes } from '@elastic/elasticsearch';
import { FetchHandlers, SearchRequest } from '../fetch';
import { defaultSearchStrategy } from './default_search_strategy';
import { ISearchOptions } from '../../index';
export function callClient(
searchRequests: SearchRequest[],
requestsOptions: ISearchOptions[] = [],
fetchHandlers: FetchHandlers
) {
// Correlate the options with the request that they're associated with
const requestOptionEntries: Array<
[SearchRequest, ISearchOptions]
> = searchRequests.map((request, i) => [request, requestsOptions[i]]);
const requestOptionsMap = new Map<SearchRequest, ISearchOptions>(requestOptionEntries);
const requestResponseMap = new Map<SearchRequest, Promise<estypes.SearchResponse<any>>>();
const { searching, abort } = defaultSearchStrategy.search({
searchRequests,
...fetchHandlers,
});
searchRequests.forEach((request, i) => {
const response = searching.then((results) => fetchHandlers.onResponse(request, results[i]));
const { abortSignal = null } = requestOptionsMap.get(request) || {};
if (abortSignal) abortSignal.addEventListener('abort', abort);
requestResponseMap.set(request, response);
});
return searchRequests.map((request) => requestResponseMap.get(request)!);
}

View file

@ -1,61 +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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { MockedKeys } from '@kbn/utility-types/jest';
import { defaultSearchStrategy } from './default_search_strategy';
import { LegacyFetchHandlers, SearchStrategySearchParams } from './types';
import { BehaviorSubject } from 'rxjs';
const { search } = defaultSearchStrategy;
describe('defaultSearchStrategy', () => {
describe('search', () => {
let searchArgs: MockedKeys<SearchStrategySearchParams>;
beforeEach(() => {
searchArgs = {
searchRequests: [
{
index: { title: 'foo' },
body: {},
},
],
getConfig: jest.fn(),
onResponse: (req, res) => res,
legacy: {
callMsearch: jest.fn().mockResolvedValue(undefined),
loadingCount$: new BehaviorSubject(0) as any,
} as jest.Mocked<LegacyFetchHandlers>,
};
});
test('calls callMsearch with the correct arguments', async () => {
await search({ ...searchArgs });
expect(searchArgs.legacy.callMsearch.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
Object {
"body": Object {
"searches": Array [
Object {
"body": Object {},
"header": Object {
"index": "foo",
"preference": undefined,
},
},
],
},
"signal": AbortSignal {},
},
],
]
`);
});
});
});

View file

@ -1,63 +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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { getPreference } from '../fetch';
import { SearchStrategyProvider, SearchStrategySearchParams } from './types';
// @deprecated
export const defaultSearchStrategy: SearchStrategyProvider = {
id: 'default',
search: (params) => {
return msearch(params);
},
};
function msearch({ searchRequests, getConfig, legacy }: SearchStrategySearchParams) {
const { callMsearch, loadingCount$ } = legacy;
const requests = searchRequests.map(({ index, body }) => {
return {
header: {
index: index.title || index,
preference: getPreference(getConfig),
},
body,
};
});
const abortController = new AbortController();
let resolved = false;
// Start LoadingIndicator
loadingCount$.next(loadingCount$.getValue() + 1);
const cleanup = () => {
if (!resolved) {
resolved = true;
// Decrement loading counter & cleanup BehaviorSubject
loadingCount$.next(loadingCount$.getValue() - 1);
loadingCount$.complete();
}
};
const searching = callMsearch({
body: { searches: requests },
signal: abortController.signal,
})
.then((res: any) => res?.body?.responses)
.finally(() => cleanup());
return {
abort: () => {
abortController.abort();
cleanup();
},
searching,
};
}

View file

@ -1,132 +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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { SearchResponse } from 'elasticsearch';
import { UI_SETTINGS } from '../../../constants';
import { GetConfigFn } from '../../../types';
import { FetchHandlers, SearchRequest } from '../fetch';
import { ISearchOptions } from '../../index';
import { callClient } from './call_client';
import { fetchSoon } from './fetch_soon';
function getConfigStub(config: any = {}): GetConfigFn {
return (key) => config[key];
}
const mockResponses: Record<string, SearchResponse<any>> = {
foo: {
took: 1,
timed_out: false,
} as SearchResponse<any>,
bar: {
took: 2,
timed_out: false,
} as SearchResponse<any>,
baz: {
took: 3,
timed_out: false,
} as SearchResponse<any>,
};
jest.useFakeTimers();
jest.mock('./call_client', () => ({
callClient: jest.fn((requests: SearchRequest[]) => {
// Allow a request object to specify which mockResponse it wants to receive (_mockResponseId)
// in addition to how long to simulate waiting before returning a response (_waitMs)
const responses = requests.map((request) => {
const waitMs = requests.reduce((total, { _waitMs }) => total + _waitMs || 0, 0);
return new Promise((resolve) => {
setTimeout(() => {
resolve(mockResponses[request._mockResponseId]);
}, waitMs);
});
});
return Promise.resolve(responses);
}),
}));
describe('fetchSoon', () => {
beforeEach(() => {
(callClient as jest.Mock).mockClear();
});
test('should execute asap if config is set to not batch searches', () => {
const getConfig = getConfigStub({ [UI_SETTINGS.COURIER_BATCH_SEARCHES]: false });
const request = {};
const options = {};
fetchSoon(request, options, { getConfig } as FetchHandlers);
expect(callClient).toBeCalled();
});
test('should delay by 50ms if config is set to batch searches', () => {
const getConfig = getConfigStub({ [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true });
const request = {};
const options = {};
fetchSoon(request, options, { getConfig } as FetchHandlers);
expect(callClient).not.toBeCalled();
jest.advanceTimersByTime(0);
expect(callClient).not.toBeCalled();
jest.advanceTimersByTime(50);
expect(callClient).toBeCalled();
});
test('should send a batch of requests to callClient', () => {
const getConfig = getConfigStub({ [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true });
const requests = [{ foo: 1 }, { foo: 2 }];
const options = [{ bar: 1 }, { bar: 2 }];
requests.forEach((request, i) => {
fetchSoon(request, options[i] as ISearchOptions, { getConfig } as FetchHandlers);
});
jest.advanceTimersByTime(50);
expect(callClient).toBeCalledTimes(1);
expect((callClient as jest.Mock).mock.calls[0][0]).toEqual(requests);
expect((callClient as jest.Mock).mock.calls[0][1]).toEqual(options);
});
test('should return the response to the corresponding call for multiple batched requests', async () => {
const getConfig = getConfigStub({ [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true });
const requests = [{ _mockResponseId: 'foo' }, { _mockResponseId: 'bar' }];
const promises = requests.map((request) => {
return fetchSoon(request, {}, { getConfig } as FetchHandlers);
});
jest.advanceTimersByTime(50);
const results = await Promise.all(promises);
expect(results).toEqual([mockResponses.foo, mockResponses.bar]);
});
test('should wait for the previous batch to start before starting a new batch', () => {
const getConfig = getConfigStub({ [UI_SETTINGS.COURIER_BATCH_SEARCHES]: true });
const firstBatch = [{ foo: 1 }, { foo: 2 }];
const secondBatch = [{ bar: 1 }, { bar: 2 }];
firstBatch.forEach((request) => {
fetchSoon(request, {}, { getConfig } as FetchHandlers);
});
jest.advanceTimersByTime(50);
secondBatch.forEach((request) => {
fetchSoon(request, {}, { getConfig } as FetchHandlers);
});
expect(callClient).toBeCalledTimes(1);
expect((callClient as jest.Mock).mock.calls[0][0]).toEqual(firstBatch);
jest.advanceTimersByTime(50);
expect(callClient).toBeCalledTimes(2);
expect((callClient as jest.Mock).mock.calls[1][0]).toEqual(secondBatch);
});
});

View file

@ -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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { estypes } from '@elastic/elasticsearch';
import { UI_SETTINGS } from '../../../constants';
import { FetchHandlers, SearchRequest } from '../fetch';
import { ISearchOptions } from '../../index';
import { callClient } from './call_client';
/**
* This function introduces a slight delay in the request process to allow multiple requests to queue
* up (e.g. when a dashboard is loading).
*/
export async function fetchSoon(
request: SearchRequest,
options: ISearchOptions,
fetchHandlers: FetchHandlers
) {
const msToDelay = fetchHandlers.getConfig(UI_SETTINGS.COURIER_BATCH_SEARCHES) ? 50 : 0;
return delayedFetch(request, options, fetchHandlers, msToDelay);
}
/**
* Delays executing a function for a given amount of time, and returns a promise that resolves
* with the result.
* @param fn The function to invoke
* @param ms The number of milliseconds to wait
* @return Promise<any> A promise that resolves with the result of executing the function
*/
function delay<T>(fn: (...args: any) => T, ms: number): Promise<T> {
return new Promise((resolve) => {
setTimeout(() => resolve(fn()), ms);
});
}
// The current batch/queue of requests to fetch
let requestsToFetch: SearchRequest[] = [];
let requestOptions: ISearchOptions[] = [];
// The in-progress fetch (if there is one)
let fetchInProgress: any = null;
/**
* Delay fetching for a given amount of time, while batching up the requests to be fetched.
* Returns a promise that resolves with the response for the given request.
* @param request The request to fetch
* @param ms The number of milliseconds to wait (and batch requests)
* @return Promise<SearchResponse> The response for the given request
*/
async function delayedFetch(
request: SearchRequest,
options: ISearchOptions,
fetchHandlers: FetchHandlers,
ms: number
): Promise<estypes.SearchResponse<any>> {
if (ms === 0) {
return callClient([request], [options], fetchHandlers)[0] as Promise<
estypes.SearchResponse<any>
>;
}
const i = requestsToFetch.length;
requestsToFetch = [...requestsToFetch, request];
requestOptions = [...requestOptions, options];
// Note: the typescript here only worked because `SearchResponse` was `any`
// Since this code is legacy, I'm leaving the any here.
const responses: any[] = await (fetchInProgress =
fetchInProgress ||
delay(() => {
const response = callClient(requestsToFetch, requestOptions, fetchHandlers);
requestsToFetch = [];
requestOptions = [];
fetchInProgress = null;
return response;
}, ms));
return responses[i];
}

View file

@ -6,5 +6,4 @@
* Side Public License, v 1.
*/
export { fetchSoon } from './fetch_soon';
export * from './types';

View file

@ -6,9 +6,7 @@
* Side Public License, v 1.
*/
import { BehaviorSubject } from 'rxjs';
import type { estypes, ApiResponse } from '@elastic/elasticsearch';
import { FetchHandlers, SearchRequest } from '../fetch';
interface MsearchHeaders {
index: string;
@ -29,27 +27,3 @@ export interface MsearchRequestBody {
export interface MsearchResponse {
body: ApiResponse<{ responses: Array<estypes.SearchResponse<any>> }>;
}
// @internal
export interface LegacyFetchHandlers {
callMsearch: (params: {
body: MsearchRequestBody;
signal: AbortSignal;
}) => Promise<MsearchResponse>;
loadingCount$: BehaviorSubject<number>;
}
export interface SearchStrategySearchParams extends FetchHandlers {
searchRequests: SearchRequest[];
}
// @deprecated
export interface SearchStrategyProvider {
id: string;
search: (params: SearchStrategySearchParams) => SearchStrategyResponse;
}
export interface SearchStrategyResponse<T = any> {
searching: Promise<Array<estypes.SearchResponse<T>>>;
abort: () => void;
}

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { BehaviorSubject, of } from 'rxjs';
import { of } from 'rxjs';
import type { MockedKeys } from '@kbn/utility-types/jest';
import { uiSettingsServiceMock } from '../../../../../core/public/mocks';
@ -47,8 +47,4 @@ export const createSearchSourceMock = (fields?: SearchSourceFields) =>
getConfig: uiSettingsServiceMock.createStartContract().get,
search: jest.fn(),
onResponse: jest.fn().mockImplementation((req, res) => res),
legacy: {
callMsearch: jest.fn(),
loadingCount$: new BehaviorSubject(0),
},
});

View file

@ -6,20 +6,15 @@
* Side Public License, v 1.
*/
import { BehaviorSubject, of } from 'rxjs';
import { of } from 'rxjs';
import { IndexPattern } from '../../index_patterns';
import { GetConfigFn } from '../../types';
import { fetchSoon } from './legacy';
import { SearchSource, SearchSourceDependencies, SortDirection } from './';
import { AggConfigs, AggTypesRegistryStart } from '../../';
import { AggConfigs, AggTypesRegistryStart, ES_SEARCH_STRATEGY } from '../../';
import { mockAggTypesRegistry } from '../aggs/test_helpers';
import { RequestResponder } from 'src/plugins/inspector/common';
import { switchMap } from 'rxjs/operators';
jest.mock('./legacy', () => ({
fetchSoon: jest.fn().mockResolvedValue({}),
}));
const getComputedFields = () => ({
storedFields: [],
scriptFields: {},
@ -89,10 +84,6 @@ describe('SearchSource', () => {
getConfig: getConfigMock,
search: mockSearchMethod,
onResponse: (req, res) => res,
legacy: {
callMsearch: jest.fn(),
loadingCount$: new BehaviorSubject(0),
},
};
searchSource = new SearchSource({}, searchSourceDependencies);
@ -869,7 +860,7 @@ describe('SearchSource', () => {
});
describe('fetch$', () => {
describe('#legacy fetch()', () => {
describe('#legacy COURIER_BATCH_SEARCHES', () => {
beforeEach(() => {
searchSourceDependencies = {
...searchSourceDependencies,
@ -879,11 +870,22 @@ describe('SearchSource', () => {
};
});
test('should call msearch', async () => {
test('should override to use sync search if not set', async () => {
searchSource = new SearchSource({ index: indexPattern }, searchSourceDependencies);
const options = {};
await searchSource.fetch$(options).toPromise();
expect(fetchSoon).toBeCalledTimes(1);
const [, callOptions] = mockSearchMethod.mock.calls[0];
expect(callOptions.strategy).toBe(ES_SEARCH_STRATEGY);
});
test('should not override strategy if set ', async () => {
searchSource = new SearchSource({ index: indexPattern }, searchSourceDependencies);
const options = { strategy: 'banana' };
await searchSource.fetch$(options).toPromise();
const [, callOptions] = mockSearchMethod.mock.calls[0];
expect(callOptions.strategy).toBe('banana');
});
});

View file

@ -75,7 +75,7 @@ import { estypes } from '@elastic/elasticsearch';
import { normalizeSortRequest } from './normalize_sort_request';
import { fieldWildcardFilter } from '../../../../kibana_utils/common';
import { IIndexPattern, IndexPattern, IndexPatternField } from '../../index_patterns';
import { AggConfigs, ISearchGeneric, ISearchOptions } from '../..';
import { AggConfigs, ES_SEARCH_STRATEGY, ISearchGeneric, ISearchOptions } from '../..';
import type {
ISearchSource,
SearchFieldValue,
@ -95,7 +95,6 @@ import {
IKibanaSearchResponse,
} from '../../../common';
import { getHighlightRequest } from '../../../common/field_formats';
import { fetchSoon } from './legacy';
import { extractReferences } from './extract_references';
/** @internal */
@ -274,6 +273,13 @@ export class SearchSource {
*/
fetch$(options: ISearchOptions = {}) {
const { getConfig } = this.dependencies;
const syncSearchByDefault = getConfig(UI_SETTINGS.COURIER_BATCH_SEARCHES);
// Use the sync search strategy if legacy search is enabled.
// This still uses bfetch for batching.
if (!options?.strategy && syncSearchByDefault) {
options.strategy = ES_SEARCH_STRATEGY;
}
const s$ = defer(() => this.requestIsStarting(options)).pipe(
switchMap(() => {
@ -283,9 +289,7 @@ export class SearchSource {
options.indexPattern = searchRequest.index;
}
return getConfig(UI_SETTINGS.COURIER_BATCH_SEARCHES)
? from(this.legacyFetch(searchRequest, options))
: this.fetchSearch$(searchRequest, options);
return this.fetchSearch$(searchRequest, options);
}),
tap((response) => {
// TODO: Remove casting when https://github.com/elastic/elasticsearch-js/issues/1287 is resolved
@ -477,27 +481,6 @@ export class SearchSource {
);
}
/**
* Run a search using the search service
* @return {Promise<SearchResponse<unknown>>}
*/
private async legacyFetch(searchRequest: SearchRequest, options: ISearchOptions) {
const { getConfig, legacy, onResponse } = this.dependencies;
return await fetchSoon(
searchRequest,
{
...(this.searchStrategyId && { searchStrategyId: this.searchStrategyId }),
...options,
},
{
getConfig,
onResponse,
legacy,
}
);
}
/**
* Called by requests of this search source when they are started
* @param options

View file

@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
import { BehaviorSubject } from 'rxjs';
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
import { SearchSourceService, SearchSourceDependencies } from './';
@ -19,10 +18,6 @@ describe('SearchSource service', () => {
getConfig: jest.fn(),
search: jest.fn(),
onResponse: jest.fn(),
legacy: {
callMsearch: jest.fn(),
loadingCount$: new BehaviorSubject(0),
},
};
});

View file

@ -7,8 +7,7 @@
import { $Values } from '@kbn/utility-types';
import { Action } from 'history';
import { Adapters as Adapters_2 } from 'src/plugins/inspector/common';
import { ApiResponse } from '@elastic/elasticsearch';
import { ApiResponse as ApiResponse_2 } from '@elastic/elasticsearch/lib/Transport';
import { ApiResponse } from '@elastic/elasticsearch/lib/Transport';
import { ApplicationStart } from 'kibana/public';
import { Assign } from '@kbn/utility-types';
import { BehaviorSubject } from 'rxjs';

View file

@ -1,43 +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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { HttpStart } from 'src/core/public';
import { coreMock } from '../../../../../core/public/mocks';
import { getCallMsearch } from './call_msearch';
describe('callMsearch', () => {
const msearchMock = jest.fn().mockResolvedValue({ body: { responses: [] } });
let http: jest.Mocked<HttpStart>;
beforeEach(() => {
msearchMock.mockClear();
http = coreMock.createStart().http;
http.post.mockResolvedValue(msearchMock);
});
test('calls http.post with the correct arguments', async () => {
const searches = [{ header: { index: 'foo' }, body: {} }];
const callMsearch = getCallMsearch({ http });
await callMsearch({
body: { searches },
signal: new AbortController().signal,
});
expect(http.post.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
"/internal/_msearch",
Object {
"body": "{\\"searches\\":[{\\"header\\":{\\"index\\":\\"foo\\"},\\"body\\":{}}]}",
"signal": AbortSignal {},
},
],
]
`);
});
});

View file

@ -1,26 +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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { HttpStart } from 'src/core/public';
import { LegacyFetchHandlers } from '../../../common/search/search_source';
/**
* Wrapper for calling the internal msearch endpoint from the client.
* This is needed to abstract away differences in the http service
* between client & server.
*
* @internal
*/
export function getCallMsearch({ http }: { http: HttpStart }): LegacyFetchHandlers['callMsearch'] {
return async ({ body, signal }) => {
return http.post('/internal/_msearch', {
body: JSON.stringify(body),
signal,
});
};
}

View file

@ -1,9 +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
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export * from './call_msearch';

View file

@ -35,7 +35,6 @@ import {
phraseFilterFunction,
esRawResponse,
} from '../../common/search';
import { getCallMsearch } from './legacy';
import { AggsService, AggsStartDependencies } from './aggs';
import { IndexPatternsContract } from '../index_patterns/index_patterns';
import { ISearchInterceptor, SearchInterceptor } from './search_interceptor';
@ -157,10 +156,10 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
}
public start(
{ application, http, notifications, uiSettings }: CoreStart,
{ http, uiSettings }: CoreStart,
{ fieldFormats, indexPatterns }: SearchServiceStartDependencies
): ISearchStart {
const search = ((request, options) => {
const search = ((request, options = {}) => {
return this.searchInterceptor.search(request, options);
}) as ISearchGeneric;
@ -171,10 +170,6 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
getConfig: uiSettings.get.bind(uiSettings),
search,
onResponse: handleResponse,
legacy: {
callMsearch: getCallMsearch({ http }),
loadingCount$,
},
};
return {

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { BehaviorSubject, from, Observable, throwError } from 'rxjs';
import { from, Observable, throwError } from 'rxjs';
import { pick } from 'lodash';
import moment from 'moment';
import {
@ -36,7 +36,7 @@ import { AggsService } from './aggs';
import { FieldFormatsStart } from '../field_formats';
import { IndexPatternsServiceStart } from '../index_patterns';
import { getCallMsearch, registerMsearchRoute, registerSearchRoute } from './routes';
import { registerMsearchRoute, registerSearchRoute } from './routes';
import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './strategies/es_search';
import { DataPluginStart, DataPluginStartDependencies } from '../plugin';
import { UsageCollectionSetup } from '../../../usage_collection/server';
@ -237,14 +237,6 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
getConfig: <T = any>(key: string): T => uiSettingsCache[key],
search: this.asScoped(request).search,
onResponse: (req, res) => res,
legacy: {
callMsearch: getCallMsearch({
esClient,
globalConfig$: this.initializerContext.config.legacy.globalConfig$,
uiSettings: uiSettingsClient,
}),
loadingCount$: new BehaviorSubject(0),
},
};
return this.searchSourceService.start(scopedIndexPatterns, searchSourceDependencies);

View file

@ -6,9 +6,7 @@
import { $Values } from '@kbn/utility-types';
import { Adapters } from 'src/plugins/inspector/common';
import { ApiResponse } from '@elastic/elasticsearch';
import { Assign } from '@kbn/utility-types';
import { BehaviorSubject } from 'rxjs';
import { BfetchServerSetup } from 'src/plugins/bfetch/server';
import { ConfigDeprecationProvider } from '@kbn/config';
import { CoreSetup } from 'src/core/server';

View file

@ -276,12 +276,12 @@ export function getUiSettings(): Record<string, UiSettingsParams<unknown>> {
},
[UI_SETTINGS.COURIER_BATCH_SEARCHES]: {
name: i18n.translate('data.advancedSettings.courier.batchSearchesTitle', {
defaultMessage: 'Use legacy search',
defaultMessage: 'Use sync search',
}),
value: false,
type: 'boolean',
description: i18n.translate('data.advancedSettings.courier.batchSearchesText', {
defaultMessage: `Kibana uses a new search and batching infrastructure.
defaultMessage: `Kibana uses a new asynchronous search and infrastructure.
Enable this option if you prefer to fallback to the legacy synchronous behavior`,
}),
deprecation: {