kibana/x-pack/plugins/lens/public/persistence/saved_object_store.ts
Marta Bondyra d4c03eb9b4
[Lens] Switch to SavedObjectClient.resolve (#110059)
* Step 2: Update client code to use resolve() method instead of get()

Following sharing Saved Objects developer guide: Step 2
This step demonstrates the changes to update client code to use the new
SavedObjectsClient `resolve()` method instead of `get()`.

* Step 3 Lens
2021-09-03 16:44:12 +02:00

105 lines
3.3 KiB
TypeScript

/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import {
SavedObjectAttributes,
SavedObjectsClientContract,
SavedObjectReference,
ResolvedSimpleSavedObject,
} from 'kibana/public';
import { Query } from '../../../../../src/plugins/data/public';
import { DOC_TYPE, PersistableFilter } from '../../common';
import { LensSavedObjectAttributes } from '../async_services';
export interface Document {
savedObjectId?: string;
type?: string;
visualizationType: string | null;
title: string;
description?: string;
state: {
datasourceStates: Record<string, unknown>;
visualization: unknown;
query: Query;
globalPalette?: {
activePaletteId: string;
state?: unknown;
};
filters: PersistableFilter[];
};
references: SavedObjectReference[];
}
export interface DocumentSaver {
save: (vis: Document) => Promise<{ savedObjectId: string }>;
}
export interface DocumentLoader {
load: (savedObjectId: string) => Promise<ResolvedSimpleSavedObject>;
}
export type SavedObjectStore = DocumentLoader & DocumentSaver;
export class SavedObjectIndexStore implements SavedObjectStore {
private client: SavedObjectsClientContract;
constructor(client: SavedObjectsClientContract) {
this.client = client;
}
save = async (vis: Document) => {
const { savedObjectId, type, references, ...rest } = vis;
// TODO: SavedObjectAttributes should support this kind of object,
// remove this workaround when SavedObjectAttributes is updated.
const attributes = (rest as unknown) as SavedObjectAttributes;
const result = await (savedObjectId
? this.safeUpdate(savedObjectId, attributes, references)
: this.client.create(DOC_TYPE, attributes, {
references,
}));
return { ...vis, savedObjectId: result.id };
};
// As Lens is using an object to store its attributes, using the update API
// will merge the new attribute object with the old one, not overwriting deleted
// keys. As Lens is using objects as maps in various places, this is a problem because
// deleted subtrees make it back into the object after a load.
// This function fixes this by doing two updates - one to empty out the document setting
// every key to null, and a second one to load the new content.
private async safeUpdate(
savedObjectId: string,
attributes: SavedObjectAttributes,
references: SavedObjectReference[]
) {
const resetAttributes: SavedObjectAttributes = {};
Object.keys(attributes).forEach((key) => {
resetAttributes[key] = null;
});
return (
await this.client.bulkUpdate([
{ type: DOC_TYPE, id: savedObjectId, attributes: resetAttributes, references },
{ type: DOC_TYPE, id: savedObjectId, attributes, references },
])
).savedObjects[1];
}
async load(savedObjectId: string): Promise<ResolvedSimpleSavedObject<LensSavedObjectAttributes>> {
const resolveResult = await this.client.resolve<LensSavedObjectAttributes>(
DOC_TYPE,
savedObjectId
);
if (resolveResult.saved_object.error) {
throw resolveResult.saved_object.error;
}
return resolveResult;
}
}