Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Reporting] Convert CSV Export libs to Typescript #55117

Merged
merged 8 commits into from
Jan 22, 2020
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

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();
};
Copy link
Member Author

@tsullivan tsullivan Jan 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There had to be a little bit of changes to this function to support Typescript. The original function was:

export function createEscapeValue(quoteValues) {
  return function escapeValue(val) {
    if (quoteValues && nonAlphaNumRE.test(val)) {
      return `"${val.replace(allDoubleQuoteRE, '""')}"`;
    }
    return val;
  };
}

(copied from the deleted file's diff)

}
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