How to perform a nested update using Ramda in the given object structure?

前端 未结 1 525
暖寄归人
暖寄归人 2021-01-14 08:37

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         


        
相关标签:
1条回答
  • 2021-01-14 09:12

    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'.

    0 讨论(0)
提交回复
热议问题