Skip to content

Commit

Permalink
@wordpress/data: Expose hasResolver property on returned selectors (#…
Browse files Browse the repository at this point in the history
…15436)

* expose `hasResolver` property on returned selectors

* account for custom stores that may not have resolvers defined in the store config
  • Loading branch information
nerrad authored May 16, 2019
1 parent b6dcb20 commit 1f52970
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
4 changes: 4 additions & 0 deletions packages/data/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

- Restore functionality of action-generators returning a Promise. Clarify intent and behaviour for `wp.data.dispatch` behaviour. Dispatch actions now always
return a promise ([#14830](https://github.com/WordPress/gutenberg/pull/14830)

### Enhancements

- Expose `hasResolver` property on returned selectors indicating whether the selector has a corresponding resolver.

## 4.3.0 (2019-03-06)

Expand Down
15 changes: 11 additions & 4 deletions packages/data/src/namespace-store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,11 @@ function createReduxStore( key, options, registry ) {
*/
function mapSelectors( selectors, store, registry ) {
const createStateSelector = ( registeredSelector ) => {
const selector = registeredSelector.isRegistrySelector ? registeredSelector( registry.select ) : registeredSelector;
const registrySelector = registeredSelector.isRegistrySelector ?
registeredSelector( registry.select ) :
registeredSelector;

return function runSelector() {
const selector = function runSelector() {
// This function is an optimized implementation of:
//
// selector( store.getState(), ...arguments )
Expand All @@ -172,8 +174,10 @@ function mapSelectors( selectors, store, registry ) {
args[ i + 1 ] = arguments[ i ];
}

return selector( ...args );
return registrySelector( ...args );
};
selector.hasResolver = false;
return selector;
};

return mapValues( selectors, createStateSelector );
Expand Down Expand Up @@ -213,10 +217,11 @@ function mapResolvers( resolvers, selectors, store ) {
const mapSelector = ( selector, selectorName ) => {
const resolver = resolvers[ selectorName ];
if ( ! resolver ) {
selector.hasResolver = false;
return selector;
}

return ( ...args ) => {
const selectorResolver = ( ...args ) => {
async function fulfillSelector() {
const state = store.getState();
if ( typeof resolver.isFulfilled === 'function' && resolver.isFulfilled( state, ...args ) ) {
Expand All @@ -236,6 +241,8 @@ function mapResolvers( resolvers, selectors, store ) {
fulfillSelector( ...args );
return selector( ...args );
};
selectorResolver.hasResolver = true;
return selectorResolver;
};

return {
Expand Down
27 changes: 27 additions & 0 deletions packages/data/src/namespace-store/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,33 @@ describe( 'controls', () => {

registry.select( 'store' ).getItems();
} );
describe( 'selectors have expected value for the `hasResolver` property', () => {
it( 'when custom store has resolvers defined', () => {
registry.registerStore( 'store', {
reducer: jest.fn(),
selectors: {
getItems: ( state ) => state,
getItem: ( state ) => state,
},
resolvers: {
* getItems() {
yield 'foo';
},
},
} );
expect( registry.select( 'store' ).getItems.hasResolver ).toBe( true );
expect( registry.select( 'store' ).getItem.hasResolver ).toBe( false );
} );
it( 'when custom store does not have resolvers defined', () => {
registry.registerStore( 'store', {
reducer: jest.fn(),
selectors: {
getItems: ( state ) => state,
},
} );
expect( registry.select( 'store' ).getItems.hasResolver ).toBe( false );
} );
} );
describe( 'various action types have expected response and resolve as ' +
'expected with controls middleware', () => {
const actions = {
Expand Down

0 comments on commit 1f52970

Please sign in to comment.