diff --git a/lib/ops/holder-store-ops.js b/lib/ops/holder-store-ops.js --- a/lib/ops/holder-store-ops.js +++ b/lib/ops/holder-store-ops.js @@ -85,3 +85,14 @@ ); }, }; + +export function createReplaceHoldersOperation( + items: $ReadOnlyArray, +): ReplaceHoldersOperation { + return { + type: 'replace_holders', + payload: { + items, + }, + }; +} diff --git a/lib/reducers/holder-reducer.js b/lib/reducers/holder-reducer.js --- a/lib/reducers/holder-reducer.js +++ b/lib/reducers/holder-reducer.js @@ -1,13 +1,16 @@ // @flow -import _omitBy from 'lodash/fp/omitBy.js'; - import { processHoldersActionTypes, storeEstablishedHolderActionType, } from '../actions/holder-actions.js'; +import type { HolderStoreOperation } from '../ops/holder-store-ops.js'; +import { + createReplaceHoldersOperation, + holderStoreOpsHandlers, +} from '../ops/holder-store-ops.js'; import { - type HolderInfo, + type HolderItem, type HolderStatus, type HolderStore, type BlobHashAndHolder, @@ -15,100 +18,113 @@ } from '../types/holder-types.js'; import type { BaseAction } from '../types/redux-types.js'; -const makeResultToStoreEntryMapper: ( +const mapResultsToHolderItems: ( status: HolderStatus, -) => BlobHashAndHolder => [string, HolderInfo] = - status => - ({ blobHash, holder }) => [blobHash, { holder, status }]; - -const mapResultsToStoreEntries: (status: HolderStatus) => ( +) => ( results: $ReadOnlyArray, -) => { - +[blobHash: string]: HolderInfo, -} = status => { - const mapFn = makeResultToStoreEntryMapper(status); - return results => Object.fromEntries(results.map(mapFn)); +) => $ReadOnlyArray = status => { + return results => + results.map((item: BlobHashAndHolder) => ({ + hash: item.blobHash, + holder: item.holder, + status, + })); }; +const { processStoreOperations: processHolderStoreOperations } = + holderStoreOpsHandlers; + +type ReduceHolderStoreResult = { + +holderStore: HolderStore, + +holderStoreOperations: $ReadOnlyArray, +}; function reduceHolderStore( store: HolderStore, action: BaseAction, -): HolderStore { +): ReduceHolderStoreResult { if (action.type === storeEstablishedHolderActionType) { const { blobHash, holder } = action.payload; - return { - ...store, - storedHolders: { - ...store.storedHolders, - [blobHash]: { - ...store.storedHolders[blobHash], + const holderStoreOperations: $ReadOnlyArray = [ + createReplaceHoldersOperation([ + { + hash: blobHash, holder, status: holderStatuses.ESTABLISHED, }, - }, + ]), + ]; + return { + holderStore: processHolderStoreOperations(store, holderStoreOperations), + holderStoreOperations, }; } else if (action.type === processHoldersActionTypes.started) { // marks processed holders as pending const { holdersToAdd, holdersToRemove } = action.payload; - const pendingEstablishmentHolders = mapResultsToStoreEntries( + const pendingEstablishmentHolders = mapResultsToHolderItems( holderStatuses.PENDING_ESTABLISHMENT, )(holdersToAdd); - const pendingRemovalHolders = mapResultsToStoreEntries( + const pendingRemovalHolders = mapResultsToHolderItems( holderStatuses.PENDING_REMOVAL, )(holdersToRemove); - return { - ...store, - storedHolders: { - ...store.storedHolders, + + const holderStoreOperations: $ReadOnlyArray = [ + createReplaceHoldersOperation([ ...pendingEstablishmentHolders, ...pendingRemovalHolders, - }, + ]), + ]; + return { + holderStore: processHolderStoreOperations(store, holderStoreOperations), + holderStoreOperations, }; } else if (action.type === processHoldersActionTypes.failed) { const { notAdded, notRemoved } = action.payload; - const notEstablishedHolders = mapResultsToStoreEntries( + const notEstablishedHolders = mapResultsToHolderItems( holderStatuses.NOT_ESTABLISHED, )(notAdded); - const notRemovedHolders = mapResultsToStoreEntries( + const notRemovedHolders = mapResultsToHolderItems( holderStatuses.NOT_REMOVED, )(notRemoved); - return { - ...store, - storedHolders: { - ...store.storedHolders, + + const holderStoreOperations: $ReadOnlyArray = [ + createReplaceHoldersOperation([ ...notEstablishedHolders, ...notRemovedHolders, - }, + ]), + ]; + return { + holderStore: processHolderStoreOperations(store, holderStoreOperations), + holderStoreOperations, }; } else if (action.type === processHoldersActionTypes.success) { const { added, removed, notAdded, notRemoved } = action.payload; const removedBlobHashes = new Set(removed.map(({ blobHash }) => blobHash)); - const filteredStore = _omitBy((_, blobHash) => - removedBlobHashes.has(blobHash), - )(store.storedHolders); - const holdersAdded = mapResultsToStoreEntries(holderStatuses.ESTABLISHED)( + const holdersAdded = mapResultsToHolderItems(holderStatuses.ESTABLISHED)( added, ); - const holdersNotAdded = mapResultsToStoreEntries( + const holdersNotAdded = mapResultsToHolderItems( holderStatuses.NOT_ESTABLISHED, )(notAdded); - const holdersNotRemoved = mapResultsToStoreEntries( + const holdersNotRemoved = mapResultsToHolderItems( holderStatuses.NOT_REMOVED, )(notRemoved); - return { - ...store, - storedHolders: { - ...filteredStore, + const holderStoreOperations: $ReadOnlyArray = [ + { type: 'remove_holders', payload: { hashes: [...removedBlobHashes] } }, + createReplaceHoldersOperation([ ...holdersAdded, ...holdersNotAdded, ...holdersNotRemoved, - }, + ]), + ]; + return { + holderStore: processHolderStoreOperations(store, holderStoreOperations), + holderStoreOperations, }; } - return store; + return { holderStore: store, holderStoreOperations: [] }; } export { reduceHolderStore }; diff --git a/lib/reducers/holder-reducer.test.js b/lib/reducers/holder-reducer.test.js --- a/lib/reducers/holder-reducer.test.js +++ b/lib/reducers/holder-reducer.test.js @@ -25,7 +25,9 @@ payload: { blobHash: 'foo', holder: 'bar' }, }; - expect(reduceHolderStore(store, action).storedHolders).toStrictEqual({ + expect( + reduceHolderStore(store, action).holderStore.storedHolders, + ).toStrictEqual({ foo: { holder: 'bar', status: 'ESTABLISHED' }, }); }); @@ -45,7 +47,9 @@ loadingInfo: mockLoadingInfo, }; - expect(reduceHolderStore(store, action).storedHolders).toStrictEqual({ + expect( + reduceHolderStore(store, action).holderStore.storedHolders, + ).toStrictEqual({ blob1: { holder: 'holder1', status: 'PENDING_REMOVAL' }, blob2: { holder: 'holder2', status: 'PENDING_ESTABLISHMENT' }, }); @@ -71,7 +75,9 @@ loadingInfo: mockLoadingInfo, }; - expect(reduceHolderStore(store, action).storedHolders).toStrictEqual({ + expect( + reduceHolderStore(store, action).holderStore.storedHolders, + ).toStrictEqual({ blob1: { holder: 'holder1', status: 'ESTABLISHED' }, blob2: { holder: 'holder2', status: 'NOT_ESTABLISHED' }, blob3: { holder: 'holder3', status: 'NOT_REMOVED' }, @@ -100,7 +106,9 @@ loadingInfo: mockLoadingInfo, }; - expect(reduceHolderStore(store, action).storedHolders).toStrictEqual({ + expect( + reduceHolderStore(store, action).holderStore.storedHolders, + ).toStrictEqual({ blob1: { holder: 'holder1', status: 'ESTABLISHED' }, blob2: { holder: 'holder2', status: 'ESTABLISHED' }, blob3: { holder: 'holder3', status: 'NOT_ESTABLISHED' }, diff --git a/lib/reducers/master-reducer.js b/lib/reducers/master-reducer.js --- a/lib/reducers/master-reducer.js +++ b/lib/reducers/master-reducer.js @@ -226,6 +226,8 @@ const { store: queuedDMOperations, operations: dmOperationStoreOperations } = reduceDMOperationsQueue(state.queuedDMOperations, action); + const { holderStore } = reduceHolderStore(state.holderStore, action); + let storeOperations = { draftStoreOperations, threadStoreOperations, @@ -289,7 +291,7 @@ action, ), queuedDMOperations, - holderStore: reduceHolderStore(state.holderStore, action), + holderStore, }, storeOperations, };