Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move search source parsing and serializing to data #59919

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
56edb43
move search source parsing and serializing to data
flash1293 Mar 11, 2020
01c1ca7
only initialize search source if it is enabled in config
flash1293 Mar 11, 2020
37cd60e
make functions state and add tests for parsing
flash1293 Mar 12, 2020
4490ae6
Merge remote-tracking branch 'upstream/master' into migrate-search-so…
flash1293 Mar 27, 2020
4f9cc2e
fix referenecs
flash1293 Mar 27, 2020
72f969d
add tests and fix bugs
flash1293 Mar 27, 2020
2079c32
Merge remote-tracking branch 'upstream/master' into migrate-search-so…
flash1293 Mar 29, 2020
e07546a
fix some problems
flash1293 Mar 29, 2020
aa57ebc
fix legacy imporrts
flash1293 Mar 29, 2020
d4e69ee
Merge remote-tracking branch 'upstream/master' into migrate-search-so…
flash1293 Mar 30, 2020
3360b12
finalize
flash1293 Mar 30, 2020
40aeded
move serialize into search source
flash1293 Mar 30, 2020
37b8510
Merge remote-tracking branch 'upstream/master' into migrate-search-so…
flash1293 Apr 6, 2020
732e990
fix tests
flash1293 Apr 6, 2020
b200ae1
Merge remote-tracking branch 'upstream/master' into migrate-search-so…
flash1293 Apr 7, 2020
8a5fc1b
rename parseSearchSource to createSearchSource
flash1293 Apr 7, 2020
babb4d6
Merge branch 'master' into migrate-search-source-serialization
elasticmachine Apr 7, 2020
a1a9fd4
Merge remote-tracking branch 'upstream/master' into migrate-search-so…
flash1293 Apr 9, 2020
40a4e97
remove unused property from type
flash1293 Apr 9, 2020
8ec0021
Merge branch 'migrate-search-source-serialization' of github.com:flas…
flash1293 Apr 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
| [FilterBar](./kibana-plugin-plugins-data-public.filterbar.md) | |
| [getKbnTypeNames](./kibana-plugin-plugins-data-public.getkbntypenames.md) | Get the esTypes known by all kbnFieldTypes {<!-- -->Array<string>} |
| [indexPatterns](./kibana-plugin-plugins-data-public.indexpatterns.md) | |
| [parseSearchSource](./kibana-plugin-plugins-data-public.parsesearchsource.md) | Deserializes a json string and a set of referenced objects to a <code>SearchSource</code> instance. Use this method to re-create the search source serialized using <code>searchSource.serialize</code>.<!-- -->This function is a factory function that returns the actual utility when calling it with the required service dependency (index patterns contract). A pre-wired version is also exposed in the start contract of the data plugin as part of the search service |
| [QueryStringInput](./kibana-plugin-plugins-data-public.querystringinput.md) | |
| [search](./kibana-plugin-plugins-data-public.search.md) | |
| [SearchBar](./kibana-plugin-plugins-data-public.searchbar.md) | |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [parseSearchSource](./kibana-plugin-plugins-data-public.parsesearchsource.md)

## parseSearchSource variable

Deserializes a json string and a set of referenced objects to a `SearchSource` instance. Use this method to re-create the search source serialized using `searchSource.serialize`<!-- -->.

This function is a factory function that returns the actual utility when calling it with the required service dependency (index patterns contract). A pre-wired version is also exposed in the start contract of the data plugin as part of the search service

<b>Signature:</b>

