mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Support pit
and search_after
in server savedObjects.find
(#89915)
This commit is contained in:
parent
13740f1cd3
commit
7fc3d125bf
75 changed files with 2724 additions and 269 deletions
File diff suppressed because one or more lines are too long
|
@ -23,9 +23,11 @@ export interface SavedObjectsFindOptions
|
|||
| [namespaces](./kibana-plugin-core-public.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
|
||||
| [page](./kibana-plugin-core-public.savedobjectsfindoptions.page.md) | <code>number</code> | |
|
||||
| [perPage](./kibana-plugin-core-public.savedobjectsfindoptions.perpage.md) | <code>number</code> | |
|
||||
| [pit](./kibana-plugin-core-public.savedobjectsfindoptions.pit.md) | <code>SavedObjectsPitParams</code> | Search against a specific Point In Time (PIT) that you've opened with . |
|
||||
| [preference](./kibana-plugin-core-public.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
|
||||
| [rootSearchFields](./kibana-plugin-core-public.savedobjectsfindoptions.rootsearchfields.md) | <code>string[]</code> | The fields to perform the parsed query against. Unlike the <code>searchFields</code> argument, these are expected to be root fields and will not be modified. If used in conjunction with <code>searchFields</code>, both are concatenated together. |
|
||||
| [search](./kibana-plugin-core-public.savedobjectsfindoptions.search.md) | <code>string</code> | Search documents using the Elasticsearch Simple Query String syntax. See Elasticsearch Simple Query String <code>query</code> argument for more information |
|
||||
| [searchAfter](./kibana-plugin-core-public.savedobjectsfindoptions.searchafter.md) | <code>unknown[]</code> | Use the sort values from the previous page to retrieve the next page of results. |
|
||||
| [searchFields](./kibana-plugin-core-public.savedobjectsfindoptions.searchfields.md) | <code>string[]</code> | The fields to perform the parsed query against. See Elasticsearch Simple Query String <code>fields</code> argument for more information |
|
||||
| [sortField](./kibana-plugin-core-public.savedobjectsfindoptions.sortfield.md) | <code>string</code> | |
|
||||
| [sortOrder](./kibana-plugin-core-public.savedobjectsfindoptions.sortorder.md) | <code>string</code> | |
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [SavedObjectsFindOptions](./kibana-plugin-core-public.savedobjectsfindoptions.md) > [pit](./kibana-plugin-core-public.savedobjectsfindoptions.pit.md)
|
||||
|
||||
## SavedObjectsFindOptions.pit property
|
||||
|
||||
Search against a specific Point In Time (PIT) that you've opened with .
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
pit?: SavedObjectsPitParams;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [SavedObjectsFindOptions](./kibana-plugin-core-public.savedobjectsfindoptions.md) > [searchAfter](./kibana-plugin-core-public.savedobjectsfindoptions.searchafter.md)
|
||||
|
||||
## SavedObjectsFindOptions.searchAfter property
|
||||
|
||||
Use the sort values from the previous page to retrieve the next page of results.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
searchAfter?: unknown[];
|
||||
```
|
|
@ -155,6 +155,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [SavedObjectsCheckConflictsResponse](./kibana-plugin-core-server.savedobjectscheckconflictsresponse.md) | |
|
||||
| [SavedObjectsClientProviderOptions](./kibana-plugin-core-server.savedobjectsclientprovideroptions.md) | Options to control the creation of the Saved Objects Client. |
|
||||
| [SavedObjectsClientWrapperOptions](./kibana-plugin-core-server.savedobjectsclientwrapperoptions.md) | Options passed to each SavedObjectsClientWrapperFactory to aid in creating the wrapper instance. |
|
||||
| [SavedObjectsClosePointInTimeResponse](./kibana-plugin-core-server.savedobjectsclosepointintimeresponse.md) | |
|
||||
| [SavedObjectsComplexFieldMapping](./kibana-plugin-core-server.savedobjectscomplexfieldmapping.md) | See [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) for documentation. |
|
||||
| [SavedObjectsCoreFieldMapping](./kibana-plugin-core-server.savedobjectscorefieldmapping.md) | See [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) for documentation. |
|
||||
| [SavedObjectsCreateOptions](./kibana-plugin-core-server.savedobjectscreateoptions.md) | |
|
||||
|
@ -188,6 +189,9 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [SavedObjectsMappingProperties](./kibana-plugin-core-server.savedobjectsmappingproperties.md) | Describe the fields of a [saved object type](./kibana-plugin-core-server.savedobjectstypemappingdefinition.md)<!-- -->. |
|
||||
| [SavedObjectsMigrationLogger](./kibana-plugin-core-server.savedobjectsmigrationlogger.md) | |
|
||||
| [SavedObjectsMigrationVersion](./kibana-plugin-core-server.savedobjectsmigrationversion.md) | Information about the migrations that have been applied to this SavedObject. When Kibana starts up, KibanaMigrator detects outdated documents and migrates them based on this value. For each migration that has been applied, the plugin's name is used as a key and the latest migration version as the value. |
|
||||
| [SavedObjectsOpenPointInTimeOptions](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.md) | |
|
||||
| [SavedObjectsOpenPointInTimeResponse](./kibana-plugin-core-server.savedobjectsopenpointintimeresponse.md) | |
|
||||
| [SavedObjectsPitParams](./kibana-plugin-core-server.savedobjectspitparams.md) | |
|
||||
| [SavedObjectsRawDoc](./kibana-plugin-core-server.savedobjectsrawdoc.md) | A raw document as represented directly in the saved object index. |
|
||||
| [SavedObjectsRawDocParseOptions](./kibana-plugin-core-server.savedobjectsrawdocparseoptions.md) | Options that can be specified when using the saved objects serializer to parse a raw document. |
|
||||
| [SavedObjectsRemoveReferencesToOptions](./kibana-plugin-core-server.savedobjectsremovereferencestooptions.md) | |
|
||||
|
@ -301,6 +305,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [SavedObjectsClientFactory](./kibana-plugin-core-server.savedobjectsclientfactory.md) | Describes the factory used to create instances of the Saved Objects Client. |
|
||||
| [SavedObjectsClientFactoryProvider](./kibana-plugin-core-server.savedobjectsclientfactoryprovider.md) | Provider to invoke to retrieve a [SavedObjectsClientFactory](./kibana-plugin-core-server.savedobjectsclientfactory.md)<!-- -->. |
|
||||
| [SavedObjectsClientWrapperFactory](./kibana-plugin-core-server.savedobjectsclientwrapperfactory.md) | Describes the factory used to create instances of Saved Objects Client Wrappers. |
|
||||
| [SavedObjectsClosePointInTimeOptions](./kibana-plugin-core-server.savedobjectsclosepointintimeoptions.md) | |
|
||||
| [SavedObjectsExportTransform](./kibana-plugin-core-server.savedobjectsexporttransform.md) | Transformation function used to mutate the exported objects of the associated type.<!-- -->A type's export transform function will be executed once per user-initiated export, for all objects of that type. |
|
||||
| [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) | Describe a [saved object type mapping](./kibana-plugin-core-server.savedobjectstypemappingdefinition.md) field.<!-- -->Please refer to [elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html) For the mapping documentation |
|
||||
| [SavedObjectsImportHook](./kibana-plugin-core-server.savedobjectsimporthook.md) | A hook associated with a specific saved object type, that will be invoked during the import process. The hook will have access to the objects of the registered type.<!-- -->Currently, the only supported feature for import hooks is to return warnings to be displayed in the UI when the import succeeds. The only interactions the hook can have with the import process is via the hook's response. Mutating the objects inside the hook's code will have no effect. |
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsClient](./kibana-plugin-core-server.savedobjectsclient.md) > [closePointInTime](./kibana-plugin-core-server.savedobjectsclient.closepointintime.md)
|
||||
|
||||
## SavedObjectsClient.closePointInTime() method
|
||||
|
||||
Closes a Point In Time (PIT) by ID. This simply proxies the request to ES via the Elasticsearch client, and is included in the Saved Objects Client as a convenience for consumers who are using [SavedObjectsClient.openPointInTimeForType()](./kibana-plugin-core-server.savedobjectsclient.openpointintimefortype.md)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
closePointInTime(id: string, options?: SavedObjectsClosePointInTimeOptions): Promise<SavedObjectsClosePointInTimeResponse>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| id | <code>string</code> | |
|
||||
| options | <code>SavedObjectsClosePointInTimeOptions</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<SavedObjectsClosePointInTimeResponse>`
|
||||
|
|
@ -30,11 +30,13 @@ The constructor for this class is marked as internal. Third-party code should no
|
|||
| [bulkGet(objects, options)](./kibana-plugin-core-server.savedobjectsclient.bulkget.md) | | Returns an array of objects by id |
|
||||
| [bulkUpdate(objects, options)](./kibana-plugin-core-server.savedobjectsclient.bulkupdate.md) | | Bulk Updates multiple SavedObject at once |
|
||||
| [checkConflicts(objects, options)](./kibana-plugin-core-server.savedobjectsclient.checkconflicts.md) | | Check what conflicts will result when creating a given array of saved objects. This includes "unresolvable conflicts", which are multi-namespace objects that exist in a different namespace; such conflicts cannot be resolved/overwritten. |
|
||||
| [closePointInTime(id, options)](./kibana-plugin-core-server.savedobjectsclient.closepointintime.md) | | Closes a Point In Time (PIT) by ID. This simply proxies the request to ES via the Elasticsearch client, and is included in the Saved Objects Client as a convenience for consumers who are using [SavedObjectsClient.openPointInTimeForType()](./kibana-plugin-core-server.savedobjectsclient.openpointintimefortype.md)<!-- -->. |
|
||||
| [create(type, attributes, options)](./kibana-plugin-core-server.savedobjectsclient.create.md) | | Persists a SavedObject |
|
||||
| [delete(type, id, options)](./kibana-plugin-core-server.savedobjectsclient.delete.md) | | Deletes a SavedObject |
|
||||
| [deleteFromNamespaces(type, id, namespaces, options)](./kibana-plugin-core-server.savedobjectsclient.deletefromnamespaces.md) | | Removes namespaces from a SavedObject |
|
||||
| [find(options)](./kibana-plugin-core-server.savedobjectsclient.find.md) | | Find all SavedObjects matching the search query |
|
||||
| [get(type, id, options)](./kibana-plugin-core-server.savedobjectsclient.get.md) | | Retrieves a single object |
|
||||
| [openPointInTimeForType(type, options)](./kibana-plugin-core-server.savedobjectsclient.openpointintimefortype.md) | | Opens a Point In Time (PIT) against the indices for the specified Saved Object types. The returned <code>id</code> can then be passed to [SavedObjectsClient.find()](./kibana-plugin-core-server.savedobjectsclient.find.md) to search against that PIT. |
|
||||
| [removeReferencesTo(type, id, options)](./kibana-plugin-core-server.savedobjectsclient.removereferencesto.md) | | Updates all objects containing a reference to the given {<!-- -->type, id<!-- -->} tuple to remove the said reference. |
|
||||
| [resolve(type, id, options)](./kibana-plugin-core-server.savedobjectsclient.resolve.md) | | Resolves a single object, using any legacy URL alias if it exists |
|
||||
| [update(type, id, attributes, options)](./kibana-plugin-core-server.savedobjectsclient.update.md) | | Updates an SavedObject |
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsClient](./kibana-plugin-core-server.savedobjectsclient.md) > [openPointInTimeForType](./kibana-plugin-core-server.savedobjectsclient.openpointintimefortype.md)
|
||||
|
||||
## SavedObjectsClient.openPointInTimeForType() method
|
||||
|
||||
Opens a Point In Time (PIT) against the indices for the specified Saved Object types. The returned `id` can then be passed to [SavedObjectsClient.find()](./kibana-plugin-core-server.savedobjectsclient.find.md) to search against that PIT.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
openPointInTimeForType(type: string | string[], options?: SavedObjectsOpenPointInTimeOptions): Promise<SavedObjectsOpenPointInTimeResponse>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| type | <code>string | string[]</code> | |
|
||||
| options | <code>SavedObjectsOpenPointInTimeOptions</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<SavedObjectsOpenPointInTimeResponse>`
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsClosePointInTimeOptions](./kibana-plugin-core-server.savedobjectsclosepointintimeoptions.md)
|
||||
|
||||
## SavedObjectsClosePointInTimeOptions type
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type SavedObjectsClosePointInTimeOptions = SavedObjectsBaseOptions;
|
||||
```
|
|
@ -0,0 +1,20 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsClosePointInTimeResponse](./kibana-plugin-core-server.savedobjectsclosepointintimeresponse.md)
|
||||
|
||||
## SavedObjectsClosePointInTimeResponse interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface SavedObjectsClosePointInTimeResponse
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [num\_freed](./kibana-plugin-core-server.savedobjectsclosepointintimeresponse.num_freed.md) | <code>number</code> | The number of search contexts that have been successfully closed. |
|
||||
| [succeeded](./kibana-plugin-core-server.savedobjectsclosepointintimeresponse.succeeded.md) | <code>boolean</code> | If true, all search contexts associated with the PIT id are successfully closed. |
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsClosePointInTimeResponse](./kibana-plugin-core-server.savedobjectsclosepointintimeresponse.md) > [num\_freed](./kibana-plugin-core-server.savedobjectsclosepointintimeresponse.num_freed.md)
|
||||
|
||||
## SavedObjectsClosePointInTimeResponse.num\_freed property
|
||||
|
||||
The number of search contexts that have been successfully closed.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
num_freed: number;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsClosePointInTimeResponse](./kibana-plugin-core-server.savedobjectsclosepointintimeresponse.md) > [succeeded](./kibana-plugin-core-server.savedobjectsclosepointintimeresponse.succeeded.md)
|
||||
|
||||
## SavedObjectsClosePointInTimeResponse.succeeded property
|
||||
|
||||
If true, all search contexts associated with the PIT id are successfully closed.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
succeeded: boolean;
|
||||
```
|
|
@ -9,10 +9,11 @@ Constructs a new instance of the `SavedObjectsExporter` class
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
constructor({ savedObjectsClient, typeRegistry, exportSizeLimit, }: {
|
||||
constructor({ savedObjectsClient, typeRegistry, exportSizeLimit, logger, }: {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
exportSizeLimit: number;
|
||||
logger: Logger;
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -20,5 +21,5 @@ constructor({ savedObjectsClient, typeRegistry, exportSizeLimit, }: {
|
|||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| { savedObjectsClient, typeRegistry, exportSizeLimit, } | <code>{</code><br/><code> savedObjectsClient: SavedObjectsClientContract;</code><br/><code> typeRegistry: ISavedObjectTypeRegistry;</code><br/><code> exportSizeLimit: number;</code><br/><code> }</code> | |
|
||||
| { savedObjectsClient, typeRegistry, exportSizeLimit, logger, } | <code>{</code><br/><code> savedObjectsClient: SavedObjectsClientContract;</code><br/><code> typeRegistry: ISavedObjectTypeRegistry;</code><br/><code> exportSizeLimit: number;</code><br/><code> logger: Logger;</code><br/><code> }</code> | |
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ export declare class SavedObjectsExporter
|
|||
|
||||
| Constructor | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [(constructor)({ savedObjectsClient, typeRegistry, exportSizeLimit, })](./kibana-plugin-core-server.savedobjectsexporter._constructor_.md) | | Constructs a new instance of the <code>SavedObjectsExporter</code> class |
|
||||
| [(constructor)({ savedObjectsClient, typeRegistry, exportSizeLimit, logger, })](./kibana-plugin-core-server.savedobjectsexporter._constructor_.md) | | Constructs a new instance of the <code>SavedObjectsExporter</code> class |
|
||||
|
||||
## Properties
|
||||
|
||||
|
|
|
@ -23,9 +23,11 @@ export interface SavedObjectsFindOptions
|
|||
| [namespaces](./kibana-plugin-core-server.savedobjectsfindoptions.namespaces.md) | <code>string[]</code> | |
|
||||
| [page](./kibana-plugin-core-server.savedobjectsfindoptions.page.md) | <code>number</code> | |
|
||||
| [perPage](./kibana-plugin-core-server.savedobjectsfindoptions.perpage.md) | <code>number</code> | |
|
||||
| [pit](./kibana-plugin-core-server.savedobjectsfindoptions.pit.md) | <code>SavedObjectsPitParams</code> | Search against a specific Point In Time (PIT) that you've opened with [SavedObjectsClient.openPointInTimeForType()](./kibana-plugin-core-server.savedobjectsclient.openpointintimefortype.md)<!-- -->. |
|
||||
| [preference](./kibana-plugin-core-server.savedobjectsfindoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query \* |
|
||||
| [rootSearchFields](./kibana-plugin-core-server.savedobjectsfindoptions.rootsearchfields.md) | <code>string[]</code> | The fields to perform the parsed query against. Unlike the <code>searchFields</code> argument, these are expected to be root fields and will not be modified. If used in conjunction with <code>searchFields</code>, both are concatenated together. |
|
||||
| [search](./kibana-plugin-core-server.savedobjectsfindoptions.search.md) | <code>string</code> | Search documents using the Elasticsearch Simple Query String syntax. See Elasticsearch Simple Query String <code>query</code> argument for more information |
|
||||
| [searchAfter](./kibana-plugin-core-server.savedobjectsfindoptions.searchafter.md) | <code>unknown[]</code> | Use the sort values from the previous page to retrieve the next page of results. |
|
||||
| [searchFields](./kibana-plugin-core-server.savedobjectsfindoptions.searchfields.md) | <code>string[]</code> | The fields to perform the parsed query against. See Elasticsearch Simple Query String <code>fields</code> argument for more information |
|
||||
| [sortField](./kibana-plugin-core-server.savedobjectsfindoptions.sortfield.md) | <code>string</code> | |
|
||||
| [sortOrder](./kibana-plugin-core-server.savedobjectsfindoptions.sortorder.md) | <code>string</code> | |
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsFindOptions](./kibana-plugin-core-server.savedobjectsfindoptions.md) > [pit](./kibana-plugin-core-server.savedobjectsfindoptions.pit.md)
|
||||
|
||||
## SavedObjectsFindOptions.pit property
|
||||
|
||||
Search against a specific Point In Time (PIT) that you've opened with [SavedObjectsClient.openPointInTimeForType()](./kibana-plugin-core-server.savedobjectsclient.openpointintimefortype.md)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
pit?: SavedObjectsPitParams;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsFindOptions](./kibana-plugin-core-server.savedobjectsfindoptions.md) > [searchAfter](./kibana-plugin-core-server.savedobjectsfindoptions.searchafter.md)
|
||||
|
||||
## SavedObjectsFindOptions.searchAfter property
|
||||
|
||||
Use the sort values from the previous page to retrieve the next page of results.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
searchAfter?: unknown[];
|
||||
```
|
|
@ -20,6 +20,7 @@ export interface SavedObjectsFindResponse<T = unknown>
|
|||
| --- | --- | --- |
|
||||
| [page](./kibana-plugin-core-server.savedobjectsfindresponse.page.md) | <code>number</code> | |
|
||||
| [per\_page](./kibana-plugin-core-server.savedobjectsfindresponse.per_page.md) | <code>number</code> | |
|
||||
| [pit\_id](./kibana-plugin-core-server.savedobjectsfindresponse.pit_id.md) | <code>string</code> | |
|
||||
| [saved\_objects](./kibana-plugin-core-server.savedobjectsfindresponse.saved_objects.md) | <code>Array<SavedObjectsFindResult<T>></code> | |
|
||||
| [total](./kibana-plugin-core-server.savedobjectsfindresponse.total.md) | <code>number</code> | |
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsFindResponse](./kibana-plugin-core-server.savedobjectsfindresponse.md) > [pit\_id](./kibana-plugin-core-server.savedobjectsfindresponse.pit_id.md)
|
||||
|
||||
## SavedObjectsFindResponse.pit\_id property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
pit_id?: string;
|
||||
```
|
|
@ -16,4 +16,5 @@ export interface SavedObjectsFindResult<T = unknown> extends SavedObject<T>
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [score](./kibana-plugin-core-server.savedobjectsfindresult.score.md) | <code>number</code> | The Elasticsearch <code>_score</code> of this result. |
|
||||
| [sort](./kibana-plugin-core-server.savedobjectsfindresult.sort.md) | <code>unknown[]</code> | The Elasticsearch <code>sort</code> value of this result. |
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsFindResult](./kibana-plugin-core-server.savedobjectsfindresult.md) > [sort](./kibana-plugin-core-server.savedobjectsfindresult.sort.md)
|
||||
|
||||
## SavedObjectsFindResult.sort property
|
||||
|
||||
The Elasticsearch `sort` value of this result.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
sort?: unknown[];
|
||||
```
|
||||
|
||||
## Remarks
|
||||
|
||||
This can be passed directly to the `searchAfter` param in the [SavedObjectsFindOptions](./kibana-plugin-core-server.savedobjectsfindoptions.md) in order to page through large numbers of hits. It is recommended you use this alongside a Point In Time (PIT) that was opened with [SavedObjectsClient.openPointInTimeForType()](./kibana-plugin-core-server.savedobjectsclient.openpointintimefortype.md)<!-- -->.
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
```ts
|
||||
const { id } = await savedObjectsClient.openPointInTimeForType('visualization');
|
||||
const page1 = await savedObjectsClient.find({
|
||||
type: 'visualization',
|
||||
sortField: 'updated_at',
|
||||
sortOrder: 'asc',
|
||||
pit,
|
||||
});
|
||||
const lastHit = page1.saved_objects[page1.saved_objects.length - 1];
|
||||
const page2 = await savedObjectsClient.find({
|
||||
type: 'visualization',
|
||||
sortField: 'updated_at',
|
||||
sortOrder: 'asc',
|
||||
pit: { id: page1.pit_id },
|
||||
searchAfter: lastHit.sort,
|
||||
});
|
||||
await savedObjectsClient.closePointInTime(page2.pit_id);
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsOpenPointInTimeOptions](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.md) > [keepAlive](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.keepalive.md)
|
||||
|
||||
## SavedObjectsOpenPointInTimeOptions.keepAlive property
|
||||
|
||||
Optionally specify how long ES should keep the PIT alive until the next request. Defaults to `5m`<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
keepAlive?: string;
|
||||
```
|
|
@ -0,0 +1,20 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsOpenPointInTimeOptions](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.md)
|
||||
|
||||
## SavedObjectsOpenPointInTimeOptions interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOptions
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [keepAlive](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.keepalive.md) | <code>string</code> | Optionally specify how long ES should keep the PIT alive until the next request. Defaults to <code>5m</code>. |
|
||||
| [preference](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.preference.md) | <code>string</code> | An optional ES preference value to be used for the query. |
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsOpenPointInTimeOptions](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.md) > [preference](./kibana-plugin-core-server.savedobjectsopenpointintimeoptions.preference.md)
|
||||
|
||||
## SavedObjectsOpenPointInTimeOptions.preference property
|
||||
|
||||
An optional ES preference value to be used for the query.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
preference?: string;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsOpenPointInTimeResponse](./kibana-plugin-core-server.savedobjectsopenpointintimeresponse.md) > [id](./kibana-plugin-core-server.savedobjectsopenpointintimeresponse.id.md)
|
||||
|
||||
## SavedObjectsOpenPointInTimeResponse.id property
|
||||
|
||||
PIT ID returned from ES.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
id: string;
|
||||
```
|
|
@ -0,0 +1,19 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsOpenPointInTimeResponse](./kibana-plugin-core-server.savedobjectsopenpointintimeresponse.md)
|
||||
|
||||
## SavedObjectsOpenPointInTimeResponse interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface SavedObjectsOpenPointInTimeResponse
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [id](./kibana-plugin-core-server.savedobjectsopenpointintimeresponse.id.md) | <code>string</code> | PIT ID returned from ES. |
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsPitParams](./kibana-plugin-core-server.savedobjectspitparams.md) > [id](./kibana-plugin-core-server.savedobjectspitparams.id.md)
|
||||
|
||||
## SavedObjectsPitParams.id property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
id: string;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsPitParams](./kibana-plugin-core-server.savedobjectspitparams.md) > [keepAlive](./kibana-plugin-core-server.savedobjectspitparams.keepalive.md)
|
||||
|
||||
## SavedObjectsPitParams.keepAlive property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
keepAlive?: string;
|
||||
```
|
|
@ -0,0 +1,20 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsPitParams](./kibana-plugin-core-server.savedobjectspitparams.md)
|
||||
|
||||
## SavedObjectsPitParams interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface SavedObjectsPitParams
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [id](./kibana-plugin-core-server.savedobjectspitparams.id.md) | <code>string</code> | |
|
||||
| [keepAlive](./kibana-plugin-core-server.savedobjectspitparams.keepalive.md) | <code>string</code> | |
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsRepository](./kibana-plugin-core-server.savedobjectsrepository.md) > [closePointInTime](./kibana-plugin-core-server.savedobjectsrepository.closepointintime.md)
|
||||
|
||||
## SavedObjectsRepository.closePointInTime() method
|
||||
|
||||
Closes a Point In Time (PIT) by ID. This simply proxies the request to ES via the Elasticsearch client, and is included in the Saved Objects Client as a convenience for consumers who are using `openPointInTimeForType`<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
closePointInTime(id: string, options?: SavedObjectsClosePointInTimeOptions): Promise<SavedObjectsClosePointInTimeResponse>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| id | <code>string</code> | |
|
||||
| options | <code>SavedObjectsClosePointInTimeOptions</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<SavedObjectsClosePointInTimeResponse>`
|
||||
|
||||
{<!-- -->promise<!-- -->} - [SavedObjectsClosePointInTimeResponse](./kibana-plugin-core-server.savedobjectsclosepointintimeresponse.md)
|
||||
|
||||
## Remarks
|
||||
|
||||
While the `keepAlive` that is provided will cause a PIT to automatically close, it is highly recommended to explicitly close a PIT when you are done with it in order to avoid consuming unneeded resources in Elasticsearch.
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
```ts
|
||||
const repository = coreStart.savedObjects.createInternalRepository();
|
||||
|
||||
const { id } = await repository.openPointInTimeForType(
|
||||
type: 'index-pattern',
|
||||
{ keepAlive: '2m' },
|
||||
);
|
||||
|
||||
const response = await repository.find({
|
||||
type: 'index-pattern',
|
||||
search: 'foo*',
|
||||
sortField: 'name',
|
||||
sortOrder: 'desc',
|
||||
pit: {
|
||||
id: 'abc123',
|
||||
keepAlive: '2m',
|
||||
},
|
||||
searchAfter: [1234, 'abcd'],
|
||||
});
|
||||
|
||||
await repository.closePointInTime(response.pit_id);
|
||||
|
||||
```
|
||||
|
|
@ -20,6 +20,7 @@ export declare class SavedObjectsRepository
|
|||
| [bulkGet(objects, options)](./kibana-plugin-core-server.savedobjectsrepository.bulkget.md) | | Returns an array of objects by id |
|
||||
| [bulkUpdate(objects, options)](./kibana-plugin-core-server.savedobjectsrepository.bulkupdate.md) | | Updates multiple objects in bulk |
|
||||
| [checkConflicts(objects, options)](./kibana-plugin-core-server.savedobjectsrepository.checkconflicts.md) | | Check what conflicts will result when creating a given array of saved objects. This includes "unresolvable conflicts", which are multi-namespace objects that exist in a different namespace; such conflicts cannot be resolved/overwritten. |
|
||||
| [closePointInTime(id, options)](./kibana-plugin-core-server.savedobjectsrepository.closepointintime.md) | | Closes a Point In Time (PIT) by ID. This simply proxies the request to ES via the Elasticsearch client, and is included in the Saved Objects Client as a convenience for consumers who are using <code>openPointInTimeForType</code>. |
|
||||
| [create(type, attributes, options)](./kibana-plugin-core-server.savedobjectsrepository.create.md) | | Persists an object |
|
||||
| [delete(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.delete.md) | | Deletes an object |
|
||||
| [deleteByNamespace(namespace, options)](./kibana-plugin-core-server.savedobjectsrepository.deletebynamespace.md) | | Deletes all objects from the provided namespace. |
|
||||
|
@ -27,6 +28,7 @@ export declare class SavedObjectsRepository
|
|||
| [find(options)](./kibana-plugin-core-server.savedobjectsrepository.find.md) | | |
|
||||
| [get(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.get.md) | | Gets a single object |
|
||||
| [incrementCounter(type, id, counterFields, options)](./kibana-plugin-core-server.savedobjectsrepository.incrementcounter.md) | | Increments all the specified counter fields (by one by default). Creates the document if one doesn't exist for the given id. |
|
||||
| [openPointInTimeForType(type, { keepAlive, preference })](./kibana-plugin-core-server.savedobjectsrepository.openpointintimefortype.md) | | Opens a Point In Time (PIT) against the indices for the specified Saved Object types. The returned <code>id</code> can then be passed to <code>SavedObjects.find</code> to search against that PIT. |
|
||||
| [removeReferencesTo(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.removereferencesto.md) | | Updates all objects containing a reference to the given {<!-- -->type, id<!-- -->} tuple to remove the said reference. |
|
||||
| [resolve(type, id, options)](./kibana-plugin-core-server.savedobjectsrepository.resolve.md) | | Resolves a single object, using any legacy URL alias if it exists |
|
||||
| [update(type, id, attributes, options)](./kibana-plugin-core-server.savedobjectsrepository.update.md) | | Updates an object |
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsRepository](./kibana-plugin-core-server.savedobjectsrepository.md) > [openPointInTimeForType](./kibana-plugin-core-server.savedobjectsrepository.openpointintimefortype.md)
|
||||
|
||||
## SavedObjectsRepository.openPointInTimeForType() method
|
||||
|
||||
Opens a Point In Time (PIT) against the indices for the specified Saved Object types. The returned `id` can then be passed to `SavedObjects.find` to search against that PIT.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
openPointInTimeForType(type: string | string[], { keepAlive, preference }?: SavedObjectsOpenPointInTimeOptions): Promise<SavedObjectsOpenPointInTimeResponse>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| type | <code>string | string[]</code> | |
|
||||
| { keepAlive, preference } | <code>SavedObjectsOpenPointInTimeOptions</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<SavedObjectsOpenPointInTimeResponse>`
|
||||
|
||||
{<!-- -->promise<!-- -->} - { id: string }
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
```ts
|
||||
const repository = coreStart.savedObjects.createInternalRepository();
|
||||
|
||||
const { id } = await repository.openPointInTimeForType(
|
||||
type: 'index-pattern',
|
||||
{ keepAlive: '2m' },
|
||||
);
|
||||
const page1 = await savedObjectsClient.find({
|
||||
type: 'visualization',
|
||||
sortField: 'updated_at',
|
||||
sortOrder: 'asc',
|
||||
pit,
|
||||
});
|
||||
|
||||
const lastHit = page1.saved_objects[page1.saved_objects.length - 1];
|
||||
const page2 = await savedObjectsClient.find({
|
||||
type: 'visualization',
|
||||
sortField: 'updated_at',
|
||||
sortOrder: 'asc',
|
||||
pit: { id: page1.pit_id },
|
||||
searchAfter: lastHit.sort,
|
||||
});
|
||||
|
||||
await savedObjectsClient.closePointInTime(page2.pit_id);
|
||||
|
||||
```
|
||||
|
|
@ -22,7 +22,7 @@ hits: {
|
|||
highlight?: any;
|
||||
inner_hits?: any;
|
||||
matched_queries?: string[];
|
||||
sort?: string[];
|
||||
sort?: unknown[];
|
||||
}>;
|
||||
};
|
||||
```
|
||||
|
|
|
@ -18,7 +18,8 @@ export interface SearchResponse<T = unknown>
|
|||
| [\_scroll\_id](./kibana-plugin-core-server.searchresponse._scroll_id.md) | <code>string</code> | |
|
||||
| [\_shards](./kibana-plugin-core-server.searchresponse._shards.md) | <code>ShardsResponse</code> | |
|
||||
| [aggregations](./kibana-plugin-core-server.searchresponse.aggregations.md) | <code>any</code> | |
|
||||
| [hits](./kibana-plugin-core-server.searchresponse.hits.md) | <code>{</code><br/><code> total: number;</code><br/><code> max_score: number;</code><br/><code> hits: Array<{</code><br/><code> _index: string;</code><br/><code> _type: string;</code><br/><code> _id: string;</code><br/><code> _score: number;</code><br/><code> _source: T;</code><br/><code> _version?: number;</code><br/><code> _explanation?: Explanation;</code><br/><code> fields?: any;</code><br/><code> highlight?: any;</code><br/><code> inner_hits?: any;</code><br/><code> matched_queries?: string[];</code><br/><code> sort?: string[];</code><br/><code> }>;</code><br/><code> }</code> | |
|
||||
| [hits](./kibana-plugin-core-server.searchresponse.hits.md) | <code>{</code><br/><code> total: number;</code><br/><code> max_score: number;</code><br/><code> hits: Array<{</code><br/><code> _index: string;</code><br/><code> _type: string;</code><br/><code> _id: string;</code><br/><code> _score: number;</code><br/><code> _source: T;</code><br/><code> _version?: number;</code><br/><code> _explanation?: Explanation;</code><br/><code> fields?: any;</code><br/><code> highlight?: any;</code><br/><code> inner_hits?: any;</code><br/><code> matched_queries?: string[];</code><br/><code> sort?: unknown[];</code><br/><code> }>;</code><br/><code> }</code> | |
|
||||
| [pit\_id](./kibana-plugin-core-server.searchresponse.pit_id.md) | <code>string</code> | |
|
||||
| [timed\_out](./kibana-plugin-core-server.searchresponse.timed_out.md) | <code>boolean</code> | |
|
||||
| [took](./kibana-plugin-core-server.searchresponse.took.md) | <code>number</code> | |
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SearchResponse](./kibana-plugin-core-server.searchresponse.md) > [pit\_id](./kibana-plugin-core-server.searchresponse.pit_id.md)
|
||||
|
||||
## SearchResponse.pit\_id property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
pit_id?: string;
|
||||
```
|
|
@ -85,6 +85,10 @@ Refer to the corresponding {es} logs for potential write errors.
|
|||
| `unknown` | User is creating a saved object.
|
||||
| `failure` | User is not authorized to create a saved object.
|
||||
|
||||
.2+| `saved_object_open_point_in_time`
|
||||
| `unknown` | User is creating a Point In Time to use when querying saved objects.
|
||||
| `failure` | User is not authorized to create a Point In Time for the provided saved object types.
|
||||
|
||||
.2+| `connector_create`
|
||||
| `unknown` | User is creating a connector.
|
||||
| `failure` | User is not authorized to create a connector.
|
||||
|
@ -171,6 +175,10 @@ Refer to the corresponding {es} logs for potential write errors.
|
|||
| `unknown` | User is deleting a saved object.
|
||||
| `failure` | User is not authorized to delete a saved object.
|
||||
|
||||
.2+| `saved_object_close_point_in_time`
|
||||
| `unknown` | User is deleting a Point In Time that was used to query saved objects.
|
||||
| `failure` | User is not authorized to delete a Point In Time.
|
||||
|
||||
.2+| `connector_delete`
|
||||
| `unknown` | User is deleting a connector.
|
||||
| `failure` | User is not authorized to delete a connector.
|
||||
|
|
|
@ -1207,9 +1207,13 @@ export interface SavedObjectsFindOptions {
|
|||
page?: number;
|
||||
// (undocumented)
|
||||
perPage?: number;
|
||||
// Warning: (ae-forgotten-export) The symbol "SavedObjectsPitParams" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-unresolved-link) The @link reference could not be resolved: No member was found with name "openPointInTimeForType"
|
||||
pit?: SavedObjectsPitParams;
|
||||
preference?: string;
|
||||
rootSearchFields?: string[];
|
||||
search?: string;
|
||||
searchAfter?: unknown[];
|
||||
searchFields?: string[];
|
||||
// (undocumented)
|
||||
sortField?: string;
|
||||
|
|
|
@ -21,12 +21,14 @@ import {
|
|||
import { SimpleSavedObject } from './simple_saved_object';
|
||||
import { HttpFetchOptions, HttpSetup } from '../http';
|
||||
|
||||
type PromiseType<T extends Promise<any>> = T extends Promise<infer U> ? U : never;
|
||||
|
||||
type SavedObjectsFindOptions = Omit<
|
||||
SavedObjectFindOptionsServer,
|
||||
'sortOrder' | 'rootSearchFields' | 'typeToNamespacesMap'
|
||||
'pit' | 'rootSearchFields' | 'searchAfter' | 'sortOrder' | 'typeToNamespacesMap'
|
||||
>;
|
||||
|
||||
type PromiseType<T extends Promise<any>> = T extends Promise<infer U> ? U : never;
|
||||
type SavedObjectsFindResponse = Omit<PromiseType<ReturnType<SavedObjectsApi['find']>>, 'pit_id'>;
|
||||
|
||||
/** @public */
|
||||
export interface SavedObjectsCreateOptions {
|
||||
|
@ -345,10 +347,7 @@ export class SavedObjectsClient {
|
|||
query,
|
||||
});
|
||||
return request.then((resp) => {
|
||||
return renameKeys<
|
||||
PromiseType<ReturnType<SavedObjectsApi['find']>>,
|
||||
SavedObjectsFindResponsePublic
|
||||
>(
|
||||
return renameKeys<SavedObjectsFindResponse, SavedObjectsFindResponsePublic>(
|
||||
{
|
||||
saved_objects: 'savedObjects',
|
||||
total: 'total',
|
||||
|
|
|
@ -96,10 +96,11 @@ export interface SearchResponse<T = unknown> {
|
|||
highlight?: any;
|
||||
inner_hits?: any;
|
||||
matched_queries?: string[];
|
||||
sort?: string[];
|
||||
sort?: unknown[];
|
||||
}>;
|
||||
};
|
||||
aggregations?: any;
|
||||
pit_id?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -260,6 +260,8 @@ export {
|
|||
SavedObjectsClientWrapperOptions,
|
||||
SavedObjectsClientFactory,
|
||||
SavedObjectsClientFactoryProvider,
|
||||
SavedObjectsClosePointInTimeOptions,
|
||||
SavedObjectsClosePointInTimeResponse,
|
||||
SavedObjectsCreateOptions,
|
||||
SavedObjectsErrorHelpers,
|
||||
SavedObjectsExportResultDetails,
|
||||
|
@ -277,6 +279,8 @@ export {
|
|||
SavedObjectsImportUnsupportedTypeError,
|
||||
SavedObjectMigrationContext,
|
||||
SavedObjectsMigrationLogger,
|
||||
SavedObjectsOpenPointInTimeOptions,
|
||||
SavedObjectsOpenPointInTimeResponse,
|
||||
SavedObjectsRawDoc,
|
||||
SavedObjectsRawDocParseOptions,
|
||||
SavedObjectSanitizedDoc,
|
||||
|
@ -373,6 +377,7 @@ export {
|
|||
SavedObjectsClientContract,
|
||||
SavedObjectsFindOptions,
|
||||
SavedObjectsFindOptionsReference,
|
||||
SavedObjectsPitParams,
|
||||
SavedObjectsMigrationVersion,
|
||||
} from './types';
|
||||
|
||||
|
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { savedObjectsClientMock } from '../service/saved_objects_client.mock';
|
||||
import { loggerMock, MockedLogger } from '../../logging/logger.mock';
|
||||
import { SavedObjectsFindOptions } from '../types';
|
||||
import { SavedObjectsFindResult } from '../service';
|
||||
|
||||
import { createPointInTimeFinder } from './point_in_time_finder';
|
||||
|
||||
const mockHits = [
|
||||
{
|
||||
id: '2',
|
||||
type: 'search',
|
||||
attributes: {},
|
||||
score: 1,
|
||||
references: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'visualization',
|
||||
id: '1',
|
||||
},
|
||||
],
|
||||
sort: [],
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
type: 'visualization',
|
||||
attributes: {},
|
||||
score: 1,
|
||||
references: [],
|
||||
sort: [],
|
||||
},
|
||||
];
|
||||
|
||||
describe('createPointInTimeFinder()', () => {
|
||||
let logger: MockedLogger;
|
||||
let savedObjectsClient: ReturnType<typeof savedObjectsClientMock.create>;
|
||||
|
||||
beforeEach(() => {
|
||||
logger = loggerMock.create();
|
||||
savedObjectsClient = savedObjectsClientMock.create();
|
||||
});
|
||||
|
||||
describe('#find', () => {
|
||||
test('throws if a PIT is already open', async () => {
|
||||
savedObjectsClient.openPointInTimeForType.mockResolvedValueOnce({
|
||||
id: 'abc123',
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: mockHits,
|
||||
pit_id: 'abc123',
|
||||
per_page: 1,
|
||||
page: 0,
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: mockHits,
|
||||
pit_id: 'abc123',
|
||||
per_page: 1,
|
||||
page: 1,
|
||||
});
|
||||
|
||||
const findOptions: SavedObjectsFindOptions = {
|
||||
type: ['visualization'],
|
||||
search: 'foo*',
|
||||
perPage: 1,
|
||||
};
|
||||
|
||||
const finder = createPointInTimeFinder({ findOptions, logger, savedObjectsClient });
|
||||
await finder.find().next();
|
||||
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
|
||||
savedObjectsClient.find.mockClear();
|
||||
|
||||
expect(async () => {
|
||||
await finder.find().next();
|
||||
}).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Point In Time has already been opened for this finder instance. Please call \`close()\` before calling \`find()\` again."`
|
||||
);
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('works with a single page of results', async () => {
|
||||
savedObjectsClient.openPointInTimeForType.mockResolvedValueOnce({
|
||||
id: 'abc123',
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: mockHits,
|
||||
pit_id: 'abc123',
|
||||
per_page: 2,
|
||||
page: 0,
|
||||
});
|
||||
|
||||
const findOptions: SavedObjectsFindOptions = {
|
||||
type: ['visualization'],
|
||||
search: 'foo*',
|
||||
};
|
||||
|
||||
const finder = createPointInTimeFinder({ findOptions, logger, savedObjectsClient });
|
||||
const hits: SavedObjectsFindResult[] = [];
|
||||
for await (const result of finder.find()) {
|
||||
hits.push(...result.saved_objects);
|
||||
}
|
||||
|
||||
expect(hits.length).toBe(2);
|
||||
expect(savedObjectsClient.openPointInTimeForType).toHaveBeenCalledTimes(1);
|
||||
expect(savedObjectsClient.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
pit: expect.objectContaining({ id: 'abc123', keepAlive: '2m' }),
|
||||
sortField: 'updated_at',
|
||||
sortOrder: 'desc',
|
||||
type: ['visualization'],
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test('works with multiple pages of results', async () => {
|
||||
savedObjectsClient.openPointInTimeForType.mockResolvedValueOnce({
|
||||
id: 'abc123',
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: [mockHits[0]],
|
||||
pit_id: 'abc123',
|
||||
per_page: 1,
|
||||
page: 0,
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: [mockHits[1]],
|
||||
pit_id: 'abc123',
|
||||
per_page: 1,
|
||||
page: 0,
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: [],
|
||||
per_page: 1,
|
||||
pit_id: 'abc123',
|
||||
page: 0,
|
||||
});
|
||||
|
||||
const findOptions: SavedObjectsFindOptions = {
|
||||
type: ['visualization'],
|
||||
search: 'foo*',
|
||||
perPage: 1,
|
||||
};
|
||||
|
||||
const finder = createPointInTimeFinder({ findOptions, logger, savedObjectsClient });
|
||||
const hits: SavedObjectsFindResult[] = [];
|
||||
for await (const result of finder.find()) {
|
||||
hits.push(...result.saved_objects);
|
||||
}
|
||||
|
||||
expect(hits.length).toBe(2);
|
||||
expect(savedObjectsClient.openPointInTimeForType).toHaveBeenCalledTimes(1);
|
||||
expect(savedObjectsClient.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
// called 3 times since we need a 3rd request to check if we
|
||||
// are done paginating through results.
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledTimes(3);
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
pit: expect.objectContaining({ id: 'abc123', keepAlive: '2m' }),
|
||||
sortField: 'updated_at',
|
||||
sortOrder: 'desc',
|
||||
type: ['visualization'],
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#close', () => {
|
||||
test('calls closePointInTime with correct ID', async () => {
|
||||
savedObjectsClient.openPointInTimeForType.mockResolvedValueOnce({
|
||||
id: 'test',
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 1,
|
||||
saved_objects: [mockHits[0]],
|
||||
pit_id: 'test',
|
||||
per_page: 1,
|
||||
page: 0,
|
||||
});
|
||||
|
||||
const findOptions: SavedObjectsFindOptions = {
|
||||
type: ['visualization'],
|
||||
search: 'foo*',
|
||||
perPage: 2,
|
||||
};
|
||||
|
||||
const finder = createPointInTimeFinder({ findOptions, logger, savedObjectsClient });
|
||||
const hits: SavedObjectsFindResult[] = [];
|
||||
for await (const result of finder.find()) {
|
||||
hits.push(...result.saved_objects);
|
||||
await finder.close();
|
||||
}
|
||||
|
||||
expect(savedObjectsClient.closePointInTime).toHaveBeenCalledWith('test');
|
||||
});
|
||||
|
||||
test('causes generator to stop', async () => {
|
||||
savedObjectsClient.openPointInTimeForType.mockResolvedValueOnce({
|
||||
id: 'test',
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: [mockHits[0]],
|
||||
pit_id: 'test',
|
||||
per_page: 1,
|
||||
page: 0,
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: [mockHits[1]],
|
||||
pit_id: 'test',
|
||||
per_page: 1,
|
||||
page: 0,
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: [],
|
||||
per_page: 1,
|
||||
pit_id: 'test',
|
||||
page: 0,
|
||||
});
|
||||
|
||||
const findOptions: SavedObjectsFindOptions = {
|
||||
type: ['visualization'],
|
||||
search: 'foo*',
|
||||
perPage: 1,
|
||||
};
|
||||
|
||||
const finder = createPointInTimeFinder({ findOptions, logger, savedObjectsClient });
|
||||
const hits: SavedObjectsFindResult[] = [];
|
||||
for await (const result of finder.find()) {
|
||||
hits.push(...result.saved_objects);
|
||||
await finder.close();
|
||||
}
|
||||
|
||||
expect(savedObjectsClient.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
expect(hits.length).toBe(1);
|
||||
});
|
||||
|
||||
test('is called if `find` throws an error', async () => {
|
||||
savedObjectsClient.openPointInTimeForType.mockResolvedValueOnce({
|
||||
id: 'test',
|
||||
});
|
||||
savedObjectsClient.find.mockRejectedValueOnce(new Error('oops'));
|
||||
|
||||
const findOptions: SavedObjectsFindOptions = {
|
||||
type: ['visualization'],
|
||||
search: 'foo*',
|
||||
perPage: 2,
|
||||
};
|
||||
|
||||
const finder = createPointInTimeFinder({ findOptions, logger, savedObjectsClient });
|
||||
const hits: SavedObjectsFindResult[] = [];
|
||||
try {
|
||||
for await (const result of finder.find()) {
|
||||
hits.push(...result.saved_objects);
|
||||
}
|
||||
} catch (e) {
|
||||
// intentionally empty
|
||||
}
|
||||
|
||||
expect(savedObjectsClient.closePointInTime).toHaveBeenCalledWith('test');
|
||||
});
|
||||
|
||||
test('finder can be reused after closing', async () => {
|
||||
savedObjectsClient.openPointInTimeForType.mockResolvedValueOnce({
|
||||
id: 'abc123',
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: mockHits,
|
||||
pit_id: 'abc123',
|
||||
per_page: 1,
|
||||
page: 0,
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
saved_objects: mockHits,
|
||||
pit_id: 'abc123',
|
||||
per_page: 1,
|
||||
page: 1,
|
||||
});
|
||||
|
||||
const findOptions: SavedObjectsFindOptions = {
|
||||
type: ['visualization'],
|
||||
search: 'foo*',
|
||||
perPage: 1,
|
||||
};
|
||||
|
||||
const finder = createPointInTimeFinder({ findOptions, logger, savedObjectsClient });
|
||||
|
||||
const findA = finder.find();
|
||||
await findA.next();
|
||||
await finder.close();
|
||||
|
||||
const findB = finder.find();
|
||||
await findB.next();
|
||||
await finder.close();
|
||||
|
||||
expect((await findA.next()).done).toBe(true);
|
||||
expect((await findB.next()).done).toBe(true);
|
||||
expect(savedObjectsClient.openPointInTimeForType).toHaveBeenCalledTimes(2);
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledTimes(2);
|
||||
expect(savedObjectsClient.closePointInTime).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
});
|
192
src/core/server/saved_objects/export/point_in_time_finder.ts
Normal file
192
src/core/server/saved_objects/export/point_in_time_finder.ts
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Logger } from '../../logging';
|
||||
import { SavedObjectsClientContract, SavedObjectsFindOptions } from '../types';
|
||||
import { SavedObjectsFindResponse } from '../service';
|
||||
|
||||
/**
|
||||
* Returns a generator to help page through large sets of saved objects.
|
||||
*
|
||||
* The generator wraps calls to `SavedObjects.find` and iterates over
|
||||
* multiple pages of results using `_pit` and `search_after`. This will
|
||||
* open a new Point In Time (PIT), and continue paging until a set of
|
||||
* results is received that's smaller than the designated `perPage`.
|
||||
*
|
||||
* Once you have retrieved all of the results you need, it is recommended
|
||||
* to call `close()` to clean up the PIT and prevent Elasticsearch from
|
||||
* consuming resources unnecessarily. This will automatically be done for
|
||||
* you if you reach the last page of results.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const findOptions: SavedObjectsFindOptions = {
|
||||
* type: 'visualization',
|
||||
* search: 'foo*',
|
||||
* perPage: 100,
|
||||
* };
|
||||
*
|
||||
* const finder = createPointInTimeFinder({
|
||||
* logger,
|
||||
* savedObjectsClient,
|
||||
* findOptions,
|
||||
* });
|
||||
*
|
||||
* const responses: SavedObjectFindResponse[] = [];
|
||||
* for await (const response of finder.find()) {
|
||||
* responses.push(...response);
|
||||
* if (doneSearching) {
|
||||
* await finder.close();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function createPointInTimeFinder({
|
||||
findOptions,
|
||||
logger,
|
||||
savedObjectsClient,
|
||||
}: {
|
||||
findOptions: SavedObjectsFindOptions;
|
||||
logger: Logger;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
}) {
|
||||
return new PointInTimeFinder({ findOptions, logger, savedObjectsClient });
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class PointInTimeFinder {
|
||||
readonly #log: Logger;
|
||||
readonly #savedObjectsClient: SavedObjectsClientContract;
|
||||
readonly #findOptions: SavedObjectsFindOptions;
|
||||
#open: boolean = false;
|
||||
#pitId?: string;
|
||||
|
||||
constructor({
|
||||
findOptions,
|
||||
logger,
|
||||
savedObjectsClient,
|
||||
}: {
|
||||
findOptions: SavedObjectsFindOptions;
|
||||
logger: Logger;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
}) {
|
||||
this.#log = logger;
|
||||
this.#savedObjectsClient = savedObjectsClient;
|
||||
this.#findOptions = {
|
||||
// Default to 1000 items per page as a tradeoff between
|
||||
// speed and memory consumption.
|
||||
perPage: 1000,
|
||||
...findOptions,
|
||||
};
|
||||
}
|
||||
|
||||
async *find() {
|
||||
if (this.#open) {
|
||||
throw new Error(
|
||||
'Point In Time has already been opened for this finder instance. ' +
|
||||
'Please call `close()` before calling `find()` again.'
|
||||
);
|
||||
}
|
||||
|
||||
// Open PIT and request our first page of hits
|
||||
await this.open();
|
||||
|
||||
let lastResultsCount: number;
|
||||
let lastHitSortValue: unknown[] | undefined;
|
||||
do {
|
||||
const results = await this.findNext({
|
||||
findOptions: this.#findOptions,
|
||||
id: this.#pitId,
|
||||
...(lastHitSortValue ? { searchAfter: lastHitSortValue } : {}),
|
||||
});
|
||||
this.#pitId = results.pit_id;
|
||||
lastResultsCount = results.saved_objects.length;
|
||||
lastHitSortValue = this.getLastHitSortValue(results);
|
||||
|
||||
this.#log.debug(`Collected [${lastResultsCount}] saved objects for export.`);
|
||||
|
||||
// Close PIT if this was our last page
|
||||
if (this.#pitId && lastResultsCount < this.#findOptions.perPage!) {
|
||||
await this.close();
|
||||
}
|
||||
|
||||
yield results;
|
||||
// We've reached the end when there are fewer hits than our perPage size,
|
||||
// or when `close()` has been called.
|
||||
} while (this.#open && lastResultsCount >= this.#findOptions.perPage!);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
async close() {
|
||||
try {
|
||||
if (this.#pitId) {
|
||||
this.#log.debug(`Closing PIT for types [${this.#findOptions.type}]`);
|
||||
await this.#savedObjectsClient.closePointInTime(this.#pitId);
|
||||
this.#pitId = undefined;
|
||||
}
|
||||
this.#open = false;
|
||||
} catch (e) {
|
||||
this.#log.error(`Failed to close PIT for types [${this.#findOptions.type}]`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private async open() {
|
||||
try {
|
||||
const { id } = await this.#savedObjectsClient.openPointInTimeForType(this.#findOptions.type);
|
||||
this.#pitId = id;
|
||||
this.#open = true;
|
||||
} catch (e) {
|
||||
// Since `find` swallows 404s, it is expected that exporter will do the same,
|
||||
// so we only rethrow non-404 errors here.
|
||||
if (e.output.statusCode !== 404) {
|
||||
throw e;
|
||||
}
|
||||
this.#log.debug(`Unable to open PIT for types [${this.#findOptions.type}]: 404 ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async findNext({
|
||||
findOptions,
|
||||
id,
|
||||
searchAfter,
|
||||
}: {
|
||||
findOptions: SavedObjectsFindOptions;
|
||||
id?: string;
|
||||
searchAfter?: unknown[];
|
||||
}) {
|
||||
try {
|
||||
return await this.#savedObjectsClient.find({
|
||||
// Sort fields are required to use searchAfter, so we set some defaults here
|
||||
sortField: 'updated_at',
|
||||
sortOrder: 'desc',
|
||||
// Bump keep_alive by 2m on every new request to allow for the ES client
|
||||
// to make multiple retries in the event of a network failure.
|
||||
...(id ? { pit: { id, keepAlive: '2m' } } : {}),
|
||||
...(searchAfter ? { searchAfter } : {}),
|
||||
...findOptions,
|
||||
});
|
||||
} catch (e) {
|
||||
if (id) {
|
||||
// Clean up PIT on any errors.
|
||||
await this.close();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private getLastHitSortValue(res: SavedObjectsFindResponse): unknown[] | undefined {
|
||||
if (res.saved_objects.length < 1) {
|
||||
return undefined;
|
||||
}
|
||||
return res.saved_objects[res.saved_objects.length - 1].sort;
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import { SavedObjectsExporter } from './saved_objects_exporter';
|
|||
import { savedObjectsClientMock } from '../service/saved_objects_client.mock';
|
||||
import { SavedObjectTypeRegistry } from '../saved_objects_type_registry';
|
||||
import { httpServerMock } from '../../http/http_server.mocks';
|
||||
import { loggerMock, MockedLogger } from '../../logging/logger.mock';
|
||||
import { Readable } from 'stream';
|
||||
import { createPromiseFromStreams, createConcatStream } from '@kbn/utils';
|
||||
|
||||
|
@ -18,18 +19,25 @@ async function readStreamToCompletion(stream: Readable): Promise<Array<SavedObje
|
|||
return createPromiseFromStreams([stream, createConcatStream([])]);
|
||||
}
|
||||
|
||||
const exportSizeLimit = 500;
|
||||
const exportSizeLimit = 10000;
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
|
||||
describe('getSortedObjectsForExport()', () => {
|
||||
let logger: MockedLogger;
|
||||
let savedObjectsClient: ReturnType<typeof savedObjectsClientMock.create>;
|
||||
let typeRegistry: SavedObjectTypeRegistry;
|
||||
let exporter: SavedObjectsExporter;
|
||||
|
||||
beforeEach(() => {
|
||||
logger = loggerMock.create();
|
||||
typeRegistry = new SavedObjectTypeRegistry();
|
||||
savedObjectsClient = savedObjectsClientMock.create();
|
||||
exporter = new SavedObjectsExporter({ savedObjectsClient, exportSizeLimit, typeRegistry });
|
||||
exporter = new SavedObjectsExporter({
|
||||
exportSizeLimit,
|
||||
logger,
|
||||
savedObjectsClient,
|
||||
typeRegistry,
|
||||
});
|
||||
});
|
||||
|
||||
describe('#exportByTypes', () => {
|
||||
|
@ -58,7 +66,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
references: [],
|
||||
},
|
||||
],
|
||||
per_page: 1,
|
||||
per_page: 1000,
|
||||
page: 0,
|
||||
});
|
||||
const exportStream = await exporter.exportByTypes({
|
||||
|
@ -96,30 +104,232 @@ describe('getSortedObjectsForExport()', () => {
|
|||
]
|
||||
`);
|
||||
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": undefined,
|
||||
"hasReferenceOperator": undefined,
|
||||
"namespaces": undefined,
|
||||
"perPage": 500,
|
||||
"search": undefined,
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
},
|
||||
],
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": undefined,
|
||||
"hasReferenceOperator": undefined,
|
||||
"namespaces": undefined,
|
||||
"perPage": 1000,
|
||||
"pit": Object {
|
||||
"id": "some_pit_id",
|
||||
"keepAlive": "2m",
|
||||
},
|
||||
"search": undefined,
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
describe('pages through results with PIT', () => {
|
||||
function generateHits(
|
||||
hitCount: number,
|
||||
{
|
||||
attributes = {},
|
||||
sort = [],
|
||||
type = 'index-pattern',
|
||||
}: {
|
||||
attributes?: Record<string, unknown>;
|
||||
sort?: unknown[];
|
||||
type?: string;
|
||||
} = {}
|
||||
) {
|
||||
const hits = [];
|
||||
for (let i = 1; i <= hitCount; i++) {
|
||||
hits.push({
|
||||
id: `${i}`,
|
||||
type,
|
||||
attributes,
|
||||
sort,
|
||||
score: 1,
|
||||
references: [],
|
||||
});
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
describe('<1k hits', () => {
|
||||
const mockHits = generateHits(20);
|
||||
|
||||
test('requests a single page', async () => {
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 20,
|
||||
saved_objects: mockHits,
|
||||
per_page: 1000,
|
||||
page: 0,
|
||||
});
|
||||
|
||||
const exportStream = await exporter.exportByTypes({
|
||||
request,
|
||||
types: ['index-pattern'],
|
||||
});
|
||||
|
||||
const response = await readStreamToCompletion(exportStream);
|
||||
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledTimes(1);
|
||||
expect(response[response.length - 1]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"exportedCount": 20,
|
||||
"missingRefCount": 0,
|
||||
"missingReferences": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('opens and closes PIT', async () => {
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 20,
|
||||
saved_objects: mockHits,
|
||||
per_page: 1000,
|
||||
page: 0,
|
||||
pit_id: 'abc123',
|
||||
});
|
||||
|
||||
const exportStream = await exporter.exportByTypes({
|
||||
request,
|
||||
types: ['index-pattern'],
|
||||
});
|
||||
|
||||
await readStreamToCompletion(exportStream);
|
||||
|
||||
expect(savedObjectsClient.openPointInTimeForType).toHaveBeenCalledTimes(1);
|
||||
expect(savedObjectsClient.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('passes correct PIT ID to `find`', async () => {
|
||||
savedObjectsClient.openPointInTimeForType.mockResolvedValueOnce({
|
||||
id: 'abc123',
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 20,
|
||||
saved_objects: mockHits,
|
||||
per_page: 1000,
|
||||
page: 0,
|
||||
});
|
||||
|
||||
const exportStream = await exporter.exportByTypes({
|
||||
request,
|
||||
types: ['index-pattern'],
|
||||
});
|
||||
|
||||
await readStreamToCompletion(exportStream);
|
||||
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
pit: expect.objectContaining({ id: 'abc123', keepAlive: '2m' }),
|
||||
sortField: 'updated_at',
|
||||
sortOrder: 'desc',
|
||||
type: ['index-pattern'],
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('>1k hits', () => {
|
||||
const firstMockHits = generateHits(1000, { sort: ['a', 'b'] });
|
||||
const secondMockHits = generateHits(500);
|
||||
|
||||
test('requests multiple pages', async () => {
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 1500,
|
||||
saved_objects: firstMockHits,
|
||||
per_page: 1000,
|
||||
page: 0,
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 1500,
|
||||
saved_objects: secondMockHits,
|
||||
per_page: 500,
|
||||
page: 1,
|
||||
});
|
||||
|
||||
const exportStream = await exporter.exportByTypes({
|
||||
request,
|
||||
types: ['index-pattern'],
|
||||
});
|
||||
|
||||
const response = await readStreamToCompletion(exportStream);
|
||||
|
||||
expect(savedObjectsClient.find).toHaveBeenCalledTimes(2);
|
||||
expect(response[response.length - 1]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"exportedCount": 1500,
|
||||
"missingRefCount": 0,
|
||||
"missingReferences": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('opens and closes PIT', async () => {
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 1500,
|
||||
saved_objects: firstMockHits,
|
||||
per_page: 1000,
|
||||
page: 0,
|
||||
pit_id: 'abc123',
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 1500,
|
||||
saved_objects: secondMockHits,
|
||||
per_page: 500,
|
||||
page: 1,
|
||||
pit_id: 'abc123',
|
||||
});
|
||||
|
||||
const exportStream = await exporter.exportByTypes({
|
||||
request,
|
||||
types: ['index-pattern'],
|
||||
});
|
||||
|
||||
await readStreamToCompletion(exportStream);
|
||||
|
||||
expect(savedObjectsClient.openPointInTimeForType).toHaveBeenCalledTimes(1);
|
||||
expect(savedObjectsClient.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('passes sort values to searchAfter', async () => {
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 1500,
|
||||
saved_objects: firstMockHits,
|
||||
per_page: 1000,
|
||||
page: 0,
|
||||
});
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 1500,
|
||||
saved_objects: secondMockHits,
|
||||
per_page: 500,
|
||||
page: 1,
|
||||
});
|
||||
|
||||
const exportStream = await exporter.exportByTypes({
|
||||
request,
|
||||
types: ['index-pattern'],
|
||||
});
|
||||
|
||||
await readStreamToCompletion(exportStream);
|
||||
|
||||
expect(savedObjectsClient.find.mock.calls[1][0]).toEqual(
|
||||
expect.objectContaining({
|
||||
searchAfter: ['a', 'b'],
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('applies the export transforms', async () => {
|
||||
|
@ -138,7 +348,12 @@ describe('getSortedObjectsForExport()', () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
exporter = new SavedObjectsExporter({ savedObjectsClient, exportSizeLimit, typeRegistry });
|
||||
exporter = new SavedObjectsExporter({
|
||||
exportSizeLimit,
|
||||
logger,
|
||||
savedObjectsClient,
|
||||
typeRegistry,
|
||||
});
|
||||
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 1,
|
||||
|
@ -233,30 +448,36 @@ describe('getSortedObjectsForExport()', () => {
|
|||
]
|
||||
`);
|
||||
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": undefined,
|
||||
"hasReferenceOperator": undefined,
|
||||
"namespaces": undefined,
|
||||
"perPage": 500,
|
||||
"search": undefined,
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
},
|
||||
],
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": undefined,
|
||||
"hasReferenceOperator": undefined,
|
||||
"namespaces": undefined,
|
||||
"perPage": 1000,
|
||||
"pit": Object {
|
||||
"id": "some_pit_id",
|
||||
"keepAlive": "2m",
|
||||
},
|
||||
"search": undefined,
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('exclude export details if option is specified', async () => {
|
||||
|
@ -383,30 +604,36 @@ describe('getSortedObjectsForExport()', () => {
|
|||
]
|
||||
`);
|
||||
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": undefined,
|
||||
"hasReferenceOperator": undefined,
|
||||
"namespaces": undefined,
|
||||
"perPage": 500,
|
||||
"search": "foo",
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
},
|
||||
],
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": undefined,
|
||||
"hasReferenceOperator": undefined,
|
||||
"namespaces": undefined,
|
||||
"perPage": 1000,
|
||||
"pit": Object {
|
||||
"id": "some_pit_id",
|
||||
"keepAlive": "2m",
|
||||
},
|
||||
"search": "foo",
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('exports selected types with references when present', async () => {
|
||||
|
@ -465,35 +692,41 @@ describe('getSortedObjectsForExport()', () => {
|
|||
]
|
||||
`);
|
||||
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
],
|
||||
"hasReferenceOperator": "OR",
|
||||
"namespaces": undefined,
|
||||
"perPage": 500,
|
||||
"search": undefined,
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
"id": "1",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
"hasReferenceOperator": "OR",
|
||||
"namespaces": undefined,
|
||||
"perPage": 1000,
|
||||
"pit": Object {
|
||||
"id": "some_pit_id",
|
||||
"keepAlive": "2m",
|
||||
},
|
||||
"search": undefined,
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('exports from the provided namespace when present', async () => {
|
||||
|
@ -521,7 +754,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
references: [],
|
||||
},
|
||||
],
|
||||
per_page: 1,
|
||||
per_page: 1000,
|
||||
page: 0,
|
||||
});
|
||||
const exportStream = await exporter.exportByTypes({
|
||||
|
@ -560,36 +793,56 @@ describe('getSortedObjectsForExport()', () => {
|
|||
]
|
||||
`);
|
||||
expect(savedObjectsClient.find).toMatchInlineSnapshot(`
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": undefined,
|
||||
"hasReferenceOperator": undefined,
|
||||
"namespaces": Array [
|
||||
"foo",
|
||||
],
|
||||
"perPage": 500,
|
||||
"search": undefined,
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
},
|
||||
],
|
||||
[MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"hasReference": undefined,
|
||||
"hasReferenceOperator": undefined,
|
||||
"namespaces": Array [
|
||||
"foo",
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
},
|
||||
"perPage": 1000,
|
||||
"pit": Object {
|
||||
"id": "some_pit_id",
|
||||
"keepAlive": "2m",
|
||||
},
|
||||
"search": undefined,
|
||||
"sortField": "updated_at",
|
||||
"sortOrder": "desc",
|
||||
"type": Array [
|
||||
"index-pattern",
|
||||
"search",
|
||||
],
|
||||
}
|
||||
`);
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": Promise {},
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('export selected types throws error when exceeding exportSizeLimit', async () => {
|
||||
exporter = new SavedObjectsExporter({ savedObjectsClient, exportSizeLimit: 1, typeRegistry });
|
||||
exporter = new SavedObjectsExporter({
|
||||
exportSizeLimit: 1,
|
||||
logger,
|
||||
savedObjectsClient,
|
||||
typeRegistry,
|
||||
});
|
||||
|
||||
savedObjectsClient.openPointInTimeForType.mockResolvedValueOnce({
|
||||
id: 'abc123',
|
||||
});
|
||||
|
||||
savedObjectsClient.closePointInTime.mockResolvedValueOnce({
|
||||
succeeded: true,
|
||||
num_freed: 1,
|
||||
});
|
||||
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 2,
|
||||
|
@ -617,6 +870,7 @@ describe('getSortedObjectsForExport()', () => {
|
|||
],
|
||||
per_page: 1,
|
||||
page: 0,
|
||||
pit_id: 'abc123',
|
||||
});
|
||||
await expect(
|
||||
exporter.exportByTypes({
|
||||
|
@ -624,12 +878,13 @@ describe('getSortedObjectsForExport()', () => {
|
|||
types: ['index-pattern', 'search'],
|
||||
})
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(`"Can't export more than 1 objects"`);
|
||||
expect(savedObjectsClient.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('sorts objects within type', async () => {
|
||||
savedObjectsClient.find.mockResolvedValueOnce({
|
||||
total: 3,
|
||||
per_page: 10000,
|
||||
per_page: 1000,
|
||||
page: 1,
|
||||
saved_objects: [
|
||||
{
|
||||
|
@ -836,7 +1091,12 @@ describe('getSortedObjectsForExport()', () => {
|
|||
});
|
||||
|
||||
test('export selected objects throws error when exceeding exportSizeLimit', async () => {
|
||||
exporter = new SavedObjectsExporter({ savedObjectsClient, exportSizeLimit: 1, typeRegistry });
|
||||
exporter = new SavedObjectsExporter({
|
||||
exportSizeLimit: 1,
|
||||
logger,
|
||||
savedObjectsClient,
|
||||
typeRegistry,
|
||||
});
|
||||
|
||||
const exportOpts = {
|
||||
request,
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
import { createListStream } from '@kbn/utils';
|
||||
import { PublicMethodsOf } from '@kbn/utility-types';
|
||||
import { SavedObject, SavedObjectsClientContract } from '../types';
|
||||
import { Logger } from '../../logging';
|
||||
import { SavedObject, SavedObjectsClientContract, SavedObjectsFindOptions } from '../types';
|
||||
import { SavedObjectsFindResult } from '../service';
|
||||
import { ISavedObjectTypeRegistry } from '../saved_objects_type_registry';
|
||||
import { fetchNestedDependencies } from './fetch_nested_dependencies';
|
||||
import { sortObjects } from './sort_objects';
|
||||
|
@ -21,6 +23,7 @@ import {
|
|||
} from './types';
|
||||
import { SavedObjectsExportError } from './errors';
|
||||
import { applyExportTransforms } from './apply_export_transforms';
|
||||
import { createPointInTimeFinder } from './point_in_time_finder';
|
||||
import { byIdAscComparator, getPreservedOrderComparator, SavedObjectComparator } from './utils';
|
||||
|
||||
/**
|
||||
|
@ -35,16 +38,20 @@ export class SavedObjectsExporter {
|
|||
readonly #savedObjectsClient: SavedObjectsClientContract;
|
||||
readonly #exportTransforms: Record<string, SavedObjectsExportTransform>;
|
||||
readonly #exportSizeLimit: number;
|
||||
readonly #log: Logger;
|
||||
|
||||
constructor({
|
||||
savedObjectsClient,
|
||||
typeRegistry,
|
||||
exportSizeLimit,
|
||||
logger,
|
||||
}: {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
exportSizeLimit: number;
|
||||
logger: Logger;
|
||||
}) {
|
||||
this.#log = logger;
|
||||
this.#savedObjectsClient = savedObjectsClient;
|
||||
this.#exportSizeLimit = exportSizeLimit;
|
||||
this.#exportTransforms = typeRegistry.getAllTypes().reduce((transforms, type) => {
|
||||
|
@ -66,6 +73,7 @@ export class SavedObjectsExporter {
|
|||
* @throws SavedObjectsExportError
|
||||
*/
|
||||
public async exportByTypes(options: SavedObjectsExportByTypeOptions) {
|
||||
this.#log.debug(`Initiating export for types: [${options.types}]`);
|
||||
const objects = await this.fetchByTypes(options);
|
||||
return this.processObjects(objects, byIdAscComparator, {
|
||||
request: options.request,
|
||||
|
@ -83,6 +91,7 @@ export class SavedObjectsExporter {
|
|||
* @throws SavedObjectsExportError
|
||||
*/
|
||||
public async exportByObjects(options: SavedObjectsExportByObjectOptions) {
|
||||
this.#log.debug(`Initiating export of [${options.objects.length}] objects.`);
|
||||
if (options.objects.length > this.#exportSizeLimit) {
|
||||
throw SavedObjectsExportError.exportSizeExceeded(this.#exportSizeLimit);
|
||||
}
|
||||
|
@ -106,6 +115,7 @@ export class SavedObjectsExporter {
|
|||
namespace,
|
||||
}: SavedObjectExportBaseOptions
|
||||
) {
|
||||
this.#log.debug(`Processing [${savedObjects.length}] saved objects.`);
|
||||
let exportedObjects: Array<SavedObject<unknown>>;
|
||||
let missingReferences: SavedObjectsExportResultDetails['missingReferences'] = [];
|
||||
|
||||
|
@ -117,6 +127,7 @@ export class SavedObjectsExporter {
|
|||
});
|
||||
|
||||
if (includeReferencesDeep) {
|
||||
this.#log.debug(`Fetching saved objects references.`);
|
||||
const fetchResult = await fetchNestedDependencies(
|
||||
savedObjects,
|
||||
this.#savedObjectsClient,
|
||||
|
@ -138,6 +149,7 @@ export class SavedObjectsExporter {
|
|||
missingRefCount: missingReferences.length,
|
||||
missingReferences,
|
||||
};
|
||||
this.#log.debug(`Exporting [${redactedObjects.length}] saved objects.`);
|
||||
return createListStream([...redactedObjects, ...(excludeExportDetails ? [] : [exportDetails])]);
|
||||
}
|
||||
|
||||
|
@ -156,21 +168,32 @@ export class SavedObjectsExporter {
|
|||
hasReference,
|
||||
search,
|
||||
}: SavedObjectsExportByTypeOptions) {
|
||||
const findResponse = await this.#savedObjectsClient.find({
|
||||
const findOptions: SavedObjectsFindOptions = {
|
||||
type: types,
|
||||
hasReference,
|
||||
hasReferenceOperator: hasReference ? 'OR' : undefined,
|
||||
search,
|
||||
perPage: this.#exportSizeLimit,
|
||||
namespaces: namespace ? [namespace] : undefined,
|
||||
};
|
||||
|
||||
const finder = createPointInTimeFinder({
|
||||
findOptions,
|
||||
logger: this.#log,
|
||||
savedObjectsClient: this.#savedObjectsClient,
|
||||
});
|
||||
if (findResponse.total > this.#exportSizeLimit) {
|
||||
throw SavedObjectsExportError.exportSizeExceeded(this.#exportSizeLimit);
|
||||
|
||||
const hits: SavedObjectsFindResult[] = [];
|
||||
for await (const result of finder.find()) {
|
||||
hits.push(...result.saved_objects);
|
||||
if (hits.length > this.#exportSizeLimit) {
|
||||
await finder.close();
|
||||
throw SavedObjectsExportError.exportSizeExceeded(this.#exportSizeLimit);
|
||||
}
|
||||
}
|
||||
|
||||
// sorts server-side by _id, since it's only available in fielddata
|
||||
return (
|
||||
findResponse.saved_objects
|
||||
hits
|
||||
// exclude the find-specific `score` property from the exported objects
|
||||
.map(({ score, ...obj }) => obj)
|
||||
.sort(byIdAscComparator)
|
||||
|
|
|
@ -459,6 +459,7 @@ export class SavedObjectsService
|
|||
savedObjectsClient,
|
||||
typeRegistry: this.typeRegistry,
|
||||
exportSizeLimit: this.config!.maxImportExportSize,
|
||||
logger: this.logger.get('exporter'),
|
||||
}),
|
||||
createImporter: (savedObjectsClient) =>
|
||||
new SavedObjectsImporter({
|
||||
|
|
|
@ -17,6 +17,8 @@ const create = (): jest.Mocked<ISavedObjectsRepository> => ({
|
|||
bulkGet: jest.fn(),
|
||||
find: jest.fn(),
|
||||
get: jest.fn(),
|
||||
closePointInTime: jest.fn(),
|
||||
openPointInTimeForType: jest.fn().mockResolvedValue({ id: 'some_pit_id' }),
|
||||
resolve: jest.fn(),
|
||||
update: jest.fn(),
|
||||
addToNamespaces: jest.fn(),
|
||||
|
|
|
@ -2813,6 +2813,13 @@ describe('SavedObjectsRepository', () => {
|
|||
expect(client.search).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it(`throws when a preference is provided with pit`, async () => {
|
||||
await expect(
|
||||
savedObjectsRepository.find({ type: 'foo', pit: { id: 'abc123' }, preference: 'hi' })
|
||||
).rejects.toThrowError('options.preference must be excluded when options.pit is used');
|
||||
expect(client.search).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it(`throws when KQL filter syntax is invalid`, async () => {
|
||||
const findOpts = {
|
||||
namespaces: [namespace],
|
||||
|
@ -2973,6 +2980,32 @@ describe('SavedObjectsRepository', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it(`accepts searchAfter`, async () => {
|
||||
const relevantOpts = {
|
||||
...commonOptions,
|
||||
searchAfter: [1, 'a'],
|
||||
};
|
||||
|
||||
await findSuccess(relevantOpts, namespace);
|
||||
expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, registry, {
|
||||
...relevantOpts,
|
||||
searchAfter: [1, 'a'],
|
||||
});
|
||||
});
|
||||
|
||||
it(`accepts pit`, async () => {
|
||||
const relevantOpts = {
|
||||
...commonOptions,
|
||||
pit: { id: 'abc123', keepAlive: '2m' },
|
||||
};
|
||||
|
||||
await findSuccess(relevantOpts, namespace);
|
||||
expect(getSearchDslNS.getSearchDsl).toHaveBeenCalledWith(mappings, registry, {
|
||||
...relevantOpts,
|
||||
pit: { id: 'abc123', keepAlive: '2m' },
|
||||
});
|
||||
});
|
||||
|
||||
it(`accepts KQL expression filter and passes KueryNode to getSearchDsl`, async () => {
|
||||
const findOpts = {
|
||||
namespaces: [namespace],
|
||||
|
@ -4393,4 +4426,136 @@ describe('SavedObjectsRepository', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#openPointInTimeForType', () => {
|
||||
const type = 'index-pattern';
|
||||
|
||||
const generateResults = (id) => ({ id: id || null });
|
||||
const successResponse = async (type, options) => {
|
||||
client.openPointInTime.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(generateResults())
|
||||
);
|
||||
const result = await savedObjectsRepository.openPointInTimeForType(type, options);
|
||||
expect(client.openPointInTime).toHaveBeenCalledTimes(1);
|
||||
return result;
|
||||
};
|
||||
|
||||
describe('client calls', () => {
|
||||
it(`should use the ES PIT API`, async () => {
|
||||
await successResponse(type);
|
||||
expect(client.openPointInTime).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it(`accepts preference`, async () => {
|
||||
await successResponse(type, { preference: 'pref' });
|
||||
expect(client.openPointInTime).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
preference: 'pref',
|
||||
}),
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
|
||||
it(`accepts keepAlive`, async () => {
|
||||
await successResponse(type, { keepAlive: '2m' });
|
||||
expect(client.openPointInTime).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
keep_alive: '2m',
|
||||
}),
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
|
||||
it(`defaults keepAlive to 5m`, async () => {
|
||||
await successResponse(type);
|
||||
expect(client.openPointInTime).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
keep_alive: '5m',
|
||||
}),
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
const expectNotFoundError = async (types) => {
|
||||
await expect(savedObjectsRepository.openPointInTimeForType(types)).rejects.toThrowError(
|
||||
createGenericNotFoundError()
|
||||
);
|
||||
};
|
||||
|
||||
it(`throws when ES is unable to find the index`, async () => {
|
||||
client.openPointInTime.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise({}, { statusCode: 404 })
|
||||
);
|
||||
await expectNotFoundError(type);
|
||||
expect(client.openPointInTime).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it(`should return generic not found error when attempting to find only invalid or hidden types`, async () => {
|
||||
const test = async (types) => {
|
||||
await expectNotFoundError(types);
|
||||
expect(client.openPointInTime).not.toHaveBeenCalled();
|
||||
};
|
||||
|
||||
await test('unknownType');
|
||||
await test(HIDDEN_TYPE);
|
||||
await test(['unknownType', HIDDEN_TYPE]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('returns', () => {
|
||||
it(`returns id in the expected format`, async () => {
|
||||
const id = 'abc123';
|
||||
const results = generateResults(id);
|
||||
client.openPointInTime.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(results)
|
||||
);
|
||||
const response = await savedObjectsRepository.openPointInTimeForType(type);
|
||||
expect(response).toEqual({ id });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#closePointInTime', () => {
|
||||
const generateResults = () => ({ succeeded: true, num_freed: 3 });
|
||||
const successResponse = async (id) => {
|
||||
client.closePointInTime.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(generateResults())
|
||||
);
|
||||
const result = await savedObjectsRepository.closePointInTime(id);
|
||||
expect(client.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
return result;
|
||||
};
|
||||
|
||||
describe('client calls', () => {
|
||||
it(`should use the ES PIT API`, async () => {
|
||||
await successResponse('abc123');
|
||||
expect(client.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it(`accepts id`, async () => {
|
||||
await successResponse('abc123');
|
||||
expect(client.closePointInTime).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
body: expect.objectContaining({
|
||||
id: 'abc123',
|
||||
}),
|
||||
}),
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('returns', () => {
|
||||
it(`returns response body from ES`, async () => {
|
||||
const results = generateResults('abc123');
|
||||
client.closePointInTime.mockResolvedValueOnce(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(results)
|
||||
);
|
||||
const response = await savedObjectsRepository.closePointInTime('abc123');
|
||||
expect(response).toEqual(results);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -36,6 +36,10 @@ import {
|
|||
SavedObjectsCreateOptions,
|
||||
SavedObjectsFindResponse,
|
||||
SavedObjectsFindResult,
|
||||
SavedObjectsClosePointInTimeOptions,
|
||||
SavedObjectsClosePointInTimeResponse,
|
||||
SavedObjectsOpenPointInTimeOptions,
|
||||
SavedObjectsOpenPointInTimeResponse,
|
||||
SavedObjectsUpdateOptions,
|
||||
SavedObjectsUpdateResponse,
|
||||
SavedObjectsBulkUpdateObject,
|
||||
|
@ -708,11 +712,13 @@ export class SavedObjectsRepository {
|
|||
* Query field argument for more information
|
||||
* @property {integer} [options.page=1]
|
||||
* @property {integer} [options.perPage=20]
|
||||
* @property {Array<unknown>} [options.searchAfter]
|
||||
* @property {string} [options.sortField]
|
||||
* @property {string} [options.sortOrder]
|
||||
* @property {Array<string>} [options.fields]
|
||||
* @property {string} [options.namespace]
|
||||
* @property {object} [options.hasReference] - { type, id }
|
||||
* @property {string} [options.pit]
|
||||
* @property {string} [options.preference]
|
||||
* @returns {promise} - { saved_objects: [{ id, type, version, attributes }], total, per_page, page }
|
||||
*/
|
||||
|
@ -726,6 +732,8 @@ export class SavedObjectsRepository {
|
|||
hasReferenceOperator,
|
||||
page = FIND_DEFAULT_PAGE,
|
||||
perPage = FIND_DEFAULT_PER_PAGE,
|
||||
pit,
|
||||
searchAfter,
|
||||
sortField,
|
||||
sortOrder,
|
||||
fields,
|
||||
|
@ -752,6 +760,10 @@ export class SavedObjectsRepository {
|
|||
throw SavedObjectsErrorHelpers.createBadRequestError(
|
||||
'options.namespaces must be an empty array when options.typeToNamespacesMap is used'
|
||||
);
|
||||
} else if (preference?.length && pit) {
|
||||
throw SavedObjectsErrorHelpers.createBadRequestError(
|
||||
'options.preference must be excluded when options.pit is used'
|
||||
);
|
||||
}
|
||||
|
||||
const types = type
|
||||
|
@ -787,20 +799,24 @@ export class SavedObjectsRepository {
|
|||
}
|
||||
|
||||
const esOptions = {
|
||||
index: this.getIndicesForTypes(allowedTypes),
|
||||
size: perPage,
|
||||
from: perPage * (page - 1),
|
||||
// If `pit` is provided, we drop the `index`, otherwise ES returns 400.
|
||||
...(pit ? {} : { index: this.getIndicesForTypes(allowedTypes) }),
|
||||
// If `searchAfter` is provided, we drop `from` as it will not be used for pagination.
|
||||
...(searchAfter ? {} : { from: perPage * (page - 1) }),
|
||||
_source: includedFields(type, fields),
|
||||
rest_total_hits_as_int: true,
|
||||
preference,
|
||||
rest_total_hits_as_int: true,
|
||||
size: perPage,
|
||||
body: {
|
||||
seq_no_primary_term: true,
|
||||
...getSearchDsl(this._mappings, this._registry, {
|
||||
search,
|
||||
defaultSearchOperator,
|
||||
searchFields,
|
||||
pit,
|
||||
rootSearchFields,
|
||||
type: allowedTypes,
|
||||
searchAfter,
|
||||
sortField,
|
||||
sortOrder,
|
||||
namespaces,
|
||||
|
@ -834,8 +850,10 @@ export class SavedObjectsRepository {
|
|||
(hit: SavedObjectsRawDoc): SavedObjectsFindResult => ({
|
||||
...this._rawToSavedObject(hit),
|
||||
score: (hit as any)._score,
|
||||
...((hit as any).sort && { sort: (hit as any).sort }),
|
||||
})
|
||||
),
|
||||
...(body.pit_id && { pit_id: body.pit_id }),
|
||||
} as SavedObjectsFindResponse<T>;
|
||||
}
|
||||
|
||||
|
@ -1764,6 +1782,118 @@ export class SavedObjectsRepository {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a Point In Time (PIT) against the indices for the specified Saved Object types.
|
||||
* The returned `id` can then be passed to `SavedObjects.find` to search against that PIT.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const { id } = await savedObjectsClient.openPointInTimeForType(
|
||||
* type: 'visualization',
|
||||
* { keepAlive: '5m' },
|
||||
* );
|
||||
* const page1 = await savedObjectsClient.find({
|
||||
* type: 'visualization',
|
||||
* sortField: 'updated_at',
|
||||
* sortOrder: 'asc',
|
||||
* pit: { id, keepAlive: '2m' },
|
||||
* });
|
||||
* const lastHit = page1.saved_objects[page1.saved_objects.length - 1];
|
||||
* const page2 = await savedObjectsClient.find({
|
||||
* type: 'visualization',
|
||||
* sortField: 'updated_at',
|
||||
* sortOrder: 'asc',
|
||||
* pit: { id: page1.pit_id },
|
||||
* searchAfter: lastHit.sort,
|
||||
* });
|
||||
* await savedObjectsClient.closePointInTime(page2.pit_id);
|
||||
* ```
|
||||
*
|
||||
* @param {string|Array<string>} type
|
||||
* @param {object} [options] - {@link SavedObjectsOpenPointInTimeOptions}
|
||||
* @property {string} [options.keepAlive]
|
||||
* @property {string} [options.preference]
|
||||
* @returns {promise} - { id: string }
|
||||
*/
|
||||
async openPointInTimeForType(
|
||||
type: string | string[],
|
||||
{ keepAlive = '5m', preference }: SavedObjectsOpenPointInTimeOptions = {}
|
||||
): Promise<SavedObjectsOpenPointInTimeResponse> {
|
||||
const types = Array.isArray(type) ? type : [type];
|
||||
const allowedTypes = types.filter((t) => this._allowedTypes.includes(t));
|
||||
if (allowedTypes.length === 0) {
|
||||
throw SavedObjectsErrorHelpers.createGenericNotFoundError();
|
||||
}
|
||||
|
||||
const esOptions = {
|
||||
index: this.getIndicesForTypes(allowedTypes),
|
||||
keep_alive: keepAlive,
|
||||
...(preference ? { preference } : {}),
|
||||
};
|
||||
|
||||
const {
|
||||
body,
|
||||
statusCode,
|
||||
} = await this.client.openPointInTime<SavedObjectsOpenPointInTimeResponse>(esOptions, {
|
||||
ignore: [404],
|
||||
});
|
||||
if (statusCode === 404) {
|
||||
throw SavedObjectsErrorHelpers.createGenericNotFoundError();
|
||||
}
|
||||
|
||||
return {
|
||||
id: body.id,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a Point In Time (PIT) by ID. This simply proxies the request to ES
|
||||
* via the Elasticsearch client, and is included in the Saved Objects Client
|
||||
* as a convenience for consumers who are using `openPointInTimeForType`.
|
||||
*
|
||||
* @remarks
|
||||
* While the `keepAlive` that is provided will cause a PIT to automatically close,
|
||||
* it is highly recommended to explicitly close a PIT when you are done with it
|
||||
* in order to avoid consuming unneeded resources in Elasticsearch.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const repository = coreStart.savedObjects.createInternalRepository();
|
||||
*
|
||||
* const { id } = await repository.openPointInTimeForType(
|
||||
* type: 'index-pattern',
|
||||
* { keepAlive: '2m' },
|
||||
* );
|
||||
*
|
||||
* const response = await repository.find({
|
||||
* type: 'index-pattern',
|
||||
* search: 'foo*',
|
||||
* sortField: 'name',
|
||||
* sortOrder: 'desc',
|
||||
* pit: {
|
||||
* id: 'abc123',
|
||||
* keepAlive: '2m',
|
||||
* },
|
||||
* searchAfter: [1234, 'abcd'],
|
||||
* });
|
||||
*
|
||||
* await repository.closePointInTime(response.pit_id);
|
||||
* ```
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {object} [options] - {@link SavedObjectsClosePointInTimeOptions}
|
||||
* @returns {promise} - {@link SavedObjectsClosePointInTimeResponse}
|
||||
*/
|
||||
async closePointInTime(
|
||||
id: string,
|
||||
options?: SavedObjectsClosePointInTimeOptions
|
||||
): Promise<SavedObjectsClosePointInTimeResponse> {
|
||||
const { body } = await this.client.closePointInTime<SavedObjectsClosePointInTimeResponse>({
|
||||
body: { id },
|
||||
});
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index specified by the given type or the default index
|
||||
*
|
||||
|
|
|
@ -14,11 +14,13 @@ import { decorateEsError } from './decorate_es_error';
|
|||
|
||||
const methods = [
|
||||
'bulk',
|
||||
'closePointInTime',
|
||||
'create',
|
||||
'delete',
|
||||
'get',
|
||||
'index',
|
||||
'mget',
|
||||
'openPointInTime',
|
||||
'search',
|
||||
'update',
|
||||
'updateByQuery',
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { getPitParams } from './pit_params';
|
||||
|
||||
describe('searchDsl/getPitParams', () => {
|
||||
it('returns only an ID by default', () => {
|
||||
expect(getPitParams({ id: 'abc123' })).toEqual({
|
||||
pit: {
|
||||
id: 'abc123',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('includes keepAlive if provided and rewrites to snake case', () => {
|
||||
expect(getPitParams({ id: 'abc123', keepAlive: '2m' })).toEqual({
|
||||
pit: {
|
||||
id: 'abc123',
|
||||
keep_alive: '2m',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectsPitParams } from '../../../types';
|
||||
|
||||
export function getPitParams(pit: SavedObjectsPitParams) {
|
||||
return {
|
||||
pit: {
|
||||
id: pit.id,
|
||||
...(pit.keepAlive ? { keep_alive: pit.keepAlive } : {}),
|
||||
},
|
||||
};
|
||||
}
|
|
@ -6,14 +6,17 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
jest.mock('./pit_params');
|
||||
jest.mock('./query_params');
|
||||
jest.mock('./sorting_params');
|
||||
|
||||
import { typeRegistryMock } from '../../../saved_objects_type_registry.mock';
|
||||
import * as pitParamsNS from './pit_params';
|
||||
import * as queryParamsNS from './query_params';
|
||||
import { getSearchDsl } from './search_dsl';
|
||||
import * as sortParamsNS from './sorting_params';
|
||||
|
||||
const getPitParams = pitParamsNS.getPitParams as jest.Mock;
|
||||
const getQueryParams = queryParamsNS.getQueryParams as jest.Mock;
|
||||
const getSortingParams = sortParamsNS.getSortingParams as jest.Mock;
|
||||
|
||||
|
@ -84,6 +87,7 @@ describe('getSearchDsl', () => {
|
|||
type: 'foo',
|
||||
sortField: 'bar',
|
||||
sortOrder: 'baz',
|
||||
pit: { id: 'abc123' },
|
||||
};
|
||||
|
||||
getSearchDsl(mappings, registry, opts);
|
||||
|
@ -92,7 +96,8 @@ describe('getSearchDsl', () => {
|
|||
mappings,
|
||||
opts.type,
|
||||
opts.sortField,
|
||||
opts.sortOrder
|
||||
opts.sortOrder,
|
||||
opts.pit
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -101,5 +106,33 @@ describe('getSearchDsl', () => {
|
|||
getSortingParams.mockReturnValue({ b: 'b' });
|
||||
expect(getSearchDsl(mappings, registry, { type: 'foo' })).toEqual({ a: 'a', b: 'b' });
|
||||
});
|
||||
|
||||
it('returns searchAfter if provided', () => {
|
||||
getQueryParams.mockReturnValue({ a: 'a' });
|
||||
getSortingParams.mockReturnValue({ b: 'b' });
|
||||
expect(getSearchDsl(mappings, registry, { type: 'foo', searchAfter: [1, 'bar'] })).toEqual({
|
||||
a: 'a',
|
||||
b: 'b',
|
||||
search_after: [1, 'bar'],
|
||||
});
|
||||
});
|
||||
|
||||
it('returns pit if provided', () => {
|
||||
getQueryParams.mockReturnValue({ a: 'a' });
|
||||
getSortingParams.mockReturnValue({ b: 'b' });
|
||||
getPitParams.mockReturnValue({ pit: { id: 'abc123' } });
|
||||
expect(
|
||||
getSearchDsl(mappings, registry, {
|
||||
type: 'foo',
|
||||
searchAfter: [1, 'bar'],
|
||||
pit: { id: 'abc123' },
|
||||
})
|
||||
).toEqual({
|
||||
a: 'a',
|
||||
b: 'b',
|
||||
pit: { id: 'abc123' },
|
||||
search_after: [1, 'bar'],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
import Boom from '@hapi/boom';
|
||||
|
||||
import { IndexMapping } from '../../../mappings';
|
||||
import { SavedObjectsPitParams } from '../../../types';
|
||||
import { getQueryParams, HasReferenceQueryParams, SearchOperator } from './query_params';
|
||||
import { getPitParams } from './pit_params';
|
||||
import { getSortingParams } from './sorting_params';
|
||||
import { ISavedObjectTypeRegistry } from '../../../saved_objects_type_registry';
|
||||
|
||||
|
@ -21,9 +23,11 @@ interface GetSearchDslOptions {
|
|||
defaultSearchOperator?: SearchOperator;
|
||||
searchFields?: string[];
|
||||
rootSearchFields?: string[];
|
||||
searchAfter?: unknown[];
|
||||
sortField?: string;
|
||||
sortOrder?: string;
|
||||
namespaces?: string[];
|
||||
pit?: SavedObjectsPitParams;
|
||||
typeToNamespacesMap?: Map<string, string[] | undefined>;
|
||||
hasReference?: HasReferenceQueryParams | HasReferenceQueryParams[];
|
||||
hasReferenceOperator?: SearchOperator;
|
||||
|
@ -41,9 +45,11 @@ export function getSearchDsl(
|
|||
defaultSearchOperator,
|
||||
searchFields,
|
||||
rootSearchFields,
|
||||
searchAfter,
|
||||
sortField,
|
||||
sortOrder,
|
||||
namespaces,
|
||||
pit,
|
||||
typeToNamespacesMap,
|
||||
hasReference,
|
||||
hasReferenceOperator,
|
||||
|
@ -72,6 +78,8 @@ export function getSearchDsl(
|
|||
hasReferenceOperator,
|
||||
kueryNode,
|
||||
}),
|
||||
...getSortingParams(mappings, type, sortField, sortOrder),
|
||||
...getSortingParams(mappings, type, sortField, sortOrder, pit),
|
||||
...(pit ? getPitParams(pit) : {}),
|
||||
...(searchAfter ? { search_after: searchAfter } : {}),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -79,6 +79,11 @@ describe('searchDsl/getSortParams', () => {
|
|||
],
|
||||
});
|
||||
});
|
||||
it('appends tiebreaker when PIT is provided', () => {
|
||||
expect(getSortingParams(MAPPINGS, 'saved', 'title', undefined, { id: 'abc' }).sort).toEqual(
|
||||
expect.arrayContaining([{ _shard_doc: 'asc' }])
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('sortField is simple root property with multiple types', () => {
|
||||
it('returns correct params', () => {
|
||||
|
@ -93,6 +98,11 @@ describe('searchDsl/getSortParams', () => {
|
|||
],
|
||||
});
|
||||
});
|
||||
it('appends tiebreaker when PIT is provided', () => {
|
||||
expect(
|
||||
getSortingParams(MAPPINGS, ['saved', 'pending'], 'type', undefined, { id: 'abc' }).sort
|
||||
).toEqual(expect.arrayContaining([{ _shard_doc: 'asc' }]));
|
||||
});
|
||||
});
|
||||
describe('sortField is simple non-root property with multiple types', () => {
|
||||
it('returns correct params', () => {
|
||||
|
@ -114,6 +124,11 @@ describe('searchDsl/getSortParams', () => {
|
|||
],
|
||||
});
|
||||
});
|
||||
it('appends tiebreaker when PIT is provided', () => {
|
||||
expect(
|
||||
getSortingParams(MAPPINGS, 'saved', 'title.raw', undefined, { id: 'abc' }).sort
|
||||
).toEqual(expect.arrayContaining([{ _shard_doc: 'asc' }]));
|
||||
});
|
||||
});
|
||||
describe('sortField is multi-field with single type as array', () => {
|
||||
it('returns correct params', () => {
|
||||
|
@ -128,6 +143,11 @@ describe('searchDsl/getSortParams', () => {
|
|||
],
|
||||
});
|
||||
});
|
||||
it('appends tiebreaker when PIT is provided', () => {
|
||||
expect(
|
||||
getSortingParams(MAPPINGS, ['saved'], 'title.raw', undefined, { id: 'abc' }).sort
|
||||
).toEqual(expect.arrayContaining([{ _shard_doc: 'asc' }]));
|
||||
});
|
||||
});
|
||||
describe('sortField is root multi-field with multiple types', () => {
|
||||
it('returns correct params', () => {
|
||||
|
@ -142,6 +162,12 @@ describe('searchDsl/getSortParams', () => {
|
|||
],
|
||||
});
|
||||
});
|
||||
it('appends tiebreaker when PIT is provided', () => {
|
||||
expect(
|
||||
getSortingParams(MAPPINGS, ['saved', 'pending'], 'type.raw', undefined, { id: 'abc' })
|
||||
.sort
|
||||
).toEqual(expect.arrayContaining([{ _shard_doc: 'asc' }]));
|
||||
});
|
||||
});
|
||||
describe('sortField is not-root multi-field with multiple types', () => {
|
||||
it('returns correct params', () => {
|
||||
|
|
|
@ -8,6 +8,12 @@
|
|||
|
||||
import Boom from '@hapi/boom';
|
||||
import { getProperty, IndexMapping } from '../../../mappings';
|
||||
import { SavedObjectsPitParams } from '../../../types';
|
||||
|
||||
// TODO: The plan is for ES to automatically add this tiebreaker when
|
||||
// using PIT. We should remove this logic once that is resolved.
|
||||
// https://github.com/elastic/elasticsearch/issues/56828
|
||||
const ES_PROVIDED_TIEBREAKER = { _shard_doc: 'asc' };
|
||||
|
||||
const TOP_LEVEL_FIELDS = ['_id', '_score'];
|
||||
|
||||
|
@ -15,7 +21,8 @@ export function getSortingParams(
|
|||
mappings: IndexMapping,
|
||||
type: string | string[],
|
||||
sortField?: string,
|
||||
sortOrder?: string
|
||||
sortOrder?: string,
|
||||
pit?: SavedObjectsPitParams
|
||||
) {
|
||||
if (!sortField) {
|
||||
return {};
|
||||
|
@ -31,6 +38,7 @@ export function getSortingParams(
|
|||
order: sortOrder,
|
||||
},
|
||||
},
|
||||
...(pit ? [ES_PROVIDED_TIEBREAKER] : []),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
@ -51,6 +59,7 @@ export function getSortingParams(
|
|||
unmapped_type: rootField.type,
|
||||
},
|
||||
},
|
||||
...(pit ? [ES_PROVIDED_TIEBREAKER] : []),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
@ -75,6 +84,7 @@ export function getSortingParams(
|
|||
unmapped_type: field.type,
|
||||
},
|
||||
},
|
||||
...(pit ? [ES_PROVIDED_TIEBREAKER] : []),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ const create = () =>
|
|||
bulkGet: jest.fn(),
|
||||
find: jest.fn(),
|
||||
get: jest.fn(),
|
||||
closePointInTime: jest.fn(),
|
||||
openPointInTimeForType: jest.fn().mockResolvedValue({ id: 'some_pit_id' }),
|
||||
resolve: jest.fn(),
|
||||
update: jest.fn(),
|
||||
addToNamespaces: jest.fn(),
|
||||
|
|
|
@ -115,6 +115,36 @@ test(`#get`, async () => {
|
|||
expect(result).toBe(returnValue);
|
||||
});
|
||||
|
||||
test(`#openPointInTimeForType`, async () => {
|
||||
const returnValue = Symbol();
|
||||
const mockRepository = {
|
||||
openPointInTimeForType: jest.fn().mockResolvedValue(returnValue),
|
||||
};
|
||||
const client = new SavedObjectsClient(mockRepository);
|
||||
|
||||
const type = Symbol();
|
||||
const options = Symbol();
|
||||
const result = await client.openPointInTimeForType(type, options);
|
||||
|
||||
expect(mockRepository.openPointInTimeForType).toHaveBeenCalledWith(type, options);
|
||||
expect(result).toBe(returnValue);
|
||||
});
|
||||
|
||||
test(`#closePointInTime`, async () => {
|
||||
const returnValue = Symbol();
|
||||
const mockRepository = {
|
||||
closePointInTime: jest.fn().mockResolvedValue(returnValue),
|
||||
};
|
||||
const client = new SavedObjectsClient(mockRepository);
|
||||
|
||||
const id = Symbol();
|
||||
const options = Symbol();
|
||||
const result = await client.closePointInTime(id, options);
|
||||
|
||||
expect(mockRepository.closePointInTime).toHaveBeenCalledWith(id, options);
|
||||
expect(result).toBe(returnValue);
|
||||
});
|
||||
|
||||
test(`#resolve`, async () => {
|
||||
const returnValue = Symbol();
|
||||
const mockRepository = {
|
||||
|
|
|
@ -129,6 +129,35 @@ export interface SavedObjectsFindResult<T = unknown> extends SavedObject<T> {
|
|||
* The Elasticsearch `_score` of this result.
|
||||
*/
|
||||
score: number;
|
||||
/**
|
||||
* The Elasticsearch `sort` value of this result.
|
||||
*
|
||||
* @remarks
|
||||
* This can be passed directly to the `searchAfter` param in the {@link SavedObjectsFindOptions}
|
||||
* in order to page through large numbers of hits. It is recommended you use this alongside
|
||||
* a Point In Time (PIT) that was opened with {@link SavedObjectsClient.openPointInTimeForType}.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const { id } = await savedObjectsClient.openPointInTimeForType('visualization');
|
||||
* const page1 = await savedObjectsClient.find({
|
||||
* type: 'visualization',
|
||||
* sortField: 'updated_at',
|
||||
* sortOrder: 'asc',
|
||||
* pit: { id },
|
||||
* });
|
||||
* const lastHit = page1.saved_objects[page1.saved_objects.length - 1];
|
||||
* const page2 = await savedObjectsClient.find({
|
||||
* type: 'visualization',
|
||||
* sortField: 'updated_at',
|
||||
* sortOrder: 'asc',
|
||||
* pit: { id: page1.pit_id },
|
||||
* searchAfter: lastHit.sort,
|
||||
* });
|
||||
* await savedObjectsClient.closePointInTime(page2.pit_id);
|
||||
* ```
|
||||
*/
|
||||
sort?: unknown[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,6 +173,7 @@ export interface SavedObjectsFindResponse<T = unknown> {
|
|||
total: number;
|
||||
per_page: number;
|
||||
page: number;
|
||||
pit_id?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -311,6 +341,50 @@ export interface SavedObjectsResolveResponse<T = unknown> {
|
|||
outcome: 'exactMatch' | 'aliasMatch' | 'conflict';
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOptions {
|
||||
/**
|
||||
* Optionally specify how long ES should keep the PIT alive until the next request. Defaults to `5m`.
|
||||
*/
|
||||
keepAlive?: string;
|
||||
/**
|
||||
* An optional ES preference value to be used for the query.
|
||||
*/
|
||||
preference?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SavedObjectsOpenPointInTimeResponse {
|
||||
/**
|
||||
* PIT ID returned from ES.
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type SavedObjectsClosePointInTimeOptions = SavedObjectsBaseOptions;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SavedObjectsClosePointInTimeResponse {
|
||||
/**
|
||||
* If true, all search contexts associated with the PIT id are
|
||||
* successfully closed.
|
||||
*/
|
||||
succeeded: boolean;
|
||||
/**
|
||||
* The number of search contexts that have been successfully closed.
|
||||
*/
|
||||
num_freed: number;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @public
|
||||
|
@ -504,4 +578,25 @@ export class SavedObjectsClient {
|
|||
) {
|
||||
return await this._repository.removeReferencesTo(type, id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a Point In Time (PIT) against the indices for the specified Saved Object types.
|
||||
* The returned `id` can then be passed to {@link SavedObjectsClient.find} to search
|
||||
* against that PIT.
|
||||
*/
|
||||
async openPointInTimeForType(
|
||||
type: string | string[],
|
||||
options: SavedObjectsOpenPointInTimeOptions = {}
|
||||
) {
|
||||
return await this._repository.openPointInTimeForType(type, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a Point In Time (PIT) by ID. This simply proxies the request to ES via the
|
||||
* Elasticsearch client, and is included in the Saved Objects Client as a convenience
|
||||
* for consumers who are using {@link SavedObjectsClient.openPointInTimeForType}.
|
||||
*/
|
||||
async closePointInTime(id: string, options?: SavedObjectsClosePointInTimeOptions) {
|
||||
return await this._repository.closePointInTime(id, options);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,14 @@ export interface SavedObjectsFindOptionsReference {
|
|||
id: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface SavedObjectsPitParams {
|
||||
id: string;
|
||||
keepAlive?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @public
|
||||
|
@ -82,6 +90,10 @@ export interface SavedObjectsFindOptions {
|
|||
search?: string;
|
||||
/** The fields to perform the parsed query against. See Elasticsearch Simple Query String `fields` argument for more information */
|
||||
searchFields?: string[];
|
||||
/**
|
||||
* Use the sort values from the previous page to retrieve the next page of results.
|
||||
*/
|
||||
searchAfter?: unknown[];
|
||||
/**
|
||||
* The fields to perform the parsed query against. Unlike the `searchFields` argument, these are expected to be root fields and will not
|
||||
* be modified. If used in conjunction with `searchFields`, both are concatenated together.
|
||||
|
@ -114,6 +126,10 @@ export interface SavedObjectsFindOptions {
|
|||
typeToNamespacesMap?: Map<string, string[] | undefined>;
|
||||
/** An optional ES preference value to be used for the query **/
|
||||
preference?: string;
|
||||
/**
|
||||
* Search against a specific Point In Time (PIT) that you've opened with {@link SavedObjectsClient.openPointInTimeForType}.
|
||||
*/
|
||||
pit?: SavedObjectsPitParams;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2223,6 +2223,7 @@ export class SavedObjectsClient {
|
|||
bulkGet<T = unknown>(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise<SavedObjectsBulkResponse<T>>;
|
||||
bulkUpdate<T = unknown>(objects: Array<SavedObjectsBulkUpdateObject<T>>, options?: SavedObjectsBulkUpdateOptions): Promise<SavedObjectsBulkUpdateResponse<T>>;
|
||||
checkConflicts(objects?: SavedObjectsCheckConflictsObject[], options?: SavedObjectsBaseOptions): Promise<SavedObjectsCheckConflictsResponse>;
|
||||
closePointInTime(id: string, options?: SavedObjectsClosePointInTimeOptions): Promise<SavedObjectsClosePointInTimeResponse>;
|
||||
create<T = unknown>(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise<SavedObject<T>>;
|
||||
delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>;
|
||||
deleteFromNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions): Promise<SavedObjectsDeleteFromNamespacesResponse>;
|
||||
|
@ -2232,6 +2233,7 @@ export class SavedObjectsClient {
|
|||
errors: typeof SavedObjectsErrorHelpers;
|
||||
find<T = unknown>(options: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
|
||||
get<T = unknown>(type: string, id: string, options?: SavedObjectsBaseOptions): Promise<SavedObject<T>>;
|
||||
openPointInTimeForType(type: string | string[], options?: SavedObjectsOpenPointInTimeOptions): Promise<SavedObjectsOpenPointInTimeResponse>;
|
||||
removeReferencesTo(type: string, id: string, options?: SavedObjectsRemoveReferencesToOptions): Promise<SavedObjectsRemoveReferencesToResponse>;
|
||||
resolve<T = unknown>(type: string, id: string, options?: SavedObjectsBaseOptions): Promise<SavedObjectsResolveResponse<T>>;
|
||||
update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?: SavedObjectsUpdateOptions): Promise<SavedObjectsUpdateResponse<T>>;
|
||||
|
@ -2270,6 +2272,15 @@ export interface SavedObjectsClientWrapperOptions {
|
|||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type SavedObjectsClosePointInTimeOptions = SavedObjectsBaseOptions;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface SavedObjectsClosePointInTimeResponse {
|
||||
num_freed: number;
|
||||
succeeded: boolean;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface SavedObjectsComplexFieldMapping {
|
||||
// (undocumented)
|
||||
|
@ -2420,10 +2431,11 @@ export interface SavedObjectsExportByTypeOptions extends SavedObjectExportBaseOp
|
|||
export class SavedObjectsExporter {
|
||||
// (undocumented)
|
||||
#private;
|
||||
constructor({ savedObjectsClient, typeRegistry, exportSizeLimit, }: {
|
||||
constructor({ savedObjectsClient, typeRegistry, exportSizeLimit, logger, }: {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
exportSizeLimit: number;
|
||||
logger: Logger;
|
||||
});
|
||||
exportByObjects(options: SavedObjectsExportByObjectOptions): Promise<import("stream").Readable>;
|
||||
exportByTypes(options: SavedObjectsExportByTypeOptions): Promise<import("stream").Readable>;
|
||||
|
@ -2481,9 +2493,11 @@ export interface SavedObjectsFindOptions {
|
|||
page?: number;
|
||||
// (undocumented)
|
||||
perPage?: number;
|
||||
pit?: SavedObjectsPitParams;
|
||||
preference?: string;
|
||||
rootSearchFields?: string[];
|
||||
search?: string;
|
||||
searchAfter?: unknown[];
|
||||
searchFields?: string[];
|
||||
// (undocumented)
|
||||
sortField?: string;
|
||||
|
@ -2509,6 +2523,8 @@ export interface SavedObjectsFindResponse<T = unknown> {
|
|||
// (undocumented)
|
||||
per_page: number;
|
||||
// (undocumented)
|
||||
pit_id?: string;
|
||||
// (undocumented)
|
||||
saved_objects: Array<SavedObjectsFindResult<T>>;
|
||||
// (undocumented)
|
||||
total: number;
|
||||
|
@ -2517,6 +2533,7 @@ export interface SavedObjectsFindResponse<T = unknown> {
|
|||
// @public (undocumented)
|
||||
export interface SavedObjectsFindResult<T = unknown> extends SavedObject<T> {
|
||||
score: number;
|
||||
sort?: unknown[];
|
||||
}
|
||||
|
||||
// @public
|
||||
|
@ -2743,6 +2760,25 @@ export interface SavedObjectsMigrationVersion {
|
|||
// @public
|
||||
export type SavedObjectsNamespaceType = 'single' | 'multiple' | 'agnostic';
|
||||
|
||||
// @public (undocumented)
|
||||
export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOptions {
|
||||
keepAlive?: string;
|
||||
preference?: string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface SavedObjectsOpenPointInTimeResponse {
|
||||
id: string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface SavedObjectsPitParams {
|
||||
// (undocumented)
|
||||
id: string;
|
||||
// (undocumented)
|
||||
keepAlive?: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface SavedObjectsRawDoc {
|
||||
// (undocumented)
|
||||
|
@ -2779,6 +2815,7 @@ export class SavedObjectsRepository {
|
|||
bulkGet<T = unknown>(objects?: SavedObjectsBulkGetObject[], options?: SavedObjectsBaseOptions): Promise<SavedObjectsBulkResponse<T>>;
|
||||
bulkUpdate<T = unknown>(objects: Array<SavedObjectsBulkUpdateObject<T>>, options?: SavedObjectsBulkUpdateOptions): Promise<SavedObjectsBulkUpdateResponse<T>>;
|
||||
checkConflicts(objects?: SavedObjectsCheckConflictsObject[], options?: SavedObjectsBaseOptions): Promise<SavedObjectsCheckConflictsResponse>;
|
||||
closePointInTime(id: string, options?: SavedObjectsClosePointInTimeOptions): Promise<SavedObjectsClosePointInTimeResponse>;
|
||||
create<T = unknown>(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise<SavedObject<T>>;
|
||||
// Warning: (ae-forgotten-export) The symbol "IKibanaMigrator" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
|
@ -2791,6 +2828,7 @@ export class SavedObjectsRepository {
|
|||
find<T = unknown>(options: SavedObjectsFindOptions): Promise<SavedObjectsFindResponse<T>>;
|
||||
get<T = unknown>(type: string, id: string, options?: SavedObjectsBaseOptions): Promise<SavedObject<T>>;
|
||||
incrementCounter<T = unknown>(type: string, id: string, counterFields: Array<string | SavedObjectsIncrementCounterField>, options?: SavedObjectsIncrementCounterOptions): Promise<SavedObject<T>>;
|
||||
openPointInTimeForType(type: string | string[], { keepAlive, preference }?: SavedObjectsOpenPointInTimeOptions): Promise<SavedObjectsOpenPointInTimeResponse>;
|
||||
removeReferencesTo(type: string, id: string, options?: SavedObjectsRemoveReferencesToOptions): Promise<SavedObjectsRemoveReferencesToResponse>;
|
||||
resolve<T = unknown>(type: string, id: string, options?: SavedObjectsBaseOptions): Promise<SavedObjectsResolveResponse<T>>;
|
||||
update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?: SavedObjectsUpdateOptions): Promise<SavedObjectsUpdateResponse<T>>;
|
||||
|
@ -2955,10 +2993,12 @@ export interface SearchResponse<T = unknown> {
|
|||
highlight?: any;
|
||||
inner_hits?: any;
|
||||
matched_queries?: string[];
|
||||
sort?: string[];
|
||||
sort?: unknown[];
|
||||
}>;
|
||||
};
|
||||
// (undocumented)
|
||||
pit_id?: string;
|
||||
// (undocumented)
|
||||
_scroll_id?: string;
|
||||
// (undocumented)
|
||||
_shards: ShardsResponse;
|
||||
|
|
|
@ -31,6 +31,7 @@ export type {
|
|||
SavedObjectStatusMeta,
|
||||
SavedObjectsFindOptionsReference,
|
||||
SavedObjectsFindOptions,
|
||||
SavedObjectsPitParams,
|
||||
SavedObjectsBaseOptions,
|
||||
MutatingOperationRefreshSetting,
|
||||
SavedObjectsClientContract,
|
||||
|
|
|
@ -1138,7 +1138,7 @@ export class Plugin implements Plugin_2<PluginSetup, PluginStart, DataPluginSetu
|
|||
fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise<import("../common").FieldFormatsRegistry>;
|
||||
};
|
||||
indexPatterns: {
|
||||
indexPatternsServiceFactory: (savedObjectsClient: Pick<import("../../../core/server").SavedObjectsClient, "get" | "delete" | "create" | "update" | "bulkCreate" | "checkConflicts" | "find" | "bulkGet" | "resolve" | "addToNamespaces" | "deleteFromNamespaces" | "bulkUpdate" | "removeReferencesTo" | "errors">, elasticsearchClient: import("../../../core/server").ElasticsearchClient) => Promise<import("../public").IndexPatternsService>;
|
||||
indexPatternsServiceFactory: (savedObjectsClient: Pick<import("../../../core/server").SavedObjectsClient, "get" | "delete" | "closePointInTime" | "create" | "update" | "bulkCreate" | "checkConflicts" | "find" | "bulkGet" | "resolve" | "addToNamespaces" | "deleteFromNamespaces" | "bulkUpdate" | "removeReferencesTo" | "openPointInTimeForType" | "errors">, elasticsearchClient: import("../../../core/server").ElasticsearchClient) => Promise<import("../public").IndexPatternsService>;
|
||||
};
|
||||
search: ISearchStart<import("./search").IEsSearchRequest, import("./search").IEsSearchResponse<any>>;
|
||||
};
|
||||
|
|
|
@ -295,43 +295,43 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
);
|
||||
expect(resp.header['content-type']).to.eql('application/ndjson');
|
||||
const objects = ndjsonToObject(resp.text);
|
||||
expect(objects).to.eql([
|
||||
{
|
||||
attributes: {
|
||||
description: '',
|
||||
hits: 0,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
objects[0].attributes.kibanaSavedObjectMeta.searchSourceJSON,
|
||||
},
|
||||
optionsJSON: objects[0].attributes.optionsJSON,
|
||||
panelsJSON: objects[0].attributes.panelsJSON,
|
||||
refreshInterval: {
|
||||
display: 'Off',
|
||||
pause: false,
|
||||
value: 0,
|
||||
},
|
||||
timeFrom: 'Wed Sep 16 2015 22:52:17 GMT-0700',
|
||||
timeRestore: true,
|
||||
timeTo: 'Fri Sep 18 2015 12:24:38 GMT-0700',
|
||||
title: 'Requests',
|
||||
version: 1,
|
||||
|
||||
// Sort values aren't deterministic so we need to exclude them
|
||||
const { sort, ...obj } = objects[0];
|
||||
expect(obj).to.eql({
|
||||
attributes: {
|
||||
description: '',
|
||||
hits: 0,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: objects[0].attributes.kibanaSavedObjectMeta.searchSourceJSON,
|
||||
},
|
||||
id: 'be3733a0-9efe-11e7-acb3-3dab96693fab',
|
||||
migrationVersion: objects[0].migrationVersion,
|
||||
coreMigrationVersion: KIBANA_VERSION,
|
||||
references: [
|
||||
{
|
||||
id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
|
||||
name: 'panel_0',
|
||||
type: 'visualization',
|
||||
},
|
||||
],
|
||||
type: 'dashboard',
|
||||
updated_at: '2017-09-21T18:57:40.826Z',
|
||||
version: objects[0].version,
|
||||
optionsJSON: objects[0].attributes.optionsJSON,
|
||||
panelsJSON: objects[0].attributes.panelsJSON,
|
||||
refreshInterval: {
|
||||
display: 'Off',
|
||||
pause: false,
|
||||
value: 0,
|
||||
},
|
||||
timeFrom: 'Wed Sep 16 2015 22:52:17 GMT-0700',
|
||||
timeRestore: true,
|
||||
timeTo: 'Fri Sep 18 2015 12:24:38 GMT-0700',
|
||||
title: 'Requests',
|
||||
version: 1,
|
||||
},
|
||||
]);
|
||||
id: 'be3733a0-9efe-11e7-acb3-3dab96693fab',
|
||||
migrationVersion: objects[0].migrationVersion,
|
||||
coreMigrationVersion: KIBANA_VERSION,
|
||||
references: [
|
||||
{
|
||||
id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
|
||||
name: 'panel_0',
|
||||
type: 'visualization',
|
||||
},
|
||||
],
|
||||
type: 'dashboard',
|
||||
updated_at: '2017-09-21T18:57:40.826Z',
|
||||
version: objects[0].version,
|
||||
});
|
||||
expect(objects[0].migrationVersion).to.be.ok();
|
||||
expect(() =>
|
||||
JSON.parse(objects[0].attributes.kibanaSavedObjectMeta.searchSourceJSON)
|
||||
|
@ -355,43 +355,43 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
);
|
||||
expect(resp.header['content-type']).to.eql('application/ndjson');
|
||||
const objects = ndjsonToObject(resp.text);
|
||||
expect(objects).to.eql([
|
||||
{
|
||||
attributes: {
|
||||
description: '',
|
||||
hits: 0,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
objects[0].attributes.kibanaSavedObjectMeta.searchSourceJSON,
|
||||
},
|
||||
optionsJSON: objects[0].attributes.optionsJSON,
|
||||
panelsJSON: objects[0].attributes.panelsJSON,
|
||||
refreshInterval: {
|
||||
display: 'Off',
|
||||
pause: false,
|
||||
value: 0,
|
||||
},
|
||||
timeFrom: 'Wed Sep 16 2015 22:52:17 GMT-0700',
|
||||
timeRestore: true,
|
||||
timeTo: 'Fri Sep 18 2015 12:24:38 GMT-0700',
|
||||
title: 'Requests',
|
||||
version: 1,
|
||||
|
||||
// Sort values aren't deterministic so we need to exclude them
|
||||
const { sort, ...obj } = objects[0];
|
||||
expect(obj).to.eql({
|
||||
attributes: {
|
||||
description: '',
|
||||
hits: 0,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: objects[0].attributes.kibanaSavedObjectMeta.searchSourceJSON,
|
||||
},
|
||||
id: 'be3733a0-9efe-11e7-acb3-3dab96693fab',
|
||||
migrationVersion: objects[0].migrationVersion,
|
||||
coreMigrationVersion: KIBANA_VERSION,
|
||||
references: [
|
||||
{
|
||||
id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
|
||||
name: 'panel_0',
|
||||
type: 'visualization',
|
||||
},
|
||||
],
|
||||
type: 'dashboard',
|
||||
updated_at: '2017-09-21T18:57:40.826Z',
|
||||
version: objects[0].version,
|
||||
optionsJSON: objects[0].attributes.optionsJSON,
|
||||
panelsJSON: objects[0].attributes.panelsJSON,
|
||||
refreshInterval: {
|
||||
display: 'Off',
|
||||
pause: false,
|
||||
value: 0,
|
||||
},
|
||||
timeFrom: 'Wed Sep 16 2015 22:52:17 GMT-0700',
|
||||
timeRestore: true,
|
||||
timeTo: 'Fri Sep 18 2015 12:24:38 GMT-0700',
|
||||
title: 'Requests',
|
||||
version: 1,
|
||||
},
|
||||
]);
|
||||
id: 'be3733a0-9efe-11e7-acb3-3dab96693fab',
|
||||
migrationVersion: objects[0].migrationVersion,
|
||||
coreMigrationVersion: KIBANA_VERSION,
|
||||
references: [
|
||||
{
|
||||
id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
|
||||
name: 'panel_0',
|
||||
type: 'visualization',
|
||||
},
|
||||
],
|
||||
type: 'dashboard',
|
||||
updated_at: '2017-09-21T18:57:40.826Z',
|
||||
version: objects[0].version,
|
||||
});
|
||||
expect(objects[0].migrationVersion).to.be.ok();
|
||||
expect(() =>
|
||||
JSON.parse(objects[0].attributes.kibanaSavedObjectMeta.searchSourceJSON)
|
||||
|
@ -420,43 +420,43 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
);
|
||||
expect(resp.header['content-type']).to.eql('application/ndjson');
|
||||
const objects = ndjsonToObject(resp.text);
|
||||
expect(objects).to.eql([
|
||||
{
|
||||
attributes: {
|
||||
description: '',
|
||||
hits: 0,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
objects[0].attributes.kibanaSavedObjectMeta.searchSourceJSON,
|
||||
},
|
||||
optionsJSON: objects[0].attributes.optionsJSON,
|
||||
panelsJSON: objects[0].attributes.panelsJSON,
|
||||
refreshInterval: {
|
||||
display: 'Off',
|
||||
pause: false,
|
||||
value: 0,
|
||||
},
|
||||
timeFrom: 'Wed Sep 16 2015 22:52:17 GMT-0700',
|
||||
timeRestore: true,
|
||||
timeTo: 'Fri Sep 18 2015 12:24:38 GMT-0700',
|
||||
title: 'Requests',
|
||||
version: 1,
|
||||
|
||||
// Sort values aren't deterministic so we need to exclude them
|
||||
const { sort, ...obj } = objects[0];
|
||||
expect(obj).to.eql({
|
||||
attributes: {
|
||||
description: '',
|
||||
hits: 0,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: objects[0].attributes.kibanaSavedObjectMeta.searchSourceJSON,
|
||||
},
|
||||
id: 'be3733a0-9efe-11e7-acb3-3dab96693fab',
|
||||
migrationVersion: objects[0].migrationVersion,
|
||||
coreMigrationVersion: KIBANA_VERSION,
|
||||
references: [
|
||||
{
|
||||
id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
|
||||
name: 'panel_0',
|
||||
type: 'visualization',
|
||||
},
|
||||
],
|
||||
type: 'dashboard',
|
||||
updated_at: '2017-09-21T18:57:40.826Z',
|
||||
version: objects[0].version,
|
||||
optionsJSON: objects[0].attributes.optionsJSON,
|
||||
panelsJSON: objects[0].attributes.panelsJSON,
|
||||
refreshInterval: {
|
||||
display: 'Off',
|
||||
pause: false,
|
||||
value: 0,
|
||||
},
|
||||
timeFrom: 'Wed Sep 16 2015 22:52:17 GMT-0700',
|
||||
timeRestore: true,
|
||||
timeTo: 'Fri Sep 18 2015 12:24:38 GMT-0700',
|
||||
title: 'Requests',
|
||||
version: 1,
|
||||
},
|
||||
]);
|
||||
id: 'be3733a0-9efe-11e7-acb3-3dab96693fab',
|
||||
migrationVersion: objects[0].migrationVersion,
|
||||
coreMigrationVersion: KIBANA_VERSION,
|
||||
references: [
|
||||
{
|
||||
id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
|
||||
name: 'panel_0',
|
||||
type: 'visualization',
|
||||
},
|
||||
],
|
||||
type: 'dashboard',
|
||||
updated_at: '2017-09-21T18:57:40.826Z',
|
||||
version: objects[0].version,
|
||||
});
|
||||
expect(objects[0].migrationVersion).to.be.ok();
|
||||
expect(() =>
|
||||
JSON.parse(objects[0].attributes.kibanaSavedObjectMeta.searchSourceJSON)
|
||||
|
@ -511,7 +511,37 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await esArchiver.unload('saved_objects/10k');
|
||||
});
|
||||
|
||||
it('should return 400 when exporting more than 10,000', async () => {
|
||||
it('should allow exporting more than 10,000 objects if permitted by maxImportExportSize', async () => {
|
||||
await supertest
|
||||
.post('/api/saved_objects/_export')
|
||||
.send({
|
||||
type: ['dashboard', 'visualization', 'search', 'index-pattern'],
|
||||
excludeExportDetails: true,
|
||||
})
|
||||
.expect(200)
|
||||
.then((resp) => {
|
||||
expect(resp.header['content-disposition']).to.eql(
|
||||
'attachment; filename="export.ndjson"'
|
||||
);
|
||||
expect(resp.header['content-type']).to.eql('application/ndjson');
|
||||
const objects = ndjsonToObject(resp.text);
|
||||
expect(objects.length).to.eql(10001);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 400 when exporting more than allowed by maxImportExportSize', async () => {
|
||||
let anotherCustomVisId: string;
|
||||
await supertest
|
||||
.post('/api/saved_objects/visualization')
|
||||
.send({
|
||||
attributes: {
|
||||
title: 'My other favorite vis',
|
||||
},
|
||||
})
|
||||
.expect(200)
|
||||
.then((resp) => {
|
||||
anotherCustomVisId = resp.body.id;
|
||||
});
|
||||
await supertest
|
||||
.post('/api/saved_objects/_export')
|
||||
.send({
|
||||
|
@ -523,9 +553,13 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(resp.body).to.eql({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: `Can't export more than 10000 objects`,
|
||||
message: `Can't export more than 10001 objects`,
|
||||
});
|
||||
});
|
||||
await supertest
|
||||
// @ts-expect-error TS complains about using `anotherCustomVisId` before it is assigned
|
||||
.delete(`/api/saved_objects/visualization/${anotherCustomVisId}`)
|
||||
.expect(200);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -166,7 +166,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
it('should return 400 when trying to import more than 10,000 objects', async () => {
|
||||
const fileChunks = [];
|
||||
for (let i = 0; i < 10001; i++) {
|
||||
for (let i = 0; i <= 10001; i++) {
|
||||
fileChunks.push(`{"type":"visualization","id":"${i}","attributes":{},"references":[]}`);
|
||||
}
|
||||
await supertest
|
||||
|
@ -177,7 +177,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(resp.body).to.eql({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: "Can't import more than 10000 objects",
|
||||
message: "Can't import more than 10001 objects",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -167,9 +167,9 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should return 400 when resolving conflicts with a file containing more than 10,000 objects', async () => {
|
||||
it('should return 400 when resolving conflicts with a file containing more than 10,001 objects', async () => {
|
||||
const fileChunks = [];
|
||||
for (let i = 0; i < 10001; i++) {
|
||||
for (let i = 0; i <= 10001; i++) {
|
||||
fileChunks.push(`{"type":"visualization","id":"${i}","attributes":{},"references":[]}`);
|
||||
}
|
||||
await supertest
|
||||
|
@ -181,7 +181,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(resp.body).to.eql({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: "Can't import more than 10000 objects",
|
||||
message: "Can't import more than 10001 objects",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -30,6 +30,7 @@ export default async function ({ readConfigFile }) {
|
|||
'--elasticsearch.healthCheck.delay=3600000',
|
||||
'--server.xsrf.disableProtection=true',
|
||||
'--server.compression.referrerWhitelist=["some-host.com"]',
|
||||
`--savedObjects.maxImportExportSize=10001`,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1757,3 +1757,65 @@ describe('#removeReferencesTo', () => {
|
|||
expect(mockBaseClient.removeReferencesTo).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#openPointInTimeForType', () => {
|
||||
it('redirects request to underlying base client', async () => {
|
||||
const options = { keepAlive: '1m' };
|
||||
|
||||
await wrapper.openPointInTimeForType('some-type', options);
|
||||
|
||||
expect(mockBaseClient.openPointInTimeForType).toHaveBeenCalledTimes(1);
|
||||
expect(mockBaseClient.openPointInTimeForType).toHaveBeenCalledWith('some-type', options);
|
||||
});
|
||||
|
||||
it('returns response from underlying client', async () => {
|
||||
const returnValue = {
|
||||
id: 'abc123',
|
||||
};
|
||||
mockBaseClient.openPointInTimeForType.mockResolvedValue(returnValue);
|
||||
|
||||
const result = await wrapper.openPointInTimeForType('known-type');
|
||||
|
||||
expect(result).toBe(returnValue);
|
||||
});
|
||||
|
||||
it('fails if base client fails', async () => {
|
||||
const failureReason = new Error('Something bad happened...');
|
||||
mockBaseClient.openPointInTimeForType.mockRejectedValue(failureReason);
|
||||
|
||||
await expect(wrapper.openPointInTimeForType('known-type')).rejects.toThrowError(failureReason);
|
||||
|
||||
expect(mockBaseClient.openPointInTimeForType).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#closePointInTime', () => {
|
||||
it('redirects request to underlying base client', async () => {
|
||||
const id = 'abc123';
|
||||
await wrapper.closePointInTime(id);
|
||||
|
||||
expect(mockBaseClient.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
expect(mockBaseClient.closePointInTime).toHaveBeenCalledWith(id, undefined);
|
||||
});
|
||||
|
||||
it('returns response from underlying client', async () => {
|
||||
const returnValue = {
|
||||
succeeded: true,
|
||||
num_freed: 1,
|
||||
};
|
||||
mockBaseClient.closePointInTime.mockResolvedValue(returnValue);
|
||||
|
||||
const result = await wrapper.closePointInTime('abc123');
|
||||
|
||||
expect(result).toBe(returnValue);
|
||||
});
|
||||
|
||||
it('fails if base client fails', async () => {
|
||||
const failureReason = new Error('Something bad happened...');
|
||||
mockBaseClient.closePointInTime.mockRejectedValue(failureReason);
|
||||
|
||||
await expect(wrapper.closePointInTime('abc123')).rejects.toThrowError(failureReason);
|
||||
|
||||
expect(mockBaseClient.closePointInTime).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,9 +15,11 @@ import {
|
|||
SavedObjectsBulkUpdateResponse,
|
||||
SavedObjectsCheckConflictsObject,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsClosePointInTimeOptions,
|
||||
SavedObjectsCreateOptions,
|
||||
SavedObjectsFindOptions,
|
||||
SavedObjectsFindResponse,
|
||||
SavedObjectsOpenPointInTimeOptions,
|
||||
SavedObjectsUpdateOptions,
|
||||
SavedObjectsUpdateResponse,
|
||||
SavedObjectsAddToNamespacesOptions,
|
||||
|
@ -249,6 +251,17 @@ export class EncryptedSavedObjectsClientWrapper implements SavedObjectsClientCon
|
|||
return await this.options.baseClient.removeReferencesTo(type, id, options);
|
||||
}
|
||||
|
||||
public async openPointInTimeForType(
|
||||
type: string | string[],
|
||||
options: SavedObjectsOpenPointInTimeOptions = {}
|
||||
) {
|
||||
return await this.options.baseClient.openPointInTimeForType(type, options);
|
||||
}
|
||||
|
||||
public async closePointInTime(id: string, options?: SavedObjectsClosePointInTimeOptions) {
|
||||
return await this.options.baseClient.closePointInTime(id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips encrypted attributes from any non-bulk Saved Objects API response. If type isn't
|
||||
* registered, response is returned as is.
|
||||
|
|
|
@ -190,6 +190,8 @@ export enum SavedObjectAction {
|
|||
ADD_TO_SPACES = 'saved_object_add_to_spaces',
|
||||
DELETE_FROM_SPACES = 'saved_object_delete_from_spaces',
|
||||
REMOVE_REFERENCES = 'saved_object_remove_references',
|
||||
OPEN_POINT_IN_TIME = 'saved_object_open_point_in_time',
|
||||
CLOSE_POINT_IN_TIME = 'saved_object_close_point_in_time',
|
||||
}
|
||||
|
||||
type VerbsTuple = [string, string, string];
|
||||
|
@ -203,6 +205,16 @@ const savedObjectAuditVerbs: Record<SavedObjectAction, VerbsTuple> = {
|
|||
saved_object_find: ['access', 'accessing', 'accessed'],
|
||||
saved_object_add_to_spaces: ['update', 'updating', 'updated'],
|
||||
saved_object_delete_from_spaces: ['update', 'updating', 'updated'],
|
||||
saved_object_open_point_in_time: [
|
||||
'open point-in-time',
|
||||
'opening point-in-time',
|
||||
'opened point-in-time',
|
||||
],
|
||||
saved_object_close_point_in_time: [
|
||||
'close point-in-time',
|
||||
'closing point-in-time',
|
||||
'closed point-in-time',
|
||||
],
|
||||
saved_object_remove_references: [
|
||||
'remove references to',
|
||||
'removing references to',
|
||||
|
@ -219,6 +231,8 @@ const savedObjectAuditTypes: Record<SavedObjectAction, EventType> = {
|
|||
saved_object_find: EventType.ACCESS,
|
||||
saved_object_add_to_spaces: EventType.CHANGE,
|
||||
saved_object_delete_from_spaces: EventType.CHANGE,
|
||||
saved_object_open_point_in_time: EventType.CREATION,
|
||||
saved_object_close_point_in_time: EventType.DELETION,
|
||||
saved_object_remove_references: EventType.CHANGE,
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,13 @@ import { flatten, uniq } from 'lodash';
|
|||
import { FeatureKibanaPrivileges } from '../../../../../features/server';
|
||||
import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder';
|
||||
|
||||
const readOperations: string[] = ['bulk_get', 'get', 'find'];
|
||||
const readOperations: string[] = [
|
||||
'bulk_get',
|
||||
'get',
|
||||
'find',
|
||||
'open_point_in_time',
|
||||
'close_point_in_time',
|
||||
];
|
||||
const writeOperations: string[] = [
|
||||
'create',
|
||||
'bulk_create',
|
||||
|
|
|
@ -101,6 +101,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('all-savedObject-all-1', 'bulk_get'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'get'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'find'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'create'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'bulk_create'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'update'),
|
||||
|
@ -110,6 +112,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('all-savedObject-all-2', 'bulk_get'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'get'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'find'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'create'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'bulk_create'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'update'),
|
||||
|
@ -119,9 +123,13 @@ describe('features', () => {
|
|||
actions.savedObject.get('all-savedObject-read-1', 'bulk_get'),
|
||||
actions.savedObject.get('all-savedObject-read-1', 'get'),
|
||||
actions.savedObject.get('all-savedObject-read-1', 'find'),
|
||||
actions.savedObject.get('all-savedObject-read-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-read-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'bulk_get'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'get'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'find'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'all-ui-1'),
|
||||
actions.ui.get('foo', 'all-ui-2'),
|
||||
];
|
||||
|
@ -132,6 +140,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('read-savedObject-all-1', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'get'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'find'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'create'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'bulk_create'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'update'),
|
||||
|
@ -141,6 +151,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('read-savedObject-all-2', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'get'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'find'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'create'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'bulk_create'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'update'),
|
||||
|
@ -150,9 +162,13 @@ describe('features', () => {
|
|||
actions.savedObject.get('read-savedObject-read-1', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'get'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'find'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'get'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'find'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'read-ui-1'),
|
||||
actions.ui.get('foo', 'read-ui-2'),
|
||||
];
|
||||
|
@ -274,6 +290,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('all-savedObject-all-1', 'bulk_get'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'get'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'find'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'create'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'bulk_create'),
|
||||
actions.savedObject.get('all-savedObject-all-1', 'update'),
|
||||
|
@ -283,6 +301,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('all-savedObject-all-2', 'bulk_get'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'get'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'find'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'create'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'bulk_create'),
|
||||
actions.savedObject.get('all-savedObject-all-2', 'update'),
|
||||
|
@ -292,9 +312,13 @@ describe('features', () => {
|
|||
actions.savedObject.get('all-savedObject-read-1', 'bulk_get'),
|
||||
actions.savedObject.get('all-savedObject-read-1', 'get'),
|
||||
actions.savedObject.get('all-savedObject-read-1', 'find'),
|
||||
actions.savedObject.get('all-savedObject-read-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-read-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'bulk_get'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'get'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'find'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-savedObject-read-2', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'all-ui-1'),
|
||||
actions.ui.get('foo', 'all-ui-2'),
|
||||
actions.ui.get('catalogue', 'read-catalogue-1'),
|
||||
|
@ -304,6 +328,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('read-savedObject-all-1', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'get'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'find'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'create'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'bulk_create'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'update'),
|
||||
|
@ -313,6 +339,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('read-savedObject-all-2', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'get'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'find'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'create'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'bulk_create'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'update'),
|
||||
|
@ -322,9 +350,13 @@ describe('features', () => {
|
|||
actions.savedObject.get('read-savedObject-read-1', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'get'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'find'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'get'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'find'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'read-ui-1'),
|
||||
actions.ui.get('foo', 'read-ui-2'),
|
||||
]);
|
||||
|
@ -388,6 +420,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('read-savedObject-all-1', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'get'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'find'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'create'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'bulk_create'),
|
||||
actions.savedObject.get('read-savedObject-all-1', 'update'),
|
||||
|
@ -397,6 +431,8 @@ describe('features', () => {
|
|||
actions.savedObject.get('read-savedObject-all-2', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'get'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'find'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'create'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'bulk_create'),
|
||||
actions.savedObject.get('read-savedObject-all-2', 'update'),
|
||||
|
@ -406,9 +442,13 @@ describe('features', () => {
|
|||
actions.savedObject.get('read-savedObject-read-1', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'get'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'find'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-read-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'bulk_get'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'get'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'find'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-savedObject-read-2', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'read-ui-1'),
|
||||
actions.ui.get('foo', 'read-ui-2'),
|
||||
]);
|
||||
|
@ -691,6 +731,8 @@ describe('reserved', () => {
|
|||
actions.savedObject.get('savedObject-all-1', 'bulk_get'),
|
||||
actions.savedObject.get('savedObject-all-1', 'get'),
|
||||
actions.savedObject.get('savedObject-all-1', 'find'),
|
||||
actions.savedObject.get('savedObject-all-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('savedObject-all-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('savedObject-all-1', 'create'),
|
||||
actions.savedObject.get('savedObject-all-1', 'bulk_create'),
|
||||
actions.savedObject.get('savedObject-all-1', 'update'),
|
||||
|
@ -700,6 +742,8 @@ describe('reserved', () => {
|
|||
actions.savedObject.get('savedObject-all-2', 'bulk_get'),
|
||||
actions.savedObject.get('savedObject-all-2', 'get'),
|
||||
actions.savedObject.get('savedObject-all-2', 'find'),
|
||||
actions.savedObject.get('savedObject-all-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('savedObject-all-2', 'close_point_in_time'),
|
||||
actions.savedObject.get('savedObject-all-2', 'create'),
|
||||
actions.savedObject.get('savedObject-all-2', 'bulk_create'),
|
||||
actions.savedObject.get('savedObject-all-2', 'update'),
|
||||
|
@ -709,9 +753,13 @@ describe('reserved', () => {
|
|||
actions.savedObject.get('savedObject-read-1', 'bulk_get'),
|
||||
actions.savedObject.get('savedObject-read-1', 'get'),
|
||||
actions.savedObject.get('savedObject-read-1', 'find'),
|
||||
actions.savedObject.get('savedObject-read-1', 'open_point_in_time'),
|
||||
actions.savedObject.get('savedObject-read-1', 'close_point_in_time'),
|
||||
actions.savedObject.get('savedObject-read-2', 'bulk_get'),
|
||||
actions.savedObject.get('savedObject-read-2', 'get'),
|
||||
actions.savedObject.get('savedObject-read-2', 'find'),
|
||||
actions.savedObject.get('savedObject-read-2', 'open_point_in_time'),
|
||||
actions.savedObject.get('savedObject-read-2', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'ui-1'),
|
||||
actions.ui.get('foo', 'ui-2'),
|
||||
]);
|
||||
|
@ -823,6 +871,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -832,6 +882,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
||||
|
@ -952,6 +1004,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -961,6 +1015,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
||||
|
@ -970,6 +1026,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -979,6 +1037,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -995,6 +1055,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1004,6 +1066,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1026,6 +1090,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1035,6 +1101,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1044,6 +1112,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1053,6 +1123,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1063,6 +1135,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1072,6 +1146,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1081,6 +1157,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1090,6 +1168,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1160,6 +1240,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1169,6 +1251,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
||||
|
@ -1178,6 +1262,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1187,6 +1273,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1203,6 +1291,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1212,6 +1302,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1304,6 +1396,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1313,6 +1407,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
||||
|
@ -1322,6 +1418,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1331,6 +1429,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1365,6 +1465,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1374,6 +1476,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1389,6 +1493,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1398,6 +1504,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1473,6 +1581,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1482,6 +1592,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
||||
|
@ -1491,6 +1603,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1500,6 +1614,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1606,6 +1722,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1615,6 +1733,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1627,6 +1747,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1636,6 +1758,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1654,6 +1778,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1663,6 +1789,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1672,6 +1800,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1681,6 +1811,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1691,6 +1823,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1700,6 +1834,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1709,6 +1845,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1718,6 +1856,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1808,6 +1948,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1817,6 +1959,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1833,6 +1977,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1842,6 +1988,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1864,6 +2012,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1873,6 +2023,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1882,6 +2034,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1891,6 +2045,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1901,6 +2057,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1910,6 +2068,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -1919,6 +2079,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -1928,6 +2090,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
]);
|
||||
|
@ -2018,6 +2182,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -2027,6 +2193,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'update'),
|
||||
|
@ -2036,9 +2204,13 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
actions.ui.get('foo', 'licensed-sub-feature-ui'),
|
||||
|
@ -2056,6 +2228,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -2065,6 +2239,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'update'),
|
||||
|
@ -2074,9 +2250,13 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
actions.ui.get('foo', 'licensed-sub-feature-ui'),
|
||||
|
@ -2100,6 +2280,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -2109,6 +2291,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'update'),
|
||||
|
@ -2118,9 +2302,13 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
actions.ui.get('foo', 'licensed-sub-feature-ui'),
|
||||
|
@ -2131,6 +2319,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -2140,6 +2330,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'update'),
|
||||
|
@ -2149,9 +2341,13 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
actions.ui.get('foo', 'licensed-sub-feature-ui'),
|
||||
|
@ -2163,6 +2359,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -2172,6 +2370,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'update'),
|
||||
|
@ -2181,9 +2381,13 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
actions.ui.get('foo', 'licensed-sub-feature-ui'),
|
||||
|
@ -2194,6 +2398,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-sub-feature-type', 'update'),
|
||||
|
@ -2203,6 +2409,8 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'bulk_create'),
|
||||
actions.savedObject.get('all-licensed-sub-feature-type', 'update'),
|
||||
|
@ -2212,9 +2420,13 @@ describe('subFeatures', () => {
|
|||
actions.savedObject.get('read-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-sub-feature-type', 'close_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'bulk_get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'get'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'find'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'open_point_in_time'),
|
||||
actions.savedObject.get('read-licensed-sub-feature-type', 'close_point_in_time'),
|
||||
actions.ui.get('foo', 'foo'),
|
||||
actions.ui.get('foo', 'sub-feature-ui'),
|
||||
actions.ui.get('foo', 'licensed-sub-feature-ui'),
|
||||
|
|
|
@ -905,6 +905,17 @@ describe('#find', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test(`throws BadRequestError when searching across namespaces when pit is provided`, async () => {
|
||||
const options = {
|
||||
type: [type1, type2],
|
||||
pit: { id: 'abc123' },
|
||||
namespaces: ['some-ns', 'another-ns'],
|
||||
};
|
||||
await expect(client.find(options)).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"_find across namespaces is not permitted when using the \`pit\` option."`
|
||||
);
|
||||
});
|
||||
|
||||
test(`checks privileges for user, actions, and namespaces`, async () => {
|
||||
const options = { type: [type1, type2], namespaces };
|
||||
await expectPrivilegeCheck(client.find, { options }, namespaces);
|
||||
|
@ -987,6 +998,64 @@ describe('#get', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#openPointInTimeForType', () => {
|
||||
const type = 'foo';
|
||||
const namespace = 'some-ns';
|
||||
|
||||
test(`throws decorated GeneralError when hasPrivileges rejects promise`, async () => {
|
||||
await expectGeneralError(client.openPointInTimeForType, { type });
|
||||
});
|
||||
|
||||
test(`returns result of baseClient.openPointInTimeForType when authorized`, async () => {
|
||||
const apiCallReturnValue = Symbol();
|
||||
clientOpts.baseClient.openPointInTimeForType.mockReturnValue(apiCallReturnValue as any);
|
||||
|
||||
const options = { namespace };
|
||||
const result = await expectSuccess(client.openPointInTimeForType, { type, options });
|
||||
expect(result).toBe(apiCallReturnValue);
|
||||
});
|
||||
|
||||
test(`adds audit event when successful`, async () => {
|
||||
const apiCallReturnValue = Symbol();
|
||||
clientOpts.baseClient.openPointInTimeForType.mockReturnValue(apiCallReturnValue as any);
|
||||
const options = { namespace };
|
||||
await expectSuccess(client.openPointInTimeForType, { type, options });
|
||||
expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1);
|
||||
expectAuditEvent('saved_object_open_point_in_time', EventOutcome.UNKNOWN);
|
||||
});
|
||||
|
||||
test(`adds audit event when not successful`, async () => {
|
||||
clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error());
|
||||
await expect(() => client.openPointInTimeForType(type, { namespace })).rejects.toThrow();
|
||||
expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1);
|
||||
expectAuditEvent('saved_object_open_point_in_time', EventOutcome.FAILURE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#closePointInTime', () => {
|
||||
const id = 'abc123';
|
||||
const namespace = 'some-ns';
|
||||
|
||||
test(`returns result of baseClient.closePointInTime`, async () => {
|
||||
const apiCallReturnValue = Symbol();
|
||||
clientOpts.baseClient.closePointInTime.mockReturnValue(apiCallReturnValue as any);
|
||||
|
||||
const options = { namespace };
|
||||
const result = await client.closePointInTime(id, options);
|
||||
expect(result).toBe(apiCallReturnValue);
|
||||
});
|
||||
|
||||
test(`adds audit event`, async () => {
|
||||
const apiCallReturnValue = Symbol();
|
||||
clientOpts.baseClient.closePointInTime.mockReturnValue(apiCallReturnValue as any);
|
||||
|
||||
const options = { namespace };
|
||||
await client.closePointInTime(id, options);
|
||||
expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1);
|
||||
expectAuditEvent('saved_object_close_point_in_time', EventOutcome.UNKNOWN);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#resolve', () => {
|
||||
const type = 'foo';
|
||||
const id = `${type}-id`;
|
||||
|
|
|
@ -17,6 +17,8 @@ import {
|
|||
SavedObjectsCreateOptions,
|
||||
SavedObjectsDeleteFromNamespacesOptions,
|
||||
SavedObjectsFindOptions,
|
||||
SavedObjectsOpenPointInTimeOptions,
|
||||
SavedObjectsClosePointInTimeOptions,
|
||||
SavedObjectsRemoveReferencesToOptions,
|
||||
SavedObjectsUpdateOptions,
|
||||
SavedObjectsUtils,
|
||||
|
@ -223,6 +225,11 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
|
|||
`_find across namespaces is not permitted when the Spaces plugin is disabled.`
|
||||
);
|
||||
}
|
||||
if (options.pit && Array.isArray(options.namespaces) && options.namespaces.length > 1) {
|
||||
throw this.errors.createBadRequestError(
|
||||
'_find across namespaces is not permitted when using the `pit` option.'
|
||||
);
|
||||
}
|
||||
|
||||
const args = { options };
|
||||
const { status, typeMap } = await this.ensureAuthorized(
|
||||
|
@ -562,6 +569,57 @@ export class SecureSavedObjectsClientWrapper implements SavedObjectsClientContra
|
|||
return await this.baseClient.removeReferencesTo(type, id, options);
|
||||
}
|
||||
|
||||
public async openPointInTimeForType(
|
||||
type: string | string[],
|
||||
options: SavedObjectsOpenPointInTimeOptions
|
||||
) {
|
||||
try {
|
||||
const args = { type, options };
|
||||
await this.ensureAuthorized(type, 'open_point_in_time', options?.namespace, {
|
||||
args,
|
||||
// Partial authorization is acceptable in this case because this method is only designed
|
||||
// to be used with `find`, which already allows for partial authorization.
|
||||
requireFullAuthorization: false,
|
||||
});
|
||||
} catch (error) {
|
||||
this.auditLogger.log(
|
||||
savedObjectEvent({
|
||||
action: SavedObjectAction.OPEN_POINT_IN_TIME,
|
||||
error,
|
||||
})
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.auditLogger.log(
|
||||
savedObjectEvent({
|
||||
action: SavedObjectAction.OPEN_POINT_IN_TIME,
|
||||
outcome: EventOutcome.UNKNOWN,
|
||||
})
|
||||
);
|
||||
|
||||
return await this.baseClient.openPointInTimeForType(type, options);
|
||||
}
|
||||
|
||||
public async closePointInTime(id: string, options?: SavedObjectsClosePointInTimeOptions) {
|
||||
// We are intentionally omitting a call to `ensureAuthorized` here, because `closePointInTime`
|
||||
// doesn't take in `types`, which are required to perform authorization. As there is no way
|
||||
// to know what index/indices a PIT was created against, we have no practical means of
|
||||
// authorizing users. We've decided we are okay with this because:
|
||||
// (a) Elasticsearch only requires `read` privileges on an index in order to open/close
|
||||
// a PIT against it, and;
|
||||
// (b) By the time a user is accessing this service, they are already authenticated
|
||||
// to Kibana, which is our closest equivalent to Elasticsearch's `read`.
|
||||
this.auditLogger.log(
|
||||
savedObjectEvent({
|
||||
action: SavedObjectAction.CLOSE_POINT_IN_TIME,
|
||||
outcome: EventOutcome.UNKNOWN,
|
||||
})
|
||||
);
|
||||
|
||||
return await this.baseClient.closePointInTime(id, options);
|
||||
}
|
||||
|
||||
private async checkPrivileges(
|
||||
actions: string | string[],
|
||||
namespaceOrNamespaces?: string | Array<undefined | string>
|
||||
|
|
|
@ -589,5 +589,57 @@ const ERROR_NAMESPACE_SPECIFIED = 'Spaces currently determines the namespaces';
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#openPointInTimeForType', () => {
|
||||
test(`throws error if options.namespace is specified`, async () => {
|
||||
const { client } = createSpacesSavedObjectsClient();
|
||||
|
||||
await expect(client.openPointInTimeForType('foo', { namespace: 'bar' })).rejects.toThrow(
|
||||
ERROR_NAMESPACE_SPECIFIED
|
||||
);
|
||||
});
|
||||
|
||||
test(`supplements options with the current namespace`, async () => {
|
||||
const { client, baseClient } = createSpacesSavedObjectsClient();
|
||||
const expectedReturnValue = { id: 'abc123' };
|
||||
baseClient.openPointInTimeForType.mockReturnValue(Promise.resolve(expectedReturnValue));
|
||||
|
||||
const options = Object.freeze({ foo: 'bar' });
|
||||
// @ts-expect-error
|
||||
const actualReturnValue = await client.openPointInTimeForType('foo', options);
|
||||
|
||||
expect(actualReturnValue).toBe(expectedReturnValue);
|
||||
expect(baseClient.openPointInTimeForType).toHaveBeenCalledWith('foo', {
|
||||
foo: 'bar',
|
||||
namespace: currentSpace.expectedNamespace,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#closePointInTime', () => {
|
||||
test(`throws error if options.namespace is specified`, async () => {
|
||||
const { client } = createSpacesSavedObjectsClient();
|
||||
|
||||
await expect(client.closePointInTime('foo', { namespace: 'bar' })).rejects.toThrow(
|
||||
ERROR_NAMESPACE_SPECIFIED
|
||||
);
|
||||
});
|
||||
|
||||
test(`supplements options with the current namespace`, async () => {
|
||||
const { client, baseClient } = createSpacesSavedObjectsClient();
|
||||
const expectedReturnValue = { succeeded: true, num_freed: 1 };
|
||||
baseClient.closePointInTime.mockReturnValue(Promise.resolve(expectedReturnValue));
|
||||
|
||||
const options = Object.freeze({ foo: 'bar' });
|
||||
// @ts-expect-error
|
||||
const actualReturnValue = await client.closePointInTime('foo', options);
|
||||
|
||||
expect(actualReturnValue).toBe(expectedReturnValue);
|
||||
expect(baseClient.closePointInTime).toHaveBeenCalledWith('foo', {
|
||||
foo: 'bar',
|
||||
namespace: currentSpace.expectedNamespace,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,6 +15,8 @@ import {
|
|||
SavedObjectsClientContract,
|
||||
SavedObjectsCreateOptions,
|
||||
SavedObjectsFindOptions,
|
||||
SavedObjectsClosePointInTimeOptions,
|
||||
SavedObjectsOpenPointInTimeOptions,
|
||||
SavedObjectsUpdateOptions,
|
||||
SavedObjectsAddToNamespacesOptions,
|
||||
SavedObjectsDeleteFromNamespacesOptions,
|
||||
|
@ -378,4 +380,42 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract {
|
|||
namespace: spaceIdToNamespace(this.spaceId),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a Point In Time (PIT) against the indices for the specified Saved Object types.
|
||||
* The returned `id` can then be passed to `SavedObjects.find` to search against that PIT.
|
||||
*
|
||||
* @param {string|Array<string>} type
|
||||
* @param {object} [options] - {@link SavedObjectsOpenPointInTimeOptions}
|
||||
* @property {string} [options.keepAlive]
|
||||
* @property {string} [options.preference]
|
||||
* @returns {promise} - { id: string }
|
||||
*/
|
||||
async openPointInTimeForType(
|
||||
type: string | string[],
|
||||
options: SavedObjectsOpenPointInTimeOptions = {}
|
||||
) {
|
||||
throwErrorIfNamespaceSpecified(options);
|
||||
return await this.client.openPointInTimeForType(type, {
|
||||
...options,
|
||||
namespace: spaceIdToNamespace(this.spaceId),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a Point In Time (PIT) by ID. This simply proxies the request to ES
|
||||
* via the Elasticsearch client, and is included in the Saved Objects Client
|
||||
* as a convenience for consumers who are using `openPointInTimeForType`.
|
||||
*
|
||||
* @param {string} id - ID returned from `openPointInTimeForType`
|
||||
* @param {object} [options] - {@link SavedObjectsClosePointInTimeOptions}
|
||||
* @returns {promise} - { succeeded: boolean; num_freed: number }
|
||||
*/
|
||||
async closePointInTime(id: string, options: SavedObjectsClosePointInTimeOptions = {}) {
|
||||
throwErrorIfNamespaceSpecified(options);
|
||||
return await this.client.closePointInTime(id, {
|
||||
...options,
|
||||
namespace: spaceIdToNamespace(this.spaceId),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue