Assuming the follow object how is it possible to use Ramda to perform a nested update in a criteria given an application, criteria ID and data?
const applica
Lenses are probably your best bet for this. Ramda has a generic lens function, and specific ones for an object property (lensProp), for an array index(lensIndex), and for a deeper path(lensPath), but it does not include one to find a matching value in an array by id. It's not hard to make our own, though.
A lens is made by passing two functions to lens
: a getter which takes the object and returns the corresponding value, and a setter which takes the new value and the object and returns an updated version of the object.
Here we write lensMatch
which find or sets the value in the array where a given property name matches the supplied value. And lensId
simply passes 'id'
to lensMatch
to get back a function which will take an id value and return a lens.
Using any lens, we have the view, set, and over functions which, respectively, get, set, and update the value.
We could use idLens
like this:
const data = [{id: 'a'}, {id: 'b'}, {id: 'c'}]
view (idLens ('b'), data)
//=> {id: 'b'}
set (idLens ('b'), 'foo', data)
//=> [ {id: 'a'}, 'foo', {id: 'c'} ]
over (idLens ('b'), merge ({name: 'foo'}), data)
//=> [ {id: 'a'}, {id: 'b', name: 'foo}, {id: 'c'} ]
So for your problem, we could write something like this:
const lensMatch = (propName) => (key) => lens
( find ( propEq (propName, key) )
, (val, arr, idx = findIndex (propEq (propName, key), arr)) =>
update (idx > -1 ? idx : length (arr), val, arr)
)
const lensId = lensMatch ('id')
const updateCriteria = (featureId, criteriaId, data, application) => over
( compose
( lensProp ('features')
, lensId (featureId)
, lensProp ('criterias')
, lensId (criteriaId)
)
, merge (data)
, application
)
const application = {id: 'a1', features: [{id: 'f1', criterias: [{ id: 'c1' }]}, {id: 'f2', criterias: [{ id: 'c2' }, { id: 'c3' }]}]}
const newApp = updateCriteria ('f2', 'c2', {name: 'foo'}, application)
console.log(newApp)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {lens, find, propEq, findIndex, update, length, view, set, over, compose, lensProp, merge} = R
</script>
But this presupposes that you know the featureId
. If you need to find both the featureId
and the nested object with your internal id, you could write a more complex lens for that, but it will be much more heavyweight.
A minor note: 'criteria' is already plural, so 'criterias' is odd. The singular is 'criterion'.