Skip to content

Commit

Permalink
[Search] Server side search API (#70446)
Browse files Browse the repository at this point in the history
* [search] Refactor the way search strategies are registered/retrieved on the server

* Fix types and tests and update docs

* Fix failing test

* Move strategy name into options

* Remove FE strategies

* TypeScript of hell
delete search explorer

* Fix search interceptor OSS tests

* test cleanup

* fix

* return search wrapper

* initial api

* Shiny happy cleanup

* docs

* fix jest test

* simplify strategy registration

* fix rebase

* fix rebase

* fix backport

* types

* TS for strategy

* docs

Co-authored-by: Lukas Olson <olson.lukas@gmail.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
3 people authored and Liza K committed Jul 14, 2020
1 parent 6e7d139 commit 072283b
Show file tree
Hide file tree
Showing 28 changed files with 135 additions and 301 deletions.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ export interface ISearchOptions
| Property | Type | Description |
| --- | --- | --- |
| [signal](./kibana-plugin-plugins-data-server.isearchoptions.signal.md) | <code>AbortSignal</code> | An <code>AbortSignal</code> that allows the caller of <code>search</code> to abort a search request. |
| [strategy](./kibana-plugin-plugins-data-server.isearchoptions.strategy.md) | <code>string</code> | |

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) &gt; [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) &gt; [strategy](./kibana-plugin-plugins-data-server.isearchoptions.strategy.md)

## ISearchOptions.strategy property

<b>Signature:</b>

```typescript
strategy?: string;
```
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ export interface ISearchSetup

| Property | Type | Description |
| --- | --- | --- |
| [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) | <code>TRegisterSearchStrategy</code> | Extension point exposed for other plugins to register their own search strategies. |
| [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) | <code>(name: string, strategy: ISearchStrategy) =&gt; void</code> | Extension point exposed for other plugins to register their own search strategies. |

Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ Extension point exposed for other plugins to register their own search strategie
<b>Signature:</b>

```typescript
registerSearchStrategy: TRegisterSearchStrategy;
registerSearchStrategy: (name: string, strategy: ISearchStrategy) => void;
```
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ Get other registered search strategies. For example, if a new strategy needs to
<b>Signature:</b>

```typescript
getSearchStrategy: TGetSearchStrategy;
getSearchStrategy: (name: string) => ISearchStrategy;
```
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export interface ISearchStart

| Property | Type | Description |
| --- | --- | --- |
| [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | <code>TGetSearchStrategy</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. |
| [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | <code>(name: string) =&gt; ISearchStrategy</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: IKibanaSearchRequest, options: ISearchOptions) =&gt; Promise&lt;IKibanaSearchResponse&gt;</code> | |

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) &gt; [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) &gt; [search](./kibana-plugin-plugins-data-server.isearchstart.search.md)

## ISearchStart.search property

<b>Signature:</b>

