From c05965597ef2592c18bf6b3785f456af752757f3 Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Thu, 21 May 2020 13:50:43 +0300 Subject: [PATCH] deletes query items, adds tests for new entity methods also adds changelog --- packages/core-data/CHANGELOG.md | 8 ++++ .../src/queried-data/test/reducer.js | 32 +++++++++++++ packages/core-data/src/test/actions.js | 46 +++++++++++++++++++ packages/core-data/src/utils/on-sub-key.js | 25 +++++++++- 4 files changed, 110 insertions(+), 1 deletion(-) diff --git a/packages/core-data/CHANGELOG.md b/packages/core-data/CHANGELOG.md index cfabdcf6918764..ec6c25aff3e7e0 100644 --- a/packages/core-data/CHANGELOG.md +++ b/packages/core-data/CHANGELOG.md @@ -2,6 +2,14 @@ ## Unreleased +## 2.3.1 (2019-05-21) + +### New Feature + +- The `deleteEntityRecord` and `removeItems` actions have been added. +- Entities now support a `forceDelete` attribute to allow the API to delete things that do not go to trash. +- A `delete` helper is created for every registered entity. + ## 2.3.0 (2019-05-21) ### New features diff --git a/packages/core-data/src/queried-data/test/reducer.js b/packages/core-data/src/queried-data/test/reducer.js index d18322a14f087b..972adf1221ced3 100644 --- a/packages/core-data/src/queried-data/test/reducer.js +++ b/packages/core-data/src/queried-data/test/reducer.js @@ -99,4 +99,36 @@ describe( 'reducer', () => { queries: {}, } ); } ); + + it( 'deletes an item', () => { + const original = deepFreeze( { + items: { + 1: { id: 1, name: 'abc' }, + 2: { id: 2, name: 'def' }, + 3: { id: 3, name: 'ghi' }, + 4: { id: 4, name: 'klm' }, + }, + queries: { + '': [ 1, 2, 3, 4 ], + 's=a': [ 1, 3 ], + }, + } ); + const state = reducer( original, { + type: 'REMOVE_ITEMS', + query: [ 3 ], + items: [ 3 ], + } ); + + expect( state ).toEqual( { + items: { + 1: { id: 1, name: 'abc' }, + 2: { id: 2, name: 'def' }, + 4: { id: 4, name: 'klm' }, + }, + queries: { + '': [ 1, 2, 4 ], + 's=a': [ 1 ], + }, + } ); + } ); } ); diff --git a/packages/core-data/src/test/actions.js b/packages/core-data/src/test/actions.js index 4ed8f389ca1adf..589ae2accf0ddb 100644 --- a/packages/core-data/src/test/actions.js +++ b/packages/core-data/src/test/actions.js @@ -4,6 +4,8 @@ import { editEntityRecord, saveEntityRecord, + deleteEntityRecord, + removeItems, receiveEntityRecords, receiveUserPermission, receiveAutosaves, @@ -30,6 +32,50 @@ describe( 'editEntityRecord', () => { } ); } ); +describe( 'removeItems', () => { + it( 'builds an action object', () => { + const postIds = [ 1, 2, 3 ]; + expect( removeItems( 'postType', 'post', postIds ) ).toEqual( { + type: 'REMOVE_ITEMS', + items: postIds, + kind: 'postType', + name: 'post', + invalidateCache: false, + } ); + } ); +} ); + +describe( 'deleteEntityRecord', () => { + it( 'triggers a DELETE request for an existing record', async () => { + const post = 10; + const entities = [ + { name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' }, + ]; + const fulfillment = deleteEntityRecord( 'postType', 'post', post ); + fulfillment.next(); + + // delete start action + expect( fulfillment.next( entities ).value.type ).toBe( + 'DELETE_ENTITY_RECORD_START' + ); + + // remove items + fulfillment.next(); + + // delete api call + const { value: apiFetchAction } = fulfillment.next(); + expect( apiFetchAction.request ).toEqual( { + path: '/wp/v2/posts/10', + method: 'DELETE', + } ); + + // delete finish + expect( fulfillment.next().value.type ).toBe( + 'DELETE_ENTITY_RECORD_FINISH' + ); + } ); +} ); + describe( 'saveEntityRecord', () => { it( 'triggers a POST request for a new record', async () => { const post = { title: 'new post' }; diff --git a/packages/core-data/src/utils/on-sub-key.js b/packages/core-data/src/utils/on-sub-key.js index 24adf06b773ebc..93dfe497fc879b 100644 --- a/packages/core-data/src/utils/on-sub-key.js +++ b/packages/core-data/src/utils/on-sub-key.js @@ -1,3 +1,7 @@ +/** + * External dependencies + */ +import { filter } from 'lodash'; /** * Higher-order reducer creator which creates a combined reducer object, keyed * by a property on the action object. @@ -10,6 +14,8 @@ export const onSubKey = ( actionProperty ) => ( reducer ) => ( state = {}, action ) => { + const newState = { ...state }; + // Retrieve subkey from action. Do not track if undefined; useful for cases // where reducer is scoped by action shape. const key = action[ actionProperty ]; @@ -24,8 +30,25 @@ export const onSubKey = ( actionProperty ) => ( reducer ) => ( return state; } + if ( action.type === 'REMOVE_ITEMS' ) { + action.query.forEach( ( queryId ) => { + Object.keys( newState ).forEach( ( stateKey ) => { + newState[ stateKey ] = filter( + newState[ stateKey ], + ( stateQueryId ) => { + return stateQueryId !== queryId; + } + ); + } ); + } ); + } + + if ( ! nextKeyState ) { + return newState; + } + return { - ...state, + ...newState, [ key ]: nextKeyState, }; };