Как выполнить вложенное обновление с использованием Ramda в заданной структуре объекта? - PullRequest
0 голосов
/ 21 февраля 2019

Предполагая следующий объект, как можно использовать Ramda для выполнения вложенного обновления в критериях с учетом приложения, идентификатора критерия и данных?

const application = {
  id: 'a1',
  features: [
    {
      id: 'f1',
      criterias: [
        { id: 'c1' }
      ]
    },
    {
      id: 'f2',
      criterias: [
        { id: 'c2' },
        { id: 'c3' }
      ]
    }
  ]
}

Функция будет выглядеть примерно так:

const updateCriteria = (application, criteriaId, data) => // magic...

updateCriteria(application, 'c2', { name: 'foo' })

// output: {
//  id: 'a1',
//  features: [
//    {
//      id: 'f1',
//      criterias: [
//        { id: 'c1' }
//      ]
//    },
//    {
//      id: 'f2',
//      criterias: [
//        { id: 'c2', name: 'foo' },
//        { id: 'c3' }
//      ]
//    }
//  ]
// }

1 Ответ

0 голосов
/ 21 февраля 2019

Объективы, вероятно, являются лучшим выбором для этого.У Ramda есть общая lens функция и специальные функции для свойства объекта (lensProp), для индекса массива (lensIndex),и для более глубокого пути (lensPath), но он не включает один, чтобы найти совпадающее значение в массиве по id.Тем не менее, сделать свое дело несложно.

Объектив создается путем передачи двух функций в lens: геттера, который получает объект и возвращает соответствующее значение, и сеттера, который принимает новое значение иобъект и возвращает обновленную версию объекта.

Здесь мы пишем lensMatch, который находит или задает значение в массиве, где заданное имя свойства соответствует заданному значению.И lensId просто передает 'id' в lensMatch, чтобы вернуть функцию, которая примет значение id и вернет объектив.

Используя любой объектив, мы получим view, set и over функции, которые, соответственно, получают, устанавливают и обновляют значение.

Мы могли бы использовать idLens вот так:

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'} ]

Итак, для вашей проблемы мы могли бы написать что-то вроде этого:

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>

Но это предполагает, что вы знаете featureId.Если вам нужно найти как featureId, так и вложенный объект со своим внутренним идентификатором, вы можете написать более сложную линзу для этого, но он будет гораздо более тяжелым.


Небольшое примечание:«критерий» уже во множественном числе, поэтому «критерии» нечетны.Единственное число является «критерием».

...