diff --git a/README.md b/README.md index 181ce59..f934c20 100644 --- a/README.md +++ b/README.md @@ -377,6 +377,142 @@ The expected output. ] ``` +### Nested Array Handling + +Suppose this is the data + +```javascript +var data = { + "name": "Sarvpriy", + "users": [ + { + id: "1", + name: "arya", + comments: [ + { + text: "user id 1 comment no 1", + replies: [{ + title: "reply 1 to user id 1 comment no 1" + }, { + title: "reply 2 to user id 1 comment no 1" + }] + }, + { + text: "user id 1 comment no 2", + replies: [{ + title: "reply 1 to user id 1 comment no 2" + }, { + title: "reply 2 to user id 1 comment no 2" + }] + } + ] + }, { + id: "2", + name: "john", + comments: [ + { + text: "user id 2 comment no 1", + replies: [{ + title: "reply 1 to user id 2 comment no 1" + }, { + title: "reply 2 to user id 2 comment no 1" + }] + }, + { + text: "user id 2 comment no 2", + replies: [{ + title: "reply 1 to user id 2 comment no 2" + }, { + title: "reply 2 to user id 2 comment no 2" + }] + } + ] + } + ] +}; +``` + +and you want this type of result +```javascript +{ + "myname":"Sarvpriy", + "myusers": [{ + "userid":"1", + "comments": [{ + "mytext":"user id 1's comment no 1", + "myreplies": [{ + "mytitle":"reply 1 to user id 1's comment no 1" + },{ + "mytitle":"reply 2 to user id 1's comment no 1" + }] + },{ + "mytext":"user id 1's comment no 2", + "myreplies": [{ + "mytitle":"reply 1 to user id 1's comment no 2" + },{ + "mytitle":"reply 2 to user id 1's comment no 2" + }] + }] + },{ + "userid":"2", + "comments": [{ + "mytext":"user id 2's comment no 1", + "myreplies": [{ + "mytitle":"reply 1 to user id 2's comment no 1" + },{ + "mytitle":"reply 2 to user id 2's comment no 1" + }] + },{ + "mytext":"user id 2's comment no 2", + "myreplies": [{ + "mytitle":"reply 1 to user id 2's comment no 2" + },{ + "mytitle":"reply 2 to user id 2's comment no 2" + }] + }] + }] +} +``` +This can be achieved through the `operate` params. +But there are two problems +- You cannot save your map object in other places ex. in Database. +- `operate` doesn't work on the nested level(more then one level deep). + +no need to say that it is extreamly complex. +To acheive this the `map` object will look like this + +```javascript +var map = { + "item" : { + "myname": "name", + "myusers[users]": { + "userid": "id", + "comments[comments]": { + "mytext": "text", + "myreplies[replies]": { + "mytitle": "title" + } + } + } + } +}; +``` +So in a nutshel the `map` object should be + +```javascript +var map = { + "item": { + "new_arr_key[array_key_in_data]": { // `map` object b/w elements inside the new_arr_key and array_key_in_data + "some_new_key": "key_from_an_elem_in_array_key_in_data" + "nested_key[nested_key_inside_an_elem_in_array_key_in_data]": { // again `map` object + . + ... // nesting goes on and on + } + } + } +} +``` + Enjoy! ## Changelog diff --git a/index.js b/index.js index e34541b..fa2356e 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,9 @@ var _ = require('lodash'); var DataTransform = function(data, map){ + if (_.hasIn(map, 'item') && _.isObject(map.item)) { + map.item = updateArrayKeys(map.item, data) + } return { @@ -171,6 +174,79 @@ var DataTransform = function(data, map){ }; +const getSrcKey = function (newkey) { + if (newkey.indexOf('[') !== -1 && newkey.endsWith(']') ) { + return [ + newkey.substring(0, newkey.indexOf('[')), + newkey.substring(newkey.indexOf('[') + 1, newkey.length - 1) + ] + } + throw `SyntaxError: no source key found` +}; + +function updateArrayKeys(map, data) { + let newmap = {} + + // loop thru map object + for(let [newkey, oldkey] of _.entries(map)) { + + // find keys ending with ] + if (_.endsWith(newkey, ']')) { + + // extract srckey, make newkey + var [ tempkey, srckey ] = getSrcKey(newkey) + newmap[tempkey] = map[newkey] + + // start creating newoldkeys array + var newoldkey = [] + + // find length of srckey + _.get(data, srckey).forEach((elem, index) => { + var obj = {} + + // loop thru the oldkey + for(let [oldkey_key, oldkey_val] of _.entries(oldkey)) { + + // if any key ends with ] + if (_.endsWith(oldkey_key, ']')) { + + // then prepend srckey with index after [ + const newoldkey_key = `${oldkey_key.slice(0, oldkey_key.indexOf('[') + 1)}${srckey}[${index}].${oldkey_key.slice(oldkey_key.indexOf('[') + 1)}` + for (const [k, v] of _.entries(updateArrayKeys({ [newoldkey_key]: oldkey_val }, data))) { + obj[k] = v + } + } + + // if val is string then prepend srckey with index + if (_.isString(oldkey_val)) { + obj[oldkey_key] = `${srckey}[${index}].${oldkey_val}` + } + // else leave + } + + // push to newoldkey array + newoldkey.push(obj) + }) + + newmap[tempkey] = newoldkey + + } + else if(_.isObject(oldkey) && !_.isArray(oldkey)) { + newmap[newkey] = updateArrayKeys(oldkey, data) + } + else if(_.isArray(oldkey)) { + newmap[newkey] = _.map(oldkey, (val) => { + if(_.isString(val)) return val + else if(_.isObject(val) && !_.isArray(val)) return updateArrayKeys(val, data) + }) + } + else { + newmap[newkey] = oldkey + } + } + return newmap +} + exports.DataTransform = DataTransform; exports.transform = function(data, map, context) { diff --git a/package-lock.json b/package-lock.json index cd27c55..f952a93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "node-json-transform", - "version": "1.1.1", + "version": "1.1.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/test/nestedArraySpec.js b/test/nestedArraySpec.js new file mode 100644 index 0000000..74fe00b --- /dev/null +++ b/test/nestedArraySpec.js @@ -0,0 +1,149 @@ +var DataTransform = require('../index.js').DataTransform, + transform = require('../index.js').transform, + _ = require("lodash"); + +var test1_data = { + "name": "Sarvpriy", + "users": [ + { + id: "1", + name: "arya", + comments: [ + { + text: "user id 1 comment no 1", + replies: [{ + title: "reply 1 to user id 1 comment no 1" + }, { + title: "reply 2 to user id 1 comment no 1" + }] + }, + { + text: "user id 1 comment no 2", + replies: [{ + title: "reply 1 to user id 1 comment no 2" + }, { + title: "reply 2 to user id 1 comment no 2" + }] + } + ] + }, { + id: "2", + name: "john", + comments: [ + { + text: "user id 2 comment no 1", + replies: [{ + title: "reply 1 to user id 2 comment no 1" + }, { + title: "reply 2 to user id 2 comment no 1" + }] + }, + { + text: "user id 2 comment no 2", + replies: [{ + title: "reply 1 to user id 2 comment no 2" + }, { + title: "reply 2 to user id 2 comment no 2" + }] + } + ] + } + ] +}; + +var test1_map = { + "item" : { + "myname": "name", + "myusers[users]": { + "userid": "id", + "comments[comments]": { + "mytext": "text", + "myreplies[replies]": { + "mytitle": "title" + } + } + } + } + }; + +var test1_expected = { + "myname":"Sarvpriy", + "myusers": [{ + "userid":"1", + "comments": [{ + "mytext":"user id 1 comment no 1", + "myreplies": [{ + "mytitle":"reply 1 to user id 1 comment no 1" + },{ + "mytitle":"reply 2 to user id 1 comment no 1" + }] + },{ + "mytext":"user id 1 comment no 2", + "myreplies": [{ + "mytitle":"reply 1 to user id 1 comment no 2" + },{ + "mytitle":"reply 2 to user id 1 comment no 2" + }] + }] + },{ + "userid":"2", + "comments": [{ + "mytext":"user id 2 comment no 1", + "myreplies": [{ + "mytitle":"reply 1 to user id 2 comment no 1" + },{ + "mytitle":"reply 2 to user id 2 comment no 1" + }] + },{ + "mytext":"user id 2 comment no 2", + "myreplies": [{ + "mytitle":"reply 1 to user id 2 comment no 2" + },{ + "mytitle":"reply 2 to user id 2 comment no 2" + }] + }] + }] +}; + +describe("node-json-transform", function() { + + it("should change array keys and prefix the oldkeys with full srckey path", function() { + expect(transform(test1_data, test1_map)).toEqual(test1_expected); + }); + +}); + + +var test2_data = { + "to": [{ + "email": "sarvpriy.arya@gmail.com", + "name": "Sarvpriy Arya" + },{ + "email": "sarvpriy.arya@gmail.com", + "name": "Sarvpriy Arya" + }] +}; + +var test2_map = { + "item": { + "personalizations": [{ + "to[to]": { + "email": "email" + } + }] + } +}; + +var test2_expected = {"personalizations":[{"to":[{"email":"sarvpriy.arya@gmail.com"},{"email":"sarvpriy.arya@gmail.com"}]}]} + +describe("node-json-transform", function() { + + it("should work when top level is not an array", function() { + expect(transform(test2_data, test2_map)).toEqual(test2_expected); + }); + + it("should handle root object ex. { item: `payload`}", function() { + expect(transform({"payload": test2_data}, { "item": "payload"})).toEqual(test2_data); + }); + +});