```typescript
parseSearchSource: (indexPatterns: Pick<import("../../index_patterns/index_patterns").IndexPatternsService, "get" | "clearCache" | "getFieldsForTimePattern" | "getFieldsForWildcard" | "getIds" | "getTitles" | "getFields" | "getCache" | "getDefault" | "make">) => (searchSourceJson: string, references: SavedObjectReference[]) => Promise<SearchSource>
```
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export declare class SearchSource
| [getParent()](./kibana-plugin-plugins-data-public.searchsource.getparent.md) | | Get the parent of this SearchSource {<!-- -->undefined\|searchSource<!-- -->} |
| [getSearchRequestBody()](./kibana-plugin-plugins-data-public.searchsource.getsearchrequestbody.md) | | |
| [onRequestStart(handler)](./kibana-plugin-plugins-data-public.searchsource.onrequeststart.md) | | Add a handler that will be notified whenever requests start |
| [serialize()](./kibana-plugin-plugins-data-public.searchsource.serialize.md) | | Serializes the instance to a JSON string and a set of referenced objects. Use this method to get a representation of the search source which can be stored in a saved object.<!-- -->The references returned by this function can be mixed with other references in the same object, however make sure there are no name-collisions. The references will be named <code>kibanaSavedObjectMeta.searchSourceJSON.index</code> and <code>kibanaSavedObjectMeta.searchSourceJSON.filter[&lt;number&gt;].meta.index</code>.<!-- -->Using <code>parseSearchSource</code>, the instance can be re-created. |
| [setField(field, value)](./kibana-plugin-plugins-data-public.searchsource.setfield.md) | | |
| [setFields(newFields)](./kibana-plugin-plugins-data-public.searchsource.setfields.md) | | |
| [setParent(parent, options)](./kibana-plugin-plugins-data-public.searchsource.setparent.md) | | Set a searchSource that this source should inherit from |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [SearchSource](./kibana-plugin-plugins-data-public.searchsource.md) &gt; [serialize](./kibana-plugin-plugins-data-public.searchsource.serialize.md)

## SearchSource.serialize() method

Serializes the instance to a JSON string and a set of referenced objects. Use this method to get a representation of the search source which can be stored in a saved object.

The references returned by this function can be mixed with other references in the same object, however make sure there are no name-collisions. The references will be named `kibanaSavedObjectMeta.searchSourceJSON.index` and `kibanaSavedObjectMeta.searchSourceJSON.filter[<number>].meta.index`<!-- -->.

Using `parseSearchSource`<!-- -->, the instance can be re-created.

<b>Signature:</b>

```typescript
serialize(): {
searchSourceJSON: string;
references: SavedObjectReference[];
};
```
<b>Returns:</b>

