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

Performance optimizations #491

Merged
merged 3 commits into from
Nov 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
language: node_js
node_js:
- "10"
- "11"
- "12"
- "13"
- "14"
- "15"
script:
- "npm run lint"
- "npm run test-with-coverage"
Expand Down
3 changes: 1 addition & 2 deletions lib/JSON2CSVAsyncParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

const { Transform } = require('stream');
const JSON2CSVTransform = require('./JSON2CSVTransform');
const { fastJoin } = require('./utils');

class JSON2CSVAsyncParser {
constructor(opts, transformOpts) {
Expand Down Expand Up @@ -51,7 +50,7 @@ class JSON2CSVAsyncParser {
let csvBuffer = [];
this.processor
.on('data', chunk => csvBuffer.push(chunk.toString()))
.on('finish', () => resolve(fastJoin(csvBuffer, '')))
.on('finish', () => resolve(csvBuffer.join('')))
.on('error', err => reject(err));
});
}
Expand Down
16 changes: 6 additions & 10 deletions lib/JSON2CSVBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const os = require('os');
const lodashGet = require('lodash.get');
const { getProp, fastJoin, flattenReducer } = require('./utils');
const { getProp } = require('./utils');
const defaultFormatter = require('./formatters/default');
const numberFormatterCtor = require('./formatters/number')
const stringFormatterCtor = require('./formatters/string');
Expand Down Expand Up @@ -111,10 +111,9 @@ class JSON2CSVBase {
* @returns {String} titles as a string
*/
getHeader() {
return fastJoin(
this.opts.fields.map(fieldInfo => this.opts.formatters.header(fieldInfo.label)),
this.opts.delimiter
);
return this.opts.fields
.map(fieldInfo => this.opts.formatters.header(fieldInfo.label))
.join(this.opts.delimiter);
}

/**
Expand All @@ -123,7 +122,7 @@ class JSON2CSVBase {
*/
preprocessRow(row) {
return this.opts.transforms.reduce((rows, transform) =>
rows.map(row => transform(row)).reduce(flattenReducer, []),
rows.flatMap(row => transform(row)),
[row]
);
}
Expand All @@ -145,10 +144,7 @@ class JSON2CSVBase {
return undefined;
}

return fastJoin(
processedRow,
this.opts.delimiter
);
return processedRow.join(this.opts.delimiter);
}

/**
Expand Down
12 changes: 5 additions & 7 deletions lib/JSON2CSVParser.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

const JSON2CSVBase = require('./JSON2CSVBase');
const { fastJoin, flattenReducer } = require('./utils');

class JSON2CSVParser extends JSON2CSVBase {
constructor(opts) {
Expand Down Expand Up @@ -60,8 +59,7 @@ class JSON2CSVParser extends JSON2CSVBase {
if (this.opts.transforms.length === 0) return processedData;

return processedData
.map(row => this.preprocessRow(row))
.reduce(flattenReducer, []);
.flatMap(row => this.preprocessRow(row));
}

/**
Expand All @@ -71,10 +69,10 @@ class JSON2CSVParser extends JSON2CSVBase {
* @returns {String} CSV string (body)
*/
processData(data) {
return fastJoin(
data.map(row => this.processRow(row)).filter(row => row), // Filter empty rows
this.opts.eol
);
return data
.map(row => this.processRow(row))
.filter(row => row) // Filter empty rows
.join(this.opts.eol);
}
}

Expand Down
10 changes: 4 additions & 6 deletions lib/transforms/unwind.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

const lodashGet = require('lodash.get');
const { setProp, flattenReducer } = require('../utils');
const { setProp } = require('../utils');

function getUnwindablePaths(obj, currentPath) {
return Object.keys(obj).reduce((unwindablePaths, key) => {
Expand All @@ -16,8 +16,7 @@ function getUnwindablePaths(obj, currentPath) {
} else if (Array.isArray(value)) {
unwindablePaths.push(newPath);
unwindablePaths = unwindablePaths.concat(value
.map(arrObj => getUnwindablePaths(arrObj, newPath))
.reduce(flattenReducer, [])
.flatMap(arrObj => getUnwindablePaths(arrObj, newPath))
.filter((item, index, arr) => arr.indexOf(item) !== index));
}

Expand All @@ -34,7 +33,7 @@ function getUnwindablePaths(obj, currentPath) {
function unwind({ paths = undefined, blankOut = false } = {}) {
function unwindReducer(rows, unwindPath) {
return rows
.map(row => {
.flatMap(row => {
const unwindArray = lodashGet(row, unwindPath);

if (!Array.isArray(unwindArray)) {
Expand All @@ -52,8 +51,7 @@ function unwind({ paths = undefined, blankOut = false } = {}) {

return setProp(clonedRow, unwindPath, unwindRow);
});
})
.reduce(flattenReducer, []);
});
}

paths = Array.isArray(paths) ? paths : (paths ? [paths] : undefined);
Expand Down
27 changes: 1 addition & 26 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,7 @@ function setProp(obj, path, value) {
return Object.assign({}, obj, { [key]: newValue });
}

function flattenReducer(acc, arr) {
try {
// This is faster but susceptible to `RangeError: Maximum call stack size exceeded`
acc.push(...arr);
return acc;
} catch (err) {
// Fallback to a slower but safer option
return acc.concat(arr);
}
}

function fastJoin(arr, separator) {
let isFirst = true;
return arr.reduce((acc, elem) => {
if (isFirst) {
isFirst = false;
return `${elem}`;
}

return `${acc}${separator}${elem}`;
}, '');
}

module.exports = {
getProp,
setProp,
fastJoin,
flattenReducer
setProp
};