Page MenuHomePhabricator

D13408.id44371.diff
No OneTemporary

D13408.id44371.diff

diff --git a/lib/actions/holder-actions.js b/lib/actions/holder-actions.js
--- a/lib/actions/holder-actions.js
+++ b/lib/actions/holder-actions.js
@@ -1,7 +1,23 @@
// @flow
+import type { BlobHashAndHolder } from '../types/holder-types.js';
+type MultipleBlobHolders = $ReadOnlyArray<BlobHashAndHolder>;
+
export const storeEstablishedHolderActionType = 'STORE_ESTABLISHED_HOLDER';
-export type StoreEstablishedHolderPayload = {
- +blobHash: string,
- +holder: string,
+export type StoreEstablishedHolderPayload = BlobHashAndHolder;
+
+export const processHoldersActionTypes = Object.freeze({
+ started: 'PROCESS_HOLDERS_STARTED',
+ success: 'PROCESS_HOLDERS_SUCCESS',
+ failed: 'PROCESS_HOLDERS_FAILED',
+});
+export type ProcessHoldersStartedPayload = {
+ holdersToAdd: MultipleBlobHolders,
+ holdersToRemove: MultipleBlobHolders,
+};
+export type ProcessHoldersFinishedPayload = {
+ added: MultipleBlobHolders,
+ removed: MultipleBlobHolders,
+ notAdded: MultipleBlobHolders,
+ notRemoved: MultipleBlobHolders,
};
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,9 +1,35 @@
// @flow
-import { storeEstablishedHolderActionType } from '../actions/holder-actions.js';
-import { type HolderStore } from '../types/holder-types.js';
+import _mapValues from 'lodash/fp/mapValues.js';
+import _omitBy from 'lodash/fp/omitBy.js';
+
+import {
+ processHoldersActionTypes,
+ storeEstablishedHolderActionType,
+} from '../actions/holder-actions.js';
+import {
+ type HolderInfo,
+ type HolderStatus,
+ type HolderStore,
+ type BlobHashAndHolder,
+} from '../types/holder-types.js';
import type { BaseAction } from '../types/redux-types.js';
+const makeResultToStoreEntryMapper: (
+ status: HolderStatus,
+) => BlobHashAndHolder => [string, HolderInfo] =
+ status =>
+ ({ blobHash, holder }) => [blobHash, { holder, status }];
+
+const mapResultsToStoreEntries: (status: HolderStatus) => (
+ results: $ReadOnlyArray<BlobHashAndHolder>,
+) => {
+ +[blobHash: string]: HolderInfo,
+} = status => {
+ const mapFn = makeResultToStoreEntryMapper(status);
+ return results => Object.fromEntries(results.map(mapFn));
+};
+
function reduceHolderStore(
store: HolderStore,
action: BaseAction,
@@ -17,6 +43,60 @@
[blobHash]: { holder, status: 'ESTABLISHED' },
},
};
+ } else if (action.type === processHoldersActionTypes.started) {
+ // marks processed holders as pending
+ const { holdersToAdd, holdersToRemove } = action.payload;
+ const pendingEstablishmentHolders = mapResultsToStoreEntries(
+ 'PENDING_ESTABLISHMENT',
+ )(holdersToAdd);
+ const pendingRemovalHolders =
+ mapResultsToStoreEntries('PENDING_REMOVAL')(holdersToRemove);
+ return {
+ ...store,
+ storedHolders: {
+ ...store.storedHolders,
+ ...pendingEstablishmentHolders,
+ ...pendingRemovalHolders,
+ },
+ };
+ } else if (action.type === processHoldersActionTypes.failed) {
+ // marks all pending holders as failed
+ const storedHolders = _mapValues((holderInfo: HolderInfo): HolderInfo => ({
+ ...holderInfo,
+ status:
+ holderInfo.status === 'PENDING_ESTABLISHMENT'
+ ? 'NOT_ESTABLISHED'
+ : holderInfo.status === 'PENDING_REMOVAL'
+ ? 'NOT_REMOVED'
+ : holderInfo.status,
+ }))(store.storedHolders);
+ return {
+ ...store,
+ storedHolders,
+ };
+ } 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('ESTABLISHED')(added);
+ const holdersNotAdded =
+ mapResultsToStoreEntries('NOT_ESTABLISHED')(notAdded);
+ const holdersNotRemoved =
+ mapResultsToStoreEntries('NOT_REMOVED')(notRemoved);
+
+ return {
+ ...store,
+ storedHolders: {
+ ...filteredStore,
+ ...holdersAdded,
+ ...holdersNotAdded,
+ ...holdersNotRemoved,
+ },
+ };
}
return store;
}
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
@@ -1,10 +1,19 @@
// @flow
import { reduceHolderStore } from './holder-reducer.js';
-import { storeEstablishedHolderActionType } from '../actions/holder-actions.js';
+import {
+ processHoldersActionTypes,
+ storeEstablishedHolderActionType,
+} from '../actions/holder-actions.js';
import { type HolderStore } from '../types/holder-types.js';
import type { BaseAction } from '../types/redux-types.js';
+const mockLoadingInfo = {
+ fetchIndex: 0,
+ trackMultipleRequests: false,
+ customKeyName: null,
+};
+
describe('reduceHolderStore', () => {
it('STORE_ESTABLISHED_HOLDER', () => {
const store: HolderStore = {
@@ -20,4 +29,78 @@
foo: { holder: 'bar', status: 'ESTABLISHED' },
});
});
+
+ it('PROCESS_HOLDERS_STARTED', () => {
+ const store: HolderStore = {
+ storedHolders: {
+ blob1: { holder: 'holder1', status: 'ESTABLISHED' },
+ },
+ };
+ const action: BaseAction = {
+ type: processHoldersActionTypes.started,
+ payload: {
+ holdersToRemove: [{ blobHash: 'blob1', holder: 'holder1' }],
+ holdersToAdd: [{ blobHash: 'blob2', holder: 'holder2' }],
+ },
+ loadingInfo: mockLoadingInfo,
+ };
+
+ expect(reduceHolderStore(store, action).storedHolders).toStrictEqual({
+ blob1: { holder: 'holder1', status: 'PENDING_REMOVAL' },
+ blob2: { holder: 'holder2', status: 'PENDING_ESTABLISHMENT' },
+ });
+ });
+
+ it('PROCESS_HOLDERS_FAILED', () => {
+ const store: HolderStore = {
+ storedHolders: {
+ blob1: { holder: 'holder1', status: 'ESTABLISHED' },
+ blob2: { holder: 'holder2', status: 'PENDING_ESTABLISHMENT' },
+ blob3: { holder: 'holder3', status: 'PENDING_REMOVAL' },
+ },
+ };
+ const action: BaseAction = {
+ type: processHoldersActionTypes.failed,
+ error: true,
+ payload: new Error('mock error'),
+ loadingInfo: mockLoadingInfo,
+ };
+
+ expect(reduceHolderStore(store, action).storedHolders).toStrictEqual({
+ blob1: { holder: 'holder1', status: 'ESTABLISHED' },
+ blob2: { holder: 'holder2', status: 'NOT_ESTABLISHED' },
+ blob3: { holder: 'holder3', status: 'NOT_REMOVED' },
+ });
+ });
+
+ it('PROCESS_HOLDERS_SUCCESS', () => {
+ const store: HolderStore = {
+ storedHolders: {
+ blob1: { holder: 'holder1', status: 'ESTABLISHED' },
+ blob2: { holder: 'holder2', status: 'PENDING_ESTABLISHMENT' },
+ blob3: { holder: 'holder3', status: 'PENDING_ESTABLISHMENT' },
+ blob4: { holder: 'holder4', status: 'PENDING_REMOVAL' },
+ blob5: { holder: 'holder5', status: 'PENDING_REMOVAL' },
+ },
+ };
+
+ const action: BaseAction = {
+ type: processHoldersActionTypes.success,
+ payload: {
+ added: [{ blobHash: 'blob2', holder: 'holder2' }],
+ notAdded: [{ blobHash: 'blob3', holder: 'holder3' }],
+ removed: [{ blobHash: 'blob4', holder: 'holder4' }],
+ notRemoved: [{ blobHash: 'blob5', holder: 'holder5' }],
+ },
+ loadingInfo: mockLoadingInfo,
+ };
+
+ expect(reduceHolderStore(store, action).storedHolders).toStrictEqual({
+ blob1: { holder: 'holder1', status: 'ESTABLISHED' },
+ blob2: { holder: 'holder2', status: 'ESTABLISHED' },
+ blob3: { holder: 'holder3', status: 'NOT_ESTABLISHED' },
+ // blob4 removed
+ blob5: { holder: 'holder5', status: 'NOT_REMOVED' },
+ });
+ });
});
diff --git a/lib/types/holder-types.js b/lib/types/holder-types.js
--- a/lib/types/holder-types.js
+++ b/lib/types/holder-types.js
@@ -22,3 +22,8 @@
+type: 'establish_holder' | 'remove_holder',
+blobHash: string,
};
+
+export type BlobHashAndHolder = {
+ +blobHash: string,
+ +holder: string,
+};
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -164,7 +164,11 @@
SetDeviceTokenActionPayload,
SetDeviceTokenStartedPayload,
} from '../actions/device-actions.js';
-import type { StoreEstablishedHolderPayload } from '../actions/holder-actions.js';
+import type {
+ ProcessHoldersStartedPayload,
+ ProcessHoldersFinishedPayload,
+ StoreEstablishedHolderPayload,
+} from '../actions/holder-actions.js';
import type {
UpdateConnectionStatusPayload,
SetLateResponsePayload,
@@ -1613,6 +1617,22 @@
| {
+type: 'STORE_ESTABLISHED_HOLDER',
+payload: StoreEstablishedHolderPayload,
+ }
+ | {
+ +type: 'PROCESS_HOLDERS_STARTED',
+ +payload: ProcessHoldersStartedPayload,
+ +loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'PROCESS_HOLDERS_FAILED',
+ +error: true,
+ +payload: Error,
+ +loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'PROCESS_HOLDERS_SUCCESS',
+ +payload: ProcessHoldersFinishedPayload,
+ +loadingInfo: LoadingInfo,
},
}>;

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 25, 7:16 PM (12 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2580770
Default Alt Text
D13408.id44371.diff (9 KB)

Event Timeline