Skip to content

Commit

Permalink
Partially convert index pattern server to typescript (#43291)
Browse files Browse the repository at this point in the history
* Partially convert index pattern server to typescript

* Update src/legacy/server/index_patterns/service/lib/field_capabilities/field_caps_response.ts

Co-Authored-By: Luke Elmers <lukeelmers@gmail.com>
  • Loading branch information
Wylie Conlon and lukeelmers committed Aug 16, 2019
1 parent 2110b9c commit 0a8926f
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
* under the License.
*/

export { IndexPatternsService } from './service';
// @ts-ignore no types
export { indexPatternsMixin } from './mixin';
export { IndexPatternsService, FieldDescriptor } from './service';
export { IndexPatternsServiceFactory } from './mixin';
20 changes: 0 additions & 20 deletions src/legacy/server/index_patterns/service/index.d.ts

This file was deleted.

20 changes: 0 additions & 20 deletions src/legacy/server/index_patterns/service/index.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
* under the License.
*/

export { indexPatternsMixin } from './mixin';
export * from './index_patterns_service';

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,41 @@
* under the License.
*/

import {
getFieldCapabilities,
resolveTimePattern,
createNoMatchingIndicesError,
} from './lib';
import { APICaller } from 'src/core/server';

import { getFieldCapabilities, resolveTimePattern, createNoMatchingIndicesError } from './lib';

export interface FieldDescriptor {
aggregatable: boolean;
name: string;
readFromDocValues: boolean;
searchable: boolean;
type: string;
esTypes: string[];
parent?: string;
subType?: string;
}

export class IndexPatternsService {
constructor(callDataCluster) {
private _callDataCluster: APICaller;

constructor(callDataCluster: APICaller) {
this._callDataCluster = callDataCluster;
}

/**
* Get a list of field objects for an index pattern that may contain wildcards
*
* @param {Object} [options={}]
* @param {Object} [options]
* @property {String} options.pattern The index pattern
* @property {Number} options.metaFields The list of underscore prefixed fields that should
* be left in the field list (all others are removed).
* @return {Promise<Array<Fields>>}
*/
async getFieldsForWildcard(options = {}) {
async getFieldsForWildcard(options: {
pattern: string | string[];
metaFields?: string[];
}): Promise<FieldDescriptor[]> {
const { pattern, metaFields } = options;
return await getFieldCapabilities(this._callDataCluster, pattern, metaFields);
}
Expand All @@ -52,7 +66,12 @@ export class IndexPatternsService {
* be left in the field list (all others are removed).
* @return {Promise<Array<Fields>>}
*/
async getFieldsForTimePattern(options = {}) {
async getFieldsForTimePattern(options: {
pattern: string;
metaFields: string[];
lookBack: number;
interval: string;
}) {
const { pattern, lookBack, metaFields } = options;
const { matches } = await resolveTimePattern(this._callDataCluster, pattern);
const indices = matches.slice(0, lookBack);
Expand All @@ -61,5 +80,4 @@ export class IndexPatternsService {
}
return await getFieldCapabilities(this._callDataCluster, indices, metaFields);
}

}
23 changes: 0 additions & 23 deletions src/legacy/server/index_patterns/service/lib/errors.test.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
* under the License.
*/

import { APICaller } from 'src/core/server';
// @ts-ignore
import { convertEsError } from './errors';
import { FieldCapsResponse } from './field_capabilities';

/**
* Call the index.getAlias API for a list of indices.
Expand All @@ -33,12 +36,12 @@ import { convertEsError } from './errors';
* @param {Array<String>|String} indices
* @return {Promise<IndexAliasResponse>}
*/
export async function callIndexAliasApi(callCluster, indices) {
export async function callIndexAliasApi(callCluster: APICaller, indices: string[] | string) {
try {
return await callCluster('indices.getAlias', {
index: indices,
ignoreUnavailable: true,
allowNoIndices: false
allowNoIndices: false,
});
} catch (error) {
throw convertEsError(indices, error);
Expand All @@ -56,14 +59,14 @@ export async function callIndexAliasApi(callCluster, indices) {
* @param {Array<String>|String} indices
* @return {Promise<FieldCapsResponse>}
*/
export async function callFieldCapsApi(callCluster, indices) {
export async function callFieldCapsApi(callCluster: APICaller, indices: string[] | string) {
try {
return await callCluster('fieldCaps', {
return (await callCluster('fieldCaps', {
index: indices,
fields: '*',
ignoreUnavailable: true,
allowNoIndices: false
});
allowNoIndices: false,
})) as FieldCapsResponse;
} catch (error) {
throw convertEsError(indices, error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@

import { defaults, indexBy, sortBy } from 'lodash';

import { APICaller } from 'src/core/server';
import { callFieldCapsApi } from '../es_api';
import { readFieldCapsResponse } from './field_caps_response';
import { FieldCapsResponse, readFieldCapsResponse } from './field_caps_response';
import { mergeOverrides } from './overrides';
import { FieldDescriptor } from '../../index_patterns_service';

export const concatIfUniq = (arr, value) => (
arr.includes(value) ? arr : arr.concat(value)
);
export function concatIfUniq<T>(arr: T[], value: T) {
return arr.includes(value) ? arr : arr.concat(value);
}

/**
* Get the field capabilities for field in `indices`, excluding
Expand All @@ -34,24 +36,29 @@ export const concatIfUniq = (arr, value) => (
* @param {Function} callCluster bound function for accessing an es client
* @param {Array} [indices=[]] the list of indexes to check
* @param {Array} [metaFields=[]] the list of internal fields to include
* @return {Promise<Array<FieldInfo>>}
* @return {Promise<Array<FieldDescriptor>>}
*/
export async function getFieldCapabilities(callCluster, indices = [], metaFields = []) {
const esFieldCaps = await callFieldCapsApi(callCluster, indices);
export async function getFieldCapabilities(
callCluster: APICaller,
indices: string | string[] = [],
metaFields: string[] = []
) {
const esFieldCaps: FieldCapsResponse = await callFieldCapsApi(callCluster, indices);
const fieldsFromFieldCapsByName = indexBy(readFieldCapsResponse(esFieldCaps), 'name');

const allFieldsUnsorted = Object
.keys(fieldsFromFieldCapsByName)
const allFieldsUnsorted = Object.keys(fieldsFromFieldCapsByName)
.filter(name => !name.startsWith('_'))
.concat(metaFields)
.reduce(concatIfUniq, [])
.map(name => defaults({}, fieldsFromFieldCapsByName[name], {
name,
type: 'string',
searchable: false,
aggregatable: false,
readFromDocValues: false
}))
.reduce(concatIfUniq, [] as string[])
.map<FieldDescriptor>(name =>
defaults({}, fieldsFromFieldCapsByName[name], {
name,
type: 'string',
searchable: false,
aggregatable: false,
readFromDocValues: false,
})
)
.map(mergeOverrides);

return sortBy(allFieldsUnsorted, 'name');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@
import { uniq } from 'lodash';
import { castEsToKbnFieldTypeName } from '../../../../../utils';
import { shouldReadFieldFromDocValues } from './should_read_field_from_doc_values';
import { FieldDescriptor } from '../..';

interface FieldCapObject {
type: string;
searchable: boolean;
aggregatable: boolean;
indices?: string[];
non_searchable_indices?: string[];
non_aggregatable_indices?: string[];
}

export interface FieldCapsResponse {
fields: Record<string, Record<string, FieldCapObject>>;
}

/**
* Read the response from the _field_caps API to determine the type and
Expand Down Expand Up @@ -75,26 +89,31 @@ import { shouldReadFieldFromDocValues } from './should_read_field_from_doc_value
* }
*
* @param {FieldCapsResponse} fieldCapsResponse
* @return {Promise<Array<FieldInfo>>}
* @return {Array<FieldDescriptor>}
*/
export function readFieldCapsResponse(fieldCapsResponse) {
export function readFieldCapsResponse(fieldCapsResponse: FieldCapsResponse): FieldDescriptor[] {
const capsByNameThenType = fieldCapsResponse.fields;
const kibanaFormattedCaps = Object.keys(capsByNameThenType).map(fieldName => {
const kibanaFormattedCaps: FieldDescriptor[] = Object.keys(capsByNameThenType).map(fieldName => {
const capsByType = capsByNameThenType[fieldName];
const types = Object.keys(capsByType);

// If a single type is marked as searchable or aggregatable, all the types are searchable or aggregatable
const isSearchable = types.some(type => {
return !!capsByType[type].searchable ||
(!!capsByType[type].non_searchable_indices && capsByType[type].non_searchable_indices.length > 0);
return (
!!capsByType[type].searchable ||
(!!capsByType[type].non_searchable_indices &&
capsByType[type].non_searchable_indices!.length > 0)
);
});

const isAggregatable = types.some(type => {
return !!capsByType[type].aggregatable ||
(!!capsByType[type].non_aggregatable_indices && capsByType[type].non_aggregatable_indices.length > 0);
return (
!!capsByType[type].aggregatable ||
(!!capsByType[type].non_aggregatable_indices &&
capsByType[type].non_aggregatable_indices!.length > 0)
);
});


// If there are multiple types but they all resolve to the same kibana type
// ignore the conflict and carry on (my wayward son)
const uniqueKibanaTypes = uniq(types.map(castEsToKbnFieldTypeName));
Expand All @@ -106,10 +125,13 @@ export function readFieldCapsResponse(fieldCapsResponse) {
searchable: isSearchable,
aggregatable: isAggregatable,
readFromDocValues: false,
conflictDescriptions: types.reduce((acc, esType) => ({
...acc,
[esType]: capsByType[esType].indices
}), {})
conflictDescriptions: types.reduce(
(acc, esType) => ({
...acc,
[esType]: capsByType[esType].indices,
}),
{}
),
};
}

Expand All @@ -132,7 +154,10 @@ export function readFieldCapsResponse(fieldCapsResponse) {
// Discern which sub fields are multi fields. If the parent field is not an object or nested field
// the child must be a multi field.
subFields.forEach(field => {
const parentFieldName = field.name.split('.').slice(0, -1).join('.');
const parentFieldName = field.name
.split('.')
.slice(0, -1)
.join('.');
const parentFieldCaps = kibanaFormattedCaps.find(caps => caps.name === parentFieldName);

if (parentFieldCaps && !['object', 'nested'].includes(parentFieldCaps.type)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
*/

export { getFieldCapabilities } from './field_capabilities';
export { FieldCapsResponse } from './field_caps_response';
Loading

0 comments on commit 0a8926f

Please sign in to comment.