Skip to content

Commit

Permalink
fix: Fix issue with unwind and empty arrays creating an extra column (#…
Browse files Browse the repository at this point in the history
…496)

* fix: Fix issue with unwind and empty arrays creating an extra column

* fix: bring text coverage back to 100%
  • Loading branch information
juanjoDiaz authored Nov 10, 2020
1 parent b37e242 commit 0b331fc
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 37 deletions.
4 changes: 2 additions & 2 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, unsetProp, flattenReducer } = require('../utils');

function getUnwindablePaths(obj, currentPath) {
return Object.keys(obj).reduce((unwindablePaths, key) => {
Expand Down Expand Up @@ -42,7 +42,7 @@ function unwind({ paths = undefined, blankOut = false } = {}) {
}

if (!unwindArray.length) {
return setProp(row, unwindPath, undefined);
return unsetProp(row, unwindPath);
}

return unwindArray.map((unwindRow, index) => {
Expand Down
23 changes: 21 additions & 2 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,29 @@ function getProp(obj, path, defaultValue) {

function setProp(obj, path, value) {
const pathArray = Array.isArray(path) ? path : path.split('.');
const key = pathArray[0];
const newValue = pathArray.length > 1 ? setProp(obj[key] || {}, pathArray.slice(1), value) : value;
const [key, ...restPath] = pathArray;
const newValue = pathArray.length > 1 ? setProp(obj[key] || {}, restPath, value) : value;
return Object.assign({}, obj, { [key]: newValue });
}

function unsetProp(obj, path) {
const pathArray = Array.isArray(path) ? path : path.split('.');
const [key, ...restPath] = pathArray;

if (typeof obj[key] !== 'object') {
// This will never be hit in the current code because unwind does the check before calling unsetProp
/* istanbul ignore next */
return obj;
}

if (pathArray.length === 1) {
delete obj[key];
return obj;
}

return unsetProp(obj[key], restPath);
}

function flattenReducer(acc, arr) {
try {
// This is faster but susceptible to `RangeError: Maximum call stack size exceeded`
Expand Down Expand Up @@ -41,6 +59,7 @@ function fastJoin(arr, separator) {
module.exports = {
getProp,
setProp,
unsetProp,
fastJoin,
flattenReducer
};
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions test/CLI.js
Original file line number Diff line number Diff line change
Expand Up @@ -830,4 +830,16 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
t.end();
});
});

testRunner.add('should unwind complex objects using the unwind transform', (t) => {
const opts = '--fields carModel,price,extras.items.name,extras.items.items.position,extras.items.items.color,extras.items.items,name,color,extras.items.color'
+ ' --unwind extras.items,extras.items.items --flatten-objects --flatten-arrays';

exec(`${cli} -i "${getFixturePath('/json/unwindComplexObject.json')}" ${opts}`, (err, stdout, stderr) => {
t.notOk(stderr);
const csv = stdout;
t.equal(csv, csvFixtures.unwindComplexObject);
t.end();
});
});
};
17 changes: 17 additions & 0 deletions test/JSON2CSVAsyncParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,23 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
t.end();
});

testRunner.add('should unwind complex objects using the unwind transform', async (t) => {
const opts = {
fields: ["carModel", "price", "extras.items.name", "extras.items.items.position", "extras.items.items.color", "extras.items.items", "name", "color", "extras.items.color"],
transforms: [unwind({ paths: ['extras.items', 'extras.items.items'] }), flatten()],
};

const parser = new AsyncParser(opts);
try {
const csv = await parser.fromInput(jsonFixtures.unwindComplexObject()).promise();
t.equal(csv, csvFixtures.unwindComplexObject);
} catch(err) {
t.fail(err.message);
}
t.end();
});


testRunner.add('should support custom transforms', async (t) => {
const opts = {
transforms: [row => ({
Expand Down
12 changes: 12 additions & 0 deletions test/JSON2CSVParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,18 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
t.end();
});

testRunner.add('should unwind complex objects using the unwind transform', (t) => {
const opts = {
transforms: [unwind({ paths: ['extras.items', 'extras.items.items'] }), flatten()],
};

const parser = new Json2csvParser(opts);
const csv = parser.parse(jsonFixtures.unwindComplexObject);

t.equal(csv, csvFixtures.unwindComplexObject);
t.end();
});

testRunner.add('should support custom transforms', (t) => {
const opts = {
transforms: [row => ({
Expand Down
23 changes: 23 additions & 0 deletions test/JSON2CSVTransform.js
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,29 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
});
});


testRunner.add('should unwind complex objects using the unwind transform', async (t) => {
const opts = {
fields: ["carModel", "price", "extras.items.name", "extras.items.items.position", "extras.items.items.color", "extras.items.items", "name", "color", "extras.items.color"],
transforms: [unwind({ paths: ['extras.items', 'extras.items.items'] }), flatten()],
};

const transform = new Json2csvTransform(opts);
const processor = jsonFixtures.unwindComplexObject().pipe(transform);

let csv = '';
processor
.on('data', chunk => (csv += chunk.toString()))
.on('end', () => {
t.equal(csv, csvFixtures.unwindComplexObject);
t.end();
})
.on('error', err => {
t.fail(err.message);
t.end();
});
});

testRunner.add('should support custom transforms', (t) => {
const opts = {
transforms: [row => ({
Expand Down
3 changes: 2 additions & 1 deletion test/fixtures/csv/unwindAndFlatten.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
"BMW",15000,"airbag","white"
"BMW",15000,"dashboard","black"
"Porsche",30000,"airbag","gray"
"Porsche",30000,"dashboard","red"
"Porsche",30000,"dashboard","red"
"Mercedes",20000,,
6 changes: 6 additions & 0 deletions test/fixtures/csv/unwindComplexObject.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"carModel","price","extras.items.name","extras.items.items.position","extras.items.items.color","extras.items.items","name","color","extras.items.color"
"Porsche",30000,"airbag","left","white",,,,
"Porsche",30000,"airbag","right","gray",,,,
"Porsche",30000,"dashboard",,,"none",,,
,,,,,,"airbag","white",
"BMW",15000,"dashboard",,,,,,"black"
57 changes: 31 additions & 26 deletions test/fixtures/json/unwindAndFlatten.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
[
{
"carModel": "BMW",
"price": 15000,
"items": [
{
"name": "airbag",
"color": "white"
}, {
"name": "dashboard",
"color": "black"
}
]
}, {
"carModel": "Porsche",
"price": 30000,
"items": [
{
"name": "airbag",
"color": "gray"
},
{
"name": "dashboard",
"color": "red"
}
]
}
{
"carModel": "BMW",
"price": 15000,
"items": [
{
"name": "airbag",
"color": "white"
}, {
"name": "dashboard",
"color": "black"
}
]
}, {
"carModel": "Porsche",
"price": 30000,
"items": [
{
"name": "airbag",
"color": "gray"
},
{
"name": "dashboard",
"color": "red"
}
]
},
{
"carModel": "Mercedes",
"price": 20000,
"items": []
}
]
41 changes: 41 additions & 0 deletions test/fixtures/json/unwindComplexObject.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[
{
"carModel": "Porsche",
"price": 30000,
"extras": {
"items": [
{
"name": "airbag",
"items": [
{
"position": "left",
"color": "white"
}, {
"position": "right",
"color": "gray"
}
]
},
{
"name": "dashboard",
"items": "none"
}
]
}
}, {
"carModel": "BMW",
"price": 15000,
"extras": {
"items": [
{
"name": "airbag",
"color": "white",
"items": []
}, {
"name": "dashboard",
"color": "black"
}
]
}
}
]

0 comments on commit 0b331fc

Please sign in to comment.