Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing multiple objects using Ramda lens

I currently have a data structure that looks mostly like that following:

var data = { "id": 123,
    "modules": [{
        "id": 1,
        "results": [{
            "status": "fail",
            "issues": [
                {"type": "change", "status": "warn", "data": {}},
                {"type": "remove", "status": "warn", "data": {}},
                {"type": "change", "status": "warn", "data": {}}
            ]
        }]
    },{
        "id": 2
        "results": [{
            "status": "pass",
            "issues": [
                {"type": "change", "status": "warn", "data": {}},
                {"type": "remove", "status": "warn", "data": {}},
                {"type": "change", "status": "warn", "data": {}}
            ]
        }]
    }]
}

I have been trying to use Ramda to make a compose query that could do something like, change the status of all issues that are of a certain type.

I have been trying to do something along the lines of composing the lens's through R.map/R.chain but I can't seem to work it out. Something like this is what im trying to do:

let approvedData = R.compose(
  R.set(R.__, 'approve', Data)
  R.lensProp('status')
  R.map(R.lensIndex),
  R.lensProp('issues'),
  R.map(R.lensIndex),
  R.lensProp('results'),
  R.map(R.lensIndex),
  R.lensProp('modules')
)(Data)

And have it return back the full data set with the statuses changed.

UPDATE:

I have come up with some code that will do what I'm trying to do, but I'm still struggling to make each of the steps into functions that can then be composed:

R.over(R.lensProp('modules'), R.map(
  R.over(R.lensProp('results'), R.map(
    R.over(R.lensProp('issues'), R.map(
      R.set(R.lensProp('status'), 'approve')
    ))
  ))
), Data)
like image 377
Shard Avatar asked Sep 05 '25 03:09

Shard


2 Answers

Your updated solution looks fine to me, but it is possible to create the transformation function via composition:

//  update$modules$results$issues$status :: (String -> String) -> Object -> Object
var update$modules$results$issues$status = R.compose(
  R.over(R.lensProp('modules')),
  R.map,
  R.over(R.lensProp('results')),
  R.map,
  R.over(R.lensProp('issues')),
  R.map,
  R.over(R.lensProp('status'))
);

update$modules$results$issues$status(R.always('approve'))(data);
like image 114
davidchambers Avatar answered Sep 07 '25 21:09

davidchambers


It seems you're probably having doubts around the transformation of values within arrays.

Now, with the data being

const data = {
  "id": 123,
  "modules": [{
    "id": 1,
    "results": [{
      "status": "fail",
      "issues": [
        {"type": "change", "status": "warn", "data": {}},
        {"type": "remove", "status": "warn", "data": {}},
        {"type": "change", "status": "warn", "data": {}}
      ]
    }]
  },{
    "id": 2,
    "results": [{
      "status": "pass",
      "issues": [
        {"type": "change", "status": "warn", "data": {}},
        {"type": "remove", "status": "warn", "data": {}},
        {"type": "change", "status": "warn", "data": {}}
      ]
    }]
  }]
};

What you want to do is create lenses for each of the keys that contain arrays. In your specific case they are modules, results and issues.

On top of that, you'll need a lens to the key you want to modify, which is status.

So:

const modulesLens = lensProp('modules')
const resultsLens = lensProp('results')
const issuesLens = lensProp('issues')
const statusLens = lensProp('status')

Now, with these in place, all you have to do is put them together. (I've broken them down to facilitate the comprehension)

const approveIssues = over(
  modulesLens,
  map(over(
    resultsLens,
    map(over(
      issuesLens,
      map(set(statusLens, 'approve'))
    ))
  ))
)

Now all that's left to do is feed approvedIssues with the data you'd like to transform, which is our data.

So, finally.

//Running this
const approvedData = approveIssues(data)

/* Outputs this
{
  "id": 123,
  "modules": [{
    "id": 1,
    "results": [{
      "issues": [
        {"data": {}, "status": "approve", "type": "change"},
        {"data": {}, "status": "approve", "type": "remove"},
        {"data": {}, "status": "approve", "type": "change"}
      ],
      "status": "fail"
    }]}, {
      "id": 2,
      "results": [{
        "issues": [
          {"data": {}, "status": "approve", "type": "change"},
          {"data": {}, "status": "approve", "type": "remove"},
          {"data": {}, "status": "approve", "type": "change"}],
        "status": "pass"
    }]}
  ]}
*/

In that case I didn't necessarily have to use compose, but that would be possible as well I guess.

like image 42
Alexandre Theodoro Avatar answered Sep 07 '25 21:09

Alexandre Theodoro