searchsource ad-hoc data views support (#134762)

This commit is contained in:
Peter Pisljar 2022-06-28 11:27:44 +02:00 committed by GitHub
parent c8520f941a
commit 1aba5428b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 85 additions and 30 deletions

View file

@ -41,7 +41,11 @@ export const createSearchSource = (
// hydrating index pattern
if (searchSourceFields.index) {
fields.index = await indexPatterns.get(searchSourceFields.index);
if (typeof searchSourceFields.index === 'string') {
fields.index = await indexPatterns.get(searchSourceFields.index);
} else {
fields.index = await indexPatterns.create(searchSourceFields.index);
}
}
if (searchSourceFields.parent) {

View file

@ -8,8 +8,8 @@
import { SavedObjectReference } from '@kbn/core/types';
import { Filter } from '@kbn/es-query';
import { DataViewPersistableStateService } from '@kbn/data-views-plugin/common';
import { SerializedSearchSourceFields } from './types';
import { DATA_VIEW_SAVED_OBJECT_TYPE } from '../..';
export const extractReferences = (
@ -18,18 +18,25 @@ export const extractReferences = (
let searchSourceFields: SerializedSearchSourceFields & { indexRefName?: string } = { ...state };
const references: SavedObjectReference[] = [];
if (searchSourceFields.index) {
const indexId = searchSourceFields.index;
const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
references.push({
name: refName,
type: DATA_VIEW_SAVED_OBJECT_TYPE,
id: indexId,
});
searchSourceFields = {
...searchSourceFields,
indexRefName: refName,
index: undefined,
};
if (typeof searchSourceFields.index === 'string') {
const indexId = searchSourceFields.index;
const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
references.push({
name: refName,
type: DATA_VIEW_SAVED_OBJECT_TYPE,
id: indexId,
});
searchSourceFields = {
...searchSourceFields,
indexRefName: refName,
index: undefined,
};
} else {
const { state: dataViewState, references: dataViewReferences } =
DataViewPersistableStateService.extract(searchSourceFields.index);
searchSourceFields.index = dataViewState;
references.push(...dataViewReferences);
}
}
if (searchSourceFields.filter) {

View file

@ -7,6 +7,7 @@
*/
import { SavedObjectReference } from '@kbn/core/types';
import { DataViewPersistableStateService } from '@kbn/data-views-plugin/common';
import { SerializedSearchSourceFields } from './types';
export const injectReferences = (
@ -26,6 +27,13 @@ export const injectReferences = (
delete searchSourceReturnFields.indexRefName;
}
if (searchSourceFields.index && typeof searchSourceFields.index !== 'string') {
searchSourceFields.index = DataViewPersistableStateService.inject(
searchSourceFields.index,
references
);
}
if (searchSourceReturnFields.filter && Array.isArray(searchSourceReturnFields.filter)) {
searchSourceReturnFields.filter.forEach((filterRow: any) => {
if (!filterRow.meta || !filterRow.meta.indexRefName) {

View file

@ -808,8 +808,8 @@ describe('SearchSource', () => {
});
describe('#serialize', () => {
const indexPattern123 = { id: '123', isPersisted: () => true } as DataView;
test('should reference index patterns', () => {
const indexPattern123 = { id: '123' } as DataView;
searchSource.setField('index', indexPattern123);
const { searchSourceJSON, references } = searchSource.serialize();
expect(references[0].id).toEqual('123');
@ -817,6 +817,22 @@ describe('SearchSource', () => {
expect(JSON.parse(searchSourceJSON).indexRefName).toEqual(references[0].name);
});
test('should contain persisted data view by value', () => {
const localDataView = {
id: 'local-123',
isPersisted: () => false,
toSpec: () => ({ id: 'local-123' }),
} as DataView;
searchSource.setField('index', localDataView);
const { searchSourceJSON, references } = searchSource.serialize();
expect(references.length).toEqual(0);
expect(JSON.parse(searchSourceJSON).index).toMatchInlineSnapshot(`
Object {
"id": "local-123",
}
`);
});
test('should add other fields', () => {
searchSource.setField('highlightAll', true);
searchSource.setField('from', 123456);
@ -851,7 +867,6 @@ describe('SearchSource', () => {
});
test('should reference index patterns in filters separately from index field', () => {
const indexPattern123 = { id: '123' } as DataView;
searchSource.setField('index', indexPattern123);
const filter = [
{
@ -908,8 +923,9 @@ describe('SearchSource', () => {
},
];
const indexPattern123 = { id: '123', isPersisted: () => true } as DataView;
test('should return serialized fields', () => {
const indexPattern123 = { id: '123' } as DataView;
searchSource.setField('index', indexPattern123);
searchSource.setField('filter', () => {
return filter;
@ -941,7 +957,6 @@ describe('SearchSource', () => {
});
test('should support nested search sources', () => {
const indexPattern123 = { id: '123' } as DataView;
searchSource.setField('index', indexPattern123);
searchSource.setField('from', 123);
const childSearchSource = searchSource.createChild();

View file

@ -885,7 +885,7 @@ export class SearchSource {
...searchSourceFields,
};
if (index) {
serializedSearchSourceFields.index = index.id;
serializedSearchSourceFields.index = index.isPersisted() ? index.id : index.toSpec();
}
if (sort) {
serializedSearchSourceFields.sort = !Array.isArray(sort) ? [sort] : sort;

View file

@ -11,7 +11,7 @@ import {
mergeMigrationFunctionMaps,
MigrateFunctionsObject,
} from '@kbn/kibana-utils-plugin/common';
import { DataViewsContract } from '@kbn/data-views-plugin/common';
import { DataViewPersistableStateService, DataViewsContract } from '@kbn/data-views-plugin/common';
import {
createSearchSource,
extractReferences,
@ -34,7 +34,20 @@ const getAllMigrations = (): MigrateFunctionsObject => {
});
});
return mergeMigrationFunctionMaps(searchSourceMigrations, filterMigrations);
const dataviewsMigrations = mapValues(
DataViewPersistableStateService.getAllMigrations(),
(migrate) => {
return (state: SerializedSearchSourceFields) => ({
...state,
index: migrate(state.index),
});
}
);
return mergeMigrationFunctionMaps(
mergeMigrationFunctionMaps(searchSourceMigrations, filterMigrations),
dataviewsMigrations
);
};
export class SearchSourceService {

View file

@ -10,7 +10,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { SerializableRecord } from '@kbn/utility-types';
import { PersistableStateService } from '@kbn/kibana-utils-plugin/common';
import type { Filter } from '@kbn/es-query';
import type { DataView } from '@kbn/data-views-plugin/common';
import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/common';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { AggConfigSerialized, IAggConfigs } from '../../../public';
import { Query } from '../..';
@ -159,7 +159,7 @@ export type SerializedSearchSourceFields = {
/**
* {@link IndexPatternService}
*/
index?: string;
index?: string | DataViewSpec;
searchAfter?: EsQuerySearchAfter;
timeout?: string;
terminate_after?: number;

View file

@ -45,10 +45,11 @@ export const createStubDataView = ({
deps?: {
fieldFormats?: FieldFormatsStartCommon;
};
}): DataView =>
new DataView({
spec,
}): DataView => {
return new DataView({
spec: { version: '1', ...spec },
metaFields: opts?.metaFields ?? ['_id', '_type', '_source'],
shortDotsEnable: opts?.shortDotsEnable,
fieldFormats: deps?.fieldFormats ?? fieldFormatsMock,
});
};

View file

@ -10,3 +10,4 @@ export * from './_pattern_cache';
export * from './flatten_hit';
export * from './data_view';
export * from './data_views';
export { DataViewPersistableStateService } from './persistable_state';

View file

@ -56,7 +56,7 @@ export type {
export { DataViewType } from './types';
export type { DataViewsContract, DataViewsServiceDeps } from './data_views';
export { DataViewsService } from './data_views';
export { DataViewsService, DataViewPersistableStateService } from './data_views';
export type {
DataViewListItem,
DataViewsServicePublicMethods,

View file

@ -97,6 +97,7 @@ export const buildDataViewMock = ({
docvalueFields: [],
getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })),
isTimeNanosBased: () => false,
isPersisted: () => true,
} as unknown as DataView;
dataView.isTimeBased = () => !!timeFieldName;

View file

@ -373,7 +373,7 @@ describe('Saved Object', () => {
} as SimpleSavedObject<SavedObjectAttributes>);
const indexPattern = createStubIndexPattern({
spec: { id: 'my-index', title: 'my-index' },
spec: { id: 'my-index', title: 'my-index', version: '1' },
});
savedObject.searchSource!.setField('index', indexPattern);
return savedObject.save(saveOptionsMock).then(() => {
@ -411,6 +411,7 @@ describe('Saved Object', () => {
const indexPattern = createStubIndexPattern({
spec: {
id: 'non-existant-index',
version: '1',
},
});

View file

@ -44,7 +44,7 @@ jest.mock('./services', () => {
getSearch: () => ({
searchSource: {
create: () => {
return new SearchSource({ index: stubIndexPattern });
return new SearchSource({ index: stubIndexPattern.stubDataView });
},
},
}),

View file

@ -167,9 +167,13 @@ export class Vis<TVisParams = VisParams> {
const configStates = this.initializeDefaultsFromSchemas(aggs, this.type.schemas.all || []);
if (!this.data.indexPattern && aggs.length) {
const dataViewId =
typeof state.data.searchSource?.index === 'string'
? state.data.searchSource?.index
: state.data.searchSource?.index?.id;
this.data.indexPattern = new DataView({
spec: {
id: state.data.savedSearchId ?? state.data.searchSource?.index,
id: state.data.savedSearchId ?? dataViewId,
},
fieldFormats: getFieldsFormats(),
});