Skip to content

Commit 09615c8

Browse files
jose-cabraljosecabral-afs
authored andcommitted
fixes mrodrig#273: nested arrays are not always unwound
1 parent 5869d1b commit 09615c8

File tree

4 files changed

+170
-9
lines changed

4 files changed

+170
-9
lines changed

src/json2csv.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,20 @@ export const Json2Csv = function (options: FullJson2CsvOptions) {
239239

240240
/** RECORD FIELD FUNCTIONS **/
241241

242+
function stillNeedsUnwind(params: Json2CsvParams): boolean{
243+
for (const record of params.records) {
244+
for (const field of params.headerFields) {
245+
const value = evaluatePath(record, field);
246+
247+
if (Array.isArray(value)) {
248+
return true;
249+
}
250+
}
251+
}
252+
253+
return false;
254+
}
255+
242256
/**
243257
* Unwinds objects in arrays within record objects if the user specifies the
244258
* expandArrayObjects option. If not specified, this passes the params
@@ -249,21 +263,17 @@ export const Json2Csv = function (options: FullJson2CsvOptions) {
249263
*/
250264
function unwindRecordsIfNecessary(params: Json2CsvParams, finalPass = false): Json2CsvParams {
251265
if (options.unwindArrays) {
252-
const originalRecordsLength = params.records.length;
253-
254-
// Unwind each of the documents at the given headerField
266+
// Unwind each document at each header field
255267
params.headerFields.forEach((headerField) => {
256268
params.records = utils.unwind(params.records, headerField);
257269
});
258270

259-
const headerFields = retrieveHeaderFields(params.records);
260-
params.headerFields = headerFields;
271+
params.headerFields = retrieveHeaderFields(params.records);
261272

262-
// If we were able to unwind more arrays, then try unwinding again...
263-
if (originalRecordsLength !== params.records.length) {
264-
return unwindRecordsIfNecessary(params);
273+
// Continue unwinding if any nested arrays remain
274+
if (stillNeedsUnwind(params)) {
275+
return unwindRecordsIfNecessary(params, finalPass);
265276
}
266-
// Otherwise, we didn't unwind any additional arrays, so continue...
267277

268278
// Run a final time in case the earlier unwinding exposed additional
269279
// arrays to unwind...

test/config/testJsonFilesList.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,5 @@ export default {
5050
arrayIndexesAsKeys: require('../data/json/arrayIndexesAsKeys.json'),
5151
keyWithEndingDot: require('../data/json/keyWithEndingDot.json'),
5252
fieldEolAtStart: require('../data/json/fieldEolAtStart.json'),
53+
deepNestedArrays: require('../data/json/deepNestedArrays.json'),
5354
};

test/data/json/deepNestedArrays.json

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
{
2+
"was_already_working": [
3+
{
4+
"Countries": [
5+
{
6+
"Cities": [
7+
{
8+
"Streets": [
9+
{
10+
"Name": "Road 1",
11+
"Number": 1
12+
},
13+
{
14+
"Name": "Road 2",
15+
"Number": 2
16+
}
17+
]
18+
},
19+
{
20+
"field": "value"
21+
}
22+
]
23+
}
24+
]
25+
}
26+
],
27+
"was_not_working_1": [
28+
{
29+
"Countries": [
30+
{
31+
"Cities": [
32+
{
33+
"Streets": [
34+
{
35+
"Name": "Road 1",
36+
"Number": 1
37+
},
38+
{
39+
"Name": "Road 2",
40+
"Number": 2
41+
}
42+
]
43+
}
44+
]
45+
}
46+
]
47+
}
48+
],
49+
"was_not_working_2": [
50+
{
51+
"Continents": [
52+
{
53+
"Countries": [
54+
{
55+
"Cities": [
56+
{
57+
"Streets": [
58+
{
59+
"Name": "Road 1",
60+
"Number": 1
61+
},
62+
{
63+
"Name": "Road 2",
64+
"Number": 2
65+
}
66+
]
67+
},
68+
{
69+
"field": "value"
70+
}
71+
]
72+
}
73+
]
74+
}
75+
]
76+
}
77+
],
78+
"seven_levels_deep": [
79+
{
80+
"SolarSystems": [
81+
{
82+
"Planets": [
83+
{
84+
"Hemispheres": [
85+
{
86+
"Continents": [
87+
{
88+
"Countries": [
89+
{
90+
"Cities": [
91+
{
92+
"Streets": [
93+
{
94+
"Name": "Road 1",
95+
"Number": 1
96+
},
97+
{
98+
"Name": "Road 2",
99+
"Number": 2
100+
}
101+
]
102+
}
103+
]
104+
}
105+
]
106+
}
107+
]
108+
}
109+
]
110+
}
111+
]
112+
}
113+
]
114+
}
115+
]
116+
}

test/json2csv.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,40 @@ export function runTests() {
760760

761761
assert.equal(csv, csvTestData.nestedNotUnwoundObjects);
762762
});
763+
764+
it('should unwind all found arrays', () => {
765+
const options = {
766+
expandArrayObjects: true,
767+
unwindArrays: true,
768+
emptyFieldValue: '---'
769+
};
770+
771+
let expectedCSV = 'Countries.Cities.Streets.Name,Countries.Cities.Streets.Number,Countries.Cities.field\n' +
772+
'Road 1,1,---\n' +
773+
'Road 2,2,---\n' +
774+
'---,---,value';
775+
let csv = json2csv(jsonTestData.deepNestedArrays.was_already_working, options);
776+
assert.equal(csv, expectedCSV);
777+
778+
expectedCSV = 'Countries.Cities.Streets.Name,Countries.Cities.Streets.Number\n' +
779+
'Road 1,1\n' +
780+
'Road 2,2';
781+
csv = json2csv(jsonTestData.deepNestedArrays.was_not_working_1, options);
782+
assert.equal(csv, expectedCSV);
783+
784+
expectedCSV = 'Continents.Countries.Cities.Streets.Name,Continents.Countries.Cities.Streets.Number,Continents.Countries.Cities.field\n' +
785+
'Road 1,1,---\n' +
786+
'Road 2,2,---\n' +
787+
'---,---,value';
788+
csv = json2csv(jsonTestData.deepNestedArrays.was_not_working_2, options);
789+
assert.equal(csv, expectedCSV);
790+
791+
expectedCSV = 'SolarSystems.Planets.Hemispheres.Continents.Countries.Cities.Streets.Name,SolarSystems.Planets.Hemispheres.Continents.Countries.Cities.Streets.Number\n' +
792+
'Road 1,1\n' +
793+
'Road 2,2';
794+
csv = json2csv(jsonTestData.deepNestedArrays.seven_levels_deep, options);
795+
assert.equal(csv, expectedCSV);
796+
});
763797
});
764798
});
765799

0 commit comments

Comments
 (0)