mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
searchsource ad-hoc data views support (#134762)
This commit is contained in:
parent
c8520f941a
commit
1aba5428b3
14 changed files with 85 additions and 30 deletions
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ jest.mock('./services', () => {
|
|||
getSearch: () => ({
|
||||
searchSource: {
|
||||
create: () => {
|
||||
return new SearchSource({ index: stubIndexPattern });
|
||||
return new SearchSource({ index: stubIndexPattern.stubDataView });
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
|
|
@ -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(),
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue