Skip to content

Commit

Permalink
[Reporting] Convert CSV Export libs to Typescript (#55117) (#55510)
Browse files Browse the repository at this point in the history
* [Reporting] Convert CSV Export libs to Typescript

* fix jest tests

* more ts conversion

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
tsullivan and elasticmachine committed Jan 22, 2020
1 parent 45ca004 commit b018858
Show file tree
Hide file tree
Showing 30 changed files with 308 additions and 206 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,4 @@ describe('Cancellation Token', () => {

expect(onCancelled).toBeCalled();
});

it('throws an error when the callback is not a function', () => {
const cancellationToken = new CancellationToken();

expect(() => {
// @ts-ignore
cancellationToken.on('cool!');
}).toThrowError('Expected callback to be a function');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
*/

import { i18n } from '@kbn/i18n';
import { ExecuteJobFactory, ESQueueWorkerExecuteFn, ServerFacade } from '../../../types';
import {
ExecuteJobFactory,
ESQueueWorkerExecuteFn,
FieldFormats,
ServerFacade,
} from '../../../types';
import { CSV_JOB_TYPE, PLUGIN_ID } from '../../../common/constants';
import { cryptoFactory, LevelLogger } from '../../../server/lib';
import { JobDocPayloadDiscoverCsv } from '../types';
// @ts-ignore untyped module TODO
import { createGenerateCsv } from './lib/generate_csv';
// @ts-ignore untyped module TODO
import { fieldFormatMapFactory } from './lib/field_format_map';

export const executeJobFactory: ExecuteJobFactory<ESQueueWorkerExecuteFn<
Expand Down Expand Up @@ -86,7 +89,7 @@ export const executeJobFactory: ExecuteJobFactory<ESQueueWorkerExecuteFn<

const [formatsMap, uiSettings] = await Promise.all([
(async () => {
const fieldFormats = await server.fieldFormatServiceFactory(uiConfig);
const fieldFormats = (await server.fieldFormatServiceFactory(uiConfig)) as FieldFormats;
return fieldFormatMapFactory(indexPatternSavedObject, fieldFormats);
})(),
(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { checkIfRowsHaveFormulas } from './check_cells_for_formulas';

const formulaValues = ['=', '+', '-', '@'];
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
*/

import expect from '@kbn/expect';
import { createEscapeValue } from '../escape_value';
import { createEscapeValue } from './escape_value';

describe('escapeValue', function() {
describe('quoteValues is true', function() {
let escapeValue;
let escapeValue: (val: string) => string;
beforeEach(function() {
escapeValue = createEscapeValue(true);
});
Expand Down Expand Up @@ -44,7 +44,7 @@ describe('escapeValue', function() {
});

describe('quoteValues is false', function() {
let escapeValue;
let escapeValue: (val: string) => string;
beforeEach(function() {
escapeValue = createEscapeValue(false);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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 { RawValue } from './types';

const nonAlphaNumRE = /[^a-zA-Z0-9]/;
const allDoubleQuoteRE = /"/g;

export function createEscapeValue(quoteValues: boolean): (val: RawValue) => string {
return function escapeValue(val: RawValue) {
if (val && typeof val === 'string') {
if (quoteValues && nonAlphaNumRE.test(val)) {
return `"${val.replace(allDoubleQuoteRE, '""')}"`;
}
}

return val == null ? '' : val.toString();
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
*/

import expect from '@kbn/expect';

import { FieldFormatsService } from '../../../../../../../../../src/legacy/ui/field_formats/mixin/field_formats_service';
import { FieldFormatsService } from '../../../../../../../../src/legacy/ui/field_formats/mixin/field_formats_service';
// Reporting uses an unconventional directory structure so the linter marks this as a violation
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { BytesFormat, NumberFormat } from '../../../../../../../../../src/plugins/data/server';
import { BytesFormat, NumberFormat } from '../../../../../../../../src/plugins/data/server';
import { fieldFormatMapFactory } from './field_format_map';

import { fieldFormatMapFactory } from '../field_format_map';
type ConfigValue = { number: { id: string; params: {} } } | string;

describe('field format map', function() {
const indexPatternSavedObject = {
Expand All @@ -26,12 +26,12 @@ describe('field format map', function() {
fieldFormatMap: '{"field1":{"id":"bytes","params":{"pattern":"0,0.[0]b"}}}',
},
};
const configMock = {};
const configMock: Record<string, ConfigValue> = {};
configMock['format:defaultTypeMap'] = {
number: { id: 'number', params: {} },
};
configMock['format:number:defaultPattern'] = '0,0.[000]';
const getConfig = key => configMock[key];
const getConfig = (key: string) => configMock[key];
const testValue = '4000';

const fieldFormats = new FieldFormatsService([BytesFormat, NumberFormat], getConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
*/

import _ from 'lodash';
import { FieldFormats } from '../../../../types';

interface IndexPatternSavedObject {
attributes: {
fieldFormatMap: string;
};
id: string;
type: string;
version: string;
}

/**
* Create a map of FieldFormat instances for index pattern fields
Expand All @@ -13,10 +23,13 @@ import _ from 'lodash';
* @param {FieldFormatsService} fieldFormats
* @return {Map} key: field name, value: FieldFormat instance
*/
export function fieldFormatMapFactory(indexPatternSavedObject, fieldFormats) {
export function fieldFormatMapFactory(
indexPatternSavedObject: IndexPatternSavedObject,
fieldFormats: FieldFormats
) {
const formatsMap = new Map();

//Add FieldFormat instances for fields with custom formatters
// Add FieldFormat instances for fields with custom formatters
if (_.has(indexPatternSavedObject, 'attributes.fieldFormatMap')) {
const fieldFormatMap = JSON.parse(indexPatternSavedObject.attributes.fieldFormatMap);
Object.keys(fieldFormatMap).forEach(fieldName => {
Expand All @@ -28,9 +41,9 @@ export function fieldFormatMapFactory(indexPatternSavedObject, fieldFormats) {
});
}

//Add default FieldFormat instances for all other fields
// Add default FieldFormat instances for all other fields
const indexFields = JSON.parse(_.get(indexPatternSavedObject, 'attributes.fields', '[]'));
indexFields.forEach(field => {
indexFields.forEach((field: any) => {
if (!formatsMap.has(field.name)) {
formatsMap.set(field.name, fieldFormats.getDefaultInstance(field.type));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
*/

import expect from '@kbn/expect';
import { createFlattenHit } from '../flatten_hit';
import { createFlattenHit } from './flatten_hit';

type Hit = Record<string, any>;

describe('flattenHit', function() {
let flattenHit;
let hit;
let metaFields;
let flattenHit: (hit: Hit) => Record<string, string>;
let hit: Hit;
let metaFields: string[];

beforeEach(function() {
const fields = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@

import _ from 'lodash';

type Hit = Record<string, any>;
type FlattenHitFn = (hit: Hit) => Record<string, string>;
type FlatHits = Record<string, string[]>;

// TODO this logic should be re-used with Discover
export function createFlattenHit(fields, metaFields, conflictedTypesFields) {
const flattenSource = (flat, obj, keyPrefix) => {
export function createFlattenHit(
fields: string[],
metaFields: string[],
conflictedTypesFields: string[]
): FlattenHitFn {
const flattenSource = (flat: FlatHits, obj: object, keyPrefix = '') => {
keyPrefix = keyPrefix ? keyPrefix + '.' : '';
_.forOwn(obj, (val, key) => {
key = keyPrefix + key;
Expand All @@ -31,17 +39,19 @@ export function createFlattenHit(fields, metaFields, conflictedTypesFields) {
});
};

const flattenMetaFields = (flat, hit) => {
const flattenMetaFields = (flat: Hit, hit: Hit) => {
_.each(metaFields, meta => {
if (meta === '_source') return;
flat[meta] = hit[meta];
});
};

const flattenFields = (flat, hitFields) => {
const flattenFields = (flat: FlatHits, hitFields: string[]) => {
_.forOwn(hitFields, (val, key) => {
if (key[0] === '_' && !_.contains(metaFields, key)) return;
flat[key] = _.isArray(val) && val.length === 1 ? val[0] : val;
if (key) {
if (key[0] === '_' && !_.contains(metaFields, key)) return;
flat[key] = _.isArray(val) && val.length === 1 ? val[0] : val;
}
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
*/

import expect from '@kbn/expect';
import { createFormatCsvValues } from '../format_csv_values';
import { createFormatCsvValues } from './format_csv_values';

describe('formatCsvValues', function() {
const separator = ',';
const fields = ['foo', 'bar'];
const mockEscapeValue = val => val;
const mockEscapeValue = (value: any, index: number, array: any[]) => value || '';
describe('with _source as one of the fields', function() {
const formatsMap = new Map();
const formatCsvValues = createFormatCsvValues(
Expand Down Expand Up @@ -62,7 +62,7 @@ describe('formatCsvValues', function() {

describe('with field formats', function() {
const mockFieldFormat = {
convert: val => String(val).toUpperCase(),
convert: (val: string) => String(val).toUpperCase(),
};
const formatsMap = new Map();
formatsMap.set('bar', mockFieldFormat);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
*/

import { isObject, isNull, isUndefined } from 'lodash';
import { RawValue } from './types';

export function createFormatCsvValues(escapeValue, separator, fields, formatsMap) {
return function formatCsvValues(values) {
export function createFormatCsvValues(
escapeValue: (value: RawValue, index: number, array: RawValue[]) => string,
separator: string,
fields: string[],
formatsMap: any
) {
return function formatCsvValues(values: Record<string, RawValue>) {
return fields
.map(field => {
let value;
Expand All @@ -29,7 +35,7 @@ export function createFormatCsvValues(escapeValue, separator, fields, formatsMap
return formattedValue;
})
.map(value => (isObject(value) ? JSON.stringify(value) : value))
.map(value => value.toString())
.map(value => (value ? value.toString() : value))
.map(escapeValue)
.join(separator);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { Logger } from '../../../../types';
import { GenerateCsvParams, SavedSearchGeneratorResult } from '../../types';
import { createFlattenHit } from './flatten_hit';
import { createFormatCsvValues } from './format_csv_values';
import { createEscapeValue } from './escape_value';
import { createHitIterator } from './hit_iterator';
import { MaxSizeStringBuilder } from './max_size_string_builder';
import { checkIfRowsHaveFormulas } from './check_cells_for_formulas';

export function createGenerateCsv(logger) {
export function createGenerateCsv(logger: Logger) {
const hitIterator = createHitIterator(logger);

return async function generateCsv({
Expand All @@ -23,12 +25,13 @@ export function createGenerateCsv(logger) {
callEndpoint,
cancellationToken,
settings,
}) {
}: GenerateCsvParams): Promise<SavedSearchGeneratorResult> {
const escapeValue = createEscapeValue(settings.quoteValues);
const builder = new MaxSizeStringBuilder(settings.maxSizeBytes);
const header = `${fields.map(escapeValue).join(settings.separator)}\n`;
if (!builder.tryAppend(header)) {
return {
size: 0,
content: '',
maxSizeReached: true,
};
Expand All @@ -49,6 +52,10 @@ export function createGenerateCsv(logger) {
while (true) {
const { done, value: hit } = await iterator.next();

if (!hit) {
break;
}

if (done) {
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

import expect from '@kbn/expect';
import sinon from 'sinon';
import { CancellationToken } from '../../../../../common/cancellation_token';
import { Logger, ScrollConfig } from '../../../../../types';
import { createHitIterator } from '../hit_iterator';
import { CancellationToken } from '../../../../common/cancellation_token';
import { Logger, ScrollConfig } from '../../../../types';
import { createHitIterator } from './hit_iterator';

const mockLogger = {
error: new Function(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { SearchParams, SearchResponse } from 'elasticsearch';

import { SearchParams, SearchResponse } from 'elasticsearch';
import { i18n } from '@kbn/i18n';
import { CancellationToken, ScrollConfig, Logger } from '../../../../types';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import expect from '@kbn/expect';
import { MaxSizeStringBuilder } from '../max_size_string_builder';
import { MaxSizeStringBuilder } from './max_size_string_builder';

describe('MaxSizeStringBuilder', function() {
describe('tryAppend', function() {
Expand Down
Loading

0 comments on commit b018858

Please sign in to comment.