`{
searchSourceJSON: string;
references: SavedObjectReference[];
}`

Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export async function buildServices(
const services = {
savedObjectsClient: core.savedObjects.client,
indexPatterns: plugins.data.indexPatterns,
search: plugins.data.search,
chrome: core.chrome,
overlays: core.overlays,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const savedObjectManagementRegistry: ISavedObjectsManagementRegistry = {
const services = {
savedObjectsClient: npStart.core.savedObjects.client,
indexPatterns: npStart.plugins.data.indexPatterns,
search: npStart.plugins.data.search,
chrome: npStart.core.chrome,
overlays: npStart.core.overlays,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,8 @@ describe('Flyout', () => {
expect(resolveIndexPatternConflicts).toHaveBeenCalledWith(
component.instance().resolutions,
mockConflictedIndexPatterns,
true
true,
defaultProps.indexPatterns
);
expect(saveObjects).toHaveBeenCalledWith(
mockConflictedSavedObjectsLinkedToSavedSearches,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,8 @@ export class Flyout extends Component {
importCount += await resolveIndexPatternConflicts(
resolutions,
conflictedIndexPatterns,
isOverwriteAllChecked
isOverwriteAllChecked,
this.props.indexPatterns
);
}
this.setState({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('resolveSavedObjects', () => {
},
} as unknown) as IndexPatternsContract;

const services = [
const services = ([
{
type: 'search',
get: async () => {
Expand Down Expand Up @@ -124,7 +124,7 @@ describe('resolveSavedObjects', () => {
};
},
},
] as SavedObjectLoader[];
] as unknown) as SavedObjectLoader[];

const overwriteAll = false;

Expand Down Expand Up @@ -176,7 +176,7 @@ describe('resolveSavedObjects', () => {
},
} as unknown) as IndexPatternsContract;

const services = [
const services = ([
{
type: 'search',
get: async () => {
Expand Down Expand Up @@ -217,7 +217,7 @@ describe('resolveSavedObjects', () => {
};
},
},
] as SavedObjectLoader[];
] as unknown) as SavedObjectLoader[];

const overwriteAll = false;

Expand All @@ -237,33 +237,38 @@ describe('resolveSavedObjects', () => {

describe('resolveIndexPatternConflicts', () => {
it('should resave resolutions', async () => {
const hydrateIndexPattern = jest.fn();
const save = jest.fn();

const conflictedIndexPatterns = [
const conflictedIndexPatterns = ([
{
obj: {
searchSource: {
getOwnField: (field: string) => {
return field === 'index' ? '1' : undefined;
save,
},
doc: {
_source: {
kibanaSavedObjectMeta: {
searchSourceJSON: JSON.stringify({
index: '1',
}),
},
},
hydrateIndexPattern,
save,
},
},
{
obj: {
searchSource: {
getOwnField: (field: string) => {
return field === 'index' ? '3' : undefined;
save,
},
doc: {
_source: {
kibanaSavedObjectMeta: {
searchSourceJSON: JSON.stringify({
index: '3',
}),
},
},
hydrateIndexPattern,
save,
},
},
];
] as unknown) as Array<{ obj: SavedObject; doc: any }>;

const resolutions = [
{
Expand All @@ -282,43 +287,49 @@ describe('resolveSavedObjects', () => {

const overwriteAll = false;

await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll);
expect(hydrateIndexPattern.mock.calls.length).toBe(2);
await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll, ({
get: (id: string) => Promise.resolve({ id }),
} as unknown) as IndexPatternsContract);
expect(conflictedIndexPatterns[0].obj.searchSource!.getField('index')!.id).toEqual('2');
expect(conflictedIndexPatterns[1].obj.searchSource!.getField('index')!.id).toEqual('4');
expect(save.mock.calls.length).toBe(2);
expect(save).toHaveBeenCalledWith({ confirmOverwrite: !overwriteAll });
expect(hydrateIndexPattern).toHaveBeenCalledWith('2');
expect(hydrateIndexPattern).toHaveBeenCalledWith('4');
});

it('should resolve filter index conflicts', async () => {
const hydrateIndexPattern = jest.fn();
const save = jest.fn();

const conflictedIndexPatterns = [
const conflictedIndexPatterns = ([
{
obj: {
searchSource: {
getOwnField: (field: string) => {
return field === 'index' ? '1' : [{ meta: { index: 'filterIndex' } }];
save,
},
doc: {
_source: {
kibanaSavedObjectMeta: {
searchSourceJSON: JSON.stringify({
index: '1',
filter: [{ meta: { index: 'filterIndex' } }],
}),
},
setField: jest.fn(),
},
hydrateIndexPattern,
save,
},
},
{
obj: {
searchSource: {
getOwnField: (field: string) => {
return field === 'index' ? '3' : undefined;
save,
},
doc: {
_source: {
kibanaSavedObjectMeta: {
searchSourceJSON: JSON.stringify({
index: '3',
}),
},
},
hydrateIndexPattern,
save,
},
},
];
] as unknown) as Array<{ obj: SavedObject; doc: any }>;

const resolutions = [
{
Expand All @@ -337,9 +348,11 @@ describe('resolveSavedObjects', () => {

const overwriteAll = false;

await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll);
await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll, ({
get: (id: string) => Promise.resolve({ id }),
} as unknown) as IndexPatternsContract);

expect(conflictedIndexPatterns[0].obj.searchSource.setField).toHaveBeenCalledWith('filter', [
expect(conflictedIndexPatterns[0].obj.searchSource!.getField('filter')).toEqual([
{ meta: { index: 'newFilterIndex' } },
]);
expect(save.mock.calls.length).toBe(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@
*/

import { i18n } from '@kbn/i18n';
import { OverlayStart } from 'src/core/public';
import { cloneDeep } from 'lodash';
import { OverlayStart, SavedObjectReference } from 'src/core/public';
import {
SavedObject,
SavedObjectLoader,
} from '../../../../../../../../plugins/saved_objects/public';
import { IndexPatternsContract, IIndexPattern } from '../../../../../../../../plugins/data/public';
import {
IndexPatternsContract,
IIndexPattern,
parseSearchSource,
} from '../../../../../../../../plugins/data/public';

type SavedObjectsRawDoc = Record<string, any>;

Expand Down Expand Up @@ -126,7 +131,7 @@ async function importIndexPattern(
async function importDocument(obj: SavedObject, doc: SavedObjectsRawDoc, overwriteAll: boolean) {
await obj.applyESResp({
references: doc._references || [],
...doc,
...cloneDeep(doc),
Comment on lines -129 to +134
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this necessary due to a change in this PR, or is it just a fix/cleanup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was necessary because of this PR - as applyESResp now errors out without creating an inconsistent search source instance (as in the old implementation), https://github.com/elastic/kibana/blob/master/src/plugins/saved_objects/public/saved_object/helpers/apply_es_resp.ts#L44 becomes a problem because this information is now lost for https://github.com/elastic/kibana/pull/59919/files/babb4d6ee332d3836ba81e213073a46b986dc913#diff-c5230517ea9644f8395ec776249ed4bbR174

I'm also fine with moving the clone into applyESResp

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably fine to keep it there

});
return await obj.save({ confirmOverwrite: !overwriteAll });
}
Expand Down Expand Up @@ -160,41 +165,57 @@ async function awaitEachItemInParallel<T, R>(list: T[], op: (item: T) => R) {
export async function resolveIndexPatternConflicts(
resolutions: Array<{ oldId: string; newId: string }>,
conflictedIndexPatterns: any[],
overwriteAll: boolean
overwriteAll: boolean,
indexPatterns: IndexPatternsContract
) {
let importCount = 0;

await awaitEachItemInParallel(conflictedIndexPatterns, async ({ obj }) => {
// Resolve search index reference:
let oldIndexId = obj.searchSource.getOwnField('index');
// Depending on the object, this can either be the raw id or the actual index pattern object
if (typeof oldIndexId !== 'string') {
oldIndexId = oldIndexId.id;
}
let resolution = resolutions.find(({ oldId }) => oldId === oldIndexId);
if (resolution) {
const newIndexId = resolution.newId;
await obj.hydrateIndexPattern(newIndexId);
await awaitEachItemInParallel(conflictedIndexPatterns, async ({ obj, doc }) => {
const serializedSearchSource = JSON.parse(
doc._source.kibanaSavedObjectMeta?.searchSourceJSON || '{}'
);
const oldIndexId = serializedSearchSource.index;
let allResolved = true;
const inlineResolution = resolutions.find(({ oldId }) => oldId === oldIndexId);
if (inlineResolution) {
serializedSearchSource.index = inlineResolution.newId;
} else {
allResolved = false;
}

// Resolve filter index reference:
const filter = (obj.searchSource.getOwnField('filter') || []).map((f: any) => {
const filter = (serializedSearchSource.filter || []).map((f: any) => {
if (!(f.meta && f.meta.index)) {
return f;
}

resolution = resolutions.find(({ oldId }) => oldId === f.meta.index);
const resolution = resolutions.find(({ oldId }) => oldId === f.meta.index);
return resolution ? { ...f, ...{ meta: { ...f.meta, index: resolution.newId } } } : f;
});

if (filter.length > 0) {
obj.searchSource.setField('filter', filter);
serializedSearchSource.filter = filter;
}

if (!resolution) {
const replacedReferences = (doc._references || []).map((reference: SavedObjectReference) => {
const resolution = resolutions.find(({ oldId }) => oldId === reference.id);
if (resolution) {
return { ...reference, id: resolution.newId };
} else {
allResolved = false;
}

return reference;
});

if (!allResolved) {
// The user decided to skip this conflict so do nothing
return;
}
obj.searchSource = await parseSearchSource(indexPatterns)(
JSON.stringify(serializedSearchSource),
replacedReferences
);
if (await saveObject(obj, overwriteAll)) {
importCount++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const getResolvedResults = deps => {
return createSavedSearchesLoader({
savedObjectsClient: core.savedObjects.client,
indexPatterns: data.indexPatterns,
search: data.search,
chrome: core.chrome,
overlays: core.overlays,
}).get(results.vis.data.savedSearchId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const savedObjectsClient = npStart.core.savedObjects.client;
const services = {
savedObjectsClient,
indexPatterns: npStart.plugins.data.indexPatterns,
search: npStart.plugins.data.search,
chrome: npStart.core.chrome,
overlays: npStart.core.overlays,
};
Expand Down
2 changes: 2 additions & 0 deletions src/legacy/ui/public/new_platform/set_services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ export function setStartServices(npStart: NpStart) {
visualizationsServices.setAggs(npStart.plugins.data.search.aggs);
visualizationsServices.setOverlays(npStart.core.overlays);
visualizationsServices.setChrome(npStart.core.chrome);
visualizationsServices.setSearch(npStart.plugins.data.search);
const savedVisualizationsLoader = createSavedVisLoader({
savedObjectsClient: npStart.core.savedObjects.client,
indexPatterns: npStart.plugins.data.indexPatterns,
search: npStart.plugins.data.search,
chrome: npStart.core.chrome,
overlays: npStart.core.overlays,
visualizationTypes: visualizationsServices.getTypes(),
Expand Down
Loading