Skip to content

Commit

Permalink
add new actions for invalidating resolution caches
Browse files Browse the repository at this point in the history
  • Loading branch information
nerrad committed Mar 6, 2019
1 parent 7e1c1ed commit 429b515
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 3 deletions.
2 changes: 2 additions & 0 deletions packages/data/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
### Enhancements

- The `registerStore` function now accepts an optional `initialState` option value.
- Introduce new `invalidateResolutionForStore` dispatch action for signalling to invalidate the resolution cache for an entire given store.
- Introduce new `invalidateResolutionForStoreSelector` dispatch action for signalling to invalidate the resolution cache for a store selector (and all variations of arguments on that selector).

### Bug Fix

Expand Down
36 changes: 36 additions & 0 deletions packages/data/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,39 @@ export function invalidateResolution( reducerKey, selectorName, args ) {
args,
};
}

/**
* Returns an action object used in signalling that the resolution cache for a
* given reducerKey should be invalidated.
*
* @param {string} reducerKey Registered store reducer key.
*
* @return {Object} Action object.
*/
export function invalidateResolutionForStore( reducerKey ) {
return {
type: 'INVALIDATE_RESOLUTION_FOR_STORE',
reducerKey,
};
}

/**
* Returns an action object used in signalling that the resolution cache for a
* given reducerKey and selectorName should be invalidated.
*
* @param {string} reducerKey Registered store reducer key.
* @param {string} selectorName Name of selector for which all resolvers should
* be invalidated.
*
* @return {Object} Action object.
*/
export function invalidateResolutionForStoreSelector(
reducerKey,
selectorName
) {
return {
type: 'INVALIDATE_RESOLUTION_FOR_STORE_SELECTOR',
reducerKey,
selectorName,
};
}
35 changes: 32 additions & 3 deletions packages/data/src/store/reducer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { flowRight } from 'lodash';
import { flowRight, omit, has } from 'lodash';
import EquivalentKeyMap from 'equivalent-key-map';

/**
Expand Down Expand Up @@ -37,8 +37,37 @@ const isResolved = flowRight( [
return nextState;
}
}

return state;
} );

export default isResolved;
/**
* Reducer function returning next state for selector resolution, object form:
*
* reducerKey -> selectorName -> EquivalentKeyMap<Array, boolean>
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Object} Next state.
*/
const topLevelIsResolved = ( state = {}, action ) => {
switch ( action.type ) {
case 'INVALIDATE_RESOLUTION_FOR_STORE':
return has( state, action.reducerKey ) ?
omit( state, action.reducerKey ) :
state;
case 'INVALIDATE_RESOLUTION_FOR_STORE_SELECTOR':
return has( state, [ action.reducerKey, action.selectorName ] ) ?
{
...state,
[ action.reducerKey ]: omit(
state[ action.reducerKey ],
action.selectorName
),
} :
state;
}
return isResolved( state, action );
};

export default topLevelIsResolved;
49 changes: 49 additions & 0 deletions packages/data/src/store/test/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,53 @@ describe( 'reducer', () => {
expect( state.test.getFoo.get( [ 'post' ] ) ).toBe( false );
expect( state.test.getFoo.get( [ 'block' ] ) ).toBe( true );
} );

it( 'should remove invalidation for store level and leave others ' +
'intact', () => {
const original = reducer( undefined, {
type: 'FINISH_RESOLUTION',
reducerKey: 'testA',
selectorName: 'getFoo',
args: [ 'post' ],
} );
let state = reducer( deepFreeze( original ), {
type: 'FINISH_RESOLUTION',
reducerKey: 'testB',
selectorName: 'getBar',
args: [ 'postBar' ],
} );
state = reducer( deepFreeze( state ), {
type: 'INVALIDATE_RESOLUTION_FOR_STORE',
reducerKey: 'testA',
} );

expect( state.testA ).toBeUndefined();
// { testB: { getBar: EquivalentKeyMap( [] => false ) } }
expect( state.testB.getBar.get( [ 'postBar' ] ) ).toBe( false );
} );

it( 'should remove invalidation for store and selector name level and ' +
'leave other selectors at store level intact', () => {
const original = reducer( undefined, {
type: 'FINISH_RESOLUTION',
reducerKey: 'test',
selectorName: 'getFoo',
args: [ 'post' ],
} );
let state = reducer( deepFreeze( original ), {
type: 'FINISH_RESOLUTION',
reducerKey: 'test',
selectorName: 'getBar',
args: [ 'postBar' ],
} );
state = reducer( deepFreeze( state ), {
type: 'INVALIDATE_RESOLUTION_FOR_STORE_SELECTOR',
reducerKey: 'test',
selectorName: 'getBar',
} );

expect( state.test.getBar ).toBeUndefined();
// { test: { getFoo: EquivalentKeyMap( [] => false ) } }
expect( state.test.getFoo.get( [ 'post' ] ) ).toBe( false );
} );
} );

0 comments on commit 429b515

Please sign in to comment.