From 6730199b04e18db6da046c8f2ed75a21682af0e3 Mon Sep 17 00:00:00 2001 From: Aleck Greenham Date: Wed, 7 Oct 2020 07:27:38 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=9F=20Add=20the=20ability=20perform=20?= =?UTF-8?q?list=20operations=20on=20all=20other=20lists=20not=20explicitly?= =?UTF-8?q?=20referenced?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++ index.d.ts | 5 +++ src/actions/RESTful/newItem.js | 1 - src/configuration.js | 5 +++ src/reducers/helpers/applyListOperators.js | 48 ++++++++++++++++++++-- 5 files changed, 63 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 30f7db4..aa05f27 100644 --- a/README.md +++ b/README.md @@ -717,6 +717,7 @@ configure({ | acceptType | String | No | The `Accept` header to use with each request. Defaults to the contentType if not defined. | | contentType | String | No | The `Content-Type` header to use with each request | | errorContentType | String | No | The `Content-Type` of error responses that should be parsed as JSON. Defaults to the `contentType` if not defined. | +| listWildcard | String | '*' | The list key used to reference all lists for action creator's option's list operations | | request | RequestInit | No | The request configuration object to be passed to the fetch method, or the new XMLHttpRequest object, when the progress option is used. | | beforeReducers | Array of reducers | No | A list of functions to call before passing the resource to the reducer. This is useful if you want to use the default reducer, but provide some additional pre-processing to standardise the resource before it is added to the store. | | afterReducers | Array of reducers | No | A list of functions to call after passing the resource to the reducer. This is useful if you want to use the default reducer, but provide some additional post-processing to standardise the resource before it is added to the store. | @@ -1389,6 +1390,14 @@ import { UNSPECIFIED_KEY } from 'redux-and-the-rest'; createUser(userAttributes, { push: [UNSPECIFIED_KEY] }) ``` +If you want to perform a list operation on all other lists whose key has not been explicitly referenced, you can use the `getConfiguration().listWildcard` value (`'*'` by default). + +For example the following will unshift an item to the `newest` list and invalidate all others: + +```javascript +createTodoItem({ title: 'Pick up milk'}, { unshift: ['newest'], invalidate: ['*'] }); +``` + When the item is successfully created, the default createItem reducer expects the server to respond with a JSON object containing the item's attributes. If the request fails, it expects the server to respond with a JSON object containing an error. ### Update a item on the server diff --git a/index.d.ts b/index.d.ts index 39e3e4e..b14d84d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1039,6 +1039,11 @@ export interface GlobalConfigurationOptions { */ contentType?: String, + /** + * The key to use use as a wildcard to mean all lists + */ + listWildcard?: String, + /** * The Content-Type of error responses that should be parsed as JSON. Defaults to the contentType if not defined. */ diff --git a/src/actions/RESTful/newItem.js b/src/actions/RESTful/newItem.js index a5bbf9b..1cd239c 100644 --- a/src/actions/RESTful/newItem.js +++ b/src/actions/RESTful/newItem.js @@ -8,7 +8,6 @@ import warn from '../../utils/dev/warn'; import applyListOperators from '../../reducers/helpers/applyListOperators'; import wrapInObject from '../../utils/object/wrapInObject'; import adaptOptionsForSingularResource from '../../action-creators/helpers/adaptOptionsForSingularResource'; -import { registerActionEnd } from '../../utils/ActionQueue'; /** ************************************************************************************************************ * Action creators diff --git a/src/configuration.js b/src/configuration.js index bef76b7..8c05047 100644 --- a/src/configuration.js +++ b/src/configuration.js @@ -40,6 +40,11 @@ const DefaultConfigurationOptions = { * Assume a default content-type of application/json */ contentType: 'application/json', + + /** + * The key to use use as a wildcard to mean all lists + */ + listWildcard: '*', }; let configuration = { diff --git a/src/reducers/helpers/applyListOperators.js b/src/reducers/helpers/applyListOperators.js index 53f0648..5dc0b51 100644 --- a/src/reducers/helpers/applyListOperators.js +++ b/src/reducers/helpers/applyListOperators.js @@ -1,10 +1,20 @@ import { LIST } from '../../constants/DataStructures'; import contains from '../../utils/list/contains'; +import { getConfiguration } from '../../configuration'; +import without from '../../utils/list/without'; function applyListOperators(lists, listOperations = {}, temporaryKey) { const updatedLists = {}; - listOperations.push.forEach((listKey) => { + const { listWildcard } = getConfiguration(); + + const keysExplicitlyReferenced = [ + ...(listOperations.push || []), + ...(listOperations.unshift || []), + ...(listOperations.invalidate || []), + ]; + + function pushPosition(listKey) { const existingList = lists[listKey] || LIST; if (contains(existingList.positions, temporaryKey)) { @@ -18,9 +28,9 @@ function applyListOperators(lists, listOperations = {}, temporaryKey) { ] }; } - }); + } - listOperations.unshift.forEach((listKey) => { + function unshiftPosition(listKey) { const existingList = lists[listKey] || LIST; if (contains(existingList.positions, temporaryKey)) { @@ -34,10 +44,40 @@ function applyListOperators(lists, listOperations = {}, temporaryKey) { ] }; } + } + + function invalidateList(listKey) { + updatedLists[listKey] = LIST; + } + + function applyToAllListsNotExplicitlyReferenced(listOperation) { + without(Object.keys(lists), keysExplicitlyReferenced).forEach((listKey) => { + listOperation(listKey); + }); + } + + listOperations.push.forEach((listKey) => { + if (listKey === listWildcard) { + applyToAllListsNotExplicitlyReferenced(pushPosition); + } else { + pushPosition(listKey); + } + }); + + listOperations.unshift.forEach((listKey) => { + if (listKey === listWildcard) { + applyToAllListsNotExplicitlyReferenced(unshiftPosition); + } else { + unshiftPosition(listKey); + } }); listOperations.invalidate.forEach((listKey) => { - updatedLists[listKey] = LIST; + if (listKey === listWildcard) { + applyToAllListsNotExplicitlyReferenced(invalidateList); + } else { + invalidateList(listKey); + } }); return {