CRUD: populates `items` and `itemsCount` when a new item is created (#47632)
* minor change in reducer * use organizeItemsById to compute new items * add reducer test with pick optimisticUrlParameters * rename constant name * add optimisticUrlParameters to CRUD actions types * use organizeItemsById to generate store IDs * add more reducer tests * compute nextItemsData based on ids * tessstssssss * add a order_by: name test * fix sorting data when url parameters * add tests * introduce filterDataByKeys helper fn * fix process to sort items optimistically * rollback wrong change in actions * changelog * set action `options` as optional * set default value for options
This commit is contained in:
parent
460d73eee0
commit
f51b93359f
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: update
|
||||
|
||||
CRUD: populates items and itemsCount when a new item is created
|
|
@ -36,7 +36,7 @@ export function createItemSuccess(
|
|||
key: IdType,
|
||||
item: Item,
|
||||
query: Partial< ItemQuery >,
|
||||
options: CrudActionOptions
|
||||
options?: CrudActionOptions
|
||||
) {
|
||||
return {
|
||||
type: TYPES.CREATE_ITEM_SUCCESS as const,
|
||||
|
|
|
@ -8,7 +8,11 @@ import { Reducer } from 'redux';
|
|||
*/
|
||||
import { Actions } from './actions';
|
||||
import CRUD_ACTIONS from './crud-actions';
|
||||
import { getRequestIdentifier, organizeItemsById } from './utils';
|
||||
import {
|
||||
filterDataByKeys,
|
||||
getRequestIdentifier,
|
||||
organizeItemsById,
|
||||
} from './utils';
|
||||
import { getTotalCountResourceName } from '../utils';
|
||||
import { TYPES } from './action-types';
|
||||
import type { IdType, Item, ItemQuery } from './types';
|
||||
|
@ -85,23 +89,41 @@ export const createReducer = (
|
|||
};
|
||||
|
||||
case TYPES.CREATE_ITEM_SUCCESS: {
|
||||
const { options = {} } = payload;
|
||||
|
||||
const { objItems, ids } = organizeItemsById(
|
||||
[ payload.item ],
|
||||
options.optimisticUrlParameters,
|
||||
itemData
|
||||
);
|
||||
|
||||
const data = {
|
||||
...itemData,
|
||||
...objItems,
|
||||
};
|
||||
|
||||
const createItemSuccessRequestId = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
payload.key,
|
||||
ids[ 0 ],
|
||||
payload.query
|
||||
);
|
||||
|
||||
const { options } = payload;
|
||||
const data = {
|
||||
...itemData,
|
||||
[ payload.key ]: {
|
||||
...( itemData[ payload.key ] || {} ),
|
||||
...payload.item,
|
||||
},
|
||||
};
|
||||
const getItemQueryId = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
let items = state.items;
|
||||
let queryItems = Object.keys( data ).map( ( key ) => +key );
|
||||
const getItemCountQueryId = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options?.optimisticQueryUpdate || {}
|
||||
);
|
||||
|
||||
let currentItems = state.items;
|
||||
|
||||
const currentItemsByQueryId =
|
||||
currentItems[ getItemQueryId ]?.data || [];
|
||||
|
||||
let nextItemsData = [ ...currentItemsByQueryId, ...ids ];
|
||||
|
||||
let itemsCount = state.itemsCount;
|
||||
|
||||
|
@ -126,49 +148,52 @@ export const createReducer = (
|
|||
const order_by = options.optimisticQueryUpdate
|
||||
?.order_by as OrderBy;
|
||||
|
||||
let sortingData = Object.values( data );
|
||||
sortingData = sortingData.sort( ( a, b ) =>
|
||||
( a[ order_by ] as string )
|
||||
.toLowerCase()
|
||||
.localeCompare(
|
||||
(
|
||||
b[ order_by ] as string
|
||||
).toLowerCase()
|
||||
)
|
||||
/*
|
||||
* Pick the data to sort by the order_by property,
|
||||
* from the data store,
|
||||
* based on the nextItemsData ids.
|
||||
*/
|
||||
let sourceDataToOrderBy = Object.values(
|
||||
filterDataByKeys( data, nextItemsData )
|
||||
) as Item[];
|
||||
|
||||
sourceDataToOrderBy = sourceDataToOrderBy.sort(
|
||||
( a, b ) =>
|
||||
String( a[ order_by ] as IdType )
|
||||
.toLowerCase()
|
||||
.localeCompare(
|
||||
String(
|
||||
b[ order_by ] as IdType
|
||||
).toLowerCase()
|
||||
)
|
||||
);
|
||||
|
||||
queryItems = sortingData.map( ( item ) =>
|
||||
Number( item.id )
|
||||
// Pick the ids from the sorted data.
|
||||
const { ids: sortedIds } = organizeItemsById(
|
||||
sourceDataToOrderBy,
|
||||
options.optimisticUrlParameters
|
||||
);
|
||||
|
||||
// Update the items data with the sorted ids.
|
||||
nextItemsData = sortedIds;
|
||||
}
|
||||
|
||||
const getItemQuery = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const getItemCountQuery = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
items = {
|
||||
...state.items,
|
||||
[ getItemQuery ]: {
|
||||
...state.items[ getItemQuery ],
|
||||
data: queryItems,
|
||||
currentItems = {
|
||||
...currentItems,
|
||||
[ getItemQueryId ]: {
|
||||
data: nextItemsData,
|
||||
},
|
||||
};
|
||||
|
||||
itemsCount = {
|
||||
...state.itemsCount,
|
||||
[ getItemCountQuery ]: Object.keys( data ).length,
|
||||
[ getItemCountQueryId ]: nextItemsData.length,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
items,
|
||||
items: currentItems,
|
||||
itemsCount,
|
||||
data,
|
||||
requesting: {
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
import { Actions } from '../actions';
|
||||
import { createReducer, ResourceState } from '../reducer';
|
||||
import { CRUD_ACTIONS } from '../crud-actions';
|
||||
import { getResourceName } from '../../utils';
|
||||
import { getRequestIdentifier } from '..//utils';
|
||||
import { getResourceName, getTotalCountResourceName } from '../../utils';
|
||||
import { getRequestIdentifier } from '../utils';
|
||||
import { Item, ItemQuery } from '../types';
|
||||
import TYPES from '../action-types';
|
||||
|
||||
|
@ -314,7 +314,7 @@ describe( 'crud reducer', () => {
|
|||
} );
|
||||
|
||||
describe( 'should handle CREATE_ITEM_SUCCESS', () => {
|
||||
it( 'when no options are passed', () => {
|
||||
it( 'with empty previous state', () => {
|
||||
const item: Item = {
|
||||
id: 2,
|
||||
name: 'Off the hook!',
|
||||
|
@ -325,12 +325,6 @@ describe( 'crud reducer', () => {
|
|||
status: 'draft',
|
||||
};
|
||||
|
||||
const resourceName = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
item.id,
|
||||
query
|
||||
);
|
||||
|
||||
const state = reducer( defaultState, {
|
||||
type: TYPES.CREATE_ITEM_SUCCESS,
|
||||
key: item.id,
|
||||
|
@ -339,15 +333,90 @@ describe( 'crud reducer', () => {
|
|||
options: {},
|
||||
} );
|
||||
|
||||
const resourceName = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
item.id,
|
||||
query
|
||||
);
|
||||
|
||||
expect( state.data[ 2 ].name ).toEqual( item.name );
|
||||
expect( state.data[ 2 ].status ).toEqual( item.status );
|
||||
expect( state.requesting[ resourceName ] ).toEqual( false );
|
||||
|
||||
// Not optimitic query update
|
||||
expect( state.items ).toEqual( {} );
|
||||
expect( state.itemsCount ).toEqual( {} );
|
||||
} );
|
||||
|
||||
it( 'when optimisticQueryUpdate is defined', () => {
|
||||
it( 'with previous state', () => {
|
||||
const item: Item = {
|
||||
id: 3,
|
||||
name: 'banana',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const query = {
|
||||
name: 'banana',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const queryId = { type: 'fruit' };
|
||||
|
||||
const getItemsQueryId = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
queryId
|
||||
);
|
||||
|
||||
const getItemsCountQueryId = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
queryId
|
||||
);
|
||||
|
||||
const initialState: ResourceState = {
|
||||
items: {
|
||||
[ getItemsQueryId ]: {
|
||||
data: [ 1, 2 ],
|
||||
},
|
||||
},
|
||||
itemsCount: {
|
||||
[ getItemsCountQueryId ]: 2,
|
||||
},
|
||||
errors: {},
|
||||
data: {
|
||||
1: { id: 1, name: 'apple', status: 'draft' },
|
||||
2: { id: 2, name: 'pine', status: 'publish' },
|
||||
},
|
||||
requesting: {},
|
||||
};
|
||||
|
||||
const state = reducer( initialState, {
|
||||
type: TYPES.CREATE_ITEM_SUCCESS,
|
||||
key: item.id,
|
||||
item,
|
||||
query,
|
||||
options: {},
|
||||
} );
|
||||
|
||||
expect( state.data ).toEqual( {
|
||||
1: { id: 1, name: 'apple', status: 'draft' },
|
||||
2: { id: 2, name: 'pine', status: 'publish' },
|
||||
3: { id: 3, name: 'banana', status: 'draft' },
|
||||
} );
|
||||
|
||||
const resourceName = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
item.id,
|
||||
query
|
||||
);
|
||||
expect( state.requesting[ resourceName ] ).toEqual( false );
|
||||
|
||||
// Not optimitic query update
|
||||
expect( state.items[ getItemsQueryId ].data ).toHaveLength( 2 );
|
||||
expect( state.items[ getItemsQueryId ].data ).toEqual( [ 1, 2 ] );
|
||||
expect( state.itemsCount[ getItemsCountQueryId ] ).toEqual( 2 );
|
||||
} );
|
||||
|
||||
it( 'with empty previous state, and optimisticQueryUpdate options', () => {
|
||||
const item: Item = {
|
||||
id: 7,
|
||||
name: 'Off the hook!',
|
||||
|
@ -370,8 +439,13 @@ describe( 'crud reducer', () => {
|
|||
options,
|
||||
} );
|
||||
|
||||
expect( state.data[ 7 ].name ).toEqual( item.name );
|
||||
expect( state.data[ 7 ].status ).toEqual( item.status );
|
||||
expect( state.data ).toEqual( {
|
||||
7: {
|
||||
id: 7,
|
||||
name: 'Off the hook!',
|
||||
status: 'draft',
|
||||
},
|
||||
} );
|
||||
|
||||
const resourceName = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
|
@ -380,30 +454,447 @@ describe( 'crud reducer', () => {
|
|||
);
|
||||
expect( state.requesting[ resourceName ] ).toEqual( false );
|
||||
|
||||
const itemQuery = getRequestIdentifier(
|
||||
const getItemsQueryId = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
expect( state.items[ itemQuery ].data ).toHaveLength( 1 );
|
||||
expect( state.items[ itemQuery ].data[ 0 ] ).toEqual( 7 ); // Item id
|
||||
expect( state.items[ getItemsQueryId ].data ).toHaveLength( 1 );
|
||||
expect( state.items[ getItemsQueryId ].data[ 0 ] ).toEqual( 7 ); // Item id
|
||||
|
||||
const itemsKey = Object.keys( state.items );
|
||||
expect( itemsKey ).toHaveLength( 1 );
|
||||
expect( itemsKey[ 0 ] ).toEqual( itemQuery );
|
||||
|
||||
const itemsCountQuery = getRequestIdentifier(
|
||||
const getItemsCountQueryId = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const itemsCountKey = Object.keys( state.itemsCount );
|
||||
expect( state.itemsCount[ getItemsCountQueryId ] ).toEqual( 1 );
|
||||
} );
|
||||
|
||||
// ItemsCount should be 1
|
||||
expect( state.itemsCount[ itemsCountQuery ] ).toEqual( 1 );
|
||||
it( 'with previous state, and optimisticQueryUpdate options', () => {
|
||||
const item: Item = {
|
||||
id: 7,
|
||||
name: 'kiwi',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
expect( itemsCountKey ).toHaveLength( 1 );
|
||||
expect( itemsCountKey[ 0 ] ).toEqual( itemsCountQuery );
|
||||
const query = {
|
||||
name: 'kiwi',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const options = {
|
||||
optimisticQueryUpdate: { random: 'fruit' },
|
||||
};
|
||||
|
||||
const getItemsQueryId = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const getItemsCountQueryId = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const initialState: ResourceState = {
|
||||
items: {
|
||||
[ getItemsQueryId ]: {
|
||||
data: [ 1, 2 ],
|
||||
},
|
||||
},
|
||||
itemsCount: {
|
||||
[ getItemsCountQueryId ]: 2,
|
||||
},
|
||||
errors: {},
|
||||
data: {
|
||||
1: { id: 1, name: 'apple', status: 'draft' },
|
||||
2: { id: 2, name: 'pine', status: 'publish' },
|
||||
},
|
||||
requesting: {},
|
||||
};
|
||||
|
||||
const state = reducer( initialState, {
|
||||
type: TYPES.CREATE_ITEM_SUCCESS,
|
||||
key: item.id,
|
||||
item,
|
||||
query,
|
||||
options,
|
||||
} );
|
||||
|
||||
expect( state.data ).toEqual( {
|
||||
1: { id: 1, name: 'apple', status: 'draft' },
|
||||
2: { id: 2, name: 'pine', status: 'publish' },
|
||||
7: { id: 7, name: 'kiwi', status: 'draft' },
|
||||
} );
|
||||
|
||||
const resourceName = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
item.id,
|
||||
query
|
||||
);
|
||||
expect( state.requesting[ resourceName ] ).toEqual( false );
|
||||
|
||||
expect( state.items[ getItemsQueryId ].data ).toHaveLength( 3 );
|
||||
expect( state.items[ getItemsQueryId ].data ).toEqual( [
|
||||
1, 2, 7,
|
||||
] );
|
||||
|
||||
expect( state.itemsCount[ getItemsCountQueryId ] ).toEqual( 3 );
|
||||
} );
|
||||
|
||||
it( `with previous state,
|
||||
and optimisticQueryUpdate options with order_by: name`, () => {
|
||||
const item: Item = {
|
||||
id: 7,
|
||||
name: 'kiwi',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const query = {
|
||||
name: 'kiwi',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const options = {
|
||||
optimisticQueryUpdate: { order_by: 'name' },
|
||||
};
|
||||
|
||||
const getItemsQueryId = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const getItemsCountQueryId = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const initialState: ResourceState = {
|
||||
items: {
|
||||
[ getItemsQueryId ]: {
|
||||
data: [ 1, 2 ],
|
||||
},
|
||||
},
|
||||
itemsCount: {
|
||||
[ getItemsCountQueryId ]: 2,
|
||||
},
|
||||
errors: {},
|
||||
data: {
|
||||
1: { id: 1, name: 'apple', status: 'draft' },
|
||||
2: { id: 2, name: 'pine', status: 'publish' },
|
||||
},
|
||||
requesting: {},
|
||||
};
|
||||
|
||||
const state = reducer( initialState, {
|
||||
type: TYPES.CREATE_ITEM_SUCCESS,
|
||||
key: item.id,
|
||||
item,
|
||||
query,
|
||||
options,
|
||||
} );
|
||||
|
||||
expect( state.data ).toEqual( {
|
||||
1: { id: 1, name: 'apple', status: 'draft' },
|
||||
2: { id: 2, name: 'pine', status: 'publish' },
|
||||
7: { id: 7, name: 'kiwi', status: 'draft' },
|
||||
} );
|
||||
|
||||
const resourceName = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
item.id,
|
||||
query
|
||||
);
|
||||
expect( state.requesting[ resourceName ] ).toEqual( false );
|
||||
|
||||
expect( state.items[ getItemsQueryId ].data ).toEqual( [
|
||||
// order by name: apple(1), kiwi(7), pine(2)
|
||||
1, 7, 2,
|
||||
] );
|
||||
} );
|
||||
|
||||
it( `with empty previous state,
|
||||
and optimisticQueryUpdate and
|
||||
optimisticUrlParameters options`, () => {
|
||||
const item: Item = {
|
||||
id: 7,
|
||||
name: 'Off the hook!',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const query = {
|
||||
name: 'Off the hook!',
|
||||
status: 'draft',
|
||||
parent_id: 200,
|
||||
};
|
||||
|
||||
const options = {
|
||||
optimisticQueryUpdate: { parent_id: 200 },
|
||||
optimisticUrlParameters: [ 200 ],
|
||||
};
|
||||
|
||||
const state = reducer( defaultState, {
|
||||
type: TYPES.CREATE_ITEM_SUCCESS,
|
||||
key: item.id,
|
||||
item,
|
||||
query,
|
||||
options,
|
||||
} );
|
||||
|
||||
expect( state.data ).toEqual( {
|
||||
'200/7': {
|
||||
id: 7,
|
||||
name: 'Off the hook!',
|
||||
status: 'draft',
|
||||
},
|
||||
} );
|
||||
|
||||
const resourceName = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
'200/7',
|
||||
query
|
||||
);
|
||||
|
||||
expect( state.requesting[ resourceName ] ).toEqual( false );
|
||||
|
||||
const getItemsQueryId = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
expect( state.items[ getItemsQueryId ] ).toBeDefined();
|
||||
expect( state.items[ getItemsQueryId ].data ).toEqual( [
|
||||
'200/7',
|
||||
] );
|
||||
|
||||
const getItemsCountQueryId = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
expect( state.itemsCount[ getItemsCountQueryId ] ).toEqual( 1 );
|
||||
} );
|
||||
|
||||
it( `with previous state,
|
||||
and optimisticQueryUpdate with order_by: name,
|
||||
and optimisticUrlParameters options`, () => {
|
||||
const item: Item = {
|
||||
id: 7,
|
||||
name: 'kiwi',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const query = {
|
||||
name: 'kiwi',
|
||||
status: 'draft',
|
||||
parent_id: 200,
|
||||
};
|
||||
|
||||
const options = {
|
||||
optimisticQueryUpdate: { parent_id: 200, order_by: 'name' },
|
||||
optimisticUrlParameters: [ 200 ],
|
||||
};
|
||||
|
||||
const getItemsQueryId = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const getItemsCountQueryId = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const initialState: ResourceState = {
|
||||
items: {
|
||||
[ getItemsQueryId ]: {
|
||||
data: [ '200/1', '200/2' ],
|
||||
},
|
||||
},
|
||||
itemsCount: {
|
||||
[ getItemsCountQueryId ]: 2,
|
||||
},
|
||||
errors: {},
|
||||
data: {
|
||||
'200/1': { id: 1, name: 'apple', status: 'draft' },
|
||||
'200/2': { id: 2, name: 'pine', status: 'publish' },
|
||||
},
|
||||
requesting: {},
|
||||
};
|
||||
|
||||
const state = reducer( initialState, {
|
||||
type: TYPES.CREATE_ITEM_SUCCESS,
|
||||
key: item.id,
|
||||
item,
|
||||
query,
|
||||
options,
|
||||
} );
|
||||
|
||||
expect( state.data ).toEqual( {
|
||||
'200/1': {
|
||||
id: 1,
|
||||
name: 'apple',
|
||||
status: 'draft',
|
||||
},
|
||||
'200/2': {
|
||||
id: 2,
|
||||
name: 'pine',
|
||||
status: 'publish',
|
||||
},
|
||||
'200/7': {
|
||||
id: 7,
|
||||
name: 'kiwi',
|
||||
status: 'draft',
|
||||
},
|
||||
} );
|
||||
|
||||
const resourceName = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
'200/7',
|
||||
query
|
||||
);
|
||||
|
||||
expect( state.requesting[ resourceName ] ).toEqual( false );
|
||||
|
||||
expect( state.items[ getItemsQueryId ] ).toBeDefined();
|
||||
expect( state.items[ getItemsQueryId ].data ).toEqual( [
|
||||
'200/1',
|
||||
'200/7',
|
||||
'200/2',
|
||||
] );
|
||||
|
||||
expect( state.itemsCount[ getItemsCountQueryId ] ).toEqual( 3 );
|
||||
} );
|
||||
|
||||
it( `with previous state,
|
||||
multiple items,
|
||||
and optimisticQueryUpdate with order_by: name,
|
||||
and optimisticUrlParameters options`, () => {
|
||||
const item: Item = {
|
||||
id: 9,
|
||||
name: 'Mootools',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const query = {
|
||||
name: 'Mootools',
|
||||
status: 'draft',
|
||||
parent_id: 500,
|
||||
};
|
||||
|
||||
const options = {
|
||||
optimisticQueryUpdate: { parent_id: 500, order_by: 'name' },
|
||||
optimisticUrlParameters: [ 500 ],
|
||||
};
|
||||
|
||||
const getItemsQueryId_200 = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
{
|
||||
parent_id: 200,
|
||||
rocking_by: 'name',
|
||||
}
|
||||
);
|
||||
|
||||
const getItemsQueryId_300 = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
{
|
||||
parent_id: 300,
|
||||
rocking_by: 'name',
|
||||
}
|
||||
);
|
||||
|
||||
const getItemsQueryId = getRequestIdentifier(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const getItemsCountQueryId_200 = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
{
|
||||
parent_id: 200,
|
||||
rocking_by: 'name',
|
||||
}
|
||||
);
|
||||
|
||||
const getItemsCountQueryId_300 = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
{
|
||||
parent_id: 300,
|
||||
order_by: 'name',
|
||||
}
|
||||
);
|
||||
|
||||
const getItemsCountQueryId = getTotalCountResourceName(
|
||||
CRUD_ACTIONS.GET_ITEMS,
|
||||
options.optimisticQueryUpdate
|
||||
);
|
||||
|
||||
const initialState: ResourceState = {
|
||||
items: {
|
||||
[ getItemsQueryId_200 ]: {
|
||||
data: [ '500/1', '500/2' ],
|
||||
},
|
||||
[ getItemsQueryId_300 ]: {
|
||||
data: [ '300/1', '300/2' ],
|
||||
},
|
||||
[ getItemsQueryId ]: {
|
||||
data: [ '500/1', '500/2', '500/3' ],
|
||||
},
|
||||
},
|
||||
itemsCount: {
|
||||
[ getItemsCountQueryId_200 ]: 2,
|
||||
[ getItemsCountQueryId_300 ]: 2,
|
||||
[ getItemsCountQueryId ]: 3,
|
||||
},
|
||||
errors: {},
|
||||
data: {
|
||||
'200/1': { id: 1, name: 'apple', status: 'draft' },
|
||||
'200/2': { id: 2, name: 'pine', status: 'publish' },
|
||||
'300/1': { id: 1, name: 'cat', status: 'draft' },
|
||||
'300/2': { id: 2, name: 'dog', status: 'draft' },
|
||||
'500/1': { id: 1, name: 'jQuery', status: 'draft' },
|
||||
'500/2': { id: 2, name: 'AlphaPro', status: 'draft' },
|
||||
'500/3': { id: 3, name: 'Vue', status: 'draft' },
|
||||
},
|
||||
requesting: {},
|
||||
};
|
||||
|
||||
const state = reducer( initialState, {
|
||||
type: TYPES.CREATE_ITEM_SUCCESS,
|
||||
key: item.id,
|
||||
item,
|
||||
query,
|
||||
options,
|
||||
} );
|
||||
|
||||
expect( state.data ).toEqual( {
|
||||
'200/1': { id: 1, name: 'apple', status: 'draft' },
|
||||
'200/2': { id: 2, name: 'pine', status: 'publish' },
|
||||
'300/1': { id: 1, name: 'cat', status: 'draft' },
|
||||
'300/2': { id: 2, name: 'dog', status: 'draft' },
|
||||
'500/1': { id: 1, name: 'jQuery', status: 'draft' },
|
||||
'500/2': { id: 2, name: 'AlphaPro', status: 'draft' },
|
||||
'500/3': { id: 3, name: 'Vue', status: 'draft' },
|
||||
'500/9': { id: 9, name: 'Mootools', status: 'draft' }, // New item
|
||||
} );
|
||||
|
||||
const resourceName = getRequestIdentifier(
|
||||
CRUD_ACTIONS.CREATE_ITEM,
|
||||
'500/9',
|
||||
query
|
||||
);
|
||||
|
||||
expect( state.requesting[ resourceName ] ).toEqual( false );
|
||||
|
||||
expect( state.items[ getItemsQueryId ] ).toBeDefined();
|
||||
expect( state.items[ getItemsQueryId ].data ).toEqual( [
|
||||
'500/2',
|
||||
'500/1',
|
||||
'500/9',
|
||||
'500/3',
|
||||
] );
|
||||
|
||||
expect( state.itemsCount[ getItemsCountQueryId ] ).toEqual( 4 );
|
||||
} );
|
||||
} );
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ type WithRequiredProperty< Type, Key extends keyof Type > = Type & {
|
|||
|
||||
export type CrudActionOptions = {
|
||||
optimisticQueryUpdate?: ItemQuery;
|
||||
optimisticUrlParameters?: IdType[];
|
||||
};
|
||||
|
||||
export type CrudActions<
|
||||
|
|
|
@ -96,6 +96,26 @@ export const organizeItemsById = (
|
|||
return { objItems, ids };
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters the input data object, returning a new object that contains only the keys
|
||||
* specified in the keys array.
|
||||
*
|
||||
* @param {Record<string, unknown>} data - The original data object to filter.
|
||||
* @param {IdType[]} keys - An array of keys that should be included in the returned object.
|
||||
* @return {Record<string, unknown>} A new object containing only the specified keys.
|
||||
*/
|
||||
export function filterDataByKeys(
|
||||
data: Record< string, unknown >,
|
||||
keys: IdType[]
|
||||
): Record< string, unknown > {
|
||||
return keys.reduce( ( acc: Record< string, unknown >, key ) => {
|
||||
if ( data[ key ] ) {
|
||||
acc[ key ] = data[ key ];
|
||||
}
|
||||
return acc;
|
||||
}, {} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an ID query into a ID string.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue