From 3727948bd847e8a488c12e7b3d587f078e5f6ea9 Mon Sep 17 00:00:00 2001 From: thiery Date: Tue, 7 Jan 2020 17:06:56 +0100 Subject: [PATCH] add addRecords and add test on data GET_MANY_REFERENCE and GET_MANY action --- .../src/reducer/admin/resource/data.spec.ts | 58 ++++++++++++++++++- .../src/reducer/admin/resource/data.ts | 33 +++++++++-- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/packages/ra-core/src/reducer/admin/resource/data.spec.ts b/packages/ra-core/src/reducer/admin/resource/data.spec.ts index 707cbec18a7..d95bf2f185d 100644 --- a/packages/ra-core/src/reducer/admin/resource/data.spec.ts +++ b/packages/ra-core/src/reducer/admin/resource/data.spec.ts @@ -1,8 +1,15 @@ import assert from 'assert'; -import { DELETE, DELETE_MANY, UPDATE } from '../../../core'; +import { + DELETE, + DELETE_MANY, + UPDATE, + GET_MANY, + GET_MANY_REFERENCE, +} from '../../../core'; import getFetchedAt from '../../../util/getFetchedAt'; import dataReducer, { replaceRecords, addOneRecord } from './data'; +import { FETCH_END } from '../../../actions'; jest.mock('../../../util/getFetchedAt'); @@ -253,4 +260,53 @@ describe('Resources data reducer', () => { assert.notDeepEqual(newState.fetchedAt.record2, before); }); }); + + describe.each([GET_MANY_REFERENCE, GET_MANY])('%s', actionType => { + it('should add new records to the old one', () => { + const before = new Date(0); + const now = new Date(); + + // @ts-ignore + getFetchedAt.mockImplementationOnce(() => ({ + new_record: now, + record2: now, + })); + + const state = { + record1: { id: 'record1', prop: 'value' }, + record2: { id: 'record2', prop: 'value' }, + record3: { id: 'record3', prop: 'value' }, + fetchedAt: { + record1: before, + record2: before, + record3: before, + }, + }; + + const newState = dataReducer(state, { + type: actionType, + payload: { + data: [ + { id: 'record2', prop: 'updated value' }, + { id: 'new_record', prop: 'new value' }, + ], + }, + meta: { + fetchResponse: actionType, + fetchStatus: FETCH_END, + }, + }); + assert.deepEqual(newState, { + record1: { id: 'record1', prop: 'value' }, + record2: { id: 'record2', prop: 'updated value' }, + record3: { id: 'record3', prop: 'value' }, + new_record: { id: 'new_record', prop: 'new value' }, + }); + assert.deepEqual(newState.fetchedAt.record1, before); + assert.deepEqual(newState.fetchedAt.record3, before); + + assert.notDeepEqual(newState.fetchedAt.record2, before); + assert.notDeepEqual(newState.fetchedAt.new_record, before); + }); + }); }); diff --git a/packages/ra-core/src/reducer/admin/resource/data.ts b/packages/ra-core/src/reducer/admin/resource/data.ts index 7b08991696d..87ad384f859 100644 --- a/packages/ra-core/src/reducer/admin/resource/data.ts +++ b/packages/ra-core/src/reducer/admin/resource/data.ts @@ -86,6 +86,34 @@ export const replaceRecords = ( return hideFetchedAt(records); }; + +/** + * Add new records to the pool, without touching the other ones. + */ +export const addRecords = ( + newRecords: Record[] = [], + oldRecords: RecordSetWithDate +): RecordSetWithDate => { + const newRecordsById = { ...oldRecords }; + newRecords.forEach(record => { + newRecordsById[record.id] = isEqual(record, oldRecords[record.id]) + ? (oldRecords[record.id] as Record) + : record; + }); + + const updatedFetchedAt = getFetchedAt( + newRecords.map(({ id }) => id), + oldRecords.fetchedAt + ); + + Object.defineProperty(newRecordsById, 'fetchedAt', { + value: { ...oldRecords.fetchedAt, ...updatedFetchedAt }, + enumerable: false, + }); + + return newRecordsById; +}; + export const addOneRecord = ( newRecord: Record, oldRecords: RecordSetWithDate, @@ -160,10 +188,7 @@ const dataReducer: Reducer = ( return replaceRecords(payload.data, previousState); case GET_MANY: case GET_MANY_REFERENCE: - return replaceRecords( - Object.values(previousState).concat(payload.data) as Record[], - previousState - ); + return addRecords(payload.data, previousState); case UPDATE: case CREATE: case GET_ONE: