YuriGor / deepdash

eachDeep, filterDeep, findDeep, someDeep, omitDeep, pickDeep, keysDeep etc.. Tree traversal library written in Underscore/Lodash fashion
https://deepdash.io/
MIT License
275 stars 12 forks source link

Inconsistency when using mapValueDeep #72

Closed zallesov closed 4 years ago

zallesov commented 4 years ago

Hi. I use mapValueDeep to replace a firebase timestamp with a regular Date value. It kinda works but the resulting Date object contains leaves from the timestamps

I've tried playing around in the examples and here is what I found

deepdash(_); // mixin Deepdash methods into Lodash

class Timestamp {
  constructor(seconds, nanos) {
    this.seconds = seconds
    this.nanos = nanos
  }

  toDate = () => {
    // return {newdate: new Date(this.seconds * 1000)};
    return new Date(this.seconds * 1000);
  }
};

let data = { hello: { from: { the: new Timestamp(123123123, 123) } } };
logJSON('Source Data',data);

let dates = _.map

let res = _.mapDeep(
    data,
    (v, k, par, ctx) => {
      if (v instanceof Timestamp) {
        return v.toDate();
      }
      else return v;
    },
    { leavesOnly: false }
  );
logJSON('Mapped Data',res);

this code yields the correct result. (which I could not get in my code)

{
  "hello": {
    "from": {
      "the": "1973-11-26T00:52:03.000Z"
    }
  }
}

but if uncomment code in toDate function it becomes

{
  "hello": {
    "from": {
      "the": {
        "newdate": "1973-11-26T00:52:03.000Z",
        "seconds": 123123123,
        "nanos": 123
      }
    }
  }
}

keeping the leaves of the original object. Looks like the examples run with older version with mapDeep instead of mapValuesDeep. In my case I use mapValuesDeep and whatever I do the resulting Date object contains garbage like this

expected { Sat, 26 Sep 2020 12:55:02 GMT _seconds: 1601124902, _nanoseconds: 253000000 } to equal Sat, 26 Sep 2020 12:55:02 GMT

Is there a way to force the replacement of the node so it does not proceed to the leaves at all?

YuriGor commented 4 years ago

Hi, thank you for question! Yes, codepen example was outdated and there were some renames / improvements related to mapXXX family of methods since that version. Now I upgraded that example (I always have no time for good doc works :( )

So for now mapValuesDeep works similar to how mapDeep used to, and mapDeep itself currently switched to return an array of values instead of the original object structure.

I already don't remember exactly how old mapDeep worked, but for now, with mapValuesDeep you can use context.skipChildren So in your case it will look like:

   let res = _.mapValuesDeep(
    data,
    (v,k,p,x) => {
      if(!(v instanceof Timestamp)){
        return v;        
      }
      x.skipChildren(true);
      return v.toDate();
    },
    { leavesOnly: false }
  );

The result seems to be as you expect: image

here is a codepen with your fixed example https://codepen.io/yurigor/pen/bGpZjZK?editors=0010