# Conflicts: # src/plugins/data/server/server.api.md
This commit is contained in:
parent
93145aba3f
commit
a95cdebbba
|
@ -17,4 +17,5 @@ export interface ISearchStart<SearchStrategyRequest extends IKibanaSearchRequest
|
|||
| [aggs](./kibana-plugin-plugins-data-server.isearchstart.aggs.md) | <code>AggsStart</code> | |
|
||||
| [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | <code>(name: string) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse></code> | 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. |
|
||||
| [search](./kibana-plugin-plugins-data-server.isearchstart.search.md) | <code>(context: RequestHandlerContext, request: SearchStrategyRequest, options: ISearchOptions) => Promise<SearchStrategyResponse></code> | |
|
||||
| [searchSource](./kibana-plugin-plugins-data-server.isearchstart.searchsource.md) | <code>{</code><br/><code> asScoped: (request: KibanaRequest) => Promise<ISearchStartSearchSource>;</code><br/><code> }</code> | |
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) > [searchSource](./kibana-plugin-plugins-data-server.isearchstart.searchsource.md)
|
||||
|
||||
## ISearchStart.searchSource property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
searchSource: {
|
||||
asScoped: (request: KibanaRequest) => Promise<ISearchStartSearchSource>;
|
||||
};
|
||||
```
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
```typescript
|
||||
start(core: CoreStart): {
|
||||
search: ISearchStart<import("./search").IEsSearchRequest, import("./search").IEsSearchResponse<any>>;
|
||||
fieldFormats: {
|
||||
fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise<import("../common").FieldFormatsRegistry>;
|
||||
};
|
||||
indexPatterns: {
|
||||
indexPatternsServiceFactory: (kibanaRequest: import("../../../core/server").KibanaRequest<unknown, unknown, unknown, any>) => Promise<import("../public").IndexPatternsService>;
|
||||
};
|
||||
search: ISearchStart<import("./search").IEsSearchRequest, import("./search").IEsSearchResponse<any>>;
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -27,12 +27,12 @@ start(core: CoreStart): {
|
|||
<b>Returns:</b>
|
||||
|
||||
`{
|
||||
search: ISearchStart<import("./search").IEsSearchRequest, import("./search").IEsSearchResponse<any>>;
|
||||
fieldFormats: {
|
||||
fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise<import("../common").FieldFormatsRegistry>;
|
||||
};
|
||||
indexPatterns: {
|
||||
indexPatternsServiceFactory: (kibanaRequest: import("../../../core/server").KibanaRequest<unknown, unknown, unknown, any>) => Promise<import("../public").IndexPatternsService>;
|
||||
};
|
||||
search: ISearchStart<import("./search").IEsSearchRequest, import("./search").IEsSearchResponse<any>>;
|
||||
}`
|
||||
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { SearchSource, ISearchSource, SearchSourceDependencies } from './search_source';
|
||||
export { createSearchSource } from './create_search_source';
|
||||
export { SortDirection, EsQuerySortValue, SearchSourceFields } from './types';
|
||||
export { injectReferences } from './inject_references';
|
||||
export { extractReferences } from './extract_references';
|
||||
export { parseSearchSourceJSON } from './parse_json';
|
||||
export * from './fetch';
|
||||
export * from './legacy';
|
||||
export * from './search_source';
|
||||
export * from './search_source_service';
|
||||
export * from './types';
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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 { SavedObjectReference } from 'src/core/types';
|
||||
import { SearchSourceFields } from './types';
|
||||
|
||||
import { injectReferences } from './inject_references';
|
||||
|
||||
describe('injectSearchSourceReferences', () => {
|
||||
let searchSourceJSON: SearchSourceFields & { indexRefName: string };
|
||||
let references: SavedObjectReference[];
|
||||
|
||||
beforeEach(() => {
|
||||
searchSourceJSON = {
|
||||
highlightAll: true,
|
||||
version: true,
|
||||
query: {
|
||||
query: 'play_name:"Henry IV"',
|
||||
language: 'kuery',
|
||||
},
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
};
|
||||
references = [
|
||||
{
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
type: 'index-pattern',
|
||||
id: '033af690-fde7-11ea-91f3-fb9e73f9bbe9',
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
test('injects references', () => {
|
||||
const actual = injectReferences(searchSourceJSON, references);
|
||||
expect(actual).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"highlightAll": true,
|
||||
"index": "033af690-fde7-11ea-91f3-fb9e73f9bbe9",
|
||||
"query": Object {
|
||||
"language": "kuery",
|
||||
"query": "play_name:\\"Henry IV\\"",
|
||||
},
|
||||
"version": true,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips injecting references if none exists', () => {
|
||||
// @ts-expect-error
|
||||
delete searchSourceJSON.indexRefName;
|
||||
references = [];
|
||||
const actual = injectReferences(searchSourceJSON, references);
|
||||
expect(actual).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"highlightAll": true,
|
||||
"query": Object {
|
||||
"language": "kuery",
|
||||
"query": "play_name:\\"Henry IV\\"",
|
||||
},
|
||||
"version": true,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('throws an error if there is a broken reference', () => {
|
||||
searchSourceJSON.indexRefName = 'oops';
|
||||
expect(() => injectReferences(searchSourceJSON, references)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Could not find reference for oops"`
|
||||
);
|
||||
});
|
||||
|
||||
test('handles filters', () => {
|
||||
searchSourceJSON.filter = [
|
||||
// @ts-expect-error
|
||||
{ meta: { indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index' } },
|
||||
];
|
||||
const actual = injectReferences(searchSourceJSON, references);
|
||||
expect(actual).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"meta": Object {
|
||||
"index": "033af690-fde7-11ea-91f3-fb9e73f9bbe9",
|
||||
},
|
||||
},
|
||||
],
|
||||
"highlightAll": true,
|
||||
"index": "033af690-fde7-11ea-91f3-fb9e73f9bbe9",
|
||||
"query": Object {
|
||||
"language": "kuery",
|
||||
"query": "play_name:\\"Henry IV\\"",
|
||||
},
|
||||
"version": true,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('throws an error if there is a broken filter reference', () => {
|
||||
// @ts-expect-error
|
||||
searchSourceJSON.filter = [{ meta: { indexRefName: 'oops' } }];
|
||||
expect(() => injectReferences(searchSourceJSON, references)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Could not find reference for oops"`
|
||||
);
|
||||
});
|
||||
});
|
|
@ -18,15 +18,36 @@
|
|||
*/
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { ApiResponse } from '@elastic/elasticsearch';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { FetchHandlers, SearchRequest } from '../fetch';
|
||||
|
||||
interface MsearchHeaders {
|
||||
index: string;
|
||||
preference?: number | string;
|
||||
}
|
||||
|
||||
interface MsearchRequest {
|
||||
header: MsearchHeaders;
|
||||
body: any;
|
||||
}
|
||||
|
||||
// @internal
|
||||
export interface MsearchRequestBody {
|
||||
searches: MsearchRequest[];
|
||||
}
|
||||
|
||||
// @internal
|
||||
export interface MsearchResponse {
|
||||
body: ApiResponse<{ responses: Array<SearchResponse<any>> }>;
|
||||
}
|
||||
|
||||
// @internal
|
||||
export interface LegacyFetchHandlers {
|
||||
callMsearch: (params: {
|
||||
body: SearchRequest;
|
||||
body: MsearchRequestBody;
|
||||
signal: AbortSignal;
|
||||
}) => Promise<Array<SearchResponse<any>>>;
|
||||
}) => Promise<MsearchResponse>;
|
||||
loadingCount$: BehaviorSubject<number>;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
import { BehaviorSubject } from 'rxjs';
|
||||
import { uiSettingsServiceMock } from '../../../../../core/public/mocks';
|
||||
|
||||
import { ISearchSource, SearchSource } from './search_source';
|
||||
import { SearchSourceFields } from './types';
|
||||
import { SearchSource } from './search_source';
|
||||
import { ISearchStartSearchSource, ISearchSource, SearchSourceFields } from './types';
|
||||
|
||||
export const searchSourceInstanceMock: MockedKeys<ISearchSource> = {
|
||||
setPreferredSearchStrategyId: jest.fn(),
|
||||
|
@ -45,7 +45,7 @@ export const searchSourceInstanceMock: MockedKeys<ISearchSource> = {
|
|||
serialize: jest.fn(),
|
||||
};
|
||||
|
||||
export const searchSourceMock = {
|
||||
export const searchSourceCommonMock: jest.Mocked<ISearchStartSearchSource> = {
|
||||
create: jest.fn().mockReturnValue(searchSourceInstanceMock),
|
||||
createEmpty: jest.fn().mockReturnValue(searchSourceInstanceMock),
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Observable, BehaviorSubject } from 'rxjs';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { IndexPattern } from '../../index_patterns';
|
||||
import { GetConfigFn } from '../../types';
|
||||
import { fetchSoon } from './legacy';
|
||||
|
@ -53,16 +53,7 @@ describe('SearchSource', () => {
|
|||
let searchSourceDependencies: SearchSourceDependencies;
|
||||
|
||||
beforeEach(() => {
|
||||
mockSearchMethod = jest.fn(() => {
|
||||
return new Observable((subscriber) => {
|
||||
setTimeout(() => {
|
||||
subscriber.next({
|
||||
rawResponse: '',
|
||||
});
|
||||
subscriber.complete();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
mockSearchMethod = jest.fn().mockResolvedValue({ rawResponse: '' });
|
||||
|
||||
searchSourceDependencies = {
|
||||
getConfig: jest.fn(),
|
||||
|
|
|
@ -71,22 +71,15 @@
|
|||
|
||||
import { setWith } from '@elastic/safer-lodash-set';
|
||||
import { uniqueId, uniq, extend, pick, difference, omit, isObject, keys, isFunction } from 'lodash';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { normalizeSortRequest } from './normalize_sort_request';
|
||||
import { filterDocvalueFields } from './filter_docvalue_fields';
|
||||
import { fieldWildcardFilter } from '../../../../kibana_utils/common';
|
||||
import { IIndexPattern } from '../../index_patterns';
|
||||
import { ISearchGeneric } from '../..';
|
||||
import { SearchSourceOptions, SearchSourceFields } from './types';
|
||||
import { IEsSearchRequest, IEsSearchResponse, ISearchOptions } from '../..';
|
||||
import { ISearchSource, SearchSourceOptions, SearchSourceFields } from './types';
|
||||
import { FetchHandlers, RequestFailure, getSearchParamsFromRequest, SearchRequest } from './fetch';
|
||||
|
||||
import {
|
||||
getEsQueryConfig,
|
||||
buildEsQuery,
|
||||
Filter,
|
||||
UI_SETTINGS,
|
||||
ISearchOptions,
|
||||
} from '../../../common';
|
||||
import { getEsQueryConfig, buildEsQuery, Filter, UI_SETTINGS } from '../../../common';
|
||||
import { getHighlightRequest } from '../../../common/field_formats';
|
||||
import { fetchSoon } from './legacy';
|
||||
import { extractReferences } from './extract_references';
|
||||
|
@ -108,7 +101,7 @@ export const searchSourceRequiredUiSettings = [
|
|||
];
|
||||
|
||||
export interface SearchSourceDependencies extends FetchHandlers {
|
||||
search: ISearchGeneric;
|
||||
search: (request: IEsSearchRequest, options: ISearchOptions) => Promise<IEsSearchResponse>;
|
||||
}
|
||||
|
||||
/** @public **/
|
||||
|
@ -264,7 +257,7 @@ export class SearchSource {
|
|||
if (getConfig(UI_SETTINGS.COURIER_BATCH_SEARCHES)) {
|
||||
response = await this.legacyFetch(searchRequest, options);
|
||||
} else {
|
||||
response = await this.fetch$(searchRequest, options).toPromise();
|
||||
response = await this.fetchSearch(searchRequest, options);
|
||||
}
|
||||
|
||||
// TODO: Remove casting when https://github.com/elastic/elasticsearch-js/issues/1287 is resolved
|
||||
|
@ -308,17 +301,17 @@ export class SearchSource {
|
|||
|
||||
/**
|
||||
* Run a search using the search service
|
||||
* @return {Observable<SearchResponse<unknown>>}
|
||||
* @return {Promise<SearchResponse<unknown>>}
|
||||
*/
|
||||
private fetch$(searchRequest: SearchRequest, options: ISearchOptions) {
|
||||
private fetchSearch(searchRequest: SearchRequest, options: ISearchOptions) {
|
||||
const { search, getConfig, onResponse } = this.dependencies;
|
||||
|
||||
const params = getSearchParamsFromRequest(searchRequest, {
|
||||
getConfig,
|
||||
});
|
||||
|
||||
return search({ params, indexType: searchRequest.indexType }, options).pipe(
|
||||
map(({ rawResponse }) => onResponse(searchRequest, rawResponse))
|
||||
return search({ params, indexType: searchRequest.indexType }, options).then(({ rawResponse }) =>
|
||||
onResponse(searchRequest, rawResponse)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -558,9 +551,3 @@ export class SearchSource {
|
|||
return [filterField];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* search source interface
|
||||
* @public
|
||||
*/
|
||||
export type ISearchSource = Pick<SearchSource, keyof SearchSource>;
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 'rxjs';
|
||||
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
|
||||
import { SearchSourceService, SearchSourceDependencies } from './';
|
||||
|
||||
describe('SearchSource service', () => {
|
||||
let dependencies: jest.Mocked<SearchSourceDependencies>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
dependencies = {
|
||||
getConfig: jest.fn(),
|
||||
search: jest.fn(),
|
||||
onResponse: jest.fn(),
|
||||
legacy: {
|
||||
callMsearch: jest.fn(),
|
||||
loadingCount$: new BehaviorSubject(0),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('start()', () => {
|
||||
test('exposes proper contract', () => {
|
||||
const start = new SearchSourceService().start(
|
||||
(jest.fn() as unknown) as jest.Mocked<IndexPatternsContract>,
|
||||
dependencies
|
||||
);
|
||||
|
||||
expect(Object.keys(start)).toEqual(['create', 'createEmpty']);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 { createSearchSource, SearchSource, SearchSourceDependencies } from './';
|
||||
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
|
||||
|
||||
export class SearchSourceService {
|
||||
public setup() {}
|
||||
|
||||
public start(indexPatterns: IndexPatternsContract, dependencies: SearchSourceDependencies) {
|
||||
return {
|
||||
/**
|
||||
* creates searchsource based on serialized search source fields
|
||||
*/
|
||||
create: createSearchSource(indexPatterns, dependencies),
|
||||
/**
|
||||
* creates an enpty search source
|
||||
*/
|
||||
createEmpty: () => {
|
||||
return new SearchSource({}, dependencies);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
}
|
|
@ -16,9 +16,32 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { NameList } from 'elasticsearch';
|
||||
import { IndexPattern, Query } from '../..';
|
||||
import { Filter } from '../../../common';
|
||||
import { Filter, IndexPattern, Query } from '../..';
|
||||
import { SearchSource } from './search_source';
|
||||
|
||||
/**
|
||||
* search source interface
|
||||
* @public
|
||||
*/
|
||||
export type ISearchSource = Pick<SearchSource, keyof SearchSource>;
|
||||
|
||||
/**
|
||||
* high level search service
|
||||
* @public
|
||||
*/
|
||||
export interface ISearchStartSearchSource {
|
||||
/**
|
||||
* creates {@link SearchSource} based on provided serialized {@link SearchSourceFields}
|
||||
* @param fields
|
||||
*/
|
||||
create: (fields?: SearchSourceFields) => Promise<ISearchSource>;
|
||||
/**
|
||||
* creates empty {@link SearchSource}
|
||||
*/
|
||||
createEmpty: () => ISearchSource;
|
||||
}
|
||||
|
||||
export type EsQuerySearchAfter = [string | number, string | number];
|
||||
|
||||
|
@ -75,8 +98,6 @@ export interface SearchSourceOptions {
|
|||
callParentStartHandlers?: boolean;
|
||||
}
|
||||
|
||||
export { ISearchSource } from './search_source';
|
||||
|
||||
export interface SortOptions {
|
||||
mode?: 'min' | 'max' | 'sum' | 'avg' | 'median';
|
||||
type?: 'double' | 'long' | 'date' | 'date_nanos';
|
||||
|
|
|
@ -78,7 +78,7 @@ const createStartContract = (): Start => {
|
|||
};
|
||||
};
|
||||
|
||||
export { createSearchSourceMock } from './search/mocks';
|
||||
export { createSearchSourceMock } from '../common/search/search_source/mocks';
|
||||
export { getCalculateAutoTimeExpression } from '../common/search/aggs';
|
||||
|
||||
export const dataPluginMock = {
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
import { $Values } from '@kbn/utility-types';
|
||||
import _ from 'lodash';
|
||||
import { Action } from 'history';
|
||||
import { ApiResponse } from '@elastic/elasticsearch/lib/Transport';
|
||||
import { ApiResponse } from '@elastic/elasticsearch';
|
||||
import { ApiResponse as ApiResponse_2 } from '@elastic/elasticsearch/lib/Transport';
|
||||
import { ApplicationStart } from 'kibana/public';
|
||||
import { Assign } from '@kbn/utility-types';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
|
|
@ -18,10 +18,8 @@
|
|||
*/
|
||||
|
||||
import { searchAggsSetupMock, searchAggsStartMock } from './aggs/mocks';
|
||||
import { searchSourceMock } from './search_source/mocks';
|
||||
import { ISearchSetup, ISearchStart } from './types';
|
||||
import { searchSourceMock, createSearchSourceMock } from '../../common/search/search_source/mocks';
|
||||
|
||||
export * from '../../common/search/search_source/mocks';
|
||||
|
||||
function createSetupContract(): jest.Mocked<ISearchSetup> {
|
||||
return {
|
||||
|
@ -35,7 +33,7 @@ function createStartContract(): jest.Mocked<ISearchStart> {
|
|||
aggs: searchAggsStartMock(),
|
||||
search: jest.fn(),
|
||||
showError: jest.fn(),
|
||||
searchSource: searchSourceMock,
|
||||
searchSource: searchSourceMock.createStartContract(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -43,5 +41,3 @@ export const searchServiceMock = {
|
|||
createSetupContract,
|
||||
createStartContract,
|
||||
};
|
||||
|
||||
export { createSearchSourceMock };
|
||||
|
|
|
@ -52,6 +52,7 @@ describe('Search service', () => {
|
|||
describe('start()', () => {
|
||||
it('exposes proper contract', async () => {
|
||||
const start = searchService.start(mockCoreStart, {
|
||||
fieldFormats: {},
|
||||
indexPatterns: {},
|
||||
} as any);
|
||||
expect(start).toHaveProperty('aggs');
|
||||
|
|
|
@ -23,9 +23,10 @@ import { ISearchSetup, ISearchStart, SearchEnhancements } from './types';
|
|||
|
||||
import { handleResponse } from './fetch';
|
||||
import {
|
||||
createSearchSource,
|
||||
IEsSearchRequest,
|
||||
ISearchGeneric,
|
||||
SearchSource,
|
||||
ISearchOptions,
|
||||
SearchSourceService,
|
||||
SearchSourceDependencies,
|
||||
} from '../../common/search';
|
||||
import { getCallMsearch } from './legacy';
|
||||
|
@ -57,6 +58,7 @@ export interface SearchServiceStartDependencies {
|
|||
|
||||
export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||
private readonly aggsService = new AggsService();
|
||||
private readonly searchSourceService = new SearchSourceService();
|
||||
private searchInterceptor!: ISearchInterceptor;
|
||||
private usageCollector?: SearchUsageCollector;
|
||||
|
||||
|
@ -115,7 +117,9 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
|
||||
const searchSourceDependencies: SearchSourceDependencies = {
|
||||
getConfig: uiSettings.get.bind(uiSettings),
|
||||
search,
|
||||
search: (request: IEsSearchRequest, options: ISearchOptions) => {
|
||||
return search(request, options).toPromise();
|
||||
},
|
||||
onResponse: handleResponse,
|
||||
legacy: {
|
||||
callMsearch: getCallMsearch({ http }),
|
||||
|
@ -129,22 +133,12 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
showError: (e: Error) => {
|
||||
this.searchInterceptor.showError(e);
|
||||
},
|
||||
searchSource: {
|
||||
/**
|
||||
* creates searchsource based on serialized search source fields
|
||||
*/
|
||||
create: createSearchSource(indexPatterns, searchSourceDependencies),
|
||||
/**
|
||||
* creates an enpty search source
|
||||
*/
|
||||
createEmpty: () => {
|
||||
return new SearchSource({}, searchSourceDependencies);
|
||||
},
|
||||
},
|
||||
searchSource: this.searchSourceService.start(indexPatterns, searchSourceDependencies),
|
||||
};
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.aggsService.stop();
|
||||
this.searchSourceService.stop();
|
||||
}
|
||||
}
|
||||
|
|
29
src/plugins/data/public/search/search_source/mocks.ts
Normal file
29
src/plugins/data/public/search/search_source/mocks.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 { searchSourceCommonMock } from '../../../common/search/search_source/mocks';
|
||||
import { ISearchStart } from '../types';
|
||||
|
||||
function createStartContract(): jest.Mocked<ISearchStart['searchSource']> {
|
||||
return searchSourceCommonMock;
|
||||
}
|
||||
|
||||
export const searchSourceMock = {
|
||||
createStartContract,
|
||||
};
|
|
@ -21,10 +21,12 @@ import { PackageInfo } from 'kibana/server';
|
|||
import { ISearchInterceptor } from './search_interceptor';
|
||||
import { SearchUsageCollector } from './collectors';
|
||||
import { AggsSetup, AggsSetupDependencies, AggsStartDependencies, AggsStart } from './aggs';
|
||||
import { ISearchGeneric, ISearchSource, SearchSourceFields } from '../../common/search';
|
||||
import { ISearchGeneric, ISearchStartSearchSource } from '../../common/search';
|
||||
import { IndexPatternsContract } from '../../common/index_patterns/index_patterns';
|
||||
import { UsageCollectionSetup } from '../../../usage_collection/public';
|
||||
|
||||
export { ISearchStartSearchSource };
|
||||
|
||||
export interface SearchEnhancements {
|
||||
searchInterceptor: ISearchInterceptor;
|
||||
}
|
||||
|
@ -42,21 +44,6 @@ export interface ISearchSetup {
|
|||
__enhance: (enhancements: SearchEnhancements) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* high level search service
|
||||
* @public
|
||||
*/
|
||||
export interface ISearchStartSearchSource {
|
||||
/**
|
||||
* creates {@link SearchSource} based on provided serialized {@link SearchSourceFields}
|
||||
* @param fields
|
||||
*/
|
||||
create: (fields?: SearchSourceFields) => Promise<ISearchSource>;
|
||||
/**
|
||||
* creates empty {@link SearchSource}
|
||||
*/
|
||||
createEmpty: () => ISearchSource;
|
||||
}
|
||||
/**
|
||||
* search service
|
||||
* @public
|
||||
|
|
|
@ -111,13 +111,15 @@ export class DataServerPlugin
|
|||
|
||||
public start(core: CoreStart) {
|
||||
const fieldFormats = this.fieldFormats.start();
|
||||
return {
|
||||
search: this.searchService.start(core, { fieldFormats }),
|
||||
const indexPatterns = this.indexPatterns.start(core, {
|
||||
fieldFormats,
|
||||
indexPatterns: this.indexPatterns.start(core, {
|
||||
fieldFormats,
|
||||
logger: this.logger.get('indexPatterns'),
|
||||
}),
|
||||
logger: this.logger.get('indexPatterns'),
|
||||
});
|
||||
|
||||
return {
|
||||
fieldFormats,
|
||||
indexPatterns,
|
||||
search: this.searchService.start(core, { fieldFormats, indexPatterns }),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
import { ISearchSetup, ISearchStart } from './types';
|
||||
import { searchAggsSetupMock, searchAggsStartMock } from './aggs/mocks';
|
||||
import { searchSourceMock } from './search_source/mocks';
|
||||
|
||||
export function createSearchSetupMock(): jest.Mocked<ISearchSetup> {
|
||||
return {
|
||||
|
@ -33,5 +34,6 @@ export function createSearchStartMock(): jest.Mocked<ISearchStart> {
|
|||
aggs: searchAggsStartMock(),
|
||||
getSearchStrategy: jest.fn(),
|
||||
search: jest.fn(),
|
||||
searchSource: searchSourceMock.createStartContract(),
|
||||
};
|
||||
}
|
||||
|
|
101
src/plugins/data/server/search/routes/call_msearch.test.ts
Normal file
101
src/plugins/data/server/search/routes/call_msearch.test.ts
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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 { IUiSettingsClient, IScopedClusterClient, SharedGlobalConfig } from 'src/core/server';
|
||||
|
||||
import {
|
||||
coreMock,
|
||||
pluginInitializerContextConfigMock,
|
||||
} from '../../../../../../src/core/server/mocks';
|
||||
import { convertRequestBody, getCallMsearch } from './call_msearch';
|
||||
|
||||
describe('callMsearch', () => {
|
||||
let esClient: DeeplyMockedKeys<IScopedClusterClient>;
|
||||
let globalConfig$: Observable<SharedGlobalConfig>;
|
||||
let uiSettings: IUiSettingsClient;
|
||||
let callMsearch: ReturnType<typeof getCallMsearch>;
|
||||
|
||||
beforeEach(() => {
|
||||
const coreContext = coreMock.createRequestHandlerContext();
|
||||
esClient = coreContext.elasticsearch.client;
|
||||
globalConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$;
|
||||
uiSettings = coreContext.uiSettings.client;
|
||||
|
||||
callMsearch = getCallMsearch({ esClient, globalConfig$, uiSettings });
|
||||
});
|
||||
|
||||
it('handler calls msearch with the given request', async () => {
|
||||
const mockBody = {
|
||||
searches: [{ header: { index: 'foo' }, body: { query: { match_all: {} } } }],
|
||||
};
|
||||
|
||||
await callMsearch({
|
||||
body: mockBody,
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
|
||||
expect(esClient.asCurrentUser.msearch).toHaveBeenCalledTimes(1);
|
||||
expect(esClient.asCurrentUser.msearch.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"body": "{\\"ignore_unavailable\\":true,\\"index\\":\\"foo\\"}
|
||||
{\\"query\\":{\\"match_all\\":{}}}
|
||||
",
|
||||
},
|
||||
Object {
|
||||
"querystring": Object {
|
||||
"ignore_throttled": true,
|
||||
"ignore_unavailable": true,
|
||||
"max_concurrent_shard_requests": undefined,
|
||||
},
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
describe('convertRequestBody', () => {
|
||||
it('combines header & body into proper msearch request', () => {
|
||||
const request = {
|
||||
searches: [{ header: { index: 'foo', preference: 0 }, body: { test: true } }],
|
||||
};
|
||||
expect(convertRequestBody(request, { timeout: '30000ms' })).toMatchInlineSnapshot(`
|
||||
"{\\"ignore_unavailable\\":true,\\"index\\":\\"foo\\",\\"preference\\":0}
|
||||
{\\"timeout\\":\\"30000ms\\",\\"test\\":true}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('handles multiple searches', () => {
|
||||
const request = {
|
||||
searches: [
|
||||
{ header: { index: 'foo', preference: 0 }, body: { test: true } },
|
||||
{ header: { index: 'bar', preference: 1 }, body: { hello: 'world' } },
|
||||
],
|
||||
};
|
||||
expect(convertRequestBody(request, { timeout: '30000ms' })).toMatchInlineSnapshot(`
|
||||
"{\\"ignore_unavailable\\":true,\\"index\\":\\"foo\\",\\"preference\\":0}
|
||||
{\\"timeout\\":\\"30000ms\\",\\"test\\":true}
|
||||
{\\"ignore_unavailable\\":true,\\"index\\":\\"bar\\",\\"preference\\":1}
|
||||
{\\"timeout\\":\\"30000ms\\",\\"hello\\":\\"world\\"}
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
100
src/plugins/data/server/search/routes/call_msearch.ts
Normal file
100
src/plugins/data/server/search/routes/call_msearch.ts
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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 { first } from 'rxjs/operators';
|
||||
import { ApiResponse } from '@elastic/elasticsearch';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { IUiSettingsClient, IScopedClusterClient, SharedGlobalConfig } from 'src/core/server';
|
||||
|
||||
import { MsearchRequestBody, MsearchResponse } from '../../../common/search/search_source';
|
||||
import { shimHitsTotal } from './shim_hits_total';
|
||||
import { getShardTimeout, getDefaultSearchParams, toSnakeCase } from '..';
|
||||
|
||||
/** @internal */
|
||||
export function convertRequestBody(
|
||||
requestBody: MsearchRequestBody,
|
||||
{ timeout }: { timeout?: string }
|
||||
): string {
|
||||
return requestBody.searches.reduce((req, curr) => {
|
||||
const header = JSON.stringify({
|
||||
ignore_unavailable: true,
|
||||
...curr.header,
|
||||
});
|
||||
const body = JSON.stringify({
|
||||
timeout,
|
||||
...curr.body,
|
||||
});
|
||||
return `${req}${header}\n${body}\n`;
|
||||
}, '');
|
||||
}
|
||||
|
||||
interface CallMsearchDependencies {
|
||||
esClient: IScopedClusterClient;
|
||||
globalConfig$: Observable<SharedGlobalConfig>;
|
||||
uiSettings: IUiSettingsClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for the `/internal/_msearch` route, exported separately here
|
||||
* so that it can be reused elsewhere in the data plugin on the server,
|
||||
* e.g. SearchSource
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function getCallMsearch(dependencies: CallMsearchDependencies) {
|
||||
return async (params: {
|
||||
body: MsearchRequestBody;
|
||||
signal?: AbortSignal;
|
||||
}): Promise<MsearchResponse> => {
|
||||
const { esClient, globalConfig$, uiSettings } = dependencies;
|
||||
|
||||
// get shardTimeout
|
||||
const config = await globalConfig$.pipe(first()).toPromise();
|
||||
const timeout = getShardTimeout(config);
|
||||
|
||||
// trackTotalHits is not supported by msearch
|
||||
const { trackTotalHits, ...defaultParams } = await getDefaultSearchParams(uiSettings);
|
||||
|
||||
const body = convertRequestBody(params.body, timeout);
|
||||
|
||||
// Temporary workaround until https://github.com/elastic/elasticsearch-js/issues/1297
|
||||
const promise = esClient.asCurrentUser.msearch(
|
||||
{
|
||||
body,
|
||||
},
|
||||
{
|
||||
querystring: toSnakeCase(defaultParams),
|
||||
}
|
||||
);
|
||||
if (params.signal) {
|
||||
params.signal.addEventListener('abort', () => promise.abort());
|
||||
}
|
||||
const response = (await promise) as ApiResponse<{ responses: Array<SearchResponse<any>> }>;
|
||||
|
||||
return {
|
||||
body: {
|
||||
...response,
|
||||
body: {
|
||||
responses: response.body.responses?.map((r: SearchResponse<any>) => shimHitsTotal(r)),
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export * from './call_msearch';
|
||||
export * from './msearch';
|
||||
export * from './search';
|
||||
export * from './shim_hits_total';
|
||||
|
|
|
@ -30,7 +30,8 @@ import {
|
|||
httpServerMock,
|
||||
pluginInitializerContextConfigMock,
|
||||
} from '../../../../../../src/core/server/mocks';
|
||||
import { registerMsearchRoute, convertRequestBody } from './msearch';
|
||||
import { convertRequestBody } from './call_msearch';
|
||||
import { registerMsearchRoute } from './msearch';
|
||||
import { DataPluginStart } from '../../plugin';
|
||||
import { dataPluginMock } from '../../mocks';
|
||||
|
||||
|
@ -49,7 +50,7 @@ describe('msearch route', () => {
|
|||
|
||||
it('handler calls /_msearch with the given request', async () => {
|
||||
const response = { id: 'yay', body: { responses: [{ hits: { total: 5 } }] } };
|
||||
const mockClient = { transport: { request: jest.fn().mockResolvedValue(response) } };
|
||||
const mockClient = { msearch: jest.fn().mockResolvedValue(response) };
|
||||
const mockContext = {
|
||||
core: {
|
||||
elasticsearch: { client: { asCurrentUser: mockClient } },
|
||||
|
@ -70,11 +71,16 @@ describe('msearch route', () => {
|
|||
const handler = mockRouter.post.mock.calls[0][1];
|
||||
await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse);
|
||||
|
||||
expect(mockClient.transport.request.mock.calls[0][0].method).toBe('GET');
|
||||
expect(mockClient.transport.request.mock.calls[0][0].path).toBe('/_msearch');
|
||||
expect(mockClient.transport.request.mock.calls[0][0].body).toEqual(
|
||||
expect(mockClient.msearch.mock.calls[0][0].body).toEqual(
|
||||
convertRequestBody(mockBody as any, {})
|
||||
);
|
||||
expect(mockClient.msearch.mock.calls[0][1].querystring).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"ignore_throttled": true,
|
||||
"ignore_unavailable": true,
|
||||
"max_concurrent_shard_requests": undefined,
|
||||
}
|
||||
`);
|
||||
expect(mockResponse.ok).toBeCalled();
|
||||
expect(mockResponse.ok.mock.calls[0][0]).toEqual({
|
||||
body: response,
|
||||
|
@ -89,7 +95,7 @@ describe('msearch route', () => {
|
|||
},
|
||||
};
|
||||
const mockClient = {
|
||||
transport: { request: jest.fn().mockReturnValue(Promise.reject(response)) },
|
||||
msearch: jest.fn().mockReturnValue(Promise.reject(response)),
|
||||
};
|
||||
const mockContext = {
|
||||
core: {
|
||||
|
@ -111,40 +117,11 @@ describe('msearch route', () => {
|
|||
const handler = mockRouter.post.mock.calls[0][1];
|
||||
await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse);
|
||||
|
||||
expect(mockClient.transport.request).toBeCalled();
|
||||
expect(mockClient.msearch).toBeCalled();
|
||||
expect(mockResponse.customError).toBeCalled();
|
||||
|
||||
const error: any = mockResponse.customError.mock.calls[0][0];
|
||||
expect(error.body.message).toBe('oh no');
|
||||
expect(error.body.attributes.error).toBe('oops');
|
||||
});
|
||||
|
||||
describe('convertRequestBody', () => {
|
||||
it('combines header & body into proper msearch request', () => {
|
||||
const request = {
|
||||
searches: [{ header: { index: 'foo', preference: 0 }, body: { test: true } }],
|
||||
};
|
||||
expect(convertRequestBody(request, { timeout: '30000ms' })).toMatchInlineSnapshot(`
|
||||
"{\\"ignore_unavailable\\":true,\\"index\\":\\"foo\\",\\"preference\\":0}
|
||||
{\\"timeout\\":\\"30000ms\\",\\"test\\":true}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('handles multiple searches', () => {
|
||||
const request = {
|
||||
searches: [
|
||||
{ header: { index: 'foo', preference: 0 }, body: { test: true } },
|
||||
{ header: { index: 'bar', preference: 1 }, body: { hello: 'world' } },
|
||||
],
|
||||
};
|
||||
expect(convertRequestBody(request, { timeout: '30000ms' })).toMatchInlineSnapshot(`
|
||||
"{\\"ignore_unavailable\\":true,\\"index\\":\\"foo\\",\\"preference\\":0}
|
||||
{\\"timeout\\":\\"30000ms\\",\\"test\\":true}
|
||||
{\\"ignore_unavailable\\":true,\\"index\\":\\"bar\\",\\"preference\\":1}
|
||||
{\\"timeout\\":\\"30000ms\\",\\"hello\\":\\"world\\"}
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,46 +17,12 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { first } from 'rxjs/operators';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { IRouter } from 'src/core/server';
|
||||
import { SearchRouteDependencies } from '../search_service';
|
||||
import { shimHitsTotal } from './shim_hits_total';
|
||||
import { getShardTimeout, getDefaultSearchParams, toSnakeCase } from '..';
|
||||
|
||||
interface MsearchHeaders {
|
||||
index: string;
|
||||
preference?: number | string;
|
||||
}
|
||||
|
||||
interface MsearchRequest {
|
||||
header: MsearchHeaders;
|
||||
body: any;
|
||||
}
|
||||
|
||||
interface RequestBody {
|
||||
searches: MsearchRequest[];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function convertRequestBody(
|
||||
requestBody: RequestBody,
|
||||
{ timeout }: { timeout?: string }
|
||||
): string {
|
||||
return requestBody.searches.reduce((req, curr) => {
|
||||
const header = JSON.stringify({
|
||||
ignore_unavailable: true,
|
||||
...curr.header,
|
||||
});
|
||||
const body = JSON.stringify({
|
||||
timeout,
|
||||
...curr.body,
|
||||
});
|
||||
return `${req}${header}\n${body}\n`;
|
||||
}, '');
|
||||
}
|
||||
import { getCallMsearch } from './call_msearch';
|
||||
|
||||
/**
|
||||
* The msearch route takes in an array of searches, each consisting of header
|
||||
|
@ -93,35 +59,15 @@ export function registerMsearchRoute(router: IRouter, deps: SearchRouteDependenc
|
|||
},
|
||||
},
|
||||
async (context, request, res) => {
|
||||
const client = context.core.elasticsearch.client.asCurrentUser;
|
||||
|
||||
// get shardTimeout
|
||||
const config = await deps.globalConfig$.pipe(first()).toPromise();
|
||||
const timeout = getShardTimeout(config);
|
||||
|
||||
const body = convertRequestBody(request.body, timeout);
|
||||
|
||||
// trackTotalHits is not supported by msearch
|
||||
const { trackTotalHits, ...defaultParams } = await getDefaultSearchParams(
|
||||
context.core.uiSettings.client
|
||||
);
|
||||
const callMsearch = getCallMsearch({
|
||||
esClient: context.core.elasticsearch.client,
|
||||
globalConfig$: deps.globalConfig$,
|
||||
uiSettings: context.core.uiSettings.client,
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await client.transport.request({
|
||||
method: 'GET',
|
||||
path: '/_msearch',
|
||||
body,
|
||||
querystring: toSnakeCase(defaultParams),
|
||||
});
|
||||
|
||||
return res.ok({
|
||||
body: {
|
||||
...response,
|
||||
body: {
|
||||
responses: response.body.responses?.map((r: SearchResponse<any>) => shimHitsTotal(r)),
|
||||
},
|
||||
},
|
||||
});
|
||||
const response = await callMsearch({ body: request.body });
|
||||
return res.ok(response);
|
||||
} catch (err) {
|
||||
return res.customError({
|
||||
statusCode: err.statusCode || 500,
|
||||
|
|
|
@ -22,6 +22,7 @@ import { coreMock } from '../../../../core/server/mocks';
|
|||
|
||||
import { DataPluginStart } from '../plugin';
|
||||
import { createFieldFormatsStartMock } from '../field_formats/mocks';
|
||||
import { createIndexPatternsStartMock } from '../index_patterns/mocks';
|
||||
|
||||
import { SearchService, SearchServiceSetupDependencies } from './search_service';
|
||||
|
||||
|
@ -54,6 +55,7 @@ describe('Search service', () => {
|
|||
it('exposes proper contract', async () => {
|
||||
const start = plugin.start(mockCoreStart, {
|
||||
fieldFormats: createFieldFormatsStartMock(),
|
||||
indexPatterns: createIndexPatternsStartMock(),
|
||||
});
|
||||
expect(start).toHaveProperty('aggs');
|
||||
expect(start).toHaveProperty('getSearchStrategy');
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { pick } from 'lodash';
|
||||
import {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
KibanaRequest,
|
||||
Logger,
|
||||
Plugin,
|
||||
PluginInitializerContext,
|
||||
|
@ -34,7 +36,8 @@ import { ISearchSetup, ISearchStart, ISearchStrategy, SearchEnhancements } from
|
|||
import { AggsService, AggsSetupDependencies } from './aggs';
|
||||
|
||||
import { FieldFormatsStart } from '../field_formats';
|
||||
import { registerMsearchRoute, registerSearchRoute } from './routes';
|
||||
import { IndexPatternsServiceStart } from '../index_patterns';
|
||||
import { getCallMsearch, registerMsearchRoute, registerSearchRoute } from './routes';
|
||||
import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './es_search';
|
||||
import { DataPluginStart } from '../plugin';
|
||||
import { UsageCollectionSetup } from '../../../usage_collection/server';
|
||||
|
@ -47,13 +50,16 @@ import {
|
|||
IEsSearchRequest,
|
||||
IEsSearchResponse,
|
||||
ISearchOptions,
|
||||
} from '../../common';
|
||||
SearchSourceDependencies,
|
||||
SearchSourceService,
|
||||
searchSourceRequiredUiSettings,
|
||||
} from '../../common/search';
|
||||
import {
|
||||
getShardDelayBucketAgg,
|
||||
SHARD_DELAY_AGG_NAME,
|
||||
} from '../../common/search/aggs/buckets/shard_delay';
|
||||
import { ConfigSchema } from '../../config';
|
||||
import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn';
|
||||
import { ConfigSchema } from '../../config';
|
||||
|
||||
type StrategyMap = Record<string, ISearchStrategy<any, any>>;
|
||||
|
||||
|
@ -66,6 +72,7 @@ export interface SearchServiceSetupDependencies {
|
|||
/** @internal */
|
||||
export interface SearchServiceStartDependencies {
|
||||
fieldFormats: FieldFormatsStart;
|
||||
indexPatterns: IndexPatternsServiceStart;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -76,6 +83,7 @@ export interface SearchRouteDependencies {
|
|||
|
||||
export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||
private readonly aggsService = new AggsService();
|
||||
private readonly searchSourceService = new SearchSourceService();
|
||||
private defaultSearchStrategyName: string = ES_SEARCH_STRATEGY;
|
||||
private searchStrategies: StrategyMap = {};
|
||||
|
||||
|
@ -137,8 +145,8 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
};
|
||||
}
|
||||
public start(
|
||||
{ uiSettings }: CoreStart,
|
||||
{ fieldFormats }: SearchServiceStartDependencies
|
||||
{ elasticsearch, savedObjects, uiSettings }: CoreStart,
|
||||
{ fieldFormats, indexPatterns }: SearchServiceStartDependencies
|
||||
): ISearchStart {
|
||||
return {
|
||||
aggs: this.aggsService.start({ fieldFormats, uiSettings }),
|
||||
|
@ -150,6 +158,58 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
) => {
|
||||
return this.search(context, searchRequest, options);
|
||||
},
|
||||
searchSource: {
|
||||
asScoped: async (request: KibanaRequest) => {
|
||||
const esClient = elasticsearch.client.asScoped(request);
|
||||
const savedObjectsClient = savedObjects.getScopedClient(request);
|
||||
const scopedIndexPatterns = await indexPatterns.indexPatternsServiceFactory(request);
|
||||
const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient);
|
||||
|
||||
// cache ui settings, only including items which are explicitly needed by SearchSource
|
||||
const uiSettingsCache = pick(
|
||||
await uiSettingsClient.getAll(),
|
||||
searchSourceRequiredUiSettings
|
||||
);
|
||||
|
||||
const searchSourceDependencies: SearchSourceDependencies = {
|
||||
getConfig: <T = any>(key: string): T => uiSettingsCache[key],
|
||||
search: (searchRequest, options) => {
|
||||
/**
|
||||
* Unless we want all SearchSource users to provide both a KibanaRequest
|
||||
* (needed for index patterns) AND the RequestHandlerContext (needed for
|
||||
* low-level search), we need to fake the context as it can be derived
|
||||
* from the request object anyway. This will pose problems for folks who
|
||||
* are registering custom search strategies as they are only getting a
|
||||
* subset of the entire context. Ideally low-level search should be
|
||||
* refactored to only require the needed dependencies: esClient & uiSettings.
|
||||
*/
|
||||
const fakeRequestHandlerContext = {
|
||||
core: {
|
||||
elasticsearch: {
|
||||
client: esClient,
|
||||
},
|
||||
uiSettings: {
|
||||
client: uiSettingsClient,
|
||||
},
|
||||
},
|
||||
} as RequestHandlerContext;
|
||||
return this.search(fakeRequestHandlerContext, searchRequest, options);
|
||||
},
|
||||
// onResponse isn't used on the server, so we just return the original value
|
||||
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);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
35
src/plugins/data/server/search/search_source/mocks.ts
Normal file
35
src/plugins/data/server/search/search_source/mocks.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 { KibanaRequest } from 'src/core/server';
|
||||
|
||||
import { searchSourceCommonMock } from '../../../common/search/search_source/mocks';
|
||||
import { ISearchStart } from '../types';
|
||||
|
||||
function createStartContract(): MockedKeys<ISearchStart['searchSource']> {
|
||||
return {
|
||||
asScoped: async (request: jest.Mocked<KibanaRequest>) => {
|
||||
return searchSourceCommonMock;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const searchSourceMock = {
|
||||
createStartContract,
|
||||
};
|
|
@ -17,8 +17,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { RequestHandlerContext } from '../../../../core/server';
|
||||
import { ISearchOptions, IKibanaSearchRequest, IKibanaSearchResponse } from '../../common/search';
|
||||
import { KibanaRequest, RequestHandlerContext } from 'src/core/server';
|
||||
import {
|
||||
ISearchOptions,
|
||||
ISearchStartSearchSource,
|
||||
IKibanaSearchRequest,
|
||||
IKibanaSearchResponse,
|
||||
} from '../../common/search';
|
||||
import { AggsSetup, AggsStart } from './aggs';
|
||||
import { SearchUsage } from './collectors';
|
||||
import { IEsSearchRequest, IEsSearchResponse } from './es_search';
|
||||
|
@ -69,6 +74,9 @@ export interface ISearchStart<
|
|||
request: SearchStrategyRequest,
|
||||
options: ISearchOptions
|
||||
) => Promise<SearchStrategyResponse>;
|
||||
searchSource: {
|
||||
asScoped: (request: KibanaRequest) => Promise<ISearchStartSearchSource>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,172 +5,51 @@
|
|||
```ts
|
||||
|
||||
import { $Values } from '@kbn/utility-types';
|
||||
import { ApiResponse } from '@elastic/elasticsearch/lib/Transport';
|
||||
import { ApiResponse } from '@elastic/elasticsearch';
|
||||
import { Assign } from '@kbn/utility-types';
|
||||
import Boom from 'boom';
|
||||
import { BulkIndexDocumentsParams } from 'elasticsearch';
|
||||
import { CatAliasesParams } from 'elasticsearch';
|
||||
import { CatAllocationParams } from 'elasticsearch';
|
||||
import { CatCommonParams } from 'elasticsearch';
|
||||
import { CatFielddataParams } from 'elasticsearch';
|
||||
import { CatHealthParams } from 'elasticsearch';
|
||||
import { CatHelpParams } from 'elasticsearch';
|
||||
import { CatIndicesParams } from 'elasticsearch';
|
||||
import { CatRecoveryParams } from 'elasticsearch';
|
||||
import { CatSegmentsParams } from 'elasticsearch';
|
||||
import { CatShardsParams } from 'elasticsearch';
|
||||
import { CatSnapshotsParams } from 'elasticsearch';
|
||||
import { CatTasksParams } from 'elasticsearch';
|
||||
import { CatThreadPoolParams } from 'elasticsearch';
|
||||
import { ClearScrollParams } from 'elasticsearch';
|
||||
import { Client } from 'elasticsearch';
|
||||
import { ClusterAllocationExplainParams } from 'elasticsearch';
|
||||
import { ClusterGetSettingsParams } from 'elasticsearch';
|
||||
import { ClusterHealthParams } from 'elasticsearch';
|
||||
import { ClusterPendingTasksParams } from 'elasticsearch';
|
||||
import { ClusterPutSettingsParams } from 'elasticsearch';
|
||||
import { ClusterRerouteParams } from 'elasticsearch';
|
||||
import { ClusterStateParams } from 'elasticsearch';
|
||||
import { ClusterStatsParams } from 'elasticsearch';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { ConfigDeprecationProvider } from '@kbn/config';
|
||||
import { CoreSetup } from 'src/core/server';
|
||||
import { CoreSetup as CoreSetup_2 } from 'kibana/server';
|
||||
import { CoreStart } from 'src/core/server';
|
||||
import { CoreStart as CoreStart_2 } from 'kibana/server';
|
||||
import { CountParams } from 'elasticsearch';
|
||||
import { CreateDocumentParams } from 'elasticsearch';
|
||||
import { DeleteDocumentByQueryParams } from 'elasticsearch';
|
||||
import { DeleteDocumentParams } from 'elasticsearch';
|
||||
import { DeleteScriptParams } from 'elasticsearch';
|
||||
import { DeleteTemplateParams } from 'elasticsearch';
|
||||
import { Duration } from 'moment';
|
||||
import { Ensure } from '@kbn/utility-types';
|
||||
import { EnvironmentMode } from '@kbn/config';
|
||||
import { ErrorToastOptions } from 'src/core/public/notifications';
|
||||
import { ExistsParams } from 'elasticsearch';
|
||||
import { ExplainParams } from 'elasticsearch';
|
||||
import { ExpressionAstFunction } from 'src/plugins/expressions/common';
|
||||
import { ExpressionsServerSetup } from 'src/plugins/expressions/server';
|
||||
import { FieldStatsParams } from 'elasticsearch';
|
||||
import { GenericParams } from 'elasticsearch';
|
||||
import { GetParams } from 'elasticsearch';
|
||||
import { GetResponse } from 'elasticsearch';
|
||||
import { GetScriptParams } from 'elasticsearch';
|
||||
import { GetSourceParams } from 'elasticsearch';
|
||||
import { GetTemplateParams } from 'elasticsearch';
|
||||
import { IncomingHttpHeaders } from 'http';
|
||||
import { IndexDocumentParams } from 'elasticsearch';
|
||||
import { IndicesAnalyzeParams } from 'elasticsearch';
|
||||
import { IndicesClearCacheParams } from 'elasticsearch';
|
||||
import { IndicesCloseParams } from 'elasticsearch';
|
||||
import { IndicesCreateParams } from 'elasticsearch';
|
||||
import { IndicesDeleteAliasParams } from 'elasticsearch';
|
||||
import { IndicesDeleteParams } from 'elasticsearch';
|
||||
import { IndicesDeleteTemplateParams } from 'elasticsearch';
|
||||
import { IndicesExistsAliasParams } from 'elasticsearch';
|
||||
import { IndicesExistsParams } from 'elasticsearch';
|
||||
import { IndicesExistsTemplateParams } from 'elasticsearch';
|
||||
import { IndicesExistsTypeParams } from 'elasticsearch';
|
||||
import { IndicesFlushParams } from 'elasticsearch';
|
||||
import { IndicesFlushSyncedParams } from 'elasticsearch';
|
||||
import { IndicesForcemergeParams } from 'elasticsearch';
|
||||
import { IndicesGetAliasParams } from 'elasticsearch';
|
||||
import { IndicesGetFieldMappingParams } from 'elasticsearch';
|
||||
import { IndicesGetMappingParams } from 'elasticsearch';
|
||||
import { IndicesGetParams } from 'elasticsearch';
|
||||
import { IndicesGetSettingsParams } from 'elasticsearch';
|
||||
import { IndicesGetTemplateParams } from 'elasticsearch';
|
||||
import { IndicesGetUpgradeParams } from 'elasticsearch';
|
||||
import { IndicesOpenParams } from 'elasticsearch';
|
||||
import { IndicesPutAliasParams } from 'elasticsearch';
|
||||
import { IndicesPutMappingParams } from 'elasticsearch';
|
||||
import { IndicesPutSettingsParams } from 'elasticsearch';
|
||||
import { IndicesPutTemplateParams } from 'elasticsearch';
|
||||
import { IndicesRecoveryParams } from 'elasticsearch';
|
||||
import { IndicesRefreshParams } from 'elasticsearch';
|
||||
import { IndicesRolloverParams } from 'elasticsearch';
|
||||
import { IndicesSegmentsParams } from 'elasticsearch';
|
||||
import { IndicesShardStoresParams } from 'elasticsearch';
|
||||
import { IndicesShrinkParams } from 'elasticsearch';
|
||||
import { IndicesStatsParams } from 'elasticsearch';
|
||||
import { IndicesUpdateAliasesParams } from 'elasticsearch';
|
||||
import { IndicesUpgradeParams } from 'elasticsearch';
|
||||
import { IndicesValidateQueryParams } from 'elasticsearch';
|
||||
import { InfoParams } from 'elasticsearch';
|
||||
import { IngestDeletePipelineParams } from 'elasticsearch';
|
||||
import { IngestGetPipelineParams } from 'elasticsearch';
|
||||
import { IngestPutPipelineParams } from 'elasticsearch';
|
||||
import { IngestSimulateParams } from 'elasticsearch';
|
||||
import { ISearchOptions as ISearchOptions_2 } from 'src/plugins/data/public';
|
||||
import { ISearchSource } from 'src/plugins/data/public';
|
||||
import { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { KibanaConfigType as KibanaConfigType_2 } from 'src/core/server/kibana_config';
|
||||
import { KibanaRequest } from 'kibana/server';
|
||||
import { LegacyAPICaller as LegacyAPICaller_2 } from 'kibana/server';
|
||||
import { Logger } from '@kbn/logging';
|
||||
import { Logger as Logger_2 } from 'kibana/server';
|
||||
import { KibanaRequest } from 'src/core/server';
|
||||
import { KibanaRequest as KibanaRequest_2 } from 'kibana/server';
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
import { Logger } from 'kibana/server';
|
||||
import { LoggerFactory } from '@kbn/logging';
|
||||
import { LogMeta } from '@kbn/logging';
|
||||
import { MGetParams } from 'elasticsearch';
|
||||
import { MGetResponse } from 'elasticsearch';
|
||||
import { Moment } from 'moment';
|
||||
import moment from 'moment';
|
||||
import { MSearchParams } from 'elasticsearch';
|
||||
import { MSearchResponse } from 'elasticsearch';
|
||||
import { MSearchTemplateParams } from 'elasticsearch';
|
||||
import { MTermVectorsParams } from 'elasticsearch';
|
||||
import { NodesHotThreadsParams } from 'elasticsearch';
|
||||
import { NodesInfoParams } from 'elasticsearch';
|
||||
import { NodesStatsParams } from 'elasticsearch';
|
||||
import { NameList } from 'elasticsearch';
|
||||
import { Observable } from 'rxjs';
|
||||
import { PackageInfo } from '@kbn/config';
|
||||
import { PathConfigType } from '@kbn/utils';
|
||||
import { PingParams } from 'elasticsearch';
|
||||
import { Plugin as Plugin_2 } from 'src/core/server';
|
||||
import { Plugin as Plugin_3 } from 'kibana/server';
|
||||
import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/server';
|
||||
import { PutScriptParams } from 'elasticsearch';
|
||||
import { PutTemplateParams } from 'elasticsearch';
|
||||
import { RecursiveReadonly } from '@kbn/utility-types';
|
||||
import { ReindexParams } from 'elasticsearch';
|
||||
import { ReindexRethrottleParams } from 'elasticsearch';
|
||||
import { RenderSearchTemplateParams } from 'elasticsearch';
|
||||
import { RequestAdapter } from 'src/plugins/inspector/common';
|
||||
import { RequestHandlerContext } from 'src/core/server';
|
||||
import { RequestStatistics } from 'src/plugins/inspector/common';
|
||||
import { SavedObject } from 'src/core/server';
|
||||
import { SavedObjectsClientContract as SavedObjectsClientContract_2 } from 'src/core/server';
|
||||
import { ScrollParams } from 'elasticsearch';
|
||||
import { SavedObjectsClientContract } from 'src/core/server';
|
||||
import { Search } from '@elastic/elasticsearch/api/requestParams';
|
||||
import { SearchParams } from 'elasticsearch';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { SearchShardsParams } from 'elasticsearch';
|
||||
import { SearchTemplateParams } from 'elasticsearch';
|
||||
import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/expressions/common';
|
||||
import { ShardsResponse } from 'elasticsearch';
|
||||
import { SnapshotCreateParams } from 'elasticsearch';
|
||||
import { SnapshotCreateRepositoryParams } from 'elasticsearch';
|
||||
import { SnapshotDeleteParams } from 'elasticsearch';
|
||||
import { SnapshotDeleteRepositoryParams } from 'elasticsearch';
|
||||
import { SnapshotGetParams } from 'elasticsearch';
|
||||
import { SnapshotGetRepositoryParams } from 'elasticsearch';
|
||||
import { SnapshotRestoreParams } from 'elasticsearch';
|
||||
import { SnapshotStatusParams } from 'elasticsearch';
|
||||
import { SnapshotVerifyRepositoryParams } from 'elasticsearch';
|
||||
import { SuggestParams } from 'elasticsearch';
|
||||
import { TasksCancelParams } from 'elasticsearch';
|
||||
import { TasksGetParams } from 'elasticsearch';
|
||||
import { TasksListParams } from 'elasticsearch';
|
||||
import { TermvectorsParams } from 'elasticsearch';
|
||||
import { ToastInputFields } from 'src/core/public/notifications';
|
||||
import { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport';
|
||||
import { TransportRequestParams } from '@elastic/elasticsearch/lib/Transport';
|
||||
import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport';
|
||||
import { Type } from '@kbn/config-schema';
|
||||
import { TypeOf } from '@kbn/config-schema';
|
||||
import { Unit } from '@elastic/datemath';
|
||||
import { UnwrapPromiseOrReturn } from '@kbn/utility-types';
|
||||
import { UpdateDocumentByQueryParams } from 'elasticsearch';
|
||||
import { UpdateDocumentParams } from 'elasticsearch';
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "AggConfigSerialized" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "AggConfigOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
@ -767,7 +646,7 @@ export const indexPatterns: {
|
|||
//
|
||||
// @public (undocumented)
|
||||
export class IndexPatternsFetcher {
|
||||
constructor(callDataCluster: LegacyAPICaller_2);
|
||||
constructor(callDataCluster: LegacyAPICaller);
|
||||
getFieldsForTimePattern(options: {
|
||||
pattern: string;
|
||||
metaFields: string[];
|
||||
|
@ -794,7 +673,7 @@ export class IndexPatternsService implements Plugin_3<void, IndexPatternsService
|
|||
//
|
||||
// (undocumented)
|
||||
start(core: CoreStart_2, { fieldFormats, logger }: IndexPatternsServiceStartDeps): {
|
||||
indexPatternsServiceFactory: (kibanaRequest: KibanaRequest) => Promise<IndexPatternsService_2>;
|
||||
indexPatternsServiceFactory: (kibanaRequest: KibanaRequest_2) => Promise<IndexPatternsService_2>;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -831,10 +710,12 @@ export interface ISearchStart<SearchStrategyRequest extends IKibanaSearchRequest
|
|||
// (undocumented)
|
||||
aggs: AggsStart;
|
||||
getSearchStrategy: (name: string) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse>;
|
||||
// Warning: (ae-forgotten-export) The symbol "RequestHandlerContext" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
search: (context: RequestHandlerContext, request: SearchStrategyRequest, options: ISearchOptions) => Promise<SearchStrategyResponse>;
|
||||
// (undocumented)
|
||||
searchSource: {
|
||||
asScoped: (request: KibanaRequest) => Promise<ISearchStartSearchSource>;
|
||||
};
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ISearchStrategy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
@ -992,13 +873,13 @@ export class Plugin implements Plugin_2<PluginSetup, PluginStart, DataPluginSetu
|
|||
};
|
||||
// (undocumented)
|
||||
start(core: CoreStart): {
|
||||
search: ISearchStart<import("./search").IEsSearchRequest, import("./search").IEsSearchResponse<any>>;
|
||||
fieldFormats: {
|
||||
fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise<import("../common").FieldFormatsRegistry>;
|
||||
};
|
||||
indexPatterns: {
|
||||
indexPatternsServiceFactory: (kibanaRequest: import("../../../core/server").KibanaRequest<unknown, unknown, unknown, any>) => Promise<import("../public").IndexPatternsService>;
|
||||
};
|
||||
search: ISearchStart<import("./search").IEsSearchRequest, import("./search").IEsSearchResponse<any>>;
|
||||
};
|
||||
// (undocumented)
|
||||
stop(): void;
|
||||
|
@ -1254,6 +1135,7 @@ export function usageProvider(core: CoreSetup_2): SearchUsage;
|
|||
// src/plugins/data/server/index.ts:252:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index_patterns/index_patterns_service.ts:50:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/plugin.ts:88:66 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/search/types.ts:78:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
|
|
9
test/plugin_functional/plugins/data_search/kibana.json
Normal file
9
test/plugin_functional/plugins/data_search/kibana.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"id": "data_search_plugin",
|
||||
"version": "0.0.1",
|
||||
"kibanaVersion": "kibana",
|
||||
"configPath": ["data_search_test_plugin"],
|
||||
"server": true,
|
||||
"ui": false,
|
||||
"requiredPlugins": ["data"]
|
||||
}
|
15
test/plugin_functional/plugins/data_search/package.json
Normal file
15
test/plugin_functional/plugins/data_search/package.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "data_search_plugin",
|
||||
"version": "1.0.0",
|
||||
"kibana": {
|
||||
"version": "kibana"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"kbn": "node ../../../../scripts/kbn.js",
|
||||
"build": "rm -rf './target' && tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "4.0.2"
|
||||
}
|
||||
}
|
24
test/plugin_functional/plugins/data_search/server/index.ts
Normal file
24
test/plugin_functional/plugins/data_search/server/index.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 { PluginInitializer } from 'src/core/server';
|
||||
import { DataSearchTestPlugin, TestPluginSetup, TestPluginStart } from './plugin';
|
||||
|
||||
export const plugin: PluginInitializer<TestPluginSetup, TestPluginStart> = () =>
|
||||
new DataSearchTestPlugin();
|
82
test/plugin_functional/plugins/data_search/server/plugin.ts
Normal file
82
test/plugin_functional/plugins/data_search/server/plugin.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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, Plugin } from 'kibana/server';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { PluginStart as DataPluginStart } from '../../../../../src/plugins/data/server';
|
||||
|
||||
export interface DataSearchTestStartDeps {
|
||||
data: DataPluginStart;
|
||||
}
|
||||
|
||||
export class DataSearchTestPlugin
|
||||
implements Plugin<TestPluginSetup, TestPluginStart, {}, DataSearchTestStartDeps> {
|
||||
public setup(core: CoreSetup<DataSearchTestStartDeps>) {
|
||||
const router = core.http.createRouter();
|
||||
|
||||
router.get(
|
||||
{ path: '/api/data_search_plugin/search_source/as_scoped', validate: false },
|
||||
async (context, req, res) => {
|
||||
const [, { data }] = await core.getStartServices();
|
||||
// Just make sure `asScoped` can be called
|
||||
await data.search.searchSource.asScoped(req);
|
||||
return res.ok();
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
{ path: '/api/data_search_plugin/search_source/create_empty', validate: false },
|
||||
async (context, req, res) => {
|
||||
const [, { data }] = await core.getStartServices();
|
||||
const service = await data.search.searchSource.asScoped(req);
|
||||
const searchSource = service.createEmpty();
|
||||
return res.ok({ body: searchSource.serialize() });
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
{
|
||||
path: '/api/data_search_plugin/search_source/create',
|
||||
validate: {
|
||||
body: schema.object({}, { unknowns: 'allow' }),
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const [, { data }] = await core.getStartServices();
|
||||
const service = await data.search.searchSource.asScoped(req);
|
||||
|
||||
// Since the index pattern ID can change on each test run, we need
|
||||
// to look it up on the fly and insert it into the request.
|
||||
const indexPatterns = await data.indexPatterns.indexPatternsServiceFactory(req);
|
||||
const ids = await indexPatterns.getIds();
|
||||
// @ts-expect-error Force overwriting the request
|
||||
req.body.index = ids[0];
|
||||
const searchSource = await service.create(req.body);
|
||||
|
||||
return res.ok({ body: searchSource.serialize() });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public start() {}
|
||||
public stop() {}
|
||||
}
|
||||
|
||||
export type TestPluginSetup = ReturnType<DataSearchTestPlugin['setup']>;
|
||||
export type TestPluginStart = ReturnType<DataSearchTestPlugin['start']>;
|
15
test/plugin_functional/plugins/data_search/tsconfig.json
Normal file
15
test/plugin_functional/plugins/data_search/tsconfig.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"server/**/*.ts",
|
||||
"../../../../typings/**/*"
|
||||
],
|
||||
"exclude": [],
|
||||
"references": [
|
||||
{ "path": "../../../../src/core/tsconfig.json" }
|
||||
]
|
||||
}
|
|
@ -17,9 +17,25 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
// @ts-expect-error
|
||||
export default function ({ loadTestFile }) {
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
export default function ({
|
||||
getPageObjects,
|
||||
getService,
|
||||
loadTestFile,
|
||||
}: PluginFunctionalProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const PageObjects = getPageObjects(['common', 'header', 'settings']);
|
||||
|
||||
describe('data plugin', () => {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded(
|
||||
'../functional/fixtures/es_archiver/getting_started/shakespeare'
|
||||
);
|
||||
await PageObjects.common.navigateToApp('settings');
|
||||
await PageObjects.settings.createIndexPattern('shakespeare', '');
|
||||
});
|
||||
loadTestFile(require.resolve('./index_patterns'));
|
||||
loadTestFile(require.resolve('./search'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,20 +20,11 @@ import expect from '@kbn/expect';
|
|||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
import '../../plugins/core_provider_plugin/types';
|
||||
|
||||
export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) {
|
||||
export default function ({ getService }: PluginFunctionalProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const PageObjects = getPageObjects(['common', 'settings']);
|
||||
|
||||
describe('index patterns', function () {
|
||||
let indexPatternId = '';
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded(
|
||||
'../functional/fixtures/es_archiver/getting_started/shakespeare'
|
||||
);
|
||||
await PageObjects.common.navigateToApp('settings');
|
||||
await PageObjects.settings.createIndexPattern('shakespeare', '');
|
||||
});
|
||||
|
||||
it('can get all ids', async () => {
|
||||
const body = await (await supertest.get('/api/index-patterns-plugin/get-all').expect(200))
|
||||
|
|
65
test/plugin_functional/test_suites/data_plugin/search.ts
Normal file
65
test/plugin_functional/test_suites/data_plugin/search.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
export default function ({ getService }: PluginFunctionalProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('data.search', () => {
|
||||
describe('searchSource', () => {
|
||||
const searchSourceFields = {
|
||||
highlightAll: true,
|
||||
index: '',
|
||||
query: {
|
||||
language: 'kuery',
|
||||
query: 'play_name:\\"Henry IV\\"',
|
||||
},
|
||||
version: true,
|
||||
};
|
||||
|
||||
it('asScoped()', async () => {
|
||||
await supertest.get('/api/data_search_plugin/search_source/as_scoped').expect(200);
|
||||
});
|
||||
|
||||
it('createEmpty()', async () => {
|
||||
await supertest
|
||||
.get('/api/data_search_plugin/search_source/create_empty')
|
||||
.expect(200)
|
||||
.expect(JSON.stringify({ searchSourceJSON: '{}', references: [] }));
|
||||
});
|
||||
|
||||
it('create()', async () => {
|
||||
await supertest
|
||||
.post('/api/data_search_plugin/search_source/create')
|
||||
.set('kbn-xsrf', 'anything')
|
||||
.send(searchSourceFields)
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
const searchSourceJSON = JSON.parse(body.searchSourceJSON);
|
||||
expect(Object.keys(body)).to.eql(['searchSourceJSON', 'references']);
|
||||
expect(searchSourceJSON.query).to.eql(searchSourceFields.query);
|
||||
expect(body.references[0].type).to.equal('index-pattern');
|
||||
expect(searchSourceJSON.indexRefName).to.equal(body.references[0].name);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue