Skip to content

Commit ef4bc3e

Browse files
committed
working on json2csv; already noticing a speed improvement on the tests
1 parent cee3c46 commit ef4bc3e

File tree

1 file changed

+45
-43
lines changed

1 file changed

+45
-43
lines changed

lib/json-2-csv.js

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,36 @@ var options = {}; // Initialize the options - this will be populated when the js
1313
* @returns {Promise}
1414
*/
1515
var generateHeading = function(data) {
16-
return new Promise(function (resolve, reject) {
17-
if (options.KEYS) { return resolve(options.KEYS); }
18-
19-
var keys = _.map(_.keys(data), function (key, indx) { // for each key
20-
if (_.isObject(data[key])) {
21-
// if the data at the key is a document, then we retrieve the subHeading starting with an empty string heading and the doc
22-
return generateSubHeading('', data[key]);
23-
}
24-
return key;
25-
});
26-
27-
// Check for a consistent schema that does not require the same order:
28-
// if we only have one document - then there is no possiblility of multiple schemas
29-
if (keys && keys.length <= 1) {
30-
return resolve(_.flatten(keys) || []);
16+
if (options.KEYS) { return Promise.resolve(options.KEYS); }
17+
18+
var keys = _.map(data, function (document, indx) { // for each key
19+
if (_.isObject(document)) {
20+
// if the data at the key is a document, then we retrieve the subHeading starting with an empty string heading and the doc
21+
return generateDocumentHeading('', document);
22+
}
23+
});
24+
25+
// Check for a consistent schema that does not require the same order:
26+
// if we only have one document - then there is no possibility of multiple schemas
27+
if (keys && keys.length <= 1) {
28+
return Promise.resolve(_.flatten(keys) || []);
29+
}
30+
// else - multiple documents - ensure only one schema (regardless of field ordering)
31+
var firstDocSchema = _.flatten(keys[0]),
32+
schemaDifferences = 0;
33+
34+
_.each(keys, function (keyList) {
35+
// If there is a difference between the schemas, increment the counter of schema inconsistencies
36+
var diff = _.difference(firstDocSchema, _.flatten(keyList));
37+
if (!_.isEqual(diff, [])) {
38+
schemaDifferences++;
3139
}
32-
// else - multiple documents - ensure only one schema (regardless of field ordering)
33-
var firstDocSchema = _.flatten(keys[0]);
34-
_.each(keys, function (keyList) {
35-
// If there is a difference between the schemas, throw the inconsistent schema error
36-
var diff = _.difference(firstDocSchema, _.flatten(keyList));
37-
if (!_.isEqual(diff, [])) {
38-
return reject(new Error(constants.Errors.json2csv.notSameSchema));
39-
}
40-
});
41-
return resolve(_.flatten(keys[0]));
4240
});
41+
42+
// If there are schema inconsistencies, throw a schema not the same error
43+
if (schemaDifferences) { return Promise.reject(new Error(constants.Errors.json2csv.notSameSchema)); }
44+
45+
return Promise.resolve(_.flatten(keys[0]));
4346
};
4447

4548
/**
@@ -48,21 +51,22 @@ var generateHeading = function(data) {
4851
* @param data
4952
* @returns {Array}
5053
*/
51-
var generateSubHeading = function(heading, data) {
52-
var subKeys, // retrieve the keys from the current document
53-
newKey = ''; // temporary variable to aid in determining the heading - used to generate the 'nested' headings
54+
var generateDocumentHeading = function(heading, data) {
55+
var keyName = ''; // temporary variable to aid in determining the heading - used to generate the 'nested' headings
5456

55-
subKeys = _.map(_.keys(data), function (subKey) {
57+
var documentKeys = _.map(_.keys(data), function (currentKey) {
5658
// If the given heading is empty, then we set the heading to be the subKey, otherwise set it as a nested heading w/ a dot
57-
newKey = heading === '' ? subKey : heading + '.' + subKey;
58-
if (_.isObject(data[subKey]) && !_.isNull(data[subKey]) && _.isUndefined(data[subKey].length) && _.keys(data[subKey]).length > 0) { // If we have another nested document
59-
return generateSubHeading(newKey, data[subKey]); // Recur on the sub-document to retrieve the full key name
60-
} else {
61-
return newKey; // Set the key name since we don't have a sub document
59+
keyName = heading ? heading + '.' + currentKey : currentKey;
60+
61+
// If we have another nested document, recur on the sub-document to retrieve the full key name
62+
if (_.isObject(data[currentKey]) && !_.isNull(data[currentKey]) && _.isUndefined(data[currentKey].length) && _.keys(data[currentKey]).length) {
63+
return generateDocumentHeading(keyName, data[currentKey]);
6264
}
65+
// Otherwise return this key name since we don't have a sub document
66+
return keyName;
6367
});
6468

65-
return subKeys; // Return the headings joined by our field delimiter
69+
return documentKeys; // Return the headings joined by our field delimiter
6670
};
6771

6872
/**
@@ -83,7 +87,7 @@ var convertData = function (data, keys) {
8387
output.push(convertData(data[pathPrefix], [pathRemainder]));
8488
} else if (keys.indexOf(key) > -1) { // If the keys contain the current key, then process the data
8589
value = data[key]; // Set the current data that we are looking at
86-
convertField(value, output);
90+
output.push(convertField(value, output));
8791
}
8892
});
8993
return output; // Return the data joined by our field delimiter
@@ -94,17 +98,15 @@ var convertData = function (data, keys) {
9498
* @param value
9599
* @param output
96100
*/
97-
var convertField = function (value, output) {
101+
var convertField = function (value) {
98102
if (_.isArray(value)) { // We have an array of values
99-
output.push(options.DELIMITER.WRAP + '[' + value.join(options.DELIMITER.ARRAY) + ']' + options.DELIMITER.WRAP);
103+
return options.DELIMITER.WRAP + '[' + value.join(options.DELIMITER.ARRAY) + ']' + options.DELIMITER.WRAP;
100104
} else if (_.isDate(value)) { // If we have a date
101-
output.push(value.toString());
105+
return options.DELIMITER.WRAP + value.toString() + options.DELIMITER.WRAP;
102106
} else if (_.isObject(value)) { // If we have an object
103-
output.push(convertData(value, _.keys(value))); // Push the recursively generated CSV
104-
} else {
105-
value = value ? value.toString() : '';
106-
output.push(options.DELIMITER.WRAP + value + options.DELIMITER.WRAP); // Otherwise push the current value
107+
return options.DELIMITER.WRAP + convertData(value, _.keys(value)) + options.DELIMITER.WRAP; // Push the recursively generated CSV
107108
}
109+
return options.DELIMITER.WRAP + (value ? value.toString() : '') + options.DELIMITER.WRAP; // Otherwise push the current value
108110
};
109111

110112
/**

0 commit comments

Comments
 (0)