mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Use Search API in TSVB (#76274)
* Use Search API for TSVB * Fixed ci * Fixed ci * Use constants * Fixed tests * Fixed ci * Fixed ci * Back old rollup search * Fixed test * Fixed tests * Fixed issue with series data * Fixed comments * Fixed comments * Fixed unit test * Deleted unused import * Fixed comments Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
9ac2fdfe26
commit
75a14594f2
30 changed files with 194 additions and 688 deletions
|
@ -21,7 +21,7 @@ import { PluginInitializerContext, PluginConfigDescriptor } from 'src/core/serve
|
|||
import { VisTypeTimeseriesConfig, config as configSchema } from './config';
|
||||
import { VisTypeTimeseriesPlugin } from './plugin';
|
||||
|
||||
export { VisTypeTimeseriesSetup, Framework } from './plugin';
|
||||
export { VisTypeTimeseriesSetup } from './plugin';
|
||||
|
||||
export const config: PluginConfigDescriptor<VisTypeTimeseriesConfig> = {
|
||||
deprecations: ({ unused, renameFromRoot }) => [
|
||||
|
@ -39,10 +39,10 @@ export const config: PluginConfigDescriptor<VisTypeTimeseriesConfig> = {
|
|||
|
||||
export { ValidationTelemetryServiceSetup } from './validation_telemetry';
|
||||
|
||||
// @ts-ignore
|
||||
export { AbstractSearchStrategy } from './lib/search_strategies/strategies/abstract_search_strategy';
|
||||
// @ts-ignore
|
||||
export { AbstractSearchRequest } from './lib/search_strategies/search_requests/abstract_request';
|
||||
export {
|
||||
AbstractSearchStrategy,
|
||||
ReqFacade,
|
||||
} from './lib/search_strategies/strategies/abstract_search_strategy';
|
||||
// @ts-ignore
|
||||
export { DefaultSearchCapabilities } from './lib/search_strategies/default_search_capabilities';
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ export async function getFields(
|
|||
// level object passed from here. The layers should be refactored fully at some point, but for now
|
||||
// this works and we are still using the New Platform services for these vis data portions.
|
||||
const reqFacade: ReqFacade = {
|
||||
requestContext,
|
||||
...request,
|
||||
framework,
|
||||
payload: {},
|
||||
|
@ -48,22 +49,6 @@ export async function getFields(
|
|||
},
|
||||
getUiSettingsService: () => requestContext.core.uiSettings.client,
|
||||
getSavedObjectsClient: () => requestContext.core.savedObjects.client,
|
||||
server: {
|
||||
plugins: {
|
||||
elasticsearch: {
|
||||
getCluster: () => {
|
||||
return {
|
||||
callWithRequest: async (req: any, endpoint: string, params: any) => {
|
||||
return await requestContext.core.elasticsearch.legacy.client.callAsCurrentUser(
|
||||
endpoint,
|
||||
params
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
getEsShardTimeout: async () => {
|
||||
return await framework.globalConfig$
|
||||
.pipe(
|
||||
|
|
|
@ -21,7 +21,7 @@ import { FakeRequest, RequestHandlerContext } from 'kibana/server';
|
|||
import _ from 'lodash';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
import { getPanelData } from './vis_data/get_panel_data';
|
||||
import { Framework } from '../index';
|
||||
import { Framework } from '../plugin';
|
||||
import { ReqFacade } from './search_strategies/strategies/abstract_search_strategy';
|
||||
|
||||
interface GetVisDataResponse {
|
||||
|
@ -65,28 +65,13 @@ export function getVisData(
|
|||
// level object passed from here. The layers should be refactored fully at some point, but for now
|
||||
// this works and we are still using the New Platform services for these vis data portions.
|
||||
const reqFacade: ReqFacade = {
|
||||
requestContext,
|
||||
...request,
|
||||
framework,
|
||||
pre: {},
|
||||
payload: request.body,
|
||||
getUiSettingsService: () => requestContext.core.uiSettings.client,
|
||||
getSavedObjectsClient: () => requestContext.core.savedObjects.client,
|
||||
server: {
|
||||
plugins: {
|
||||
elasticsearch: {
|
||||
getCluster: () => {
|
||||
return {
|
||||
callWithRequest: async (req: any, endpoint: string, params: any) => {
|
||||
return await requestContext.core.elasticsearch.legacy.client.callAsCurrentUser(
|
||||
endpoint,
|
||||
params
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
getEsShardTimeout: async () => {
|
||||
return await framework.globalConfig$
|
||||
.pipe(
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
export class AbstractSearchRequest {
|
||||
constructor(req, callWithRequest) {
|
||||
this.req = req;
|
||||
this.callWithRequest = callWithRequest;
|
||||
}
|
||||
|
||||
search() {
|
||||
throw new Error('AbstractSearchRequest: search method should be defined');
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { AbstractSearchRequest } from './abstract_request';
|
||||
|
||||
describe('AbstractSearchRequest', () => {
|
||||
let searchRequest;
|
||||
let req;
|
||||
let callWithRequest;
|
||||
|
||||
beforeEach(() => {
|
||||
req = {};
|
||||
callWithRequest = jest.fn();
|
||||
searchRequest = new AbstractSearchRequest(req, callWithRequest);
|
||||
});
|
||||
|
||||
test('should init an AbstractSearchRequest instance', () => {
|
||||
expect(searchRequest.req).toBe(req);
|
||||
expect(searchRequest.callWithRequest).toBe(callWithRequest);
|
||||
expect(searchRequest.search).toBeDefined();
|
||||
});
|
||||
|
||||
test('should throw an error trying to search', () => {
|
||||
try {
|
||||
searchRequest.search();
|
||||
} catch (error) {
|
||||
expect(error instanceof Error).toBe(true);
|
||||
expect(error.message).toEqual('AbstractSearchRequest: search method should be defined');
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { AbstractSearchRequest } from './abstract_request';
|
||||
import { UI_SETTINGS } from '../../../../../data/server';
|
||||
|
||||
const SEARCH_METHOD = 'msearch';
|
||||
|
||||
export class MultiSearchRequest extends AbstractSearchRequest {
|
||||
async search(searches) {
|
||||
const includeFrozen = await this.req
|
||||
.getUiSettingsService()
|
||||
.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN);
|
||||
const multiSearchBody = searches.reduce(
|
||||
(acc, { body, index }) => [
|
||||
...acc,
|
||||
{
|
||||
index,
|
||||
ignoreUnavailable: true,
|
||||
},
|
||||
body,
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const { responses } = await this.callWithRequest(this.req, SEARCH_METHOD, {
|
||||
body: multiSearchBody,
|
||||
rest_total_hits_as_int: true,
|
||||
ignore_throttled: !includeFrozen,
|
||||
});
|
||||
|
||||
return responses;
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { MultiSearchRequest } from './multi_search_request';
|
||||
import { UI_SETTINGS } from '../../../../../data/server';
|
||||
|
||||
describe('MultiSearchRequest', () => {
|
||||
let searchRequest;
|
||||
let req;
|
||||
let callWithRequest;
|
||||
let getServiceMock;
|
||||
let includeFrozen;
|
||||
|
||||
beforeEach(() => {
|
||||
includeFrozen = false;
|
||||
getServiceMock = jest.fn().mockResolvedValue(includeFrozen);
|
||||
req = {
|
||||
getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock }),
|
||||
};
|
||||
callWithRequest = jest.fn().mockReturnValue({ responses: [] });
|
||||
searchRequest = new MultiSearchRequest(req, callWithRequest);
|
||||
});
|
||||
|
||||
test('should init an MultiSearchRequest instance', () => {
|
||||
expect(searchRequest.req).toBe(req);
|
||||
expect(searchRequest.callWithRequest).toBe(callWithRequest);
|
||||
expect(searchRequest.search).toBeDefined();
|
||||
});
|
||||
|
||||
test('should get the response from elastic msearch', async () => {
|
||||
const searches = [
|
||||
{ body: 'body1', index: 'index' },
|
||||
{ body: 'body2', index: 'index' },
|
||||
];
|
||||
|
||||
const responses = await searchRequest.search(searches);
|
||||
|
||||
expect(responses).toEqual([]);
|
||||
expect(req.getUiSettingsService).toHaveBeenCalled();
|
||||
expect(getServiceMock).toHaveBeenCalledWith(UI_SETTINGS.SEARCH_INCLUDE_FROZEN);
|
||||
expect(callWithRequest).toHaveBeenCalledWith(req, 'msearch', {
|
||||
body: [
|
||||
{ ignoreUnavailable: true, index: 'index' },
|
||||
'body1',
|
||||
{ ignoreUnavailable: true, index: 'index' },
|
||||
'body2',
|
||||
],
|
||||
rest_total_hits_as_int: true,
|
||||
ignore_throttled: !includeFrozen,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { AbstractSearchRequest } from './abstract_request';
|
||||
|
||||
import { MultiSearchRequest } from './multi_search_request';
|
||||
import { SingleSearchRequest } from './single_search_request';
|
||||
|
||||
export class SearchRequest extends AbstractSearchRequest {
|
||||
getSearchRequestType(searches) {
|
||||
const isMultiSearch = Array.isArray(searches) && searches.length > 1;
|
||||
const SearchRequest = isMultiSearch ? MultiSearchRequest : SingleSearchRequest;
|
||||
|
||||
return new SearchRequest(this.req, this.callWithRequest);
|
||||
}
|
||||
|
||||
async search(options) {
|
||||
const concreteSearchRequest = this.getSearchRequestType(options);
|
||||
|
||||
return concreteSearchRequest.search(options);
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { SearchRequest } from './search_request';
|
||||
import { MultiSearchRequest } from './multi_search_request';
|
||||
import { SingleSearchRequest } from './single_search_request';
|
||||
|
||||
describe('SearchRequest', () => {
|
||||
let searchRequest;
|
||||
let req;
|
||||
let callWithRequest;
|
||||
let getServiceMock;
|
||||
let includeFrozen;
|
||||
|
||||
beforeEach(() => {
|
||||
includeFrozen = false;
|
||||
getServiceMock = jest.fn().mockResolvedValue(includeFrozen);
|
||||
req = {
|
||||
getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock }),
|
||||
};
|
||||
callWithRequest = jest.fn().mockReturnValue({ responses: [] });
|
||||
searchRequest = new SearchRequest(req, callWithRequest);
|
||||
});
|
||||
|
||||
test('should init an AbstractSearchRequest instance', () => {
|
||||
expect(searchRequest.req).toBe(req);
|
||||
expect(searchRequest.callWithRequest).toBe(callWithRequest);
|
||||
expect(searchRequest.search).toBeDefined();
|
||||
});
|
||||
|
||||
test('should return search value', async () => {
|
||||
const concreteSearchRequest = {
|
||||
search: jest.fn().mockReturnValue('concreteSearchRequest'),
|
||||
};
|
||||
const options = {};
|
||||
searchRequest.getSearchRequestType = jest.fn().mockReturnValue(concreteSearchRequest);
|
||||
|
||||
const result = await searchRequest.search(options);
|
||||
|
||||
expect(result).toBe('concreteSearchRequest');
|
||||
});
|
||||
|
||||
test('should return a MultiSearchRequest for multi searches', () => {
|
||||
const searches = [
|
||||
{ index: 'index', body: 'body' },
|
||||
{ index: 'index', body: 'body' },
|
||||
];
|
||||
|
||||
const result = searchRequest.getSearchRequestType(searches);
|
||||
|
||||
expect(result instanceof MultiSearchRequest).toBe(true);
|
||||
});
|
||||
|
||||
test('should return a SingleSearchRequest for single search', () => {
|
||||
const searches = [{ index: 'index', body: 'body' }];
|
||||
|
||||
const result = searchRequest.getSearchRequestType(searches);
|
||||
|
||||
expect(result instanceof SingleSearchRequest).toBe(true);
|
||||
});
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { AbstractSearchRequest } from './abstract_request';
|
||||
import { UI_SETTINGS } from '../../../../../data/server';
|
||||
|
||||
const SEARCH_METHOD = 'search';
|
||||
|
||||
export class SingleSearchRequest extends AbstractSearchRequest {
|
||||
async search([{ body, index }]) {
|
||||
const includeFrozen = await this.req
|
||||
.getUiSettingsService()
|
||||
.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN);
|
||||
const resp = await this.callWithRequest(this.req, SEARCH_METHOD, {
|
||||
ignore_throttled: !includeFrozen,
|
||||
body,
|
||||
index,
|
||||
});
|
||||
|
||||
return [resp];
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { SingleSearchRequest } from './single_search_request';
|
||||
import { UI_SETTINGS } from '../../../../../data/server';
|
||||
|
||||
describe('SingleSearchRequest', () => {
|
||||
let searchRequest;
|
||||
let req;
|
||||
let callWithRequest;
|
||||
let getServiceMock;
|
||||
let includeFrozen;
|
||||
|
||||
beforeEach(() => {
|
||||
includeFrozen = false;
|
||||
getServiceMock = jest.fn().mockResolvedValue(includeFrozen);
|
||||
req = {
|
||||
getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock }),
|
||||
};
|
||||
callWithRequest = jest.fn().mockReturnValue({});
|
||||
searchRequest = new SingleSearchRequest(req, callWithRequest);
|
||||
});
|
||||
|
||||
test('should init an SingleSearchRequest instance', () => {
|
||||
expect(searchRequest.req).toBe(req);
|
||||
expect(searchRequest.callWithRequest).toBe(callWithRequest);
|
||||
expect(searchRequest.search).toBeDefined();
|
||||
});
|
||||
|
||||
test('should get the response from elastic search', async () => {
|
||||
const searches = [{ body: 'body', index: 'index' }];
|
||||
|
||||
const responses = await searchRequest.search(searches);
|
||||
|
||||
expect(responses).toEqual([{}]);
|
||||
expect(req.getUiSettingsService).toHaveBeenCalled();
|
||||
expect(getServiceMock).toHaveBeenCalledWith(UI_SETTINGS.SEARCH_INCLUDE_FROZEN);
|
||||
expect(callWithRequest).toHaveBeenCalledWith(req, 'search', {
|
||||
body: 'body',
|
||||
index: 'index',
|
||||
ignore_throttled: !includeFrozen,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -65,7 +65,7 @@ describe('SearchStrategyRegister', () => {
|
|||
});
|
||||
|
||||
test('should add a strategy if it is an instance of AbstractSearchStrategy', () => {
|
||||
const anotherSearchStrategy = new MockSearchStrategy({}, {} as any, {});
|
||||
const anotherSearchStrategy = new MockSearchStrategy('es');
|
||||
const addedStrategies = registry.addStrategy(anotherSearchStrategy);
|
||||
|
||||
expect(addedStrategies.length).toEqual(2);
|
||||
|
@ -75,7 +75,7 @@ describe('SearchStrategyRegister', () => {
|
|||
test('should return a MockSearchStrategy instance', async () => {
|
||||
const req = {};
|
||||
const indexPattern = '*';
|
||||
const anotherSearchStrategy = new MockSearchStrategy({}, {} as any, {});
|
||||
const anotherSearchStrategy = new MockSearchStrategy('es');
|
||||
registry.addStrategy(anotherSearchStrategy);
|
||||
|
||||
const { searchStrategy, capabilities } = (await registry.getViableStrategy(req, indexPattern))!;
|
||||
|
|
|
@ -18,24 +18,13 @@
|
|||
*/
|
||||
import { AbstractSearchStrategy } from './abstract_search_strategy';
|
||||
|
||||
class SearchRequest {
|
||||
constructor(req, callWithRequest) {
|
||||
this.req = req;
|
||||
this.callWithRequest = callWithRequest;
|
||||
}
|
||||
}
|
||||
|
||||
describe('AbstractSearchStrategy', () => {
|
||||
let abstractSearchStrategy;
|
||||
let server;
|
||||
let callWithRequestFactory;
|
||||
let req;
|
||||
let mockedFields;
|
||||
let indexPattern;
|
||||
|
||||
beforeEach(() => {
|
||||
server = {};
|
||||
callWithRequestFactory = jest.fn().mockReturnValue('callWithRequest');
|
||||
mockedFields = {};
|
||||
req = {
|
||||
pre: {
|
||||
|
@ -45,16 +34,11 @@ describe('AbstractSearchStrategy', () => {
|
|||
},
|
||||
};
|
||||
|
||||
abstractSearchStrategy = new AbstractSearchStrategy(
|
||||
server,
|
||||
callWithRequestFactory,
|
||||
SearchRequest
|
||||
);
|
||||
abstractSearchStrategy = new AbstractSearchStrategy('es');
|
||||
});
|
||||
|
||||
test('should init an AbstractSearchStrategy instance', () => {
|
||||
expect(abstractSearchStrategy.getCallWithRequestInstance).toBeDefined();
|
||||
expect(abstractSearchStrategy.getSearchRequest).toBeDefined();
|
||||
expect(abstractSearchStrategy.search).toBeDefined();
|
||||
expect(abstractSearchStrategy.getFieldsForWildcard).toBeDefined();
|
||||
expect(abstractSearchStrategy.checkForViability).toBeDefined();
|
||||
});
|
||||
|
@ -68,17 +52,46 @@ describe('AbstractSearchStrategy', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('should invoke callWithRequestFactory with req param passed', () => {
|
||||
abstractSearchStrategy.getCallWithRequestInstance(req);
|
||||
test('should return response', async () => {
|
||||
const searches = [{ body: 'body', index: 'index' }];
|
||||
const searchFn = jest.fn().mockReturnValue(Promise.resolve({}));
|
||||
|
||||
expect(callWithRequestFactory).toHaveBeenCalledWith(server, req);
|
||||
});
|
||||
const responses = await abstractSearchStrategy.search(
|
||||
{
|
||||
requestContext: {},
|
||||
framework: {
|
||||
core: {
|
||||
getStartServices: jest.fn().mockReturnValue(
|
||||
Promise.resolve([
|
||||
{},
|
||||
{
|
||||
data: {
|
||||
search: {
|
||||
search: searchFn,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
searches
|
||||
);
|
||||
|
||||
test('should return a search request', () => {
|
||||
const searchRequest = abstractSearchStrategy.getSearchRequest(req);
|
||||
|
||||
expect(searchRequest instanceof SearchRequest).toBe(true);
|
||||
expect(searchRequest.callWithRequest).toBe('callWithRequest');
|
||||
expect(searchRequest.req).toBe(req);
|
||||
expect(responses).toEqual([{}]);
|
||||
expect(searchFn).toHaveBeenCalledWith(
|
||||
{},
|
||||
{
|
||||
params: {
|
||||
body: 'body',
|
||||
index: 'index',
|
||||
},
|
||||
indexType: undefined,
|
||||
},
|
||||
{
|
||||
strategy: 'es',
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
LegacyAPICaller,
|
||||
RequestHandlerContext,
|
||||
FakeRequest,
|
||||
IUiSettingsClient,
|
||||
SavedObjectsClientContract,
|
||||
|
@ -33,6 +33,7 @@ import { IndexPatternsFetcher } from '../../../../../data/server';
|
|||
* This will be replaced by standard KibanaRequest and RequestContext objects in a later version.
|
||||
*/
|
||||
export type ReqFacade = FakeRequest & {
|
||||
requestContext: RequestHandlerContext;
|
||||
framework: Framework;
|
||||
payload: unknown;
|
||||
pre: {
|
||||
|
@ -40,34 +41,42 @@ export type ReqFacade = FakeRequest & {
|
|||
};
|
||||
getUiSettingsService: () => IUiSettingsClient;
|
||||
getSavedObjectsClient: () => SavedObjectsClientContract;
|
||||
server: {
|
||||
plugins: {
|
||||
elasticsearch: {
|
||||
getCluster: () => {
|
||||
callWithRequest: (req: ReqFacade, endpoint: string, params: any) => Promise<any>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
getEsShardTimeout: () => Promise<number>;
|
||||
};
|
||||
|
||||
export class AbstractSearchStrategy {
|
||||
public getCallWithRequestInstance: (req: ReqFacade) => LegacyAPICaller;
|
||||
public getSearchRequest: (req: ReqFacade) => any;
|
||||
public searchStrategyName!: string;
|
||||
public indexType?: string;
|
||||
public additionalParams: any;
|
||||
|
||||
constructor(
|
||||
server: any,
|
||||
callWithRequestFactory: (server: any, req: ReqFacade) => LegacyAPICaller,
|
||||
SearchRequest: any
|
||||
) {
|
||||
this.getCallWithRequestInstance = (req) => callWithRequestFactory(server, req);
|
||||
constructor(name: string, type?: string, additionalParams: any = {}) {
|
||||
this.searchStrategyName = name;
|
||||
this.indexType = type;
|
||||
this.additionalParams = additionalParams;
|
||||
}
|
||||
|
||||
this.getSearchRequest = (req) => {
|
||||
const callWithRequest = this.getCallWithRequestInstance(req);
|
||||
|
||||
return new SearchRequest(req, callWithRequest);
|
||||
};
|
||||
async search(req: ReqFacade, bodies: any[], options = {}) {
|
||||
const [, deps] = await req.framework.core.getStartServices();
|
||||
const requests: any[] = [];
|
||||
bodies.forEach((body) => {
|
||||
requests.push(
|
||||
deps.data.search.search(
|
||||
req.requestContext,
|
||||
{
|
||||
params: {
|
||||
...body,
|
||||
...this.additionalParams,
|
||||
},
|
||||
indexType: this.indexType,
|
||||
},
|
||||
{
|
||||
...options,
|
||||
strategy: this.searchStrategyName,
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
return Promise.all(requests);
|
||||
}
|
||||
|
||||
async getFieldsForWildcard(req: ReqFacade, indexPattern: string, capabilities: any) {
|
||||
|
|
|
@ -16,21 +16,16 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ES_SEARCH_STRATEGY } from '../../../../../data/server';
|
||||
import { AbstractSearchStrategy } from './abstract_search_strategy';
|
||||
import { SearchRequest } from '../search_requests/search_request';
|
||||
import { DefaultSearchCapabilities } from '../default_search_capabilities';
|
||||
|
||||
const callWithRequestFactory = (server, request) => {
|
||||
const { callWithRequest } = request.server.plugins.elasticsearch.getCluster('data');
|
||||
|
||||
return callWithRequest;
|
||||
};
|
||||
|
||||
export class DefaultSearchStrategy extends AbstractSearchStrategy {
|
||||
name = 'default';
|
||||
|
||||
constructor(server) {
|
||||
super(server, callWithRequestFactory, SearchRequest);
|
||||
constructor() {
|
||||
super(ES_SEARCH_STRATEGY);
|
||||
}
|
||||
|
||||
checkForViability(req) {
|
||||
|
|
|
@ -20,42 +20,20 @@ import { DefaultSearchStrategy } from './default_search_strategy';
|
|||
|
||||
describe('DefaultSearchStrategy', () => {
|
||||
let defaultSearchStrategy;
|
||||
let server;
|
||||
let callWithRequest;
|
||||
let req;
|
||||
|
||||
beforeEach(() => {
|
||||
server = {};
|
||||
callWithRequest = jest.fn();
|
||||
req = {
|
||||
server: {
|
||||
plugins: {
|
||||
elasticsearch: {
|
||||
getCluster: jest.fn().mockReturnValue({
|
||||
callWithRequest,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
defaultSearchStrategy = new DefaultSearchStrategy(server);
|
||||
req = {};
|
||||
defaultSearchStrategy = new DefaultSearchStrategy();
|
||||
});
|
||||
|
||||
test('should init an DefaultSearchStrategy instance', () => {
|
||||
expect(defaultSearchStrategy.name).toBe('default');
|
||||
expect(defaultSearchStrategy.checkForViability).toBeDefined();
|
||||
expect(defaultSearchStrategy.getCallWithRequestInstance).toBeDefined();
|
||||
expect(defaultSearchStrategy.getSearchRequest).toBeDefined();
|
||||
expect(defaultSearchStrategy.search).toBeDefined();
|
||||
expect(defaultSearchStrategy.getFieldsForWildcard).toBeDefined();
|
||||
});
|
||||
|
||||
test('should invoke callWithRequestFactory with passed params', () => {
|
||||
const value = defaultSearchStrategy.getCallWithRequestInstance(req);
|
||||
|
||||
expect(value).toBe(callWithRequest);
|
||||
expect(req.server.plugins.elasticsearch.getCluster).toHaveBeenCalledWith('data');
|
||||
});
|
||||
|
||||
test('should check a strategy for viability', () => {
|
||||
const value = defaultSearchStrategy.checkForViability(req);
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@ export async function getAnnotations({
|
|||
capabilities,
|
||||
series,
|
||||
}) {
|
||||
const searchRequest = searchStrategy.getSearchRequest(req);
|
||||
const annotations = panel.annotations.filter(validAnnotation);
|
||||
const lastSeriesTimestamp = getLastSeriesTimestamp(series);
|
||||
const handleAnnotationResponseBy = handleAnnotationResponse(lastSeriesTimestamp);
|
||||
|
@ -47,6 +46,7 @@ export async function getAnnotations({
|
|||
const bodiesPromises = annotations.map((annotation) =>
|
||||
getAnnotationRequestParams(req, panel, annotation, esQueryConfig, capabilities)
|
||||
);
|
||||
|
||||
const searches = (await Promise.all(bodiesPromises)).reduce(
|
||||
(acc, items) => acc.concat(items),
|
||||
[]
|
||||
|
@ -55,10 +55,10 @@ export async function getAnnotations({
|
|||
if (!searches.length) return { responses: [] };
|
||||
|
||||
try {
|
||||
const data = await searchRequest.search(searches);
|
||||
const data = await searchStrategy.search(req.framework.core, req.requestContext, searches);
|
||||
|
||||
return annotations.reduce((acc, annotation, index) => {
|
||||
acc[annotation.id] = handleAnnotationResponseBy(data[index], annotation);
|
||||
acc[annotation.id] = handleAnnotationResponseBy(data[index].rawResponse, annotation);
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
|
|
@ -28,7 +28,6 @@ export async function getSeriesData(req, panel) {
|
|||
searchStrategy,
|
||||
capabilities,
|
||||
} = await req.framework.searchStrategyRegistry.getViableStrategyForPanel(req, panel);
|
||||
const searchRequest = searchStrategy.getSearchRequest(req);
|
||||
const esQueryConfig = await getEsQueryConfig(req);
|
||||
const meta = {
|
||||
type: panel.type,
|
||||
|
@ -45,8 +44,13 @@ export async function getSeriesData(req, panel) {
|
|||
[]
|
||||
);
|
||||
|
||||
const data = await searchRequest.search(searches);
|
||||
const series = data.map(handleResponseBody(panel));
|
||||
const data = await searchStrategy.search(req, searches);
|
||||
|
||||
const handleResponseBodyFn = handleResponseBody(panel);
|
||||
|
||||
const series = data.map((resp) =>
|
||||
handleResponseBodyFn(resp.rawResponse ? resp.rawResponse : resp)
|
||||
);
|
||||
let annotations = null;
|
||||
|
||||
if (panel.annotations && panel.annotations.length) {
|
||||
|
|
|
@ -30,7 +30,6 @@ export async function getTableData(req, panel) {
|
|||
searchStrategy,
|
||||
capabilities,
|
||||
} = await req.framework.searchStrategyRegistry.getViableStrategy(req, panelIndexPattern);
|
||||
const searchRequest = searchStrategy.getSearchRequest(req);
|
||||
const esQueryConfig = await getEsQueryConfig(req);
|
||||
const { indexPatternObject } = await getIndexPatternObject(req, panelIndexPattern);
|
||||
|
||||
|
@ -41,13 +40,18 @@ export async function getTableData(req, panel) {
|
|||
|
||||
try {
|
||||
const body = buildRequestBody(req, panel, esQueryConfig, indexPatternObject, capabilities);
|
||||
const [resp] = await searchRequest.search([
|
||||
const [resp] = await searchStrategy.search(req, [
|
||||
{
|
||||
body,
|
||||
index: panelIndexPattern,
|
||||
},
|
||||
]);
|
||||
const buckets = get(resp, 'aggregations.pivot.buckets', []);
|
||||
|
||||
const buckets = get(
|
||||
resp.rawResponse ? resp.rawResponse : resp,
|
||||
'aggregations.pivot.buckets',
|
||||
[]
|
||||
);
|
||||
|
||||
return {
|
||||
...meta,
|
||||
|
|
|
@ -33,6 +33,7 @@ import { VisTypeTimeseriesConfig } from './config';
|
|||
import { getVisData, GetVisData, GetVisDataOptions } from './lib/get_vis_data';
|
||||
import { ValidationTelemetryService } from './validation_telemetry';
|
||||
import { UsageCollectionSetup } from '../../usage_collection/server';
|
||||
import { PluginStart } from '../../data/server';
|
||||
import { visDataRoutes } from './routes/vis';
|
||||
// @ts-ignore
|
||||
import { fieldsRoutes } from './routes/fields';
|
||||
|
@ -47,6 +48,10 @@ interface VisTypeTimeseriesPluginSetupDependencies {
|
|||
usageCollection?: UsageCollectionSetup;
|
||||
}
|
||||
|
||||
interface VisTypeTimeseriesPluginStartDependencies {
|
||||
data: PluginStart;
|
||||
}
|
||||
|
||||
export interface VisTypeTimeseriesSetup {
|
||||
getVisData: (
|
||||
requestContext: RequestHandlerContext,
|
||||
|
@ -57,7 +62,7 @@ export interface VisTypeTimeseriesSetup {
|
|||
}
|
||||
|
||||
export interface Framework {
|
||||
core: CoreSetup;
|
||||
core: CoreSetup<VisTypeTimeseriesPluginStartDependencies>;
|
||||
plugins: any;
|
||||
config$: Observable<VisTypeTimeseriesConfig>;
|
||||
globalConfig$: PluginInitializerContext['config']['legacy']['globalConfig$'];
|
||||
|
@ -74,7 +79,10 @@ export class VisTypeTimeseriesPlugin implements Plugin<VisTypeTimeseriesSetup> {
|
|||
this.validationTelementryService = new ValidationTelemetryService();
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup, plugins: VisTypeTimeseriesPluginSetupDependencies) {
|
||||
public setup(
|
||||
core: CoreSetup<VisTypeTimeseriesPluginStartDependencies>,
|
||||
plugins: VisTypeTimeseriesPluginSetupDependencies
|
||||
) {
|
||||
const logger = this.initializerContext.logger.get('visTypeTimeseries');
|
||||
core.uiSettings.register(uiSettings);
|
||||
const config$ = this.initializerContext.config.create<VisTypeTimeseriesConfig>();
|
||||
|
|
|
@ -21,7 +21,8 @@ import { IRouter, KibanaRequest } from 'kibana/server';
|
|||
import { schema } from '@kbn/config-schema';
|
||||
import { getVisData, GetVisDataOptions } from '../lib/get_vis_data';
|
||||
import { visPayloadSchema } from '../../common/vis_schema';
|
||||
import { Framework, ValidationTelemetryServiceSetup } from '../index';
|
||||
import { ValidationTelemetryServiceSetup } from '../index';
|
||||
import { Framework } from '../plugin';
|
||||
|
||||
const escapeHatch = schema.object({}, { unknowns: 'allow' });
|
||||
|
||||
|
|
|
@ -11,4 +11,6 @@ export function plugin(initializerContext: PluginInitializerContext) {
|
|||
return new EnhancedDataServerPlugin(initializerContext);
|
||||
}
|
||||
|
||||
export { ENHANCED_ES_SEARCH_STRATEGY } from '../common';
|
||||
|
||||
export { EnhancedDataServerPlugin as Plugin };
|
||||
|
|
|
@ -6,21 +6,16 @@
|
|||
import { registerRollupSearchStrategy } from './register_rollup_search_strategy';
|
||||
|
||||
describe('Register Rollup Search Strategy', () => {
|
||||
let routeDependencies;
|
||||
let addSearchStrategy;
|
||||
let getRollupService;
|
||||
|
||||
beforeEach(() => {
|
||||
routeDependencies = {
|
||||
router: jest.fn().mockName('router'),
|
||||
elasticsearchService: jest.fn().mockName('elasticsearchService'),
|
||||
elasticsearch: jest.fn().mockName('elasticsearch'),
|
||||
};
|
||||
|
||||
addSearchStrategy = jest.fn().mockName('addSearchStrategy');
|
||||
getRollupService = jest.fn().mockName('getRollupService');
|
||||
});
|
||||
|
||||
test('should run initialization', () => {
|
||||
registerRollupSearchStrategy(routeDependencies, addSearchStrategy);
|
||||
registerRollupSearchStrategy(addSearchStrategy, getRollupService);
|
||||
|
||||
expect(addSearchStrategy).toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
@ -4,27 +4,24 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ILegacyScopedClusterClient } from 'src/core/server';
|
||||
import {
|
||||
AbstractSearchRequest,
|
||||
DefaultSearchCapabilities,
|
||||
AbstractSearchStrategy,
|
||||
ReqFacade,
|
||||
} from '../../../../../../src/plugins/vis_type_timeseries/server';
|
||||
import { CallWithRequestFactoryShim } from '../../types';
|
||||
import { getRollupSearchStrategy } from './rollup_search_strategy';
|
||||
import { getRollupSearchRequest } from './rollup_search_request';
|
||||
import { getRollupSearchCapabilities } from './rollup_search_capabilities';
|
||||
|
||||
export const registerRollupSearchStrategy = (
|
||||
callWithRequestFactory: CallWithRequestFactoryShim,
|
||||
addSearchStrategy: (searchStrategy: any) => void
|
||||
addSearchStrategy: (searchStrategy: any) => void,
|
||||
getRollupService: (reg: ReqFacade) => Promise<ILegacyScopedClusterClient>
|
||||
) => {
|
||||
const RollupSearchRequest = getRollupSearchRequest(AbstractSearchRequest);
|
||||
const RollupSearchCapabilities = getRollupSearchCapabilities(DefaultSearchCapabilities);
|
||||
const RollupSearchStrategy = getRollupSearchStrategy(
|
||||
AbstractSearchStrategy,
|
||||
RollupSearchRequest,
|
||||
RollupSearchCapabilities,
|
||||
callWithRequestFactory
|
||||
getRollupService
|
||||
);
|
||||
|
||||
addSearchStrategy(new RollupSearchStrategy());
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { getRollupSearchRequest } from './rollup_search_request';
|
||||
|
||||
class AbstractSearchRequest {
|
||||
indexPattern = 'indexPattern';
|
||||
callWithRequest = jest.fn(({ body }) => Promise.resolve(body));
|
||||
}
|
||||
|
||||
describe('Rollup search request', () => {
|
||||
let RollupSearchRequest;
|
||||
|
||||
beforeEach(() => {
|
||||
RollupSearchRequest = getRollupSearchRequest(AbstractSearchRequest);
|
||||
});
|
||||
|
||||
test('should create instance of RollupSearchRequest', () => {
|
||||
const rollupSearchRequest = new RollupSearchRequest();
|
||||
|
||||
expect(rollupSearchRequest).toBeInstanceOf(AbstractSearchRequest);
|
||||
expect(rollupSearchRequest.search).toBeDefined();
|
||||
expect(rollupSearchRequest.callWithRequest).toBeDefined();
|
||||
});
|
||||
|
||||
test('should send one request for single search', async () => {
|
||||
const rollupSearchRequest = new RollupSearchRequest();
|
||||
const searches = [{ body: 'body', index: 'index' }];
|
||||
|
||||
await rollupSearchRequest.search(searches);
|
||||
|
||||
expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledTimes(1);
|
||||
expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledWith('rollup.search', {
|
||||
body: 'body',
|
||||
index: 'index',
|
||||
rest_total_hits_as_int: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('should send multiple request for multi search', async () => {
|
||||
const rollupSearchRequest = new RollupSearchRequest();
|
||||
const searches = [
|
||||
{ body: 'body', index: 'index' },
|
||||
{ body: 'body1', index: 'index' },
|
||||
];
|
||||
|
||||
await rollupSearchRequest.search(searches);
|
||||
|
||||
expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
const SEARCH_METHOD = 'rollup.search';
|
||||
|
||||
interface Search {
|
||||
index: string;
|
||||
body: {
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export const getRollupSearchRequest = (AbstractSearchRequest: any) =>
|
||||
class RollupSearchRequest extends AbstractSearchRequest {
|
||||
async search(searches: Search[]) {
|
||||
const requests = searches.map(({ body, index }) =>
|
||||
this.callWithRequest(SEARCH_METHOD, {
|
||||
body,
|
||||
index,
|
||||
rest_total_hits_as_int: true,
|
||||
})
|
||||
);
|
||||
|
||||
return await Promise.all(requests);
|
||||
}
|
||||
};
|
|
@ -7,13 +7,32 @@ import { getRollupSearchStrategy } from './rollup_search_strategy';
|
|||
|
||||
describe('Rollup Search Strategy', () => {
|
||||
let RollupSearchStrategy;
|
||||
let RollupSearchRequest;
|
||||
let RollupSearchCapabilities;
|
||||
let callWithRequest;
|
||||
let rollupResolvedData;
|
||||
|
||||
const server = 'server';
|
||||
const request = 'request';
|
||||
const request = {
|
||||
requestContext: {
|
||||
core: {
|
||||
elasticsearch: {
|
||||
client: {
|
||||
asCurrentUser: {
|
||||
rollup: {
|
||||
getRollupIndexCaps: jest.fn().mockImplementation(() => rollupResolvedData),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const getRollupService = jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
callAsCurrentUser: async () => {
|
||||
return rollupResolvedData;
|
||||
},
|
||||
};
|
||||
});
|
||||
const indexPattern = 'indexPattern';
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -33,19 +52,17 @@ describe('Rollup Search Strategy', () => {
|
|||
}
|
||||
}
|
||||
|
||||
RollupSearchRequest = jest.fn();
|
||||
RollupSearchCapabilities = jest.fn(() => 'capabilities');
|
||||
callWithRequest = jest.fn().mockImplementation(() => rollupResolvedData);
|
||||
|
||||
RollupSearchStrategy = getRollupSearchStrategy(
|
||||
AbstractSearchStrategy,
|
||||
RollupSearchRequest,
|
||||
RollupSearchCapabilities
|
||||
RollupSearchCapabilities,
|
||||
getRollupService
|
||||
);
|
||||
});
|
||||
|
||||
test('should create instance of RollupSearchRequest', () => {
|
||||
const rollupSearchStrategy = new RollupSearchStrategy(server);
|
||||
const rollupSearchStrategy = new RollupSearchStrategy();
|
||||
|
||||
expect(rollupSearchStrategy.name).toBe('rollup');
|
||||
});
|
||||
|
@ -55,7 +72,7 @@ describe('Rollup Search Strategy', () => {
|
|||
const rollupIndex = 'rollupIndex';
|
||||
|
||||
beforeEach(() => {
|
||||
rollupSearchStrategy = new RollupSearchStrategy(server);
|
||||
rollupSearchStrategy = new RollupSearchStrategy();
|
||||
rollupSearchStrategy.getRollupData = jest.fn(() => ({
|
||||
[rollupIndex]: {
|
||||
rollup_jobs: [
|
||||
|
@ -104,7 +121,7 @@ describe('Rollup Search Strategy', () => {
|
|||
let rollupSearchStrategy;
|
||||
|
||||
beforeEach(() => {
|
||||
rollupSearchStrategy = new RollupSearchStrategy(server);
|
||||
rollupSearchStrategy = new RollupSearchStrategy();
|
||||
});
|
||||
|
||||
test('should return rollup data', async () => {
|
||||
|
@ -112,10 +129,7 @@ describe('Rollup Search Strategy', () => {
|
|||
|
||||
const rollupData = await rollupSearchStrategy.getRollupData(request, indexPattern);
|
||||
|
||||
expect(callWithRequest).toHaveBeenCalledWith('rollup.rollupIndexCapabilities', {
|
||||
indexPattern,
|
||||
});
|
||||
expect(rollupSearchStrategy.getCallWithRequestInstance).toHaveBeenCalledWith(request);
|
||||
expect(getRollupService).toHaveBeenCalled();
|
||||
expect(rollupData).toBe('data');
|
||||
});
|
||||
|
||||
|
@ -135,7 +149,7 @@ describe('Rollup Search Strategy', () => {
|
|||
const rollupIndex = 'rollupIndex';
|
||||
|
||||
beforeEach(() => {
|
||||
rollupSearchStrategy = new RollupSearchStrategy(server);
|
||||
rollupSearchStrategy = new RollupSearchStrategy();
|
||||
fieldsCapabilities = {
|
||||
[rollupIndex]: {
|
||||
aggs: {
|
||||
|
|
|
@ -4,15 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { keyBy, isString } from 'lodash';
|
||||
import { KibanaRequest } from 'src/core/server';
|
||||
|
||||
import { CallWithRequestFactoryShim } from '../../types';
|
||||
import { ILegacyScopedClusterClient } from 'src/core/server';
|
||||
import { ReqFacade } from '../../../../../../src/plugins/vis_type_timeseries/server';
|
||||
import { ENHANCED_ES_SEARCH_STRATEGY } from '../../../../data_enhanced/server';
|
||||
import { mergeCapabilitiesWithFields } from '../merge_capabilities_with_fields';
|
||||
import { getCapabilitiesForRollupIndices } from '../map_capabilities';
|
||||
|
||||
const ROLLUP_INDEX_CAPABILITIES_METHOD = 'rollup.rollupIndexCapabilities';
|
||||
|
||||
const getRollupIndices = (rollupData: { [key: string]: any[] }) => Object.keys(rollupData);
|
||||
const getRollupIndices = (rollupData: { [key: string]: any }) => Object.keys(rollupData);
|
||||
|
||||
const isIndexPatternContainsWildcard = (indexPattern: string) => indexPattern.includes('*');
|
||||
const isIndexPatternValid = (indexPattern: string) =>
|
||||
|
@ -20,28 +18,40 @@ const isIndexPatternValid = (indexPattern: string) =>
|
|||
|
||||
export const getRollupSearchStrategy = (
|
||||
AbstractSearchStrategy: any,
|
||||
RollupSearchRequest: any,
|
||||
RollupSearchCapabilities: any,
|
||||
callWithRequestFactory: CallWithRequestFactoryShim
|
||||
getRollupService: (reg: ReqFacade) => Promise<ILegacyScopedClusterClient>
|
||||
) =>
|
||||
class RollupSearchStrategy extends AbstractSearchStrategy {
|
||||
name = 'rollup';
|
||||
|
||||
constructor() {
|
||||
// TODO: When vis_type_timeseries and AbstractSearchStrategy are migrated to the NP, it
|
||||
// shouldn't require elasticsearchService to be injected, and we can remove this null argument.
|
||||
super(null, callWithRequestFactory, RollupSearchRequest);
|
||||
super(ENHANCED_ES_SEARCH_STRATEGY, 'rollup', { rest_total_hits_as_int: true });
|
||||
}
|
||||
|
||||
getRollupData(req: KibanaRequest, indexPattern: string) {
|
||||
const callWithRequest = this.getCallWithRequestInstance(req);
|
||||
|
||||
return callWithRequest(ROLLUP_INDEX_CAPABILITIES_METHOD, {
|
||||
indexPattern,
|
||||
}).catch(() => Promise.resolve({}));
|
||||
async search(req: ReqFacade, bodies: any[], options = {}) {
|
||||
const rollupService = await getRollupService(req);
|
||||
const requests: any[] = [];
|
||||
bodies.forEach((body) => {
|
||||
requests.push(
|
||||
rollupService.callAsCurrentUser('rollup.search', {
|
||||
...body,
|
||||
rest_total_hits_as_int: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
return Promise.all(requests);
|
||||
}
|
||||
|
||||
async checkForViability(req: KibanaRequest, indexPattern: string) {
|
||||
async getRollupData(req: ReqFacade, indexPattern: string) {
|
||||
const rollupService = await getRollupService(req);
|
||||
return rollupService
|
||||
.callAsCurrentUser('rollup.rollupIndexCapabilities', {
|
||||
indexPattern,
|
||||
})
|
||||
.catch(() => Promise.resolve({}));
|
||||
}
|
||||
|
||||
async checkForViability(req: ReqFacade, indexPattern: string) {
|
||||
let isViable = false;
|
||||
let capabilities = null;
|
||||
|
||||
|
@ -66,7 +76,7 @@ export const getRollupSearchStrategy = (
|
|||
}
|
||||
|
||||
async getFieldsForWildcard(
|
||||
req: KibanaRequest,
|
||||
req: ReqFacade,
|
||||
indexPattern: string,
|
||||
{
|
||||
fieldsCapabilities,
|
||||
|
|
|
@ -17,17 +17,16 @@ import {
|
|||
ILegacyCustomClusterClient,
|
||||
Plugin,
|
||||
Logger,
|
||||
KibanaRequest,
|
||||
PluginInitializerContext,
|
||||
ILegacyScopedClusterClient,
|
||||
LegacyAPICaller,
|
||||
SharedGlobalConfig,
|
||||
} from 'src/core/server';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import { ReqFacade } from '../../../../src/plugins/vis_type_timeseries/server';
|
||||
import { PLUGIN, CONFIG_ROLLUPS } from '../common';
|
||||
import { Dependencies, CallWithRequestFactoryShim } from './types';
|
||||
import { Dependencies } from './types';
|
||||
import { registerApiRoutes } from './routes';
|
||||
import { License } from './services';
|
||||
import { registerRollupUsageCollector } from './collectors';
|
||||
|
@ -132,19 +131,12 @@ export class RollupPlugin implements Plugin<void, void, any, any> {
|
|||
});
|
||||
|
||||
if (visTypeTimeseries) {
|
||||
// TODO: When vis_type_timeseries is fully migrated to the NP, it shouldn't require this shim.
|
||||
const callWithRequestFactoryShim = (
|
||||
elasticsearchServiceShim: CallWithRequestFactoryShim,
|
||||
request: KibanaRequest
|
||||
): LegacyAPICaller => {
|
||||
return async (...args: Parameters<LegacyAPICaller>) => {
|
||||
this.rollupEsClient = this.rollupEsClient ?? (await getCustomEsClient(getStartServices));
|
||||
return await this.rollupEsClient.asScoped(request).callAsCurrentUser(...args);
|
||||
};
|
||||
const getRollupService = async (request: ReqFacade) => {
|
||||
this.rollupEsClient = this.rollupEsClient ?? (await getCustomEsClient(getStartServices));
|
||||
return this.rollupEsClient.asScoped(request);
|
||||
};
|
||||
|
||||
const { addSearchStrategy } = visTypeTimeseries;
|
||||
registerRollupSearchStrategy(callWithRequestFactoryShim, addSearchStrategy);
|
||||
registerRollupSearchStrategy(addSearchStrategy, getRollupService);
|
||||
}
|
||||
|
||||
if (usageCollection) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { IRouter, LegacyAPICaller, KibanaRequest } from 'src/core/server';
|
||||
import { IRouter } from 'src/core/server';
|
||||
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||
import { VisTypeTimeseriesSetup } from 'src/plugins/vis_type_timeseries/server';
|
||||
|
||||
|
@ -39,9 +39,3 @@ export interface RouteDependencies {
|
|||
IndexPatternsFetcher: typeof IndexPatternsFetcher;
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: When vis_type_timeseries is fully migrated to the NP, it shouldn't require this shim.
|
||||
export type CallWithRequestFactoryShim = (
|
||||
elasticsearchServiceShim: CallWithRequestFactoryShim,
|
||||
request: KibanaRequest
|
||||
) => LegacyAPICaller;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue