ngrx EntityAdapter upsertMany с частичными обновлениями

#ngrx #ngrx-entity

#ngrx #ngrx-сущность

Вопрос:

У меня есть EntityState, скажем, типа Model : EntityState<Model> .

У меня есть API, который возвращает список частичных моделей. Partial<Model>[] .

Я хочу обновить этот список. Для объектов, которые уже присутствуют в состоянии хранилища / объекта (конечно, по идентификатору), я хочу обновить все существующие свойства.

Для объектов, которых нет, я хотел бы обнулить отсутствующие поля и добавить эти объекты.

Каков наилучший способ добиться этого? Документация о том, как именно работают методы адаптера, довольно скудна (https://ngrx.io/guide/entity/adapter#adapter-collection-methods ).

upsert требует Model[] , не принимает Partial<Model>[] , хотя в документации подразумевается, что он каким-то образом поддерживает частичные обновления.

add Методы не указывают, что они делают для существующих совпадений идентификаторов … предположительно, они игнорируют новые элементы и не добавляют / заменяют?

update Методы не указывают, что произойдет, если указанный идентификатор отсутствует.

Я думаю, что лучше всего было бы позвонить addMany , а затем updateMany , чтобы получить желаемое поведение, но, похоже upsert , оно предназначено для этой цели. Проблема, вероятно, заключается в отображении этих Partial<Model> типов в Model экземпляры, которые отсутствуют в состоянии объекта … т. е. обнуление отсутствующих полей для новых записей.

Мысли / советы? Спасибо!

Ответ №1:

На данный момент это мое решение, если я не услышу о лучшем варианте от кого-то, кто лучше знает сущности ngrx.

 interface IModel {
  id: string;
}

export function upsertMany<TApiType extends IModel, TStoreModel>(
  adapter: EntityAdapter<TStoreModel>,
  models: TApiType[],
  addMap: ((model: TApiType) => TStoreModel),
  updateMap: ((model: TApiType) => Partial<TStoreModel>),
  state: EntityState<TStoreModel>,
): EntityState<TStoreModel> {
  state = adapter.updateMany(models.map(model => ({
    id: model.id,
    changes: updateMap(model),
  })), state);
  return adapter.addMany(models.map(addMap), state);
}
 

Комментарии:

1. Это решение, вероятно, в два раза дороже обычного, потому что мы дважды сопоставляем все объекты api и пытаемся добавить каждый, а затем обновить каждый независимо.

Ответ №2:

А как насчет этого:

 on(MyActions.partialUpdate, (state, action) => {
  return {
    ...state,
    courses: adapter.upsertMany(action.partialCourses.map(c => {

      let course = state.courses.entities[c.id] !== undefined ?
        { ...state.courses.entities[c.id] } :
        new Course();

      course.someProperty = c.someProperty;

      return course;
    }), state.courses)
  }
})