```typescript
search: (context: RequestHandlerContext, request: IKibanaSearchRequest, options: ISearchOptions) => Promise<IKibanaSearchResponse>;
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
<b>Signature:</b>

```typescript
cancel?: ISearchCancel<T>;
cancel?: (context: RequestHandlerContext, id: string) => Promise<void>;
```
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ Search strategy interface contains a search method that takes in a request and r
<b>Signature:</b>

```typescript
export interface ISearchStrategy<T extends TStrategyTypes>
export interface ISearchStrategy
```

## Properties

| Property | Type | Description |
| --- | --- | --- |
| [cancel](./kibana-plugin-plugins-data-server.isearchstrategy.cancel.md) | <code>ISearchCancel&lt;T&gt;</code> | |
| [search](./kibana-plugin-plugins-data-server.isearchstrategy.search.md) | <code>ISearch&lt;T&gt;</code> | |
| [cancel](./kibana-plugin-plugins-data-server.isearchstrategy.cancel.md) | <code>(context: RequestHandlerContext, id: string) =&gt; Promise&lt;void&gt;</code> | |
| [search](./kibana-plugin-plugins-data-server.isearchstrategy.search.md) | <code>(context: RequestHandlerContext, request: IEsSearchRequest, options?: ISearchOptions) =&gt; Promise&lt;IEsSearchResponse&gt;</code> | |

Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
<b>Signature:</b>

```typescript
search: ISearch<T>;
search: (context: RequestHandlerContext, request: IEsSearchRequest, options?: ISearchOptions) => Promise<IEsSearchResponse>;
```
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@
| [IIndexPattern](./kibana-plugin-plugins-data-server.iindexpattern.md) | |
| [IndexPatternAttributes](./kibana-plugin-plugins-data-server.indexpatternattributes.md) | Use data plugin interface instead |
| [IndexPatternFieldDescriptor](./kibana-plugin-plugins-data-server.indexpatternfielddescriptor.md) | |
| [IRequestTypesMap](./kibana-plugin-plugins-data-server.irequesttypesmap.md) | The map of search strategy IDs to the corresponding request type definitions. |
| [IResponseTypesMap](./kibana-plugin-plugins-data-server.iresponsetypesmap.md) | The map of search strategy IDs to the corresponding response type definitions. |
| [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) | |
| [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) | |
| [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) | |
Expand Down Expand Up @@ -73,8 +71,5 @@
| --- | --- |
| [FieldFormatsGetConfigFn](./kibana-plugin-plugins-data-server.fieldformatsgetconfigfn.md) | |
| [IFieldFormatsRegistry](./kibana-plugin-plugins-data-server.ifieldformatsregistry.md) | |
| [ISearch](./kibana-plugin-plugins-data-server.isearch.md) | |
| [ISearchCancel](./kibana-plugin-plugins-data-server.isearchcancel.md) | |
| [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | |
| [TStrategyTypes](./kibana-plugin-plugins-data-server.tstrategytypes.md) | Contains all known strategy type identifiers that will be used to map to request and response shapes. Plugins that wish to add their own custom search strategies should extend this type via:<!-- -->const MY\_STRATEGY = 'MY\_STRATEGY';<!-- -->declare module 'src/plugins/search/server' { export interface IRequestTypesMap { \[MY\_STRATEGY\]: IMySearchRequest; }<!-- -->export interface IResponseTypesMap { \[MY\_STRATEGY\]: IMySearchResponse } } |

This file was deleted.

7 changes: 1 addition & 6 deletions src/plugins/data/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,10 @@ import {
export { ParsedInterval } from '../common';

export {
ISearch,
ISearchCancel,
ISearchStrategy,
ISearchOptions,
IRequestTypesMap,
IResponseTypesMap,
ISearchSetup,
ISearchStart,
TStrategyTypes,
ISearchStrategy,
getDefaultSearchParams,
getTotalLoaded,
} from './search';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,16 @@
* under the License.
*/
import { first } from 'rxjs/operators';
import { RequestHandlerContext, SharedGlobalConfig } from 'kibana/server';
import { SharedGlobalConfig } from 'kibana/server';
import { SearchResponse } from 'elasticsearch';
import { Observable } from 'rxjs';
import { ES_SEARCH_STRATEGY } from '../../../common/search';
import { ISearchStrategy, getDefaultSearchParams, getTotalLoaded } from '..';

export const esSearchStrategyProvider = (
config$: Observable<SharedGlobalConfig>
): ISearchStrategy<typeof ES_SEARCH_STRATEGY> => {
): ISearchStrategy => {
return {
search: async (context: RequestHandlerContext, request, options) => {
search: async (context, request, options) => {
const config = await config$.pipe(first()).toPromise();
const defaultParams = getDefaultSearchParams(config);

Expand Down
12 changes: 1 addition & 11 deletions src/plugins/data/server/search/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,6 @@
* under the License.
*/

export {
ISearch,
ISearchCancel,
ISearchOptions,
IRequestTypesMap,
IResponseTypesMap,
ISearchSetup,
ISearchStart,
TStrategyTypes,
ISearchStrategy,
} from './types';
export { ISearchStrategy, ISearchOptions, ISearchSetup, ISearchStart } from './types';

export { getDefaultSearchParams, getTotalLoaded } from './es_search';
1 change: 1 addition & 0 deletions src/plugins/data/server/search/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ export function createSearchSetupMock() {
export function createSearchStartMock() {
return {
getSearchStrategy: jest.fn(),
search: jest.fn(),
};
}
22 changes: 10 additions & 12 deletions src/plugins/data/server/search/routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ describe('Search service', () => {
});

it('handler calls context.search.search with the given request and strategy', async () => {
const mockSearch = jest.fn().mockResolvedValue('yay');
mockDataStart.search.getSearchStrategy.mockReturnValueOnce({ search: mockSearch });

const response = { id: 'yay' };
mockDataStart.search.search.mockResolvedValue(response);
const mockContext = {};
const mockBody = { params: {} };
const mockParams = { strategy: 'foo' };
Expand All @@ -51,21 +50,21 @@ describe('Search service', () => {
const handler = mockRouter.post.mock.calls[0][1];
await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse);

expect(mockDataStart.search.getSearchStrategy.mock.calls[0][0]).toBe(mockParams.strategy);
expect(mockSearch).toBeCalled();
expect(mockSearch.mock.calls[0][1]).toStrictEqual(mockBody);
expect(mockDataStart.search.search).toBeCalled();
expect(mockDataStart.search.search.mock.calls[0][1]).toStrictEqual(mockBody);
expect(mockResponse.ok).toBeCalled();
expect(mockResponse.ok.mock.calls[0][0]).toEqual({ body: 'yay' });
expect(mockResponse.ok.mock.calls[0][0]).toEqual({
body: response,
});
});

it('handler throws an error if the search throws an error', async () => {
const mockSearch = jest.fn().mockRejectedValue({
mockDataStart.search.search.mockRejectedValue({
message: 'oh no',
body: {
error: 'oops',
},
});
mockDataStart.search.getSearchStrategy.mockReturnValueOnce({ search: mockSearch });

const mockContext = {};
const mockBody = { params: {} };
Expand All @@ -82,9 +81,8 @@ describe('Search service', () => {
const handler = mockRouter.post.mock.calls[0][1];
await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse);

expect(mockDataStart.search.getSearchStrategy.mock.calls[0][0]).toBe(mockParams.strategy);
expect(mockSearch).toBeCalled();
expect(mockSearch.mock.calls[0][1]).toStrictEqual(mockBody);
expect(mockDataStart.search.search).toBeCalled();
expect(mockDataStart.search.search.mock.calls[0][1]).toStrictEqual(mockBody);
expect(mockResponse.customError).toBeCalled();
const error: any = mockResponse.customError.mock.calls[0][0];
expect(error.body.message).toBe('oh no');
Expand Down
6 changes: 4 additions & 2 deletions src/plugins/data/server/search/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ export function registerSearchRoute(core: CoreSetup<object, DataPluginStart>): v
const signal = getRequestAbortedSignal(request.events.aborted$);

const [, , selfStart] = await core.getStartServices();
const searchStrategy = selfStart.search.getSearchStrategy(strategy);

try {
const response = await searchStrategy.search(context, searchRequest, { signal });
const response = await selfStart.search.search(context, searchRequest, {
signal,
strategy,
});
return res.ok({ body: response });
} catch (err) {
return res.customError({
Expand Down
Loading

0 comments on commit 072283b

Please sign in to comment.