Source: app/actions/entities/entityActions.js

import createAction from 'redux-actions/lib/createAction';

/**
 * All functions in this module are action creators and the return value should be passed to the
 * redux store dispatch() function.
 *
 * @module
 */

export const REMOVE_ENTITIES = 'entityActions/REMOVE_ENTITIES';
export const REMOVE_ENTIRE_ENTITY = 'entityActions/REMOVE_ENTIRE_ENTITY';
export const ADD_ENTITIES = 'entityActions/ADD_ENTITIES';
export const SET_ENTITY = 'entityActions/SET_ENTITY';
export const UPDATE_ENTITIES = 'entityActions/UPDATE_ENTITIES';
export const ADD_ENTITIES_OF_TYPE = 'entityActions/ADD_ENTITIES_OF_TYPE';

/**
 * Removes entities from the entity reducer
 *
 * @function removeEntities
 * @param {Array} ids The ids of the entities to remove
 * @param {string} entityType The type of the entities to remove
 */
export const removeEntities = createAction(
  REMOVE_ENTITIES,
  ids => ids,
  (ids, entityType) => ({ entityType }),
);

export const removeEntireEntity = createAction(
  REMOVE_ENTIRE_ENTITY,
  entityType => entityType,
  entityType => ({ entityType }),
);

/**
 * Add an object of new entities that all have the same type.
 *
 * @function addEntitiesOfType
 * @param {object} entities An object containing new entities. The keys of the object are the ids
 * for the entities. The values are the entities themselves. This will overwrite any existing
 * entities in the reducer for that entity type.
 * @param {string} entityType The entity type of the given entities.
 */
export const addEntitiesOfType = createAction(
  ADD_ENTITIES_OF_TYPE,
  entities => entities,
  (entities, entityType) => ({ entityType }),
);

/**
 * Add an object of new entities
 *
 * @function addEntities
 * @param {object} entities An object containing new entities. This object should be structured
 * as a map by entity type and then by entity id, like so:
 * {
 *   [entityType]: {
 *     [entityId]: { <entity data> },
 *     ...
 *   }
 *   ...
 * }
 */
export const addEntities = createAction(ADD_ENTITIES);

/**
 * Sets the data for a single entity. If the entity does not exist, it will be created.
 *
 * @function setEntity
 * @param {string} entityType The type of entity
 * @param {string} enitityId The id of the entity
 * @param {object} data The data to set
 * @param {boolean|function} [merge=false] Indicates if existing data should be replaced or merged.
 * By default, existing data will be replaced. If merge is true, existing and new data will be
 * merged by a simple Object.assign(). merge may also be a function that takes the old and new
 * data, and returns a merge result.
 */
export const setEntity = createAction(
  SET_ENTITY,
  (entityType, entityId, data, merge = false) => ({ data, merge }),
  (entityType, entityId) => ({ entityType, entityId }),
);

/**
 * Updates one or more entities by merging the given data into the entities
 *
 * _note: all matching entities will update to a new object reference, even if the new data is the
 * same as the current data. For performance reasons, make sure not to match more entities than
 * necessary._
 * @function updateEntities
 * @param entityType {string} The type of the entity to update
 * @param data {object} The data to merge into the matched entities
 * @param [predicate] {object} An object with properties that should match the entities to update
 * (strict equality). If not given, will update all entities of the given type
 */
export const updateEntities = createAction(
  UPDATE_ENTITIES,
  (entityType, data) => ({ data }),
  (entityType, data, predicate = null) => ({ entityType, predicate }),
);