mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[data.search] Add search session methods to search service contract (#87966)
* [data.search] Add search session methods to search service contract * Fix types * Fix tests and switch to cancel * Update docs * Fix types/tests * Fix tests * Update status of SO before cancelling search requests * Add API integration test * Fix types * Update expiration route to use config defaultExpiration * Fix test * Update docs * New logic for extend * Remove declare module * Review feedback * fix ts * Remove test that is no longer valid * Fix undefined bug * Use DataRequestHandlerContext in maps * ts Co-authored-by: Liza K <liza.katz@elastic.co>
This commit is contained in:
parent
2145768c0d
commit
a9273ca001
48 changed files with 641 additions and 704 deletions
|
@ -1,18 +0,0 @@
|
||||||
<!-- 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) > [DataApiRequestHandlerContext](./kibana-plugin-plugins-data-server.dataapirequesthandlercontext.md)
|
|
||||||
|
|
||||||
## DataApiRequestHandlerContext interface
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export interface DataApiRequestHandlerContext extends ISearchClient
|
|
||||||
```
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [session](./kibana-plugin-plugins-data-server.dataapirequesthandlercontext.session.md) | <code>IScopedSessionService</code> | |
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<!-- 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) > [DataApiRequestHandlerContext](./kibana-plugin-plugins-data-server.dataapirequesthandlercontext.md) > [session](./kibana-plugin-plugins-data-server.dataapirequesthandlercontext.session.md)
|
|
||||||
|
|
||||||
## DataApiRequestHandlerContext.session property
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
session: IScopedSessionService;
|
|
||||||
```
|
|
|
@ -1,18 +0,0 @@
|
||||||
<!-- 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) > [IScopedSessionService](./kibana-plugin-plugins-data-server.iscopedsessionservice.md)
|
|
||||||
|
|
||||||
## IScopedSessionService interface
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export interface IScopedSessionService
|
|
||||||
```
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [search](./kibana-plugin-plugins-data-server.iscopedsessionservice.search.md) | <code><Request extends IKibanaSearchRequest, Response extends IKibanaSearchResponse>(strategy: ISearchStrategy<Request, Response>, ...args: Parameters<ISearchStrategy<Request, Response>['search']>) => Observable<Response></code> | |
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<!-- 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) > [IScopedSessionService](./kibana-plugin-plugins-data-server.iscopedsessionservice.md) > [search](./kibana-plugin-plugins-data-server.iscopedsessionservice.search.md)
|
|
||||||
|
|
||||||
## IScopedSessionService.search property
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
search: <Request extends IKibanaSearchRequest, Response extends IKibanaSearchResponse>(strategy: ISearchStrategy<Request, Response>, ...args: Parameters<ISearchStrategy<Request, Response>['search']>) => Observable<Response>;
|
|
||||||
```
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- 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) > [ISearchSessionService](./kibana-plugin-plugins-data-server.isearchsessionservice.md) > [asScopedProvider](./kibana-plugin-plugins-data-server.isearchsessionservice.asscopedprovider.md)
|
||||||
|
|
||||||
|
## ISearchSessionService.asScopedProvider property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient<T>;
|
||||||
|
```
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!-- 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) > [ISearchSessionService](./kibana-plugin-plugins-data-server.isearchsessionservice.md)
|
||||||
|
|
||||||
|
## ISearchSessionService interface
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export interface ISearchSessionService<T = unknown>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [asScopedProvider](./kibana-plugin-plugins-data-server.isearchsessionservice.asscopedprovider.md) | <code>(core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient<T></code> | |
|
||||||
|
|
|
@ -7,5 +7,5 @@
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
asScoped: (request: KibanaRequest) => ISearchClient;
|
asScoped: (request: KibanaRequest) => IScopedSearchClient;
|
||||||
```
|
```
|
||||||
|
|
|
@ -15,7 +15,7 @@ export interface ISearchStart<SearchStrategyRequest extends IKibanaSearchRequest
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| [aggs](./kibana-plugin-plugins-data-server.isearchstart.aggs.md) | <code>AggsStart</code> | |
|
| [aggs](./kibana-plugin-plugins-data-server.isearchstart.aggs.md) | <code>AggsStart</code> | |
|
||||||
| [asScoped](./kibana-plugin-plugins-data-server.isearchstart.asscoped.md) | <code>(request: KibanaRequest) => ISearchClient</code> | |
|
| [asScoped](./kibana-plugin-plugins-data-server.isearchstart.asscoped.md) | <code>(request: KibanaRequest) => IScopedSearchClient</code> | |
|
||||||
| [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | <code>(name?: string) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse></code> | Get other registered search strategies by name (or, by default, the Elasticsearch strategy). 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) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse></code> | Get other registered search strategies by name (or, by default, the Elasticsearch strategy). For example, if a new strategy needs to use the already-registered ES search strategy, it can use this function to accomplish that. |
|
||||||
| [searchSource](./kibana-plugin-plugins-data-server.isearchstart.searchsource.md) | <code>{</code><br/><code> asScoped: (request: KibanaRequest) => Promise<ISearchStartSearchSource>;</code><br/><code> }</code> | |
|
| [searchSource](./kibana-plugin-plugins-data-server.isearchstart.searchsource.md) | <code>{</code><br/><code> asScoped: (request: KibanaRequest) => Promise<ISearchStartSearchSource>;</code><br/><code> }</code> | |
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<!-- 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) > [ISessionService](./kibana-plugin-plugins-data-server.isessionservice.md) > [asScopedProvider](./kibana-plugin-plugins-data-server.isessionservice.asscopedprovider.md)
|
|
||||||
|
|
||||||
## ISessionService.asScopedProvider property
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSessionService;
|
|
||||||
```
|
|
|
@ -1,18 +0,0 @@
|
||||||
<!-- 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) > [ISessionService](./kibana-plugin-plugins-data-server.isessionservice.md)
|
|
||||||
|
|
||||||
## ISessionService interface
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export interface ISessionService
|
|
||||||
```
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [asScopedProvider](./kibana-plugin-plugins-data-server.isessionservice.asscopedprovider.md) | <code>(core: CoreStart) => (request: KibanaRequest) => IScopedSessionService</code> | |
|
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
| [IndexPatternsService](./kibana-plugin-plugins-data-server.indexpatternsservice.md) | |
|
| [IndexPatternsService](./kibana-plugin-plugins-data-server.indexpatternsservice.md) | |
|
||||||
| [OptionedParamType](./kibana-plugin-plugins-data-server.optionedparamtype.md) | |
|
| [OptionedParamType](./kibana-plugin-plugins-data-server.optionedparamtype.md) | |
|
||||||
| [Plugin](./kibana-plugin-plugins-data-server.plugin.md) | |
|
| [Plugin](./kibana-plugin-plugins-data-server.plugin.md) | |
|
||||||
| [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md) | The OSS session service. See data\_enhanced in X-Pack for the search session service. |
|
|
||||||
|
|
||||||
## Enumerations
|
## Enumerations
|
||||||
|
|
||||||
|
@ -45,7 +44,6 @@
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| [AggFunctionsMapping](./kibana-plugin-plugins-data-server.aggfunctionsmapping.md) | A global list of the expression function definitions for each agg type function. |
|
| [AggFunctionsMapping](./kibana-plugin-plugins-data-server.aggfunctionsmapping.md) | A global list of the expression function definitions for each agg type function. |
|
||||||
| [AggParamOption](./kibana-plugin-plugins-data-server.aggparamoption.md) | |
|
| [AggParamOption](./kibana-plugin-plugins-data-server.aggparamoption.md) | |
|
||||||
| [DataApiRequestHandlerContext](./kibana-plugin-plugins-data-server.dataapirequesthandlercontext.md) | |
|
|
||||||
| [EsQueryConfig](./kibana-plugin-plugins-data-server.esqueryconfig.md) | |
|
| [EsQueryConfig](./kibana-plugin-plugins-data-server.esqueryconfig.md) | |
|
||||||
| [FieldDescriptor](./kibana-plugin-plugins-data-server.fielddescriptor.md) | |
|
| [FieldDescriptor](./kibana-plugin-plugins-data-server.fielddescriptor.md) | |
|
||||||
| [FieldFormatConfig](./kibana-plugin-plugins-data-server.fieldformatconfig.md) | |
|
| [FieldFormatConfig](./kibana-plugin-plugins-data-server.fieldformatconfig.md) | |
|
||||||
|
@ -53,12 +51,11 @@
|
||||||
| [IFieldSubType](./kibana-plugin-plugins-data-server.ifieldsubtype.md) | |
|
| [IFieldSubType](./kibana-plugin-plugins-data-server.ifieldsubtype.md) | |
|
||||||
| [IFieldType](./kibana-plugin-plugins-data-server.ifieldtype.md) | |
|
| [IFieldType](./kibana-plugin-plugins-data-server.ifieldtype.md) | |
|
||||||
| [IndexPatternAttributes](./kibana-plugin-plugins-data-server.indexpatternattributes.md) | Interface for an index pattern saved object |
|
| [IndexPatternAttributes](./kibana-plugin-plugins-data-server.indexpatternattributes.md) | Interface for an index pattern saved object |
|
||||||
| [IScopedSessionService](./kibana-plugin-plugins-data-server.iscopedsessionservice.md) | |
|
|
||||||
| [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) | |
|
| [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) | |
|
||||||
|
| [ISearchSessionService](./kibana-plugin-plugins-data-server.isearchsessionservice.md) | |
|
||||||
| [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) | |
|
| [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) | |
|
||||||
| [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) | |
|
| [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) | |
|
||||||
| [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) | Search strategy interface contains a search method that takes in a request and returns a promise that resolves to a response. |
|
| [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) | Search strategy interface contains a search method that takes in a request and returns a promise that resolves to a response. |
|
||||||
| [ISessionService](./kibana-plugin-plugins-data-server.isessionservice.md) | |
|
|
||||||
| [KueryNode](./kibana-plugin-plugins-data-server.kuerynode.md) | |
|
| [KueryNode](./kibana-plugin-plugins-data-server.kuerynode.md) | |
|
||||||
| [OptionedValueProp](./kibana-plugin-plugins-data-server.optionedvalueprop.md) | |
|
| [OptionedValueProp](./kibana-plugin-plugins-data-server.optionedvalueprop.md) | |
|
||||||
| [PluginSetup](./kibana-plugin-plugins-data-server.pluginsetup.md) | |
|
| [PluginSetup](./kibana-plugin-plugins-data-server.pluginsetup.md) | |
|
||||||
|
@ -110,5 +107,6 @@
|
||||||
| [KibanaContext](./kibana-plugin-plugins-data-server.kibanacontext.md) | |
|
| [KibanaContext](./kibana-plugin-plugins-data-server.kibanacontext.md) | |
|
||||||
| [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | |
|
| [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | |
|
||||||
| [Query](./kibana-plugin-plugins-data-server.query.md) | |
|
| [Query](./kibana-plugin-plugins-data-server.query.md) | |
|
||||||
|
| [SearchRequestHandlerContext](./kibana-plugin-plugins-data-server.searchrequesthandlercontext.md) | |
|
||||||
| [TimeRange](./kibana-plugin-plugins-data-server.timerange.md) | |
|
| [TimeRange](./kibana-plugin-plugins-data-server.timerange.md) | |
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- 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) > [SearchRequestHandlerContext](./kibana-plugin-plugins-data-server.searchrequesthandlercontext.md)
|
||||||
|
|
||||||
|
## SearchRequestHandlerContext type
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export declare type SearchRequestHandlerContext = IScopedSearchClient;
|
||||||
|
```
|
|
@ -16,5 +16,6 @@ export interface SearchStrategyDependencies
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| [esClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.esclient.md) | <code>IScopedClusterClient</code> | |
|
| [esClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.esclient.md) | <code>IScopedClusterClient</code> | |
|
||||||
| [savedObjectsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.savedobjectsclient.md) | <code>SavedObjectsClientContract</code> | |
|
| [savedObjectsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.savedobjectsclient.md) | <code>SavedObjectsClientContract</code> | |
|
||||||
|
| [searchSessionsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.searchsessionsclient.md) | <code>IScopedSearchSessionsClient</code> | |
|
||||||
| [uiSettingsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.uisettingsclient.md) | <code>IUiSettingsClient</code> | |
|
| [uiSettingsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.uisettingsclient.md) | <code>IUiSettingsClient</code> | |
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- 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) > [SearchStrategyDependencies](./kibana-plugin-plugins-data-server.searchstrategydependencies.md) > [searchSessionsClient](./kibana-plugin-plugins-data-server.searchstrategydependencies.searchsessionsclient.md)
|
||||||
|
|
||||||
|
## SearchStrategyDependencies.searchSessionsClient property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
searchSessionsClient: IScopedSearchSessionsClient;
|
||||||
|
```
|
|
@ -1,13 +0,0 @@
|
||||||
<!-- 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) > [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md) > [(constructor)](./kibana-plugin-plugins-data-server.sessionservice._constructor_.md)
|
|
||||||
|
|
||||||
## SessionService.(constructor)
|
|
||||||
|
|
||||||
Constructs a new instance of the `SessionService` class
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
constructor();
|
|
||||||
```
|
|
|
@ -1,26 +0,0 @@
|
||||||
<!-- 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) > [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md) > [asScopedProvider](./kibana-plugin-plugins-data-server.sessionservice.asscopedprovider.md)
|
|
||||||
|
|
||||||
## SessionService.asScopedProvider() method
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
asScopedProvider(core: CoreStart): (request: KibanaRequest) => {
|
|
||||||
search: <Request_1 extends IKibanaSearchRequest<any>, Response_1 extends IKibanaSearchResponse<any>>(strategy: ISearchStrategy<Request_1, Response_1>, request: Request_1, options: import("../../../common").ISearchOptions, deps: import("../types").SearchStrategyDependencies) => import("rxjs").Observable<Response_1>;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| core | <code>CoreStart</code> | |
|
|
||||||
|
|
||||||
<b>Returns:</b>
|
|
||||||
|
|
||||||
`(request: KibanaRequest) => {
|
|
||||||
search: <Request_1 extends IKibanaSearchRequest<any>, Response_1 extends IKibanaSearchResponse<any>>(strategy: ISearchStrategy<Request_1, Response_1>, request: Request_1, options: import("../../../common").ISearchOptions, deps: import("../types").SearchStrategyDependencies) => import("rxjs").Observable<Response_1>;
|
|
||||||
}`
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
<!-- 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) > [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md)
|
|
||||||
|
|
||||||
## SessionService class
|
|
||||||
|
|
||||||
The OSS session service. See data\_enhanced in X-Pack for the search session service.
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export declare class SessionService implements ISessionService
|
|
||||||
```
|
|
||||||
|
|
||||||
## Constructors
|
|
||||||
|
|
||||||
| Constructor | Modifiers | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [(constructor)()](./kibana-plugin-plugins-data-server.sessionservice._constructor_.md) | | Constructs a new instance of the <code>SessionService</code> class |
|
|
||||||
|
|
||||||
## Methods
|
|
||||||
|
|
||||||
| Method | Modifiers | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [asScopedProvider(core)](./kibana-plugin-plugins-data-server.sessionservice.asscopedprovider.md) | | |
|
|
||||||
| [search(strategy, args)](./kibana-plugin-plugins-data-server.sessionservice.search.md) | | |
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
<!-- 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) > [SessionService](./kibana-plugin-plugins-data-server.sessionservice.md) > [search](./kibana-plugin-plugins-data-server.sessionservice.search.md)
|
|
||||||
|
|
||||||
## SessionService.search() method
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
search<Request extends IKibanaSearchRequest, Response extends IKibanaSearchResponse>(strategy: ISearchStrategy<Request, Response>, ...args: Parameters<ISearchStrategy<Request, Response>['search']>): import("rxjs").Observable<Response>;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| strategy | <code>ISearchStrategy<Request, Response></code> | |
|
|
||||||
| args | <code>Parameters<ISearchStrategy<Request, Response>['search']></code> | |
|
|
||||||
|
|
||||||
<b>Returns:</b>
|
|
||||||
|
|
||||||
`import("rxjs").Observable<Response>`
|
|
||||||
|
|
|
@ -12,10 +12,9 @@ import type {
|
||||||
CoreStart,
|
CoreStart,
|
||||||
Plugin,
|
Plugin,
|
||||||
Logger,
|
Logger,
|
||||||
RequestHandlerContext,
|
|
||||||
} from 'src/core/server';
|
} from 'src/core/server';
|
||||||
|
|
||||||
import type { DataApiRequestHandlerContext } from 'src/plugins/data/server';
|
import type { DataRequestHandlerContext } from 'src/plugins/data/server';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SearchExamplesPluginSetup,
|
SearchExamplesPluginSetup,
|
||||||
|
@ -45,9 +44,7 @@ export class SearchExamplesPlugin
|
||||||
deps: SearchExamplesPluginSetupDeps
|
deps: SearchExamplesPluginSetupDeps
|
||||||
) {
|
) {
|
||||||
this.logger.debug('search_examples: Setup');
|
this.logger.debug('search_examples: Setup');
|
||||||
const router = core.http.createRouter<
|
const router = core.http.createRouter<DataRequestHandlerContext>();
|
||||||
RequestHandlerContext & { search: DataApiRequestHandlerContext }
|
|
||||||
>();
|
|
||||||
|
|
||||||
core.getStartServices().then(([_, depsStart]) => {
|
core.getStartServices().then(([_, depsStart]) => {
|
||||||
const myStrategy = mySearchStrategyProvider(depsStart.data);
|
const myStrategy = mySearchStrategyProvider(depsStart.data);
|
||||||
|
|
|
@ -6,12 +6,10 @@
|
||||||
* Public License, v 1.
|
* Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { IRouter, RequestHandlerContext } from 'kibana/server';
|
import type { IRouter } from 'kibana/server';
|
||||||
import { DataApiRequestHandlerContext } from 'src/plugins/data/server';
|
import { DataRequestHandlerContext } from 'src/plugins/data/server';
|
||||||
import { registerServerSearchRoute } from './server_search_route';
|
import { registerServerSearchRoute } from './server_search_route';
|
||||||
|
|
||||||
export function registerRoutes(
|
export function registerRoutes(router: IRouter<DataRequestHandlerContext>) {
|
||||||
router: IRouter<RequestHandlerContext & { search: DataApiRequestHandlerContext }>
|
|
||||||
) {
|
|
||||||
registerServerSearchRoute(router);
|
registerServerSearchRoute(router);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,11 @@
|
||||||
import { IEsSearchRequest } from 'src/plugins/data/server';
|
import { IEsSearchRequest } from 'src/plugins/data/server';
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
import { IEsSearchResponse } from 'src/plugins/data/common';
|
import { IEsSearchResponse } from 'src/plugins/data/common';
|
||||||
import type { DataApiRequestHandlerContext } from 'src/plugins/data/server';
|
import type { DataRequestHandlerContext } from 'src/plugins/data/server';
|
||||||
import type { IRouter, RequestHandlerContext } from 'src/core/server';
|
import type { IRouter } from 'src/core/server';
|
||||||
import { SERVER_SEARCH_ROUTE_PATH } from '../../common';
|
import { SERVER_SEARCH_ROUTE_PATH } from '../../common';
|
||||||
|
|
||||||
export function registerServerSearchRoute(
|
export function registerServerSearchRoute(router: IRouter<DataRequestHandlerContext>) {
|
||||||
router: IRouter<RequestHandlerContext & { search: DataApiRequestHandlerContext }>
|
|
||||||
) {
|
|
||||||
router.get(
|
router.get(
|
||||||
{
|
{
|
||||||
path: SERVER_SEARCH_ROUTE_PATH,
|
path: SERVER_SEARCH_ROUTE_PATH,
|
||||||
|
|
|
@ -17,6 +17,7 @@ export function getSessionsClientMock(): jest.Mocked<ISessionsClient> {
|
||||||
create: jest.fn(),
|
create: jest.fn(),
|
||||||
find: jest.fn(),
|
find: jest.fn(),
|
||||||
update: jest.fn(),
|
update: jest.fn(),
|
||||||
|
extend: jest.fn(),
|
||||||
delete: jest.fn(),
|
delete: jest.fn(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,12 @@ export class SessionsClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public extend(sessionId: string, keepAlive: string): Promise<SavedObjectsFindResponse> {
|
||||||
|
return this.http!.post(`/internal/session/${encodeURIComponent(sessionId)}/_extend`, {
|
||||||
|
body: JSON.stringify({ keepAlive }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public delete(sessionId: string): Promise<void> {
|
public delete(sessionId: string): Promise<void> {
|
||||||
return this.http!.delete(`/internal/session/${encodeURIComponent(sessionId)}`);
|
return this.http!.delete(`/internal/session/${encodeURIComponent(sessionId)}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,10 +229,9 @@ export {
|
||||||
searchUsageObserver,
|
searchUsageObserver,
|
||||||
shimAbortSignal,
|
shimAbortSignal,
|
||||||
SearchUsage,
|
SearchUsage,
|
||||||
SessionService,
|
SearchSessionService,
|
||||||
ISessionService,
|
ISearchSessionService,
|
||||||
IScopedSessionService,
|
SearchRequestHandlerContext,
|
||||||
DataApiRequestHandlerContext,
|
|
||||||
DataRequestHandlerContext,
|
DataRequestHandlerContext,
|
||||||
} from './search';
|
} from './search';
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,14 @@
|
||||||
* Public License, v 1.
|
* Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createSearchSetupMock, createSearchStartMock } from './search/mocks';
|
import {
|
||||||
|
createSearchSetupMock,
|
||||||
|
createSearchStartMock,
|
||||||
|
createSearchRequestHandlerContext,
|
||||||
|
} from './search/mocks';
|
||||||
import { createFieldFormatsSetupMock, createFieldFormatsStartMock } from './field_formats/mocks';
|
import { createFieldFormatsSetupMock, createFieldFormatsStartMock } from './field_formats/mocks';
|
||||||
import { createIndexPatternsStartMock } from './index_patterns/mocks';
|
import { createIndexPatternsStartMock } from './index_patterns/mocks';
|
||||||
|
import { DataRequestHandlerContext } from './search';
|
||||||
|
|
||||||
function createSetupContract() {
|
function createSetupContract() {
|
||||||
return {
|
return {
|
||||||
|
@ -25,7 +30,14 @@ function createStartContract() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createRequestHandlerContext() {
|
||||||
|
return ({
|
||||||
|
search: createSearchRequestHandlerContext(),
|
||||||
|
} as unknown) as jest.Mocked<DataRequestHandlerContext>;
|
||||||
|
}
|
||||||
|
|
||||||
export const dataPluginMock = {
|
export const dataPluginMock = {
|
||||||
createSetupContract,
|
createSetupContract,
|
||||||
createStartContract,
|
createStartContract,
|
||||||
|
createRequestHandlerContext,
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,8 @@ import { ISearchSetup, ISearchStart } from './types';
|
||||||
import { searchAggsSetupMock, searchAggsStartMock } from './aggs/mocks';
|
import { searchAggsSetupMock, searchAggsStartMock } from './aggs/mocks';
|
||||||
import { searchSourceMock } from './search_source/mocks';
|
import { searchSourceMock } from './search_source/mocks';
|
||||||
|
|
||||||
|
export { createSearchSessionsClientMock } from './session/mocks';
|
||||||
|
|
||||||
export function createSearchSetupMock(): jest.Mocked<ISearchSetup> {
|
export function createSearchSetupMock(): jest.Mocked<ISearchSetup> {
|
||||||
return {
|
return {
|
||||||
aggs: searchAggsSetupMock(),
|
aggs: searchAggsSetupMock(),
|
||||||
|
@ -22,10 +24,21 @@ export function createSearchStartMock(): jest.Mocked<ISearchStart> {
|
||||||
return {
|
return {
|
||||||
aggs: searchAggsStartMock(),
|
aggs: searchAggsStartMock(),
|
||||||
getSearchStrategy: jest.fn(),
|
getSearchStrategy: jest.fn(),
|
||||||
asScoped: jest.fn().mockReturnValue({
|
asScoped: jest.fn().mockReturnValue(createSearchRequestHandlerContext()),
|
||||||
search: jest.fn(),
|
|
||||||
cancel: jest.fn(),
|
|
||||||
}),
|
|
||||||
searchSource: searchSourceMock.createStartContract(),
|
searchSource: searchSourceMock.createStartContract(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createSearchRequestHandlerContext() {
|
||||||
|
return {
|
||||||
|
search: jest.fn(),
|
||||||
|
cancel: jest.fn(),
|
||||||
|
extend: jest.fn(),
|
||||||
|
saveSession: jest.fn(),
|
||||||
|
getSession: jest.fn(),
|
||||||
|
findSessions: jest.fn(),
|
||||||
|
updateSession: jest.fn(),
|
||||||
|
extendSession: jest.fn(),
|
||||||
|
cancelSession: jest.fn(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -7,21 +7,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { catchError, first } from 'rxjs/operators';
|
import { catchError, first } from 'rxjs/operators';
|
||||||
import { CoreStart, KibanaRequest } from 'src/core/server';
|
|
||||||
import { BfetchServerSetup } from 'src/plugins/bfetch/server';
|
import { BfetchServerSetup } from 'src/plugins/bfetch/server';
|
||||||
import {
|
import {
|
||||||
IKibanaSearchRequest,
|
IKibanaSearchRequest,
|
||||||
IKibanaSearchResponse,
|
IKibanaSearchResponse,
|
||||||
ISearchClient,
|
|
||||||
ISearchOptions,
|
ISearchOptions,
|
||||||
} from '../../../common/search';
|
} from '../../../common/search';
|
||||||
|
import { ISearchStart } from '../types';
|
||||||
type GetScopedProider = (coreStart: CoreStart) => (request: KibanaRequest) => ISearchClient;
|
|
||||||
|
|
||||||
export function registerBsearchRoute(
|
export function registerBsearchRoute(
|
||||||
bfetch: BfetchServerSetup,
|
bfetch: BfetchServerSetup,
|
||||||
coreStartPromise: Promise<[CoreStart, {}, {}]>,
|
getScoped: ISearchStart['asScoped']
|
||||||
getScopedProvider: GetScopedProider
|
|
||||||
): void {
|
): void {
|
||||||
bfetch.addBatchProcessingRoute<
|
bfetch.addBatchProcessingRoute<
|
||||||
{ request: IKibanaSearchRequest; options?: ISearchOptions },
|
{ request: IKibanaSearchRequest; options?: ISearchOptions },
|
||||||
|
@ -33,8 +29,7 @@ export function registerBsearchRoute(
|
||||||
* @throws `KibanaServerError`
|
* @throws `KibanaServerError`
|
||||||
*/
|
*/
|
||||||
onBatchItem: async ({ request: requestData, options }) => {
|
onBatchItem: async ({ request: requestData, options }) => {
|
||||||
const coreStart = await coreStartPromise;
|
const search = getScoped(request);
|
||||||
const search = getScopedProvider(coreStart[0])(request);
|
|
||||||
return search
|
return search
|
||||||
.search(requestData, options)
|
.search(requestData, options)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
* Public License, v 1.
|
* Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BehaviorSubject, Observable, throwError } from 'rxjs';
|
import { BehaviorSubject, from, Observable, throwError } from 'rxjs';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
|
import moment from 'moment';
|
||||||
import {
|
import {
|
||||||
CoreSetup,
|
CoreSetup,
|
||||||
CoreStart,
|
CoreStart,
|
||||||
|
@ -18,10 +19,11 @@ import {
|
||||||
SharedGlobalConfig,
|
SharedGlobalConfig,
|
||||||
StartServicesAccessor,
|
StartServicesAccessor,
|
||||||
} from 'src/core/server';
|
} from 'src/core/server';
|
||||||
import { first } from 'rxjs/operators';
|
import { first, switchMap } from 'rxjs/operators';
|
||||||
import { BfetchServerSetup } from 'src/plugins/bfetch/server';
|
import { BfetchServerSetup } from 'src/plugins/bfetch/server';
|
||||||
import { ExpressionsServerSetup } from 'src/plugins/expressions/server';
|
import { ExpressionsServerSetup } from 'src/plugins/expressions/server';
|
||||||
import type {
|
import type {
|
||||||
|
IScopedSearchClient,
|
||||||
ISearchSetup,
|
ISearchSetup,
|
||||||
ISearchStart,
|
ISearchStart,
|
||||||
ISearchStrategy,
|
ISearchStrategy,
|
||||||
|
@ -46,7 +48,6 @@ import {
|
||||||
IEsSearchResponse,
|
IEsSearchResponse,
|
||||||
IKibanaSearchRequest,
|
IKibanaSearchRequest,
|
||||||
IKibanaSearchResponse,
|
IKibanaSearchResponse,
|
||||||
ISearchClient,
|
|
||||||
ISearchOptions,
|
ISearchOptions,
|
||||||
kibana,
|
kibana,
|
||||||
kibanaContext,
|
kibanaContext,
|
||||||
|
@ -62,8 +63,9 @@ import {
|
||||||
} from '../../common/search/aggs/buckets/shard_delay';
|
} from '../../common/search/aggs/buckets/shard_delay';
|
||||||
import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn';
|
import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn';
|
||||||
import { ConfigSchema } from '../../config';
|
import { ConfigSchema } from '../../config';
|
||||||
import { IScopedSessionService, ISessionService, SessionService } from './session';
|
import { ISearchSessionService, SearchSessionService } from './session';
|
||||||
import { KbnServerError } from '../../../kibana_utils/server';
|
import { KbnServerError } from '../../../kibana_utils/server';
|
||||||
|
import { tapFirst } from '../../common';
|
||||||
import { registerBsearchRoute } from './routes/bsearch';
|
import { registerBsearchRoute } from './routes/bsearch';
|
||||||
|
|
||||||
type StrategyMap = Record<string, ISearchStrategy<any, any>>;
|
type StrategyMap = Record<string, ISearchStrategy<any, any>>;
|
||||||
|
@ -92,14 +94,14 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
private readonly searchSourceService = new SearchSourceService();
|
private readonly searchSourceService = new SearchSourceService();
|
||||||
private defaultSearchStrategyName: string = ES_SEARCH_STRATEGY;
|
private defaultSearchStrategyName: string = ES_SEARCH_STRATEGY;
|
||||||
private searchStrategies: StrategyMap = {};
|
private searchStrategies: StrategyMap = {};
|
||||||
private sessionService: ISessionService;
|
private sessionService: ISearchSessionService;
|
||||||
private coreStart?: CoreStart;
|
private asScoped!: ISearchStart['asScoped'];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private initializerContext: PluginInitializerContext<ConfigSchema>,
|
private initializerContext: PluginInitializerContext<ConfigSchema>,
|
||||||
private readonly logger: Logger
|
private readonly logger: Logger
|
||||||
) {
|
) {
|
||||||
this.sessionService = new SessionService();
|
this.sessionService = new SearchSessionService();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setup(
|
public setup(
|
||||||
|
@ -116,16 +118,10 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
registerSearchRoute(router);
|
registerSearchRoute(router);
|
||||||
registerMsearchRoute(router, routeDependencies);
|
registerMsearchRoute(router, routeDependencies);
|
||||||
|
|
||||||
core.getStartServices().then(([coreStart]) => {
|
|
||||||
this.coreStart = coreStart;
|
|
||||||
});
|
|
||||||
|
|
||||||
core.http.registerRouteHandlerContext<DataRequestHandlerContext, 'search'>(
|
core.http.registerRouteHandlerContext<DataRequestHandlerContext, 'search'>(
|
||||||
'search',
|
'search',
|
||||||
async (context, request) => {
|
async (context, request) => {
|
||||||
const search = this.asScopedProvider(this.coreStart!)(request);
|
return this.asScoped(request);
|
||||||
const session = this.sessionService.asScopedProvider(this.coreStart!)(request);
|
|
||||||
return { ...search, session };
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -138,7 +134,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
registerBsearchRoute(bfetch, core.getStartServices(), this.asScopedProvider);
|
registerBsearchRoute(bfetch, (request: KibanaRequest) => this.asScoped(request));
|
||||||
|
|
||||||
core.savedObjects.registerType(searchTelemetry);
|
core.savedObjects.registerType(searchTelemetry);
|
||||||
if (usageCollection) {
|
if (usageCollection) {
|
||||||
|
@ -181,7 +177,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
{ fieldFormats, indexPatterns }: SearchServiceStartDependencies
|
{ fieldFormats, indexPatterns }: SearchServiceStartDependencies
|
||||||
): ISearchStart {
|
): ISearchStart {
|
||||||
const { elasticsearch, savedObjects, uiSettings } = core;
|
const { elasticsearch, savedObjects, uiSettings } = core;
|
||||||
const asScoped = this.asScopedProvider(core);
|
this.asScoped = this.asScopedProvider(core);
|
||||||
return {
|
return {
|
||||||
aggs: this.aggsService.start({
|
aggs: this.aggsService.start({
|
||||||
fieldFormats,
|
fieldFormats,
|
||||||
|
@ -189,7 +185,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
indexPatterns,
|
indexPatterns,
|
||||||
}),
|
}),
|
||||||
getSearchStrategy: this.getSearchStrategy,
|
getSearchStrategy: this.getSearchStrategy,
|
||||||
asScoped,
|
asScoped: this.asScoped,
|
||||||
searchSource: {
|
searchSource: {
|
||||||
asScoped: async (request: KibanaRequest) => {
|
asScoped: async (request: KibanaRequest) => {
|
||||||
const esClient = elasticsearch.client.asScoped(request);
|
const esClient = elasticsearch.client.asScoped(request);
|
||||||
|
@ -208,7 +204,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
|
|
||||||
const searchSourceDependencies: SearchSourceDependencies = {
|
const searchSourceDependencies: SearchSourceDependencies = {
|
||||||
getConfig: <T = any>(key: string): T => uiSettingsCache[key],
|
getConfig: <T = any>(key: string): T => uiSettingsCache[key],
|
||||||
search: asScoped(request).search,
|
search: this.asScoped(request).search,
|
||||||
onResponse: (req, res) => res,
|
onResponse: (req, res) => res,
|
||||||
legacy: {
|
legacy: {
|
||||||
callMsearch: getCallMsearch({
|
callMsearch: getCallMsearch({
|
||||||
|
@ -241,49 +237,6 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
this.searchStrategies[name] = strategy;
|
this.searchStrategies[name] = strategy;
|
||||||
};
|
};
|
||||||
|
|
||||||
private search = <
|
|
||||||
SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest,
|
|
||||||
SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse
|
|
||||||
>(
|
|
||||||
session: IScopedSessionService,
|
|
||||||
request: SearchStrategyRequest,
|
|
||||||
options: ISearchOptions,
|
|
||||||
deps: SearchStrategyDependencies
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const strategy = this.getSearchStrategy<SearchStrategyRequest, SearchStrategyResponse>(
|
|
||||||
options.strategy
|
|
||||||
);
|
|
||||||
return session.search(strategy, request, options, deps);
|
|
||||||
} catch (e) {
|
|
||||||
return throwError(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private cancel = (id: string, options: ISearchOptions, deps: SearchStrategyDependencies) => {
|
|
||||||
const strategy = this.getSearchStrategy(options.strategy);
|
|
||||||
if (!strategy.cancel) {
|
|
||||||
throw new KbnServerError(
|
|
||||||
`Search strategy ${options.strategy} doesn't support cancellations`,
|
|
||||||
400
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return strategy.cancel(id, options, deps);
|
|
||||||
};
|
|
||||||
|
|
||||||
private extend = (
|
|
||||||
id: string,
|
|
||||||
keepAlive: string,
|
|
||||||
options: ISearchOptions,
|
|
||||||
deps: SearchStrategyDependencies
|
|
||||||
) => {
|
|
||||||
const strategy = this.getSearchStrategy(options.strategy);
|
|
||||||
if (!strategy.extend) {
|
|
||||||
throw new KbnServerError(`Search strategy ${options.strategy} does not support extend`, 400);
|
|
||||||
}
|
|
||||||
return strategy.extend(id, keepAlive, options, deps);
|
|
||||||
};
|
|
||||||
|
|
||||||
private getSearchStrategy = <
|
private getSearchStrategy = <
|
||||||
SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest,
|
SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest,
|
||||||
SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse
|
SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse
|
||||||
|
@ -298,22 +251,128 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
return strategy;
|
return strategy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private search = <
|
||||||
|
SearchStrategyRequest extends IKibanaSearchRequest,
|
||||||
|
SearchStrategyResponse extends IKibanaSearchResponse
|
||||||
|
>(
|
||||||
|
deps: SearchStrategyDependencies,
|
||||||
|
request: SearchStrategyRequest,
|
||||||
|
options: ISearchOptions
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const strategy = this.getSearchStrategy<SearchStrategyRequest, SearchStrategyResponse>(
|
||||||
|
options.strategy
|
||||||
|
);
|
||||||
|
|
||||||
|
const getSearchRequest = async () =>
|
||||||
|
!options.sessionId || !options.isRestore || request.id
|
||||||
|
? request
|
||||||
|
: {
|
||||||
|
...request,
|
||||||
|
id: await deps.searchSessionsClient.getId(request, options),
|
||||||
|
};
|
||||||
|
|
||||||
|
return from(getSearchRequest()).pipe(
|
||||||
|
switchMap((searchRequest) => strategy.search(searchRequest, options, deps)),
|
||||||
|
tapFirst((response) => {
|
||||||
|
if (request.id || !options.sessionId || !response.id || options.isRestore) return;
|
||||||
|
deps.searchSessionsClient.trackId(request, response.id, options);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return throwError(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private cancel = (deps: SearchStrategyDependencies, id: string, options: ISearchOptions = {}) => {
|
||||||
|
const strategy = this.getSearchStrategy(options.strategy);
|
||||||
|
if (!strategy.cancel) {
|
||||||
|
throw new KbnServerError(
|
||||||
|
`Search strategy ${options.strategy} doesn't support cancellations`,
|
||||||
|
400
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return strategy.cancel(id, options, deps);
|
||||||
|
};
|
||||||
|
|
||||||
|
private extend = (
|
||||||
|
deps: SearchStrategyDependencies,
|
||||||
|
id: string,
|
||||||
|
keepAlive: string,
|
||||||
|
options: ISearchOptions = {}
|
||||||
|
) => {
|
||||||
|
const strategy = this.getSearchStrategy(options.strategy);
|
||||||
|
if (!strategy.extend) {
|
||||||
|
throw new KbnServerError(`Search strategy ${options.strategy} does not support extend`, 400);
|
||||||
|
}
|
||||||
|
return strategy.extend(id, keepAlive, options, deps);
|
||||||
|
};
|
||||||
|
|
||||||
|
private cancelSession = async (deps: SearchStrategyDependencies, sessionId: string) => {
|
||||||
|
const searchIdMapping = await deps.searchSessionsClient.getSearchIdMapping(sessionId);
|
||||||
|
const response = await deps.searchSessionsClient.cancel(sessionId);
|
||||||
|
|
||||||
|
for (const [searchId, strategyName] of searchIdMapping.entries()) {
|
||||||
|
const searchOptions = {
|
||||||
|
sessionId,
|
||||||
|
strategy: strategyName,
|
||||||
|
isStored: true,
|
||||||
|
};
|
||||||
|
this.cancel(deps, searchId, searchOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
|
||||||
|
private extendSession = async (
|
||||||
|
deps: SearchStrategyDependencies,
|
||||||
|
sessionId: string,
|
||||||
|
expires: Date
|
||||||
|
) => {
|
||||||
|
const searchIdMapping = await deps.searchSessionsClient.getSearchIdMapping(sessionId);
|
||||||
|
const keepAlive = `${moment(expires).diff(moment())}ms`;
|
||||||
|
|
||||||
|
for (const [searchId, strategyName] of searchIdMapping.entries()) {
|
||||||
|
const searchOptions = {
|
||||||
|
sessionId,
|
||||||
|
strategy: strategyName,
|
||||||
|
isStored: true,
|
||||||
|
};
|
||||||
|
await this.extend(deps, searchId, keepAlive, searchOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deps.searchSessionsClient.extend(sessionId, expires);
|
||||||
|
};
|
||||||
|
|
||||||
private asScopedProvider = (core: CoreStart) => {
|
private asScopedProvider = (core: CoreStart) => {
|
||||||
const { elasticsearch, savedObjects, uiSettings } = core;
|
const { elasticsearch, savedObjects, uiSettings } = core;
|
||||||
const getSessionAsScoped = this.sessionService.asScopedProvider(core);
|
const getSessionAsScoped = this.sessionService.asScopedProvider(core);
|
||||||
return (request: KibanaRequest): ISearchClient => {
|
return (request: KibanaRequest): IScopedSearchClient => {
|
||||||
const scopedSession = getSessionAsScoped(request);
|
|
||||||
const savedObjectsClient = savedObjects.getScopedClient(request);
|
const savedObjectsClient = savedObjects.getScopedClient(request);
|
||||||
|
const searchSessionsClient = getSessionAsScoped(request);
|
||||||
const deps = {
|
const deps = {
|
||||||
|
searchSessionsClient,
|
||||||
savedObjectsClient,
|
savedObjectsClient,
|
||||||
esClient: elasticsearch.client.asScoped(request),
|
esClient: elasticsearch.client.asScoped(request),
|
||||||
uiSettingsClient: uiSettings.asScopedToClient(savedObjectsClient),
|
uiSettingsClient: uiSettings.asScopedToClient(savedObjectsClient),
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
search: (searchRequest, options = {}) =>
|
search: <
|
||||||
this.search(scopedSession, searchRequest, options, deps),
|
SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest,
|
||||||
cancel: (id, options = {}) => this.cancel(id, options, deps),
|
SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse
|
||||||
extend: (id, keepAlive, options = {}) => this.extend(id, keepAlive, options, deps),
|
>(
|
||||||
|
searchRequest: SearchStrategyRequest,
|
||||||
|
options: ISearchOptions = {}
|
||||||
|
) =>
|
||||||
|
this.search<SearchStrategyRequest, SearchStrategyResponse>(deps, searchRequest, options),
|
||||||
|
cancel: this.cancel.bind(this, deps),
|
||||||
|
extend: this.extend.bind(this, deps),
|
||||||
|
saveSession: searchSessionsClient.save,
|
||||||
|
getSession: searchSessionsClient.get,
|
||||||
|
findSessions: searchSessionsClient.find,
|
||||||
|
updateSession: searchSessionsClient.update,
|
||||||
|
extendSession: this.extendSession.bind(this, deps),
|
||||||
|
cancelSession: this.cancelSession.bind(this, deps),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
25
src/plugins/data/server/search/session/mocks.ts
Normal file
25
src/plugins/data/server/search/session/mocks.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { IScopedSearchSessionsClient } from './types';
|
||||||
|
|
||||||
|
export function createSearchSessionsClientMock<T = unknown>(): jest.Mocked<
|
||||||
|
IScopedSearchSessionsClient<T>
|
||||||
|
> {
|
||||||
|
return {
|
||||||
|
getId: jest.fn(),
|
||||||
|
trackId: jest.fn(),
|
||||||
|
getSearchIdMapping: jest.fn(),
|
||||||
|
save: jest.fn(),
|
||||||
|
get: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
update: jest.fn(),
|
||||||
|
cancel: jest.fn(),
|
||||||
|
extend: jest.fn(),
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,27 +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
|
|
||||||
* and the Server Side Public License, v 1; you may not use this file except in
|
|
||||||
* compliance with, at your election, the Elastic License or the Server Side
|
|
||||||
* Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
import { SearchStrategyDependencies } from '../types';
|
|
||||||
import { SessionService } from './session_service';
|
|
||||||
|
|
||||||
describe('SessionService', () => {
|
|
||||||
it('search invokes `strategy.search`', async () => {
|
|
||||||
const service = new SessionService();
|
|
||||||
const mockSearch = jest.fn().mockReturnValue(of({}));
|
|
||||||
const mockStrategy = { search: mockSearch };
|
|
||||||
const mockRequest = { id: 'bar' };
|
|
||||||
const mockOptions = { sessionId: '1234' };
|
|
||||||
const mockDeps = { savedObjectsClient: {} } as SearchStrategyDependencies;
|
|
||||||
|
|
||||||
await service.search(mockStrategy, mockRequest, mockOptions, mockDeps);
|
|
||||||
|
|
||||||
expect(mockSearch).toHaveBeenCalled();
|
|
||||||
expect(mockSearch).toHaveBeenCalledWith(mockRequest, mockOptions, mockDeps);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -6,27 +6,41 @@
|
||||||
* Public License, v 1.
|
* Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CoreStart, KibanaRequest } from 'kibana/server';
|
import { ISearchSessionService } from './types';
|
||||||
import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../../common';
|
|
||||||
import { ISearchStrategy } from '../types';
|
|
||||||
import { ISessionService } from './types';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The OSS session service. See data_enhanced in X-Pack for the search session service.
|
* The OSS session service, which leaves most search session-related logic unimplemented.
|
||||||
|
* @see x-pack/plugins/data_enhanced/server/search/session/session_service.ts
|
||||||
|
* @internal
|
||||||
*/
|
*/
|
||||||
export class SessionService implements ISessionService {
|
export class SearchSessionService implements ISearchSessionService {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
public search<Request extends IKibanaSearchRequest, Response extends IKibanaSearchResponse>(
|
public asScopedProvider() {
|
||||||
strategy: ISearchStrategy<Request, Response>,
|
return () => ({
|
||||||
...args: Parameters<ISearchStrategy<Request, Response>['search']>
|
getId: () => {
|
||||||
) {
|
throw new Error('getId not implemented in OSS search session service');
|
||||||
return strategy.search(...args);
|
},
|
||||||
}
|
trackId: async () => {},
|
||||||
|
getSearchIdMapping: async () => new Map<string, string>(),
|
||||||
public asScopedProvider(core: CoreStart) {
|
save: async () => {
|
||||||
return (request: KibanaRequest) => ({
|
throw new Error('save not implemented in OSS search session service');
|
||||||
search: this.search,
|
},
|
||||||
|
get: async () => {
|
||||||
|
throw new Error('get not implemented in OSS search session service');
|
||||||
|
},
|
||||||
|
find: async () => {
|
||||||
|
throw new Error('find not implemented in OSS search session service');
|
||||||
|
},
|
||||||
|
update: async () => {
|
||||||
|
throw new Error('update not implemented in OSS search session service');
|
||||||
|
},
|
||||||
|
extend: async () => {
|
||||||
|
throw new Error('extend not implemented in OSS search session service');
|
||||||
|
},
|
||||||
|
cancel: async () => {
|
||||||
|
throw new Error('cancel not implemented in OSS search session service');
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,32 @@
|
||||||
* Public License, v 1.
|
* Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Observable } from 'rxjs';
|
import {
|
||||||
import { CoreStart, KibanaRequest } from 'kibana/server';
|
CoreStart,
|
||||||
import { ISearchStrategy } from '../types';
|
KibanaRequest,
|
||||||
import { IKibanaSearchRequest, IKibanaSearchResponse } from '../../../common/search';
|
SavedObject,
|
||||||
|
SavedObjectsFindOptions,
|
||||||
|
SavedObjectsFindResponse,
|
||||||
|
SavedObjectsUpdateResponse,
|
||||||
|
} from 'kibana/server';
|
||||||
|
import { IKibanaSearchRequest, ISearchOptions } from '../../../common/search';
|
||||||
|
|
||||||
export interface IScopedSessionService {
|
export interface IScopedSearchSessionsClient<T = unknown> {
|
||||||
search: <Request extends IKibanaSearchRequest, Response extends IKibanaSearchResponse>(
|
getId: (request: IKibanaSearchRequest, options: ISearchOptions) => Promise<string>;
|
||||||
strategy: ISearchStrategy<Request, Response>,
|
trackId: (
|
||||||
...args: Parameters<ISearchStrategy<Request, Response>['search']>
|
request: IKibanaSearchRequest,
|
||||||
) => Observable<Response>;
|
searchId: string,
|
||||||
[prop: string]: any;
|
options: ISearchOptions
|
||||||
|
) => Promise<void>;
|
||||||
|
getSearchIdMapping: (sessionId: string) => Promise<Map<string, string>>;
|
||||||
|
save: (sessionId: string, attributes: Partial<T>) => Promise<SavedObject<T>>;
|
||||||
|
get: (sessionId: string) => Promise<SavedObject<T>>;
|
||||||
|
find: (options: Omit<SavedObjectsFindOptions, 'type'>) => Promise<SavedObjectsFindResponse<T>>;
|
||||||
|
update: (sessionId: string, attributes: Partial<T>) => Promise<SavedObjectsUpdateResponse<T>>;
|
||||||
|
cancel: (sessionId: string) => Promise<{}>;
|
||||||
|
extend: (sessionId: string, expires: Date) => Promise<SavedObjectsUpdateResponse<T>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISessionService {
|
export interface ISearchSessionService<T = unknown> {
|
||||||
asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSessionService;
|
asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient<T>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,17 +25,18 @@ import {
|
||||||
import { AggsSetup, AggsStart } from './aggs';
|
import { AggsSetup, AggsStart } from './aggs';
|
||||||
import { SearchUsage } from './collectors';
|
import { SearchUsage } from './collectors';
|
||||||
import { IEsSearchRequest, IEsSearchResponse } from './es_search';
|
import { IEsSearchRequest, IEsSearchResponse } from './es_search';
|
||||||
import { ISessionService, IScopedSessionService } from './session';
|
import { IScopedSearchSessionsClient, ISearchSessionService } from './session';
|
||||||
|
|
||||||
export interface SearchEnhancements {
|
export interface SearchEnhancements {
|
||||||
defaultStrategy: string;
|
defaultStrategy: string;
|
||||||
sessionService: ISessionService;
|
sessionService: ISearchSessionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchStrategyDependencies {
|
export interface SearchStrategyDependencies {
|
||||||
savedObjectsClient: SavedObjectsClientContract;
|
savedObjectsClient: SavedObjectsClientContract;
|
||||||
esClient: IScopedClusterClient;
|
esClient: IScopedClusterClient;
|
||||||
uiSettingsClient: IUiSettingsClient;
|
uiSettingsClient: IUiSettingsClient;
|
||||||
|
searchSessionsClient: IScopedSearchSessionsClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISearchSetup {
|
export interface ISearchSetup {
|
||||||
|
@ -85,6 +86,15 @@ export interface ISearchStrategy<
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IScopedSearchClient extends ISearchClient {
|
||||||
|
saveSession: IScopedSearchSessionsClient['save'];
|
||||||
|
getSession: IScopedSearchSessionsClient['get'];
|
||||||
|
findSessions: IScopedSearchSessionsClient['find'];
|
||||||
|
updateSession: IScopedSearchSessionsClient['update'];
|
||||||
|
cancelSession: IScopedSearchSessionsClient['cancel'];
|
||||||
|
extendSession: IScopedSearchSessionsClient['extend'];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ISearchStart<
|
export interface ISearchStart<
|
||||||
SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest,
|
SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest,
|
||||||
SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse
|
SearchStrategyResponse extends IKibanaSearchResponse = IEsSearchResponse
|
||||||
|
@ -98,21 +108,19 @@ export interface ISearchStart<
|
||||||
getSearchStrategy: (
|
getSearchStrategy: (
|
||||||
name?: string // Name of the search strategy (defaults to the Elasticsearch strategy)
|
name?: string // Name of the search strategy (defaults to the Elasticsearch strategy)
|
||||||
) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse>;
|
) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse>;
|
||||||
asScoped: (request: KibanaRequest) => ISearchClient;
|
asScoped: (request: KibanaRequest) => IScopedSearchClient;
|
||||||
searchSource: {
|
searchSource: {
|
||||||
asScoped: (request: KibanaRequest) => Promise<ISearchStartSearchSource>;
|
asScoped: (request: KibanaRequest) => Promise<ISearchStartSearchSource>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DataApiRequestHandlerContext extends ISearchClient {
|
export type SearchRequestHandlerContext = IScopedSearchClient;
|
||||||
session: IScopedSessionService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export interface DataRequestHandlerContext extends RequestHandlerContext {
|
export interface DataRequestHandlerContext extends RequestHandlerContext {
|
||||||
search: DataApiRequestHandlerContext;
|
search: SearchRequestHandlerContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DataPluginRouter = IRouter<DataRequestHandlerContext>;
|
export type DataPluginRouter = IRouter<DataRequestHandlerContext>;
|
||||||
|
|
|
@ -55,9 +55,13 @@ import { RecursiveReadonly } from '@kbn/utility-types';
|
||||||
import { RequestAdapter } from 'src/plugins/inspector/common';
|
import { RequestAdapter } from 'src/plugins/inspector/common';
|
||||||
import { RequestHandlerContext } from 'src/core/server';
|
import { RequestHandlerContext } from 'src/core/server';
|
||||||
import { RequestStatistics } from 'src/plugins/inspector/common';
|
import { RequestStatistics } from 'src/plugins/inspector/common';
|
||||||
import { SavedObject } from 'src/core/server';
|
import { SavedObject } from 'kibana/server';
|
||||||
|
import { SavedObject as SavedObject_2 } from 'src/core/server';
|
||||||
import { SavedObjectsClientContract } from 'src/core/server';
|
import { SavedObjectsClientContract } from 'src/core/server';
|
||||||
import { SavedObjectsClientContract as SavedObjectsClientContract_2 } from 'kibana/server';
|
import { SavedObjectsClientContract as SavedObjectsClientContract_2 } from 'kibana/server';
|
||||||
|
import { SavedObjectsFindOptions } from 'kibana/server';
|
||||||
|
import { SavedObjectsFindResponse } from 'kibana/server';
|
||||||
|
import { SavedObjectsUpdateResponse } from 'kibana/server';
|
||||||
import { Search } from '@elastic/elasticsearch/api/requestParams';
|
import { Search } from '@elastic/elasticsearch/api/requestParams';
|
||||||
import { SearchResponse } from 'elasticsearch';
|
import { SearchResponse } from 'elasticsearch';
|
||||||
import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/expressions/common';
|
import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/expressions/common';
|
||||||
|
@ -305,19 +309,10 @@ export const castEsToKbnFieldTypeName: (esType: ES_FIELD_TYPES | string) => KBN_
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const config: PluginConfigDescriptor<ConfigSchema>;
|
export const config: PluginConfigDescriptor<ConfigSchema>;
|
||||||
|
|
||||||
// Warning: (ae-forgotten-export) The symbol "ISearchClient" needs to be exported by the entry point index.d.ts
|
|
||||||
// Warning: (ae-missing-release-tag) "DataApiRequestHandlerContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
|
||||||
//
|
|
||||||
// @public (undocumented)
|
|
||||||
export interface DataApiRequestHandlerContext extends ISearchClient {
|
|
||||||
// (undocumented)
|
|
||||||
session: IScopedSessionService;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @internal (undocumented)
|
// @internal (undocumented)
|
||||||
export interface DataRequestHandlerContext extends RequestHandlerContext {
|
export interface DataRequestHandlerContext extends RequestHandlerContext {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
search: DataApiRequestHandlerContext;
|
search: SearchRequestHandlerContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
|
@ -910,16 +905,6 @@ export class IndexPatternsService implements Plugin_3<void, IndexPatternsService
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "IScopedSessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
|
||||||
//
|
|
||||||
// @public (undocumented)
|
|
||||||
export interface IScopedSessionService {
|
|
||||||
// (undocumented)
|
|
||||||
[prop: string]: any;
|
|
||||||
// (undocumented)
|
|
||||||
search: <Request extends IKibanaSearchRequest, Response extends IKibanaSearchResponse>(strategy: ISearchStrategy<Request, Response>, ...args: Parameters<ISearchStrategy<Request, Response>['search']>) => Observable<Response>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "ISearchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "ISearchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
|
@ -932,6 +917,16 @@ export interface ISearchOptions {
|
||||||
strategy?: string;
|
strategy?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warning: (ae-missing-release-tag) "ISearchSessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
|
//
|
||||||
|
// @public (undocumented)
|
||||||
|
export interface ISearchSessionService<T = unknown> {
|
||||||
|
// Warning: (ae-forgotten-export) The symbol "IScopedSearchSessionsClient" needs to be exported by the entry point index.d.ts
|
||||||
|
//
|
||||||
|
// (undocumented)
|
||||||
|
asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient<T>;
|
||||||
|
}
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "ISearchSetup" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "ISearchSetup" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
|
@ -956,8 +951,10 @@ export interface ISearchStart<SearchStrategyRequest extends IKibanaSearchRequest
|
||||||
//
|
//
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
aggs: AggsStart;
|
aggs: AggsStart;
|
||||||
|
// Warning: (ae-forgotten-export) The symbol "IScopedSearchClient" needs to be exported by the entry point index.d.ts
|
||||||
|
//
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
asScoped: (request: KibanaRequest_2) => ISearchClient;
|
asScoped: (request: KibanaRequest_2) => IScopedSearchClient;
|
||||||
getSearchStrategy: (name?: string) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse>;
|
getSearchStrategy: (name?: string) => ISearchStrategy<SearchStrategyRequest, SearchStrategyResponse>;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
searchSource: {
|
searchSource: {
|
||||||
|
@ -977,14 +974,6 @@ export interface ISearchStrategy<SearchStrategyRequest extends IKibanaSearchRequ
|
||||||
search: (request: SearchStrategyRequest, options: ISearchOptions, deps: SearchStrategyDependencies) => Observable<SearchStrategyResponse>;
|
search: (request: SearchStrategyRequest, options: ISearchOptions, deps: SearchStrategyDependencies) => Observable<SearchStrategyResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "ISessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
|
||||||
//
|
|
||||||
// @public (undocumented)
|
|
||||||
export interface ISessionService {
|
|
||||||
// (undocumented)
|
|
||||||
asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSessionService;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export enum KBN_FIELD_TYPES {
|
export enum KBN_FIELD_TYPES {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -1246,6 +1235,28 @@ export const search: {
|
||||||
tabifyGetColumns: typeof tabifyGetColumns;
|
tabifyGetColumns: typeof tabifyGetColumns;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Warning: (ae-missing-release-tag) "SearchRequestHandlerContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
|
//
|
||||||
|
// @public (undocumented)
|
||||||
|
export type SearchRequestHandlerContext = IScopedSearchClient;
|
||||||
|
|
||||||
|
// @internal
|
||||||
|
export class SearchSessionService implements ISearchSessionService {
|
||||||
|
constructor();
|
||||||
|
// (undocumented)
|
||||||
|
asScopedProvider(): () => {
|
||||||
|
getId: () => never;
|
||||||
|
trackId: () => Promise<void>;
|
||||||
|
getSearchIdMapping: () => Promise<Map<string, string>>;
|
||||||
|
save: () => Promise<never>;
|
||||||
|
get: () => Promise<never>;
|
||||||
|
find: () => Promise<never>;
|
||||||
|
update: () => Promise<never>;
|
||||||
|
extend: () => Promise<never>;
|
||||||
|
cancel: () => Promise<never>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "SearchStrategyDependencies" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "SearchStrategyDependencies" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
|
@ -1255,6 +1266,8 @@ export interface SearchStrategyDependencies {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
savedObjectsClient: SavedObjectsClientContract;
|
savedObjectsClient: SavedObjectsClientContract;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
searchSessionsClient: IScopedSearchSessionsClient;
|
||||||
|
// (undocumented)
|
||||||
uiSettingsClient: IUiSettingsClient;
|
uiSettingsClient: IUiSettingsClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1276,19 +1289,6 @@ export function searchUsageObserver(logger: Logger_2, usage?: SearchUsage): {
|
||||||
error(): void;
|
error(): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "SessionService" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
|
||||||
//
|
|
||||||
// @public
|
|
||||||
export class SessionService implements ISessionService {
|
|
||||||
constructor();
|
|
||||||
// (undocumented)
|
|
||||||
asScopedProvider(core: CoreStart): (request: KibanaRequest) => {
|
|
||||||
search: <Request_1 extends IKibanaSearchRequest<any>, Response_1 extends IKibanaSearchResponse<any>>(strategy: ISearchStrategy<Request_1, Response_1>, request: Request_1, options: import("../../../common").ISearchOptions, deps: import("../types").SearchStrategyDependencies) => import("rxjs").Observable<Response_1>;
|
|
||||||
};
|
|
||||||
// (undocumented)
|
|
||||||
search<Request extends IKibanaSearchRequest, Response extends IKibanaSearchResponse>(strategy: ISearchStrategy<Request, Response>, ...args: Parameters<ISearchStrategy<Request, Response>['search']>): import("rxjs").Observable<Response>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @internal
|
// @internal
|
||||||
export const shimAbortSignal: <T>(promise: TransportRequestPromise<T>, signal?: AbortSignal | undefined) => TransportRequestPromise<T>;
|
export const shimAbortSignal: <T>(promise: TransportRequestPromise<T>, signal?: AbortSignal | undefined) => TransportRequestPromise<T>;
|
||||||
|
|
||||||
|
@ -1414,23 +1414,23 @@ export function usageProvider(core: CoreSetup_2): SearchUsage;
|
||||||
// src/plugins/data/server/index.ts:100:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:100:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:126:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:126:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:126:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:126:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:240:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:239:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:240:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:239:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:240:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:239:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:240:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:239:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:242:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:241:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:243:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:242:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:252:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:251:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:253:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:252:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:254:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:253:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:258:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:257:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:259:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:258:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:263:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:262:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:266:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:265:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index.ts:267:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index.ts:266:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/index_patterns/index_patterns_service.ts:59:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/index_patterns/index_patterns_service.ts:59:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/plugin.ts:79:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/plugin.ts:79:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/server/search/types.ts:103:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/server/search/types.ts:113:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts
|
||||||
|
|
||||||
// (No @packageDocumentation comment for this package)
|
// (No @packageDocumentation comment for this package)
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,8 @@ import { first } from 'rxjs/operators';
|
||||||
import { TypeOf, schema } from '@kbn/config-schema';
|
import { TypeOf, schema } from '@kbn/config-schema';
|
||||||
import { RecursiveReadonly } from '@kbn/utility-types';
|
import { RecursiveReadonly } from '@kbn/utility-types';
|
||||||
import { deepFreeze } from '@kbn/std';
|
import { deepFreeze } from '@kbn/std';
|
||||||
import type { RequestHandlerContext } from 'src/core/server';
|
|
||||||
|
|
||||||
import type {
|
import type { PluginStart, DataRequestHandlerContext } from '../../../../src/plugins/data/server';
|
||||||
PluginStart,
|
|
||||||
DataApiRequestHandlerContext,
|
|
||||||
} from '../../../../src/plugins/data/server';
|
|
||||||
import { CoreSetup, PluginInitializerContext } from '../../../../src/core/server';
|
import { CoreSetup, PluginInitializerContext } from '../../../../src/core/server';
|
||||||
import { configSchema } from '../config';
|
import { configSchema } from '../config';
|
||||||
import loadFunctions from './lib/load_functions';
|
import loadFunctions from './lib/load_functions';
|
||||||
|
@ -73,9 +69,7 @@ export class Plugin {
|
||||||
|
|
||||||
const logger = this.initializerContext.logger.get('timelion');
|
const logger = this.initializerContext.logger.get('timelion');
|
||||||
|
|
||||||
const router = core.http.createRouter<
|
const router = core.http.createRouter<DataRequestHandlerContext>();
|
||||||
RequestHandlerContext & { search: DataApiRequestHandlerContext }
|
|
||||||
>();
|
|
||||||
|
|
||||||
const deps = {
|
const deps = {
|
||||||
configManager,
|
configManager,
|
||||||
|
|
|
@ -7,12 +7,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { IRouter, RequestHandlerContext } from 'kibana/server';
|
import { IRouter } from 'kibana/server';
|
||||||
import type { DataApiRequestHandlerContext } from '../../../data/server';
|
import type { DataRequestHandlerContext } from '../../../data/server';
|
||||||
|
|
||||||
export function validateEsRoute(
|
export function validateEsRoute(router: IRouter<DataRequestHandlerContext>) {
|
||||||
router: IRouter<RequestHandlerContext & { search: DataApiRequestHandlerContext }>
|
|
||||||
) {
|
|
||||||
router.get(
|
router.get(
|
||||||
{
|
{
|
||||||
path: '/api/timelion/validate/es',
|
path: '/api/timelion/validate/es',
|
||||||
|
|
|
@ -6,11 +6,8 @@
|
||||||
* Public License, v 1.
|
* Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { IRouter, RequestHandlerContext } from 'src/core/server';
|
import type { IRouter } from 'src/core/server';
|
||||||
import type { DataApiRequestHandlerContext } from '../../data/server';
|
import type { DataRequestHandlerContext } from '../../data/server';
|
||||||
|
|
||||||
export interface VisTypeTimeseriesRequestHandlerContext extends RequestHandlerContext {
|
|
||||||
search: DataApiRequestHandlerContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export type VisTypeTimeseriesRequestHandlerContext = DataRequestHandlerContext;
|
||||||
export type VisTypeTimeseriesRouter = IRouter<VisTypeTimeseriesRequestHandlerContext>;
|
export type VisTypeTimeseriesRouter = IRouter<VisTypeTimeseriesRequestHandlerContext>;
|
||||||
|
|
|
@ -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;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { DataRequestHandlerContext } from '../../../../../src/plugins/data/server';
|
|
||||||
import { coreMock } from '../../../../../src/core/server/mocks';
|
|
||||||
|
|
||||||
export function createSearchRequestHandlerContext() {
|
|
||||||
return ({
|
|
||||||
core: coreMock.createRequestHandlerContext(),
|
|
||||||
search: {
|
|
||||||
search: jest.fn(),
|
|
||||||
cancel: jest.fn(),
|
|
||||||
session: {
|
|
||||||
search: jest.fn(),
|
|
||||||
save: jest.fn(),
|
|
||||||
get: jest.fn(),
|
|
||||||
find: jest.fn(),
|
|
||||||
delete: jest.fn(),
|
|
||||||
update: jest.fn(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as unknown) as jest.Mocked<DataRequestHandlerContext>;
|
|
||||||
}
|
|
|
@ -12,7 +12,7 @@ import type {
|
||||||
PluginStart as DataPluginStart,
|
PluginStart as DataPluginStart,
|
||||||
DataRequestHandlerContext,
|
DataRequestHandlerContext,
|
||||||
} from '../../../../../src/plugins/data/server';
|
} from '../../../../../src/plugins/data/server';
|
||||||
import { createSearchRequestHandlerContext } from './mocks';
|
import { dataPluginMock } from '../../../../../src/plugins/data/server/mocks';
|
||||||
import { registerSessionRoutes } from './session';
|
import { registerSessionRoutes } from './session';
|
||||||
|
|
||||||
describe('registerSessionRoutes', () => {
|
describe('registerSessionRoutes', () => {
|
||||||
|
@ -23,11 +23,11 @@ describe('registerSessionRoutes', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockCoreSetup = coreMock.createSetup();
|
mockCoreSetup = coreMock.createSetup();
|
||||||
mockLogger = coreMock.createPluginInitializerContext().logger.get();
|
mockLogger = coreMock.createPluginInitializerContext().logger.get();
|
||||||
mockContext = createSearchRequestHandlerContext();
|
mockContext = dataPluginMock.createRequestHandlerContext();
|
||||||
registerSessionRoutes(mockCoreSetup.http.createRouter(), mockLogger);
|
registerSessionRoutes(mockCoreSetup.http.createRouter(), mockLogger);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('save calls session.save with sessionId and attributes', async () => {
|
it('save calls saveSession with sessionId and attributes', async () => {
|
||||||
const sessionId = 'd7170a35-7e2c-48d6-8dec-9a056721b489';
|
const sessionId = 'd7170a35-7e2c-48d6-8dec-9a056721b489';
|
||||||
const name = 'my saved background search session';
|
const name = 'my saved background search session';
|
||||||
const body = { sessionId, name };
|
const body = { sessionId, name };
|
||||||
|
@ -40,10 +40,10 @@ describe('registerSessionRoutes', () => {
|
||||||
|
|
||||||
saveHandler(mockContext, mockRequest, mockResponse);
|
saveHandler(mockContext, mockRequest, mockResponse);
|
||||||
|
|
||||||
expect(mockContext.search!.session.save).toHaveBeenCalledWith(sessionId, { name });
|
expect(mockContext.search!.saveSession).toHaveBeenCalledWith(sessionId, { name });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('get calls session.get with sessionId', async () => {
|
it('get calls getSession with sessionId', async () => {
|
||||||
const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489';
|
const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489';
|
||||||
const params = { id };
|
const params = { id };
|
||||||
|
|
||||||
|
@ -55,10 +55,10 @@ describe('registerSessionRoutes', () => {
|
||||||
|
|
||||||
getHandler(mockContext, mockRequest, mockResponse);
|
getHandler(mockContext, mockRequest, mockResponse);
|
||||||
|
|
||||||
expect(mockContext.search!.session.get).toHaveBeenCalledWith(id);
|
expect(mockContext.search!.getSession).toHaveBeenCalledWith(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('find calls session.find with options', async () => {
|
it('find calls findSession with options', async () => {
|
||||||
const page = 1;
|
const page = 1;
|
||||||
const perPage = 5;
|
const perPage = 5;
|
||||||
const sortField = 'my_field';
|
const sortField = 'my_field';
|
||||||
|
@ -74,10 +74,10 @@ describe('registerSessionRoutes', () => {
|
||||||
|
|
||||||
findHandler(mockContext, mockRequest, mockResponse);
|
findHandler(mockContext, mockRequest, mockResponse);
|
||||||
|
|
||||||
expect(mockContext.search!.session.find).toHaveBeenCalledWith(body);
|
expect(mockContext.search!.findSessions).toHaveBeenCalledWith(body);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('update calls session.update with id and attributes', async () => {
|
it('update calls updateSession with id and attributes', async () => {
|
||||||
const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489';
|
const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489';
|
||||||
const name = 'my saved background search session';
|
const name = 'my saved background search session';
|
||||||
const expires = new Date().toISOString();
|
const expires = new Date().toISOString();
|
||||||
|
@ -92,10 +92,10 @@ describe('registerSessionRoutes', () => {
|
||||||
|
|
||||||
updateHandler(mockContext, mockRequest, mockResponse);
|
updateHandler(mockContext, mockRequest, mockResponse);
|
||||||
|
|
||||||
expect(mockContext.search!.session.update).toHaveBeenCalledWith(id, body);
|
expect(mockContext.search!.updateSession).toHaveBeenCalledWith(id, body);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('delete calls session.delete with id', async () => {
|
it('delete calls cancelSession with id', async () => {
|
||||||
const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489';
|
const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489';
|
||||||
const params = { id };
|
const params = { id };
|
||||||
|
|
||||||
|
@ -107,6 +107,23 @@ describe('registerSessionRoutes', () => {
|
||||||
|
|
||||||
deleteHandler(mockContext, mockRequest, mockResponse);
|
deleteHandler(mockContext, mockRequest, mockResponse);
|
||||||
|
|
||||||
expect(mockContext.search!.session.delete).toHaveBeenCalledWith(id);
|
expect(mockContext.search!.cancelSession).toHaveBeenCalledWith(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('extend calls extendSession with id', async () => {
|
||||||
|
const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489';
|
||||||
|
const expires = new Date().toISOString();
|
||||||
|
const params = { id };
|
||||||
|
const body = { expires };
|
||||||
|
|
||||||
|
const mockRequest = httpServerMock.createKibanaRequest({ params, body });
|
||||||
|
const mockResponse = httpServerMock.createResponseFactory();
|
||||||
|
|
||||||
|
const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value;
|
||||||
|
const [, , [, extendHandler]] = mockRouter.post.mock.calls;
|
||||||
|
|
||||||
|
extendHandler(mockContext, mockRequest, mockResponse);
|
||||||
|
|
||||||
|
expect(mockContext.search.extendSession).toHaveBeenCalledWith(id, new Date(expires));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -37,7 +37,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger:
|
||||||
} = request.body;
|
} = request.body;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await context.search!.session.save(sessionId, {
|
const response = await context.search!.saveSession(sessionId, {
|
||||||
name,
|
name,
|
||||||
appId,
|
appId,
|
||||||
expires,
|
expires,
|
||||||
|
@ -68,7 +68,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger:
|
||||||
async (context, request, res) => {
|
async (context, request, res) => {
|
||||||
const { id } = request.params;
|
const { id } = request.params;
|
||||||
try {
|
try {
|
||||||
const response = await context.search!.session.get(id);
|
const response = await context.search!.getSession(id);
|
||||||
|
|
||||||
return res.ok({
|
return res.ok({
|
||||||
body: response,
|
body: response,
|
||||||
|
@ -97,7 +97,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger:
|
||||||
async (context, request, res) => {
|
async (context, request, res) => {
|
||||||
const { page, perPage, sortField, sortOrder, filter } = request.body;
|
const { page, perPage, sortField, sortOrder, filter } = request.body;
|
||||||
try {
|
try {
|
||||||
const response = await context.search!.session.find({
|
const response = await context.search!.findSessions({
|
||||||
page,
|
page,
|
||||||
perPage,
|
perPage,
|
||||||
sortField,
|
sortField,
|
||||||
|
@ -127,7 +127,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger:
|
||||||
async (context, request, res) => {
|
async (context, request, res) => {
|
||||||
const { id } = request.params;
|
const { id } = request.params;
|
||||||
try {
|
try {
|
||||||
await context.search!.session.delete(id);
|
await context.search!.cancelSession(id);
|
||||||
|
|
||||||
return res.ok();
|
return res.ok();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -155,7 +155,7 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger:
|
||||||
const { id } = request.params;
|
const { id } = request.params;
|
||||||
const { name, expires } = request.body;
|
const { name, expires } = request.body;
|
||||||
try {
|
try {
|
||||||
const response = await context.search!.session.update(id, { name, expires });
|
const response = await context.search!.updateSession(id, { name, expires });
|
||||||
|
|
||||||
return res.ok({
|
return res.ok({
|
||||||
body: response,
|
body: response,
|
||||||
|
@ -166,4 +166,33 @@ export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
{
|
||||||
|
path: '/internal/session/{id}/_extend',
|
||||||
|
validate: {
|
||||||
|
params: schema.object({
|
||||||
|
id: schema.string(),
|
||||||
|
}),
|
||||||
|
body: schema.object({
|
||||||
|
expires: schema.string(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (context, request, res) => {
|
||||||
|
const { id } = request.params;
|
||||||
|
const { expires } = request.body;
|
||||||
|
try {
|
||||||
|
const response = await context.search!.extendSession(id, new Date(expires));
|
||||||
|
|
||||||
|
return res.ok({
|
||||||
|
body: response,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
const err = e.output?.payload || e;
|
||||||
|
logger.error(err);
|
||||||
|
return reportServerError(res, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,20 +4,18 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BehaviorSubject, of } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
import type { SavedObject, SavedObjectsClientContract } from 'kibana/server';
|
import type { SavedObject, SavedObjectsClientContract } from 'kibana/server';
|
||||||
import type { SearchStrategyDependencies } from '../../../../../../src/plugins/data/server';
|
|
||||||
import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks';
|
import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks';
|
||||||
import { SearchSessionStatus } from '../../../common';
|
import { SearchSessionStatus } from '../../../common';
|
||||||
import { SEARCH_SESSION_TYPE } from '../../saved_objects';
|
import { SEARCH_SESSION_TYPE } from '../../saved_objects';
|
||||||
import { SearchSessionDependencies, SearchSessionService, SessionInfo } from './session_service';
|
import { SearchSessionService, SessionInfo } from './session_service';
|
||||||
import { createRequestHash } from './utils';
|
import { createRequestHash } from './utils';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { coreMock } from 'src/core/server/mocks';
|
import { coreMock } from 'src/core/server/mocks';
|
||||||
import { ConfigSchema } from '../../../config';
|
import { ConfigSchema } from '../../../config';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { taskManagerMock } from '../../../../task_manager/server/mocks';
|
import { taskManagerMock } from '../../../../task_manager/server/mocks';
|
||||||
import { SearchStatus } from './types';
|
|
||||||
|
|
||||||
const INMEM_TRACKING_INTERVAL = 10000;
|
const INMEM_TRACKING_INTERVAL = 10000;
|
||||||
const MAX_UPDATE_RETRIES = 3;
|
const MAX_UPDATE_RETRIES = 3;
|
||||||
|
@ -139,13 +137,13 @@ describe('SearchSessionService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('search throws if `name` is not provided', () => {
|
it('search throws if `name` is not provided', () => {
|
||||||
expect(() => service.save(sessionId, {}, { savedObjectsClient })).rejects.toMatchInlineSnapshot(
|
expect(() => service.save({ savedObjectsClient }, sessionId, {})).rejects.toMatchInlineSnapshot(
|
||||||
`[Error: Name is required]`
|
`[Error: Name is required]`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('save throws if `name` is not provided', () => {
|
it('save throws if `name` is not provided', () => {
|
||||||
expect(() => service.save(sessionId, {}, { savedObjectsClient })).rejects.toMatchInlineSnapshot(
|
expect(() => service.save({ savedObjectsClient }, sessionId, {})).rejects.toMatchInlineSnapshot(
|
||||||
`[Error: Name is required]`
|
`[Error: Name is required]`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -153,7 +151,7 @@ describe('SearchSessionService', () => {
|
||||||
it('get calls saved objects client', async () => {
|
it('get calls saved objects client', async () => {
|
||||||
savedObjectsClient.get.mockResolvedValue(mockSavedObject);
|
savedObjectsClient.get.mockResolvedValue(mockSavedObject);
|
||||||
|
|
||||||
const response = await service.get(sessionId, { savedObjectsClient });
|
const response = await service.get({ savedObjectsClient }, sessionId);
|
||||||
|
|
||||||
expect(response).toBe(mockSavedObject);
|
expect(response).toBe(mockSavedObject);
|
||||||
expect(savedObjectsClient.get).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId);
|
expect(savedObjectsClient.get).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId);
|
||||||
|
@ -173,7 +171,7 @@ describe('SearchSessionService', () => {
|
||||||
savedObjectsClient.find.mockResolvedValue(mockResponse);
|
savedObjectsClient.find.mockResolvedValue(mockResponse);
|
||||||
|
|
||||||
const options = { page: 0, perPage: 5 };
|
const options = { page: 0, perPage: 5 };
|
||||||
const response = await service.find(options, { savedObjectsClient });
|
const response = await service.find({ savedObjectsClient }, options);
|
||||||
|
|
||||||
expect(response).toBe(mockResponse);
|
expect(response).toBe(mockResponse);
|
||||||
expect(savedObjectsClient.find).toHaveBeenCalledWith({
|
expect(savedObjectsClient.find).toHaveBeenCalledWith({
|
||||||
|
@ -190,7 +188,7 @@ describe('SearchSessionService', () => {
|
||||||
savedObjectsClient.update.mockResolvedValue(mockUpdateSavedObject);
|
savedObjectsClient.update.mockResolvedValue(mockUpdateSavedObject);
|
||||||
|
|
||||||
const attributes = { name: 'new_name' };
|
const attributes = { name: 'new_name' };
|
||||||
const response = await service.update(sessionId, attributes, { savedObjectsClient });
|
const response = await service.update({ savedObjectsClient }, sessionId, attributes);
|
||||||
|
|
||||||
expect(response).toBe(mockUpdateSavedObject);
|
expect(response).toBe(mockUpdateSavedObject);
|
||||||
expect(savedObjectsClient.update).toHaveBeenCalledWith(
|
expect(savedObjectsClient.update).toHaveBeenCalledWith(
|
||||||
|
@ -200,93 +198,11 @@ describe('SearchSessionService', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('delete calls saved objects client', async () => {
|
it('cancel updates object status', async () => {
|
||||||
savedObjectsClient.delete.mockResolvedValue({});
|
await service.cancel({ savedObjectsClient }, sessionId);
|
||||||
|
|
||||||
const response = await service.delete(sessionId, { savedObjectsClient });
|
expect(savedObjectsClient.update).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId, {
|
||||||
|
status: SearchSessionStatus.CANCELLED,
|
||||||
expect(response).toEqual({});
|
|
||||||
expect(savedObjectsClient.delete).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('search', () => {
|
|
||||||
const mockSearch = jest.fn().mockReturnValue(of({}));
|
|
||||||
const mockStrategy = { search: mockSearch };
|
|
||||||
const mockSearchDeps = {} as SearchStrategyDependencies;
|
|
||||||
const mockDeps = {} as SearchSessionDependencies;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockSearch.mockClear();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('searches using the original request if not restoring', async () => {
|
|
||||||
const searchRequest = { params: {} };
|
|
||||||
const options = { sessionId, isStored: false, isRestore: false };
|
|
||||||
|
|
||||||
await service
|
|
||||||
.search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps)
|
|
||||||
.toPromise();
|
|
||||||
|
|
||||||
expect(mockSearch).toBeCalledWith(searchRequest, options, mockSearchDeps);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('searches using the original request if `id` is provided', async () => {
|
|
||||||
const searchId = 'FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0';
|
|
||||||
const searchRequest = { id: searchId, params: {} };
|
|
||||||
const options = { sessionId, isStored: true, isRestore: true };
|
|
||||||
|
|
||||||
await service
|
|
||||||
.search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps)
|
|
||||||
.toPromise();
|
|
||||||
|
|
||||||
expect(mockSearch).toBeCalledWith(searchRequest, options, mockSearchDeps);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('searches by looking up an `id` if restoring and `id` is not provided', async () => {
|
|
||||||
const searchRequest = { params: {} };
|
|
||||||
const options = { sessionId, isStored: true, isRestore: true };
|
|
||||||
const spyGetId = jest.spyOn(service, 'getId').mockResolvedValueOnce('my_id');
|
|
||||||
|
|
||||||
await service
|
|
||||||
.search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps)
|
|
||||||
.toPromise();
|
|
||||||
|
|
||||||
expect(mockSearch).toBeCalledWith({ ...searchRequest, id: 'my_id' }, options, mockSearchDeps);
|
|
||||||
|
|
||||||
spyGetId.mockRestore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls `trackId` once if the response contains an `id` and not restoring', async () => {
|
|
||||||
const searchRequest = { params: {} };
|
|
||||||
const options = { sessionId, isStored: false, isRestore: false };
|
|
||||||
const spyTrackId = jest.spyOn(service, 'trackId').mockResolvedValue();
|
|
||||||
mockSearch.mockReturnValueOnce(of({ id: 'my_id' }, { id: 'my_id' }));
|
|
||||||
|
|
||||||
await service
|
|
||||||
.search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps)
|
|
||||||
.toPromise();
|
|
||||||
|
|
||||||
expect(spyTrackId).toBeCalledTimes(1);
|
|
||||||
expect(spyTrackId).toBeCalledWith(searchRequest, 'my_id', options, {});
|
|
||||||
|
|
||||||
spyTrackId.mockRestore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not call `trackId` if restoring', async () => {
|
|
||||||
const searchRequest = { params: {} };
|
|
||||||
const options = { sessionId, isStored: true, isRestore: true };
|
|
||||||
const spyGetId = jest.spyOn(service, 'getId').mockResolvedValueOnce('my_id');
|
|
||||||
const spyTrackId = jest.spyOn(service, 'trackId').mockResolvedValue();
|
|
||||||
mockSearch.mockReturnValueOnce(of({ id: 'my_id' }));
|
|
||||||
|
|
||||||
await service
|
|
||||||
.search(mockStrategy, searchRequest, options, mockSearchDeps, mockDeps)
|
|
||||||
.toPromise();
|
|
||||||
|
|
||||||
expect(spyTrackId).not.toBeCalled();
|
|
||||||
|
|
||||||
spyGetId.mockRestore();
|
|
||||||
spyTrackId.mockRestore();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -309,20 +225,21 @@ describe('SearchSessionService', () => {
|
||||||
get: () => mockIdMapping,
|
get: () => mockIdMapping,
|
||||||
});
|
});
|
||||||
|
|
||||||
await service.trackId(
|
await service.trackId({ savedObjectsClient }, searchRequest, searchId, {
|
||||||
searchRequest,
|
sessionId,
|
||||||
searchId,
|
isStored,
|
||||||
{ sessionId, isStored, strategy: MOCK_STRATEGY },
|
strategy: MOCK_STRATEGY,
|
||||||
{ savedObjectsClient }
|
});
|
||||||
);
|
|
||||||
|
|
||||||
expect(savedObjectsClient.update).not.toHaveBeenCalled();
|
expect(savedObjectsClient.update).not.toHaveBeenCalled();
|
||||||
|
|
||||||
await service.save(
|
await service.save({ savedObjectsClient }, sessionId, {
|
||||||
sessionId,
|
name,
|
||||||
{ name, created, expires, appId, urlGeneratorId },
|
created,
|
||||||
{ savedObjectsClient }
|
expires,
|
||||||
);
|
appId,
|
||||||
|
urlGeneratorId,
|
||||||
|
});
|
||||||
|
|
||||||
expect(savedObjectsClient.create).toHaveBeenCalledWith(
|
expect(savedObjectsClient.create).toHaveBeenCalledWith(
|
||||||
SEARCH_SESSION_TYPE,
|
SEARCH_SESSION_TYPE,
|
||||||
|
@ -346,30 +263,6 @@ describe('SearchSessionService', () => {
|
||||||
expect(setParams.ids.get(requestHash).strategy).toBe(MOCK_STRATEGY);
|
expect(setParams.ids.get(requestHash).strategy).toBe(MOCK_STRATEGY);
|
||||||
expect(setSessionId).toBe(sessionId);
|
expect(setSessionId).toBe(sessionId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updates saved object when `isStored` is `true`', async () => {
|
|
||||||
const searchRequest = { params: {} };
|
|
||||||
const requestHash = createRequestHash(searchRequest.params);
|
|
||||||
const searchId = 'FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0';
|
|
||||||
const isStored = true;
|
|
||||||
|
|
||||||
await service.trackId(
|
|
||||||
searchRequest,
|
|
||||||
searchId,
|
|
||||||
{ sessionId, isStored, strategy: MOCK_STRATEGY },
|
|
||||||
{ savedObjectsClient }
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(savedObjectsClient.update).toHaveBeenCalledWith(SEARCH_SESSION_TYPE, sessionId, {
|
|
||||||
idMapping: {
|
|
||||||
[requestHash]: {
|
|
||||||
id: searchId,
|
|
||||||
strategy: MOCK_STRATEGY,
|
|
||||||
status: SearchStatus.IN_PROGRESS,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getId', () => {
|
describe('getId', () => {
|
||||||
|
@ -377,7 +270,7 @@ describe('SearchSessionService', () => {
|
||||||
const searchRequest = { params: {} };
|
const searchRequest = { params: {} };
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
service.getId(searchRequest, {}, { savedObjectsClient })
|
service.getId({ savedObjectsClient }, searchRequest, {})
|
||||||
).rejects.toMatchInlineSnapshot(`[Error: Session ID is required]`);
|
).rejects.toMatchInlineSnapshot(`[Error: Session ID is required]`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -385,7 +278,7 @@ describe('SearchSessionService', () => {
|
||||||
const searchRequest = { params: {} };
|
const searchRequest = { params: {} };
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
service.getId(searchRequest, { sessionId, isStored: false }, { savedObjectsClient })
|
service.getId({ savedObjectsClient }, searchRequest, { sessionId, isStored: false })
|
||||||
).rejects.toMatchInlineSnapshot(
|
).rejects.toMatchInlineSnapshot(
|
||||||
`[Error: Cannot get search ID from a session that is not stored]`
|
`[Error: Cannot get search ID from a session that is not stored]`
|
||||||
);
|
);
|
||||||
|
@ -395,11 +288,11 @@ describe('SearchSessionService', () => {
|
||||||
const searchRequest = { params: {} };
|
const searchRequest = { params: {} };
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
service.getId(
|
service.getId({ savedObjectsClient }, searchRequest, {
|
||||||
searchRequest,
|
sessionId,
|
||||||
{ sessionId, isStored: true, isRestore: false },
|
isStored: true,
|
||||||
{ savedObjectsClient }
|
isRestore: false,
|
||||||
)
|
})
|
||||||
).rejects.toMatchInlineSnapshot(
|
).rejects.toMatchInlineSnapshot(
|
||||||
`[Error: Get search ID is only supported when restoring a session]`
|
`[Error: Get search ID is only supported when restoring a session]`
|
||||||
);
|
);
|
||||||
|
@ -427,16 +320,47 @@ describe('SearchSessionService', () => {
|
||||||
};
|
};
|
||||||
savedObjectsClient.get.mockResolvedValue(mockSession);
|
savedObjectsClient.get.mockResolvedValue(mockSession);
|
||||||
|
|
||||||
const id = await service.getId(
|
const id = await service.getId({ savedObjectsClient }, searchRequest, {
|
||||||
searchRequest,
|
sessionId,
|
||||||
{ sessionId, isStored: true, isRestore: true },
|
isStored: true,
|
||||||
{ savedObjectsClient }
|
isRestore: true,
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(id).toBe(searchId);
|
expect(id).toBe(searchId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getSearchIdMapping', () => {
|
||||||
|
it('retrieves the search IDs and strategies from the saved object', async () => {
|
||||||
|
const mockSession = {
|
||||||
|
id: 'd7170a35-7e2c-48d6-8dec-9a056721b489',
|
||||||
|
type: SEARCH_SESSION_TYPE,
|
||||||
|
attributes: {
|
||||||
|
name: 'my_name',
|
||||||
|
appId: 'my_app_id',
|
||||||
|
urlGeneratorId: 'my_url_generator_id',
|
||||||
|
idMapping: {
|
||||||
|
foo: {
|
||||||
|
id: 'FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0',
|
||||||
|
strategy: MOCK_STRATEGY,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
references: [],
|
||||||
|
};
|
||||||
|
savedObjectsClient.get.mockResolvedValue(mockSession);
|
||||||
|
const searchIdMapping = await service.getSearchIdMapping(
|
||||||
|
{ savedObjectsClient },
|
||||||
|
mockSession.id
|
||||||
|
);
|
||||||
|
expect(searchIdMapping).toMatchInlineSnapshot(`
|
||||||
|
Map {
|
||||||
|
"FnpFYlBpeXdCUTMyZXhCLTc1TWFKX0EbdDFDTzJzTE1Sck9PVTBIcW1iU05CZzo4MDA0" => "ese",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Monitor', () => {
|
describe('Monitor', () => {
|
||||||
it('schedules the next iteration', async () => {
|
it('schedules the next iteration', async () => {
|
||||||
const findSpy = jest.fn().mockResolvedValue({ saved_objects: [] });
|
const findSpy = jest.fn().mockResolvedValue({ saved_objects: [] });
|
||||||
|
|
|
@ -5,39 +5,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import moment, { Moment } from 'moment';
|
import moment, { Moment } from 'moment';
|
||||||
import { from, Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { first, switchMap } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
|
CoreSetup,
|
||||||
CoreStart,
|
CoreStart,
|
||||||
KibanaRequest,
|
KibanaRequest,
|
||||||
SavedObjectsClient,
|
|
||||||
SavedObjectsClientContract,
|
|
||||||
Logger,
|
Logger,
|
||||||
SavedObject,
|
SavedObject,
|
||||||
CoreSetup,
|
|
||||||
SavedObjectsBulkUpdateObject,
|
SavedObjectsBulkUpdateObject,
|
||||||
|
SavedObjectsClient,
|
||||||
|
SavedObjectsClientContract,
|
||||||
SavedObjectsFindOptions,
|
SavedObjectsFindOptions,
|
||||||
} from '../../../../../../src/core/server';
|
} from '../../../../../../src/core/server';
|
||||||
import {
|
import {
|
||||||
IKibanaSearchRequest,
|
IKibanaSearchRequest,
|
||||||
IKibanaSearchResponse,
|
|
||||||
ISearchOptions,
|
ISearchOptions,
|
||||||
KueryNode,
|
KueryNode,
|
||||||
nodeBuilder,
|
nodeBuilder,
|
||||||
tapFirst,
|
|
||||||
} from '../../../../../../src/plugins/data/common';
|
} from '../../../../../../src/plugins/data/common';
|
||||||
import {
|
import { ISearchSessionService } from '../../../../../../src/plugins/data/server';
|
||||||
ISearchStrategy,
|
|
||||||
ISessionService,
|
|
||||||
SearchStrategyDependencies,
|
|
||||||
} from '../../../../../../src/plugins/data/server';
|
|
||||||
import {
|
import {
|
||||||
TaskManagerSetupContract,
|
TaskManagerSetupContract,
|
||||||
TaskManagerStartContract,
|
TaskManagerStartContract,
|
||||||
} from '../../../../task_manager/server';
|
} from '../../../../task_manager/server';
|
||||||
import {
|
import {
|
||||||
SearchSessionSavedObjectAttributes,
|
|
||||||
SearchSessionRequestInfo,
|
SearchSessionRequestInfo,
|
||||||
|
SearchSessionSavedObjectAttributes,
|
||||||
SearchSessionStatus,
|
SearchSessionStatus,
|
||||||
} from '../../../common';
|
} from '../../../common';
|
||||||
import { SEARCH_SESSION_TYPE } from '../../saved_objects';
|
import { SEARCH_SESSION_TYPE } from '../../saved_objects';
|
||||||
|
@ -66,7 +60,11 @@ interface StartDependencies {
|
||||||
|
|
||||||
type SearchSessionsConfig = ConfigSchema['search']['sessions'];
|
type SearchSessionsConfig = ConfigSchema['search']['sessions'];
|
||||||
|
|
||||||
export class SearchSessionService implements ISessionService {
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export class SearchSessionService
|
||||||
|
implements ISearchSessionService<SearchSessionSavedObjectAttributes> {
|
||||||
/**
|
/**
|
||||||
* Map of sessionId to { [requestHash]: searchId }
|
* Map of sessionId to { [requestHash]: searchId }
|
||||||
* @private
|
* @private
|
||||||
|
@ -228,33 +226,9 @@ export class SearchSessionService implements ISessionService {
|
||||||
return updateResults.saved_objects;
|
return updateResults.saved_objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
public search<Request extends IKibanaSearchRequest, Response extends IKibanaSearchResponse>(
|
|
||||||
strategy: ISearchStrategy<Request, Response>,
|
|
||||||
searchRequest: Request,
|
|
||||||
options: ISearchOptions,
|
|
||||||
searchDeps: SearchStrategyDependencies,
|
|
||||||
deps: SearchSessionDependencies
|
|
||||||
): Observable<Response> {
|
|
||||||
// If this is a restored background search session, look up the ID using the provided sessionId
|
|
||||||
const getSearchRequest = async () =>
|
|
||||||
!options.isRestore || searchRequest.id
|
|
||||||
? searchRequest
|
|
||||||
: {
|
|
||||||
...searchRequest,
|
|
||||||
id: await this.getId(searchRequest, options, deps),
|
|
||||||
};
|
|
||||||
|
|
||||||
return from(getSearchRequest()).pipe(
|
|
||||||
switchMap((request) => strategy.search(request, options, searchDeps)),
|
|
||||||
tapFirst((response) => {
|
|
||||||
if (searchRequest.id || !options.sessionId || !response.id || options.isRestore) return;
|
|
||||||
this.trackId(searchRequest, response.id, options, deps);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Generate the `userId` from the realm type/realm name/username
|
// TODO: Generate the `userId` from the realm type/realm name/username
|
||||||
public save = async (
|
public save = async (
|
||||||
|
{ savedObjectsClient }: SearchSessionDependencies,
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
|
@ -265,8 +239,7 @@ export class SearchSessionService implements ISessionService {
|
||||||
urlGeneratorId,
|
urlGeneratorId,
|
||||||
initialState = {},
|
initialState = {},
|
||||||
restoreState = {},
|
restoreState = {},
|
||||||
}: Partial<SearchSessionSavedObjectAttributes>,
|
}: Partial<SearchSessionSavedObjectAttributes>
|
||||||
{ savedObjectsClient }: SearchSessionDependencies
|
|
||||||
) => {
|
) => {
|
||||||
if (!name) throw new Error('Name is required');
|
if (!name) throw new Error('Name is required');
|
||||||
if (!appId) throw new Error('AppId is required');
|
if (!appId) throw new Error('AppId is required');
|
||||||
|
@ -296,7 +269,7 @@ export class SearchSessionService implements ISessionService {
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Throw an error if this session doesn't belong to this user
|
// TODO: Throw an error if this session doesn't belong to this user
|
||||||
public get = (sessionId: string, { savedObjectsClient }: SearchSessionDependencies) => {
|
public get = ({ savedObjectsClient }: SearchSessionDependencies, sessionId: string) => {
|
||||||
this.logger.debug(`get | ${sessionId}`);
|
this.logger.debug(`get | ${sessionId}`);
|
||||||
return savedObjectsClient.get<SearchSessionSavedObjectAttributes>(
|
return savedObjectsClient.get<SearchSessionSavedObjectAttributes>(
|
||||||
SEARCH_SESSION_TYPE,
|
SEARCH_SESSION_TYPE,
|
||||||
|
@ -306,8 +279,8 @@ export class SearchSessionService implements ISessionService {
|
||||||
|
|
||||||
// TODO: Throw an error if this session doesn't belong to this user
|
// TODO: Throw an error if this session doesn't belong to this user
|
||||||
public find = (
|
public find = (
|
||||||
options: Omit<SavedObjectsFindOptions, 'type'>,
|
{ savedObjectsClient }: SearchSessionDependencies,
|
||||||
{ savedObjectsClient }: SearchSessionDependencies
|
options: Omit<SavedObjectsFindOptions, 'type'>
|
||||||
) => {
|
) => {
|
||||||
return savedObjectsClient.find<SearchSessionSavedObjectAttributes>({
|
return savedObjectsClient.find<SearchSessionSavedObjectAttributes>({
|
||||||
...options,
|
...options,
|
||||||
|
@ -317,9 +290,9 @@ export class SearchSessionService implements ISessionService {
|
||||||
|
|
||||||
// TODO: Throw an error if this session doesn't belong to this user
|
// TODO: Throw an error if this session doesn't belong to this user
|
||||||
public update = (
|
public update = (
|
||||||
|
{ savedObjectsClient }: SearchSessionDependencies,
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
attributes: Partial<SearchSessionSavedObjectAttributes>,
|
attributes: Partial<SearchSessionSavedObjectAttributes>
|
||||||
{ savedObjectsClient }: SearchSessionDependencies
|
|
||||||
) => {
|
) => {
|
||||||
this.logger.debug(`update | ${sessionId}`);
|
this.logger.debug(`update | ${sessionId}`);
|
||||||
return savedObjectsClient.update<SearchSessionSavedObjectAttributes>(
|
return savedObjectsClient.update<SearchSessionSavedObjectAttributes>(
|
||||||
|
@ -329,9 +302,17 @@ export class SearchSessionService implements ISessionService {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public extend(deps: SearchSessionDependencies, sessionId: string, expires: Date) {
|
||||||
|
this.logger.debug(`extend | ${sessionId}`);
|
||||||
|
|
||||||
|
return this.update(deps, sessionId, { expires: expires.toISOString() });
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Throw an error if this session doesn't belong to this user
|
// TODO: Throw an error if this session doesn't belong to this user
|
||||||
public delete = (sessionId: string, { savedObjectsClient }: SearchSessionDependencies) => {
|
public cancel = (deps: SearchSessionDependencies, sessionId: string) => {
|
||||||
return savedObjectsClient.delete(SEARCH_SESSION_TYPE, sessionId);
|
return this.update(deps, sessionId, {
|
||||||
|
status: SearchSessionStatus.CANCELLED,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -340,10 +321,10 @@ export class SearchSessionService implements ISessionService {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
public trackId = async (
|
public trackId = async (
|
||||||
|
deps: SearchSessionDependencies,
|
||||||
searchRequest: IKibanaSearchRequest,
|
searchRequest: IKibanaSearchRequest,
|
||||||
searchId: string,
|
searchId: string,
|
||||||
{ sessionId, isStored, strategy }: ISearchOptions,
|
{ sessionId, strategy }: ISearchOptions
|
||||||
deps: SearchSessionDependencies
|
|
||||||
) => {
|
) => {
|
||||||
if (!sessionId || !searchId) return;
|
if (!sessionId || !searchId) return;
|
||||||
this.logger.debug(`trackId | ${sessionId} | ${searchId}`);
|
this.logger.debug(`trackId | ${sessionId} | ${searchId}`);
|
||||||
|
@ -354,33 +335,34 @@ export class SearchSessionService implements ISessionService {
|
||||||
status: SearchStatus.IN_PROGRESS,
|
status: SearchStatus.IN_PROGRESS,
|
||||||
};
|
};
|
||||||
|
|
||||||
// If there is already a saved object for this session, update it to include this request/ID.
|
// Update the in-memory mapping for this session for when the session is saved.
|
||||||
// Otherwise, just update the in-memory mapping for this session for when the session is saved.
|
const map = this.sessionSearchMap.get(sessionId) ?? {
|
||||||
if (isStored) {
|
insertTime: moment(),
|
||||||
const attributes = {
|
retryCount: 0,
|
||||||
idMapping: { [requestHash]: searchInfo },
|
ids: new Map<string, SearchSessionRequestInfo>(),
|
||||||
};
|
};
|
||||||
await this.update(sessionId, attributes, deps);
|
map.ids.set(requestHash, searchInfo);
|
||||||
} else {
|
this.sessionSearchMap.set(sessionId, map);
|
||||||
const map = this.sessionSearchMap.get(sessionId) ?? {
|
|
||||||
insertTime: moment(),
|
|
||||||
retryCount: 0,
|
|
||||||
ids: new Map<string, SearchSessionRequestInfo>(),
|
|
||||||
};
|
|
||||||
map.ids.set(requestHash, searchInfo);
|
|
||||||
this.sessionSearchMap.set(sessionId, map);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public async getSearchIdMapping(deps: SearchSessionDependencies, sessionId: string) {
|
||||||
|
const searchSession = await this.get(deps, sessionId);
|
||||||
|
const searchIdMapping = new Map<string, string>();
|
||||||
|
Object.values(searchSession.attributes.idMapping).forEach((requestInfo) => {
|
||||||
|
searchIdMapping.set(requestInfo.id, requestInfo.strategy);
|
||||||
|
});
|
||||||
|
return searchIdMapping;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up an existing search ID that matches the given request in the given session so that the
|
* Look up an existing search ID that matches the given request in the given session so that the
|
||||||
* request can continue rather than restart.
|
* request can continue rather than restart.
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
public getId = async (
|
public getId = async (
|
||||||
|
deps: SearchSessionDependencies,
|
||||||
searchRequest: IKibanaSearchRequest,
|
searchRequest: IKibanaSearchRequest,
|
||||||
{ sessionId, isStored, isRestore }: ISearchOptions,
|
{ sessionId, isStored, isRestore }: ISearchOptions
|
||||||
deps: SearchSessionDependencies
|
|
||||||
) => {
|
) => {
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
throw new Error('Session ID is required');
|
throw new Error('Session ID is required');
|
||||||
|
@ -390,7 +372,7 @@ export class SearchSessionService implements ISessionService {
|
||||||
throw new Error('Get search ID is only supported when restoring a session');
|
throw new Error('Get search ID is only supported when restoring a session');
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = await this.get(sessionId, deps);
|
const session = await this.get(deps, sessionId);
|
||||||
const requestHash = createRequestHash(searchRequest.params);
|
const requestHash = createRequestHash(searchRequest.params);
|
||||||
if (!session.attributes.idMapping.hasOwnProperty(requestHash)) {
|
if (!session.attributes.idMapping.hasOwnProperty(requestHash)) {
|
||||||
throw new Error('No search ID in this session matching the given search request');
|
throw new Error('No search ID in this session matching the given search request');
|
||||||
|
@ -406,17 +388,15 @@ export class SearchSessionService implements ISessionService {
|
||||||
});
|
});
|
||||||
const deps = { savedObjectsClient };
|
const deps = { savedObjectsClient };
|
||||||
return {
|
return {
|
||||||
search: <Request extends IKibanaSearchRequest, Response extends IKibanaSearchResponse>(
|
getId: this.getId.bind(this, deps),
|
||||||
strategy: ISearchStrategy<Request, Response>,
|
trackId: this.trackId.bind(this, deps),
|
||||||
...args: Parameters<ISearchStrategy<Request, Response>['search']>
|
getSearchIdMapping: this.getSearchIdMapping.bind(this, deps),
|
||||||
) => this.search(strategy, ...args, deps),
|
save: this.save.bind(this, deps),
|
||||||
save: (sessionId: string, attributes: Partial<SearchSessionSavedObjectAttributes>) =>
|
get: this.get.bind(this, deps),
|
||||||
this.save(sessionId, attributes, deps),
|
find: this.find.bind(this, deps),
|
||||||
get: (sessionId: string) => this.get(sessionId, deps),
|
update: this.update.bind(this, deps),
|
||||||
find: (options: SavedObjectsFindOptions) => this.find(options, deps),
|
extend: this.extend.bind(this, deps),
|
||||||
update: (sessionId: string, attributes: Partial<SearchSessionSavedObjectAttributes>) =>
|
cancel: this.cancel.bind(this, deps),
|
||||||
this.update(sessionId, attributes, deps),
|
|
||||||
delete: (sessionId: string) => this.delete(sessionId, deps),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {
|
||||||
ISearchStrategy,
|
ISearchStrategy,
|
||||||
SearchStrategyDependencies,
|
SearchStrategyDependencies,
|
||||||
} from 'src/plugins/data/server';
|
} from 'src/plugins/data/server';
|
||||||
|
import { createSearchSessionsClientMock } from '../../../../../../src/plugins/data/server/search/mocks';
|
||||||
import { InfraSource } from '../../lib/sources';
|
import { InfraSource } from '../../lib/sources';
|
||||||
import { createInfraSourcesMock } from '../../lib/sources/mocks';
|
import { createInfraSourcesMock } from '../../lib/sources/mocks';
|
||||||
import {
|
import {
|
||||||
|
@ -307,6 +308,7 @@ const createSearchStrategyDependenciesMock = (): SearchStrategyDependencies => (
|
||||||
uiSettingsClient: uiSettingsServiceMock.createClient(),
|
uiSettingsClient: uiSettingsServiceMock.createClient(),
|
||||||
esClient: elasticsearchServiceMock.createScopedClusterClient(),
|
esClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
savedObjectsClient: savedObjectsClientMock.create(),
|
savedObjectsClient: savedObjectsClientMock.create(),
|
||||||
|
searchSessionsClient: createSearchSessionsClientMock(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// using the official data mock from within x-pack doesn't type-check successfully,
|
// using the official data mock from within x-pack doesn't type-check successfully,
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
logEntrySearchRequestStateRT,
|
logEntrySearchRequestStateRT,
|
||||||
logEntrySearchStrategyProvider,
|
logEntrySearchStrategyProvider,
|
||||||
} from './log_entry_search_strategy';
|
} from './log_entry_search_strategy';
|
||||||
|
import { createSearchSessionsClientMock } from '../../../../../../src/plugins/data/server/search/mocks';
|
||||||
|
|
||||||
describe('LogEntry search strategy', () => {
|
describe('LogEntry search strategy', () => {
|
||||||
it('handles initial search requests', async () => {
|
it('handles initial search requests', async () => {
|
||||||
|
@ -244,6 +245,7 @@ const createSearchStrategyDependenciesMock = (): SearchStrategyDependencies => (
|
||||||
uiSettingsClient: uiSettingsServiceMock.createClient(),
|
uiSettingsClient: uiSettingsServiceMock.createClient(),
|
||||||
esClient: elasticsearchServiceMock.createScopedClusterClient(),
|
esClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
savedObjectsClient: savedObjectsClientMock.create(),
|
savedObjectsClient: savedObjectsClientMock.create(),
|
||||||
|
searchSessionsClient: createSearchSessionsClientMock(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// using the official data mock from within x-pack doesn't type-check successfully,
|
// using the official data mock from within x-pack doesn't type-check successfully,
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
import type { RequestHandlerContext } from 'src/core/server';
|
import type { RequestHandlerContext } from 'src/core/server';
|
||||||
import type { DataApiRequestHandlerContext } from '../../../../src/plugins/data/server';
|
import type { SearchRequestHandlerContext } from '../../../../src/plugins/data/server';
|
||||||
import { MlPluginSetup } from '../../ml/server';
|
import { MlPluginSetup } from '../../ml/server';
|
||||||
|
|
||||||
export type MlSystem = ReturnType<MlPluginSetup['mlSystemProvider']>;
|
export type MlSystem = ReturnType<MlPluginSetup['mlSystemProvider']>;
|
||||||
|
@ -27,5 +27,5 @@ export type InfraRequestHandlerContext = InfraMlRequestHandlerContext &
|
||||||
*/
|
*/
|
||||||
export interface InfraPluginRequestHandlerContext extends RequestHandlerContext {
|
export interface InfraPluginRequestHandlerContext extends RequestHandlerContext {
|
||||||
infra: InfraRequestHandlerContext;
|
infra: InfraRequestHandlerContext;
|
||||||
search: DataApiRequestHandlerContext;
|
search: SearchRequestHandlerContext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
import geojsonvt from 'geojson-vt';
|
import geojsonvt from 'geojson-vt';
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import vtpbf from 'vt-pbf';
|
import vtpbf from 'vt-pbf';
|
||||||
import { Logger, RequestHandlerContext } from 'src/core/server';
|
import { Logger } from 'src/core/server';
|
||||||
import type { DataApiRequestHandlerContext } from 'src/plugins/data/server';
|
import type { DataRequestHandlerContext } from 'src/plugins/data/server';
|
||||||
import { Feature, FeatureCollection, Polygon } from 'geojson';
|
import { Feature, FeatureCollection, Polygon } from 'geojson';
|
||||||
import {
|
import {
|
||||||
ES_GEO_FIELD_TYPE,
|
ES_GEO_FIELD_TYPE,
|
||||||
|
@ -45,7 +45,7 @@ export async function getGridTile({
|
||||||
z: number;
|
z: number;
|
||||||
geometryFieldName: string;
|
geometryFieldName: string;
|
||||||
index: string;
|
index: string;
|
||||||
context: RequestHandlerContext & { search: DataApiRequestHandlerContext };
|
context: DataRequestHandlerContext;
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
requestBody: any;
|
requestBody: any;
|
||||||
requestType: RENDER_AS;
|
requestType: RENDER_AS;
|
||||||
|
@ -125,7 +125,7 @@ export async function getTile({
|
||||||
z: number;
|
z: number;
|
||||||
geometryFieldName: string;
|
geometryFieldName: string;
|
||||||
index: string;
|
index: string;
|
||||||
context: RequestHandlerContext & { search: DataApiRequestHandlerContext };
|
context: DataRequestHandlerContext;
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
requestBody: any;
|
requestBody: any;
|
||||||
geoFieldType: ES_GEO_FIELD_TYPE;
|
geoFieldType: ES_GEO_FIELD_TYPE;
|
||||||
|
|
|
@ -6,14 +6,9 @@
|
||||||
|
|
||||||
import rison from 'rison-node';
|
import rison from 'rison-node';
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
import {
|
import { KibanaRequest, KibanaResponseFactory, Logger } from 'src/core/server';
|
||||||
KibanaRequest,
|
|
||||||
KibanaResponseFactory,
|
|
||||||
Logger,
|
|
||||||
RequestHandlerContext,
|
|
||||||
} from 'src/core/server';
|
|
||||||
import { IRouter } from 'src/core/server';
|
import { IRouter } from 'src/core/server';
|
||||||
import type { DataApiRequestHandlerContext } from 'src/plugins/data/server';
|
import type { DataRequestHandlerContext } from 'src/plugins/data/server';
|
||||||
import {
|
import {
|
||||||
MVT_GETTILE_API_PATH,
|
MVT_GETTILE_API_PATH,
|
||||||
API_ROOT_PATH,
|
API_ROOT_PATH,
|
||||||
|
@ -29,7 +24,7 @@ export function initMVTRoutes({
|
||||||
router,
|
router,
|
||||||
logger,
|
logger,
|
||||||
}: {
|
}: {
|
||||||
router: IRouter<RequestHandlerContext & { search: DataApiRequestHandlerContext }>;
|
router: IRouter<DataRequestHandlerContext>;
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
}) {
|
}) {
|
||||||
router.get(
|
router.get(
|
||||||
|
@ -49,7 +44,7 @@ export function initMVTRoutes({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async (
|
async (
|
||||||
context: RequestHandlerContext & { search: DataApiRequestHandlerContext },
|
context: DataRequestHandlerContext,
|
||||||
request: KibanaRequest<unknown, Record<string, any>, unknown>,
|
request: KibanaRequest<unknown, Record<string, any>, unknown>,
|
||||||
response: KibanaResponseFactory
|
response: KibanaResponseFactory
|
||||||
) => {
|
) => {
|
||||||
|
@ -91,7 +86,7 @@ export function initMVTRoutes({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async (
|
async (
|
||||||
context: RequestHandlerContext & { search: DataApiRequestHandlerContext },
|
context: DataRequestHandlerContext,
|
||||||
request: KibanaRequest<unknown, Record<string, any>, unknown>,
|
request: KibanaRequest<unknown, Record<string, any>, unknown>,
|
||||||
response: KibanaResponseFactory
|
response: KibanaResponseFactory
|
||||||
) => {
|
) => {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||||
|
import { SearchSessionStatus } from '../../../../plugins/data_enhanced/common';
|
||||||
|
|
||||||
export default function ({ getService }: FtrProviderContext) {
|
export default function ({ getService }: FtrProviderContext) {
|
||||||
const supertest = getService('supertest');
|
const supertest = getService('supertest');
|
||||||
|
@ -29,11 +30,11 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
await supertest.get(`/internal/session/${sessionId}`).set('kbn-xsrf', 'foo').expect(200);
|
await supertest.get(`/internal/session/${sessionId}`).set('kbn-xsrf', 'foo').expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail to delete an unknown session', async () => {
|
it('should fail to cancel an unknown session', async () => {
|
||||||
await supertest.delete(`/internal/session/123`).set('kbn-xsrf', 'foo').expect(404);
|
await supertest.delete(`/internal/session/123`).set('kbn-xsrf', 'foo').expect(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create and delete a session', async () => {
|
it('should create and cancel a session', async () => {
|
||||||
const sessionId = `my-session-${Math.random()}`;
|
const sessionId = `my-session-${Math.random()}`;
|
||||||
await supertest
|
await supertest
|
||||||
.post(`/internal/session`)
|
.post(`/internal/session`)
|
||||||
|
@ -49,7 +50,13 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
|
|
||||||
await supertest.delete(`/internal/session/${sessionId}`).set('kbn-xsrf', 'foo').expect(200);
|
await supertest.delete(`/internal/session/${sessionId}`).set('kbn-xsrf', 'foo').expect(200);
|
||||||
|
|
||||||
await supertest.get(`/internal/session/${sessionId}`).set('kbn-xsrf', 'foo').expect(404);
|
const resp = await supertest
|
||||||
|
.get(`/internal/session/${sessionId}`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
const { status } = resp.body.attributes;
|
||||||
|
expect(status).to.equal(SearchSessionStatus.CANCELLED);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should sync search ids into session', async () => {
|
it('should sync search ids into session', async () => {
|
||||||
|
@ -123,6 +130,39 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
expect(idMappings).to.contain(id1);
|
expect(idMappings).to.contain(id1);
|
||||||
expect(idMappings).to.contain(id2);
|
expect(idMappings).to.contain(id2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create and extend a session', async () => {
|
||||||
|
const sessionId = `my-session-${Math.random()}`;
|
||||||
|
await supertest
|
||||||
|
.post(`/internal/session`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send({
|
||||||
|
sessionId,
|
||||||
|
name: 'My Session',
|
||||||
|
appId: 'discover',
|
||||||
|
expires: '123',
|
||||||
|
urlGeneratorId: 'discover',
|
||||||
|
})
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
await supertest
|
||||||
|
.post(`/internal/session/${sessionId}/_extend`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send({
|
||||||
|
expires: '2021-02-26T21:02:43.742Z',
|
||||||
|
})
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail to extend a nonexistent session', async () => {
|
||||||
|
await supertest
|
||||||
|
.post(`/internal/session/123/_extend`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send({
|
||||||
|
expires: '2021-02-26T21:02:43.742Z',
|
||||||
|
})
|
||||||
|
.expect(404);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue