mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Add upsert support for savedObjects update (#98712)
* Add upsert support for savedObjects update * fix types * update generated docs * update docs * fix types * do not use update attributes for upsert
This commit is contained in:
parent
6b6ad111c0
commit
05e2ab4df1
22 changed files with 184 additions and 45 deletions
|
@ -36,6 +36,9 @@ WARNING: When you update, attributes are not validated, which allows you to pass
|
|||
`references`::
|
||||
(Optional, array) Objects with `name`, `id`, and `type` properties that describe the other saved objects this object references. To refer to the other saved object, use `name` in the attributes, but never the `id`, which automatically updates during migrations or import/export.
|
||||
|
||||
`upsert`::
|
||||
(Optional, object) If specified, will create the document with the given upsert attributes if it doesn't exist.
|
||||
|
||||
[[saved-objects-api-update-errors-codes]]
|
||||
==== Response code
|
||||
|
||||
|
|
|
@ -32,5 +32,5 @@ The constructor for this class is marked as internal. Third-party code should no
|
|||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [bulkUpdate(objects)](./kibana-plugin-core-public.savedobjectsclient.bulkupdate.md) | | Update multiple documents at once |
|
||||
| [update(type, id, attributes, { version, migrationVersion, references })](./kibana-plugin-core-public.savedobjectsclient.update.md) | | Updates an object |
|
||||
| [update(type, id, attributes, { version, references, upsert })](./kibana-plugin-core-public.savedobjectsclient.update.md) | | Updates an object |
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ Updates an object
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
update<T = unknown>(type: string, id: string, attributes: T, { version, migrationVersion, references }?: SavedObjectsUpdateOptions): Promise<SimpleSavedObject<T>>;
|
||||
update<T = unknown>(type: string, id: string, attributes: T, { version, references, upsert }?: SavedObjectsUpdateOptions): Promise<SimpleSavedObject<T>>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -19,7 +19,7 @@ update<T = unknown>(type: string, id: string, attributes: T, { version, migratio
|
|||
| type | <code>string</code> | |
|
||||
| id | <code>string</code> | |
|
||||
| attributes | <code>T</code> | |
|
||||
| { version, migrationVersion, references } | <code>SavedObjectsUpdateOptions</code> | |
|
||||
| { version, references, upsert } | <code>SavedObjectsUpdateOptions</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface SavedObjectsUpdateOptions
|
||||
export interface SavedObjectsUpdateOptions<Attributes = unknown>
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [migrationVersion](./kibana-plugin-core-public.savedobjectsupdateoptions.migrationversion.md) | <code>SavedObjectsMigrationVersion</code> | 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. |
|
||||
| [references](./kibana-plugin-core-public.savedobjectsupdateoptions.references.md) | <code>SavedObjectReference[]</code> | |
|
||||
| [upsert](./kibana-plugin-core-public.savedobjectsupdateoptions.upsert.md) | <code>Attributes</code> | |
|
||||
| [version](./kibana-plugin-core-public.savedobjectsupdateoptions.version.md) | <code>string</code> | |
|
||||
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [SavedObjectsUpdateOptions](./kibana-plugin-core-public.savedobjectsupdateoptions.md) > [migrationVersion](./kibana-plugin-core-public.savedobjectsupdateoptions.migrationversion.md)
|
||||
|
||||
## SavedObjectsUpdateOptions.migrationVersion property
|
||||
|
||||
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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
migrationVersion?: SavedObjectsMigrationVersion;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [SavedObjectsUpdateOptions](./kibana-plugin-core-public.savedobjectsupdateoptions.md) > [upsert](./kibana-plugin-core-public.savedobjectsupdateoptions.upsert.md)
|
||||
|
||||
## SavedObjectsUpdateOptions.upsert property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
upsert?: Attributes;
|
||||
```
|
|
@ -8,7 +8,7 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface SavedObjectsBulkUpdateObject<T = unknown> extends Pick<SavedObjectsUpdateOptions, 'version' | 'references'>
|
||||
export interface SavedObjectsBulkUpdateObject<T = unknown> extends Pick<SavedObjectsUpdateOptions<T>, 'version' | 'references'>
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
|
|
@ -9,7 +9,7 @@ Updates an SavedObject
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?: SavedObjectsUpdateOptions): Promise<SavedObjectsUpdateResponse<T>>;
|
||||
update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?: SavedObjectsUpdateOptions<T>): Promise<SavedObjectsUpdateResponse<T>>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -19,7 +19,7 @@ update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?:
|
|||
| type | <code>string</code> | |
|
||||
| id | <code>string</code> | |
|
||||
| attributes | <code>Partial<T></code> | |
|
||||
| options | <code>SavedObjectsUpdateOptions</code> | |
|
||||
| options | <code>SavedObjectsUpdateOptions<T></code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ Updates an object
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?: SavedObjectsUpdateOptions): Promise<SavedObjectsUpdateResponse<T>>;
|
||||
update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?: SavedObjectsUpdateOptions<T>): Promise<SavedObjectsUpdateResponse<T>>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -19,7 +19,7 @@ update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?:
|
|||
| type | <code>string</code> | |
|
||||
| id | <code>string</code> | |
|
||||
| attributes | <code>Partial<T></code> | |
|
||||
| options | <code>SavedObjectsUpdateOptions</code> | |
|
||||
| options | <code>SavedObjectsUpdateOptions<T></code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface SavedObjectsUpdateOptions extends SavedObjectsBaseOptions
|
||||
export interface SavedObjectsUpdateOptions<Attributes = unknown> extends SavedObjectsBaseOptions
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
@ -17,5 +17,6 @@ export interface SavedObjectsUpdateOptions extends SavedObjectsBaseOptions
|
|||
| --- | --- | --- |
|
||||
| [references](./kibana-plugin-core-server.savedobjectsupdateoptions.references.md) | <code>SavedObjectReference[]</code> | A reference to another saved object. |
|
||||
| [refresh](./kibana-plugin-core-server.savedobjectsupdateoptions.refresh.md) | <code>MutatingOperationRefreshSetting</code> | The Elasticsearch Refresh setting for this operation |
|
||||
| [upsert](./kibana-plugin-core-server.savedobjectsupdateoptions.upsert.md) | <code>Attributes</code> | If specified, will be used to perform an upsert if the document doesn't exist |
|
||||
| [version](./kibana-plugin-core-server.savedobjectsupdateoptions.version.md) | <code>string</code> | An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control. |
|
||||
|
||||
|
|
|
@ -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) > [SavedObjectsUpdateOptions](./kibana-plugin-core-server.savedobjectsupdateoptions.md) > [upsert](./kibana-plugin-core-server.savedobjectsupdateoptions.upsert.md)
|
||||
|
||||
## SavedObjectsUpdateOptions.upsert property
|
||||
|
||||
If specified, will be used to perform an upsert if the document doesn't exist
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
upsert?: Attributes;
|
||||
```
|
|
@ -1226,7 +1226,7 @@ export class SavedObjectsClient {
|
|||
// Warning: (ae-forgotten-export) The symbol "SavedObjectsFindOptions" needs to be exported by the entry point index.d.ts
|
||||
find: <T = unknown, A = unknown>(options: SavedObjectsFindOptions_2) => Promise<SavedObjectsFindResponsePublic<T, unknown>>;
|
||||
get: <T = unknown>(type: string, id: string) => Promise<SimpleSavedObject<T>>;
|
||||
update<T = unknown>(type: string, id: string, attributes: T, { version, migrationVersion, references }?: SavedObjectsUpdateOptions): Promise<SimpleSavedObject<T>>;
|
||||
update<T = unknown>(type: string, id: string, attributes: T, { version, references, upsert }?: SavedObjectsUpdateOptions): Promise<SimpleSavedObject<T>>;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
@ -1447,11 +1447,12 @@ export interface SavedObjectsStart {
|
|||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface SavedObjectsUpdateOptions {
|
||||
migrationVersion?: SavedObjectsMigrationVersion;
|
||||
export interface SavedObjectsUpdateOptions<Attributes = unknown> {
|
||||
// (undocumented)
|
||||
references?: SavedObjectReference[];
|
||||
// (undocumented)
|
||||
upsert?: Attributes;
|
||||
// (undocumented)
|
||||
version?: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -223,6 +223,26 @@ describe('SavedObjectsClient', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
test('handles the `upsert` option', () => {
|
||||
savedObjectsClient.update('index-pattern', 'logstash-*', attributes, {
|
||||
upsert: {
|
||||
hello: 'dolly',
|
||||
},
|
||||
});
|
||||
expect(http.fetch.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"/api/saved_objects/index-pattern/logstash-*",
|
||||
Object {
|
||||
"body": "{\\"attributes\\":{\\"foo\\":\\"Foo\\",\\"bar\\":\\"Bar\\"},\\"upsert\\":{\\"hello\\":\\"dolly\\"}}",
|
||||
"method": "PUT",
|
||||
"query": undefined,
|
||||
},
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('rejects when HTTP call fails', async () => {
|
||||
http.fetch.mockRejectedValueOnce(new Error('Request failed'));
|
||||
await expect(
|
||||
|
|
|
@ -77,10 +77,9 @@ export interface SavedObjectsBulkUpdateOptions {
|
|||
}
|
||||
|
||||
/** @public */
|
||||
export interface SavedObjectsUpdateOptions {
|
||||
export interface SavedObjectsUpdateOptions<Attributes = unknown> {
|
||||
version?: string;
|
||||
/** {@inheritDoc SavedObjectsMigrationVersion} */
|
||||
migrationVersion?: SavedObjectsMigrationVersion;
|
||||
upsert?: Attributes;
|
||||
references?: SavedObjectReference[];
|
||||
}
|
||||
|
||||
|
@ -437,7 +436,7 @@ export class SavedObjectsClient {
|
|||
type: string,
|
||||
id: string,
|
||||
attributes: T,
|
||||
{ version, migrationVersion, references }: SavedObjectsUpdateOptions = {}
|
||||
{ version, references, upsert }: SavedObjectsUpdateOptions = {}
|
||||
): Promise<SimpleSavedObject<T>> {
|
||||
if (!type || !id || !attributes) {
|
||||
return Promise.reject(new Error('requires type, id and attributes'));
|
||||
|
@ -446,9 +445,9 @@ export class SavedObjectsClient {
|
|||
const path = this.getPath([type, id]);
|
||||
const body = {
|
||||
attributes,
|
||||
migrationVersion,
|
||||
references,
|
||||
version,
|
||||
upsert,
|
||||
};
|
||||
|
||||
return this.savedObjectsFetch(path, {
|
||||
|
|
|
@ -71,7 +71,6 @@ export class SimpleSavedObject<T = unknown> {
|
|||
public save(): Promise<SimpleSavedObject<T>> {
|
||||
if (this.id) {
|
||||
return this.client.update(this.type, this.id, this.attributes, {
|
||||
migrationVersion: this.migrationVersion,
|
||||
references: this.references,
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import { schema } from '@kbn/config-schema';
|
||||
import { IRouter } from '../../http';
|
||||
import { CoreUsageDataSetup } from '../../core_usage_data';
|
||||
import type { SavedObjectsUpdateOptions } from '../service/saved_objects_client';
|
||||
import { catchAndReturnBoomErrors } from './utils';
|
||||
|
||||
interface RouteDependencies {
|
||||
|
@ -36,13 +37,14 @@ export const registerUpdateRoute = (router: IRouter, { coreUsageData }: RouteDep
|
|||
})
|
||||
)
|
||||
),
|
||||
upsert: schema.maybe(schema.recordOf(schema.string(), schema.any())),
|
||||
}),
|
||||
},
|
||||
},
|
||||
catchAndReturnBoomErrors(async (context, req, res) => {
|
||||
const { type, id } = req.params;
|
||||
const { attributes, version, references } = req.body;
|
||||
const options = { version, references };
|
||||
const { attributes, version, references, upsert } = req.body;
|
||||
const options: SavedObjectsUpdateOptions = { version, references, upsert };
|
||||
|
||||
const usageStatsClient = coreUsageData.getClient();
|
||||
usageStatsClient.incrementSavedObjectsUpdate({ request: req }).catch(() => {});
|
||||
|
|
|
@ -4326,6 +4326,30 @@ describe('SavedObjectsRepository', () => {
|
|||
await test([]);
|
||||
});
|
||||
|
||||
it(`uses the 'upsertAttributes' option when specified`, async () => {
|
||||
await updateSuccess(type, id, attributes, {
|
||||
upsert: {
|
||||
title: 'foo',
|
||||
description: 'bar',
|
||||
},
|
||||
});
|
||||
expect(client.update).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
id: 'index-pattern:logstash-*',
|
||||
body: expect.objectContaining({
|
||||
upsert: expect.objectContaining({
|
||||
type: 'index-pattern',
|
||||
'index-pattern': {
|
||||
title: 'foo',
|
||||
description: 'bar',
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
|
||||
it(`doesn't accept custom references if not an array`, async () => {
|
||||
const test = async (references) => {
|
||||
await updateSuccess(type, id, attributes, { references });
|
||||
|
|
|
@ -1174,13 +1174,13 @@ export class SavedObjectsRepository {
|
|||
type: string,
|
||||
id: string,
|
||||
attributes: Partial<T>,
|
||||
options: SavedObjectsUpdateOptions = {}
|
||||
options: SavedObjectsUpdateOptions<T> = {}
|
||||
): Promise<SavedObjectsUpdateResponse<T>> {
|
||||
if (!this._allowedTypes.includes(type)) {
|
||||
throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
|
||||
}
|
||||
|
||||
const { version, references, refresh = DEFAULT_REFRESH_SETTING } = options;
|
||||
const { version, references, upsert, refresh = DEFAULT_REFRESH_SETTING } = options;
|
||||
const namespace = normalizeNamespace(options.namespace);
|
||||
|
||||
let preflightResult: SavedObjectsRawDoc | undefined;
|
||||
|
@ -1190,6 +1190,30 @@ export class SavedObjectsRepository {
|
|||
|
||||
const time = this._getCurrentTime();
|
||||
|
||||
let rawUpsert: SavedObjectsRawDoc | undefined;
|
||||
if (upsert) {
|
||||
let savedObjectNamespace: string | undefined;
|
||||
let savedObjectNamespaces: string[] | undefined;
|
||||
|
||||
if (this._registry.isSingleNamespace(type) && namespace) {
|
||||
savedObjectNamespace = namespace;
|
||||
} else if (this._registry.isMultiNamespace(type)) {
|
||||
savedObjectNamespaces = await this.preflightGetNamespaces(type, id, namespace);
|
||||
}
|
||||
|
||||
const migrated = this._migrator.migrateDocument({
|
||||
id,
|
||||
type,
|
||||
...(savedObjectNamespace && { namespace: savedObjectNamespace }),
|
||||
...(savedObjectNamespaces && { namespaces: savedObjectNamespaces }),
|
||||
attributes: {
|
||||
...upsert,
|
||||
},
|
||||
updated_at: time,
|
||||
});
|
||||
rawUpsert = this._serializer.savedObjectToRaw(migrated as SavedObjectSanitizedDoc);
|
||||
}
|
||||
|
||||
const doc = {
|
||||
[type]: attributes,
|
||||
updated_at: time,
|
||||
|
@ -1205,6 +1229,7 @@ export class SavedObjectsRepository {
|
|||
|
||||
body: {
|
||||
doc,
|
||||
...(rawUpsert && { upsert: rawUpsert._source }),
|
||||
},
|
||||
_source_includes: ['namespace', 'namespaces', 'originId'],
|
||||
require_alias: true,
|
||||
|
|
|
@ -101,7 +101,7 @@ export interface SavedObjectsBulkCreateObject<T = unknown> {
|
|||
* @public
|
||||
*/
|
||||
export interface SavedObjectsBulkUpdateObject<T = unknown>
|
||||
extends Pick<SavedObjectsUpdateOptions, 'version' | 'references'> {
|
||||
extends Pick<SavedObjectsUpdateOptions<T>, 'version' | 'references'> {
|
||||
/** The ID of this Saved Object, guaranteed to be unique for all objects of the same `type` */
|
||||
id: string;
|
||||
/** The type of this Saved Object. Each plugin can define it's own custom Saved Object types. */
|
||||
|
@ -207,13 +207,15 @@ export interface SavedObjectsCheckConflictsResponse {
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
export interface SavedObjectsUpdateOptions extends SavedObjectsBaseOptions {
|
||||
export interface SavedObjectsUpdateOptions<Attributes = unknown> extends SavedObjectsBaseOptions {
|
||||
/** An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control. */
|
||||
version?: string;
|
||||
/** {@inheritdoc SavedObjectReference} */
|
||||
references?: SavedObjectReference[];
|
||||
/** The Elasticsearch Refresh setting for this operation */
|
||||
refresh?: MutatingOperationRefreshSetting;
|
||||
/** If specified, will be used to perform an upsert if the document doesn't exist */
|
||||
upsert?: Attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -529,7 +531,7 @@ export class SavedObjectsClient {
|
|||
type: string,
|
||||
id: string,
|
||||
attributes: Partial<T>,
|
||||
options: SavedObjectsUpdateOptions = {}
|
||||
options: SavedObjectsUpdateOptions<T> = {}
|
||||
): Promise<SavedObjectsUpdateResponse<T>> {
|
||||
return await this._repository.update(type, id, attributes, options);
|
||||
}
|
||||
|
|
|
@ -2233,7 +2233,7 @@ export interface SavedObjectsBulkResponse<T = unknown> {
|
|||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface SavedObjectsBulkUpdateObject<T = unknown> extends Pick<SavedObjectsUpdateOptions, 'version' | 'references'> {
|
||||
export interface SavedObjectsBulkUpdateObject<T = unknown> extends Pick<SavedObjectsUpdateOptions<T>, 'version' | 'references'> {
|
||||
attributes: Partial<T>;
|
||||
id: string;
|
||||
namespace?: string;
|
||||
|
@ -2292,7 +2292,7 @@ export class SavedObjectsClient {
|
|||
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>>;
|
||||
update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?: SavedObjectsUpdateOptions<T>): Promise<SavedObjectsUpdateResponse<T>>;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
@ -2902,7 +2902,7 @@ export class SavedObjectsRepository {
|
|||
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>>;
|
||||
update<T = unknown>(type: string, id: string, attributes: Partial<T>, options?: SavedObjectsUpdateOptions<T>): Promise<SavedObjectsUpdateResponse<T>>;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
@ -3001,9 +3001,10 @@ export interface SavedObjectsTypeMappingDefinition {
|
|||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface SavedObjectsUpdateOptions extends SavedObjectsBaseOptions {
|
||||
export interface SavedObjectsUpdateOptions<Attributes = unknown> extends SavedObjectsBaseOptions {
|
||||
references?: SavedObjectReference[];
|
||||
refresh?: MutatingOperationRefreshSetting;
|
||||
upsert?: Attributes;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,6 +96,52 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(resp.body.references).to.eql([]);
|
||||
});
|
||||
|
||||
it('handles upsert', async () => {
|
||||
await supertest
|
||||
.put(`/api/saved_objects/visualization/upserted-viz`)
|
||||
.send({
|
||||
attributes: {
|
||||
title: 'foo',
|
||||
},
|
||||
upsert: {
|
||||
title: 'upserted title',
|
||||
description: 'upserted description',
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
const { body: upserted } = await supertest
|
||||
.get(`/api/saved_objects/visualization/upserted-viz`)
|
||||
.expect(200);
|
||||
|
||||
expect(upserted.attributes).to.eql({
|
||||
title: 'upserted title',
|
||||
description: 'upserted description',
|
||||
});
|
||||
|
||||
await supertest
|
||||
.put(`/api/saved_objects/visualization/upserted-viz`)
|
||||
.send({
|
||||
attributes: {
|
||||
title: 'foobar',
|
||||
},
|
||||
upsert: {
|
||||
description: 'new upserted description',
|
||||
version: 9000,
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
const { body: notUpserted } = await supertest
|
||||
.get(`/api/saved_objects/visualization/upserted-viz`)
|
||||
.expect(200);
|
||||
|
||||
expect(notUpserted.attributes).to.eql({
|
||||
title: 'foobar',
|
||||
description: 'upserted description',
|
||||
});
|
||||
});
|
||||
|
||||
describe('unknown id', () => {
|
||||
it('should return a generic 404', async () => {
|
||||
await supertest
|
||||
|
|
|
@ -40,7 +40,12 @@ export async function partiallyUpdateAlert(
|
|||
): Promise<void> {
|
||||
// ensure we only have the valid attributes excluded from AAD
|
||||
const attributeUpdates = pick(attributes, AlertAttributesExcludedFromAAD);
|
||||
const updateOptions: SavedObjectsUpdateOptions = pick(options, 'namespace', 'version', 'refresh');
|
||||
const updateOptions: SavedObjectsUpdateOptions<RawAlert> = pick(
|
||||
options,
|
||||
'namespace',
|
||||
'version',
|
||||
'refresh'
|
||||
);
|
||||
|
||||
try {
|
||||
await savedObjectsClient.update<RawAlert>('alert', id, attributeUpdates, updateOptions);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue