mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* Migrated es fields route to NP and added tests * Removed extraneous import * Removed check for index query * Fixed broken test
This commit is contained in:
parent
f89299ada4
commit
41120ae84a
7 changed files with 236 additions and 75 deletions
|
@ -1,33 +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 { mapValues, keys } from 'lodash';
|
||||
import { normalizeType } from '../../lib/normalize_type';
|
||||
|
||||
export function getESFieldTypes(index, fields, elasticsearchClient) {
|
||||
const config = {
|
||||
index: index,
|
||||
fields: fields || '*',
|
||||
};
|
||||
|
||||
if (fields && fields.length === 0) {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
return elasticsearchClient('fieldCaps', config).then(resp => {
|
||||
return mapValues(resp.fields, types => {
|
||||
if (keys(types).length > 1) {
|
||||
return 'conflict';
|
||||
}
|
||||
|
||||
try {
|
||||
return normalizeType(keys(types)[0]);
|
||||
} catch (e) {
|
||||
return 'unsupported';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,40 +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 { partial } from 'lodash';
|
||||
import { API_ROUTE } from '../../../common/lib/constants';
|
||||
import { CoreSetup } from '../../shim';
|
||||
// @ts-ignore untyped local
|
||||
import { getESFieldTypes } from './get_es_field_types';
|
||||
|
||||
// TODO: Error handling, note: esErrors
|
||||
|
||||
interface ESFieldsRequest {
|
||||
query: {
|
||||
index: string;
|
||||
fields: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export function esFields(
|
||||
route: CoreSetup['http']['route'],
|
||||
elasticsearch: CoreSetup['elasticsearch']
|
||||
) {
|
||||
const { callWithRequest } = elasticsearch.getCluster('data');
|
||||
|
||||
route({
|
||||
method: 'GET',
|
||||
path: `${API_ROUTE}/es_fields`,
|
||||
handler(request: ESFieldsRequest, h: any) {
|
||||
const { index, fields } = request.query;
|
||||
if (!index) {
|
||||
return h.response({ error: '"index" query is required' }).code(400);
|
||||
}
|
||||
|
||||
return getESFieldTypes(index, fields, partial(callWithRequest, request));
|
||||
},
|
||||
});
|
||||
}
|
|
@ -4,11 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { esFields } from './es_fields';
|
||||
import { shareableWorkpads } from './shareables';
|
||||
import { CoreSetup } from '../shim';
|
||||
|
||||
export function routes(setup: CoreSetup): void {
|
||||
esFields(setup.http.route, setup.elasticsearch);
|
||||
shareableWorkpads(setup.http.route);
|
||||
}
|
||||
|
|
164
x-pack/plugins/canvas/server/routes/es_fields/es_fields.test.ts
Normal file
164
x-pack/plugins/canvas/server/routes/es_fields/es_fields.test.ts
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* 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 { initializeESFieldsRoute } from './es_fields';
|
||||
import {
|
||||
IRouter,
|
||||
kibanaResponseFactory,
|
||||
RequestHandlerContext,
|
||||
RequestHandler,
|
||||
} from 'src/core/server';
|
||||
import {
|
||||
httpServiceMock,
|
||||
httpServerMock,
|
||||
loggingServiceMock,
|
||||
elasticsearchServiceMock,
|
||||
} from 'src/core/server/mocks';
|
||||
|
||||
const mockRouteContext = ({
|
||||
core: {
|
||||
elasticsearch: { dataClient: elasticsearchServiceMock.createScopedClusterClient() },
|
||||
},
|
||||
} as unknown) as RequestHandlerContext;
|
||||
|
||||
const path = `api/canvas/workpad/find`;
|
||||
|
||||
describe('Retrieve ES Fields', () => {
|
||||
let routeHandler: RequestHandler<any, any, any>;
|
||||
|
||||
beforeEach(() => {
|
||||
const httpService = httpServiceMock.createSetupContract();
|
||||
const router = httpService.createRouter('') as jest.Mocked<IRouter>;
|
||||
initializeESFieldsRoute({
|
||||
router,
|
||||
logger: loggingServiceMock.create().get(),
|
||||
});
|
||||
|
||||
routeHandler = router.get.mock.calls[0][1];
|
||||
});
|
||||
|
||||
it(`returns 200 with fields from existing index/index pattern`, async () => {
|
||||
const index = 'test';
|
||||
const mockResults = {
|
||||
indices: ['test'],
|
||||
fields: {
|
||||
'@timestamp': {
|
||||
date: {
|
||||
type: 'date',
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
},
|
||||
},
|
||||
name: {
|
||||
text: {
|
||||
type: 'text',
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
},
|
||||
},
|
||||
products: {
|
||||
object: {
|
||||
type: 'object',
|
||||
searchable: false,
|
||||
aggregatable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
method: 'get',
|
||||
path,
|
||||
query: {
|
||||
index,
|
||||
},
|
||||
});
|
||||
|
||||
const callAsCurrentUserMock = mockRouteContext.core.elasticsearch.dataClient
|
||||
.callAsCurrentUser as jest.Mock;
|
||||
|
||||
callAsCurrentUserMock.mockResolvedValueOnce(mockResults);
|
||||
|
||||
const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.payload).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"@timestamp": "date",
|
||||
"name": "string",
|
||||
"products": "unsupported",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it(`returns 200 with empty object when index/index pattern has no fields`, async () => {
|
||||
const index = 'test';
|
||||
const mockResults = { indices: [index], fields: {} };
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
method: 'get',
|
||||
path,
|
||||
query: {
|
||||
index,
|
||||
},
|
||||
});
|
||||
|
||||
const callAsCurrentUserMock = mockRouteContext.core.elasticsearch.dataClient
|
||||
.callAsCurrentUser as jest.Mock;
|
||||
|
||||
callAsCurrentUserMock.mockResolvedValueOnce(mockResults);
|
||||
|
||||
const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.payload).toMatchInlineSnapshot('Object {}');
|
||||
});
|
||||
|
||||
it(`returns 200 with empty object when index/index pattern does not have specified field(s)`, async () => {
|
||||
const index = 'test';
|
||||
|
||||
const mockResults = {
|
||||
indices: [index],
|
||||
fields: {},
|
||||
};
|
||||
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
method: 'get',
|
||||
path,
|
||||
query: {
|
||||
index,
|
||||
fields: ['foo', 'bar'],
|
||||
},
|
||||
});
|
||||
|
||||
const callAsCurrentUserMock = mockRouteContext.core.elasticsearch.dataClient
|
||||
.callAsCurrentUser as jest.Mock;
|
||||
|
||||
callAsCurrentUserMock.mockResolvedValueOnce(mockResults);
|
||||
|
||||
const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.payload).toMatchInlineSnapshot(`Object {}`);
|
||||
});
|
||||
|
||||
it(`returns 500 when index does not exist`, async () => {
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
method: 'get',
|
||||
path,
|
||||
query: {
|
||||
index: 'foo',
|
||||
},
|
||||
});
|
||||
|
||||
const callAsCurrentUserMock = mockRouteContext.core.elasticsearch.dataClient
|
||||
.callAsCurrentUser as jest.Mock;
|
||||
|
||||
callAsCurrentUserMock.mockRejectedValueOnce(new Error('Index not found'));
|
||||
|
||||
const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory);
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
});
|
||||
});
|
58
x-pack/plugins/canvas/server/routes/es_fields/es_fields.ts
Normal file
58
x-pack/plugins/canvas/server/routes/es_fields/es_fields.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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 { mapValues, keys } from 'lodash';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { API_ROUTE } from '../../../../../legacy/plugins/canvas/common/lib';
|
||||
import { catchErrorHandler } from '../catch_error_handler';
|
||||
// @ts-ignore unconverted lib
|
||||
import { normalizeType } from '../../../../../legacy/plugins/canvas/server/lib/normalize_type';
|
||||
import { RouteInitializerDeps } from '..';
|
||||
|
||||
const ESFieldsRequestSchema = schema.object({
|
||||
index: schema.string(),
|
||||
fields: schema.maybe(schema.arrayOf(schema.string())),
|
||||
});
|
||||
|
||||
export function initializeESFieldsRoute(deps: RouteInitializerDeps) {
|
||||
const { router } = deps;
|
||||
|
||||
router.get(
|
||||
{
|
||||
path: `${API_ROUTE}/es_fields`,
|
||||
validate: {
|
||||
query: ESFieldsRequestSchema,
|
||||
},
|
||||
},
|
||||
catchErrorHandler(async (context, request, response) => {
|
||||
const { callAsCurrentUser } = context.core.elasticsearch.dataClient;
|
||||
const { index, fields } = request.query;
|
||||
|
||||
const config = {
|
||||
index,
|
||||
fields: fields || '*',
|
||||
};
|
||||
|
||||
const esFields = await callAsCurrentUser('fieldCaps', config).then(resp => {
|
||||
return mapValues(resp.fields, types => {
|
||||
if (keys(types).length > 1) {
|
||||
return 'conflict';
|
||||
}
|
||||
|
||||
try {
|
||||
return normalizeType(keys(types)[0]);
|
||||
} catch (e) {
|
||||
return 'unsupported';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return response.ok({
|
||||
body: esFields,
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
12
x-pack/plugins/canvas/server/routes/es_fields/index.ts
Normal file
12
x-pack/plugins/canvas/server/routes/es_fields/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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 { initializeESFieldsRoute } from './es_fields';
|
||||
import { RouteInitializerDeps } from '..';
|
||||
|
||||
export function initESFieldsRoutes(deps: RouteInitializerDeps) {
|
||||
initializeESFieldsRoute(deps);
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
import { IRouter, Logger } from 'src/core/server';
|
||||
import { initWorkpadRoutes } from './workpad';
|
||||
import { initCustomElementsRoutes } from './custom_elements';
|
||||
import { initESFieldsRoutes } from './es_fields';
|
||||
|
||||
export interface RouteInitializerDeps {
|
||||
router: IRouter;
|
||||
|
@ -16,4 +17,5 @@ export interface RouteInitializerDeps {
|
|||
export function initRoutes(deps: RouteInitializerDeps) {
|
||||
initWorkpadRoutes(deps);
|
||||
initCustomElementsRoutes(deps);
|
||||
initESFieldsRoutes(deps);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue