From 4edd1d0fcd311101e2db359992384a231fbe88cb Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Sat, 20 Jul 2019 11:54:38 +0200 Subject: [PATCH] Data: Create registry selector with self-contained registry proxying --- packages/data/src/factory.js | 25 +++++++++++++++-- packages/data/src/namespace-store/index.js | 17 +++--------- packages/data/src/test/registry.js | 32 ++++++++++++++++++++++ 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/packages/data/src/factory.js b/packages/data/src/factory.js index f7dbb7f269a869..e734d41f1a4c6c 100644 --- a/packages/data/src/factory.js +++ b/packages/data/src/factory.js @@ -1,3 +1,8 @@ +/** + * Internal dependencies + */ +import defaultRegistry from './default-registry'; + /** * Mark a selector as a registry selector. * @@ -6,9 +11,25 @@ * @return {function} marked registry selector. */ export function createRegistrySelector( registrySelector ) { - registrySelector.isRegistrySelector = true; + const selector = ( ...args ) => registrySelector( selector.registry.select )( ...args ); + + /** + * Flag indicating to selector registration mapping that the selector should + * be mapped as a registry selector. + * + * @type {boolean} + */ + selector.isRegistrySelector = true; + + /** + * Registry on which to call `select`, stubbed for non-standard usage to + * use the default registry. + * + * @type {WPDataRegistry} + */ + selector.registry = defaultRegistry; - return registrySelector; + return selector; } /** diff --git a/packages/data/src/namespace-store/index.js b/packages/data/src/namespace-store/index.js index 6c8d7d94094eba..16c3d288ce94a1 100644 --- a/packages/data/src/namespace-store/index.js +++ b/packages/data/src/namespace-store/index.js @@ -45,16 +45,12 @@ export default function createNamespace( key, options, registry ) { ...mapValues( metadataSelectors, ( selector ) => ( state, ...args ) => selector( state.metadata, ...args ) ), ...mapValues( options.selectors, ( selector ) => { if ( selector.isRegistrySelector ) { - const mappedSelector = ( reg ) => ( state, ...args ) => { - return selector( reg )( state.root, ...args ); - }; - mappedSelector.isRegistrySelector = selector.isRegistrySelector; - return mappedSelector; + selector.registry = registry; } return ( state, ...args ) => selector( state.root, ...args ); } ), - }, store, registry ); + }, store ); if ( options.resolvers ) { const result = mapResolvers( options.resolvers, selectors, store ); resolvers = result.resolvers; @@ -149,16 +145,11 @@ function createReduxStore( key, options, registry ) { * public facing API. Selectors will get passed the * state as first argument. * @param {Object} store The redux store to which the selectors should be mapped. - * @param {Object} registry Registry reference. * * @return {Object} Selectors mapped to the redux store provided. */ -function mapSelectors( selectors, store, registry ) { - const createStateSelector = ( registeredSelector ) => { - const registrySelector = registeredSelector.isRegistrySelector ? - registeredSelector( registry.select ) : - registeredSelector; - +function mapSelectors( selectors, store ) { + const createStateSelector = ( registrySelector ) => { const selector = function runSelector() { // This function is an optimized implementation of: // diff --git a/packages/data/src/test/registry.js b/packages/data/src/test/registry.js index 57b8789e7095c3..23a6d399ce7786 100644 --- a/packages/data/src/test/registry.js +++ b/packages/data/src/test/registry.js @@ -464,6 +464,38 @@ describe( 'createRegistry', () => { expect( registry.select( 'reducer2' ).selector2() ).toEqual( 'result1' ); } ); + + it( 'should run the registry selector from a non-registry selector', () => { + const selector1 = () => 'result1'; + const selector2 = createRegistrySelector( ( select ) => () => + select( 'reducer1' ).selector1() + ); + const selector3 = () => selector2(); + registry.registerStore( 'reducer1', { + reducer: () => 'state1', + selectors: { + selector1, + }, + } ); + registry.registerStore( 'reducer2', { + reducer: () => 'state1', + selectors: { + selector2, + selector3, + }, + } ); + + expect( registry.select( 'reducer2' ).selector3() ).toEqual( 'result1' ); + } ); + + it( 'gracefully stubs select on selector calls', () => { + const selector = createRegistrySelector( ( select ) => () => select ); + + const maybeSelect = selector(); + + expect( maybeSelect ).toEqual( expect.any( Function ) ); + expect( maybeSelect() ).toEqual( expect.any( Object ) ); + } ); } ); describe( 'subscribe', () => {