Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reset state actions to our stores. #998

Merged
merged 12 commits into from
Mar 12, 2019
2 changes: 1 addition & 1 deletion assets/dist/build-manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"components.css": "ee-components.997177945b17ee98a639.dist.css",
"components.js": "ee-components.cf0aaacfef0cb46b08ec.dist.js",
"data-stores.js": "ee-data-stores.fc604083647264add736.dist.js",
"data-stores.js": "ee-data-stores.b9c742685b104fe37411.dist.js",
"editor-hocs.js": "ee-editor-hocs.15a813aac7a51b5473cb.dist.js",
"eejs.js": "ee-eejs.4bd48b02f85a875e3121.dist.js",
"eventespresso-core-blocks-frontend.css": "ee-eventespresso-core-blocks-frontend.f0ea9ad96d720bc8dc9b.dist.css",
Expand Down

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion assets/src/data/eventespresso/core/actions/action-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ const relations = {
RECEIVE_UPDATED_ENTITY_ID_FOR_RELATIONS:
'RECEIVE_UPDATED_ENTITY_ID_FOR_RELATIONS',
};
const resets = {
RESET_ALL_STATE: 'RESET_ALL_STATE',
RESET_STATE_FOR_MODEL: 'RESET_STATE_FOR_MODEL',
RESET_ALL_MODEL_SPECIFIC: 'RESET_ALL_MODEL_SPECIFIC_STATE',
RESET_MODEL_SPECIFIC_FOR_SELECTOR: 'RESET_MODEL_SPECIFIC_FOR_SELECTOR',
};

const modelSpecific = {
RECEIVE_SELECTOR_VALUE: 'RECEIVE_SELECTOR_VALUE',
};

export const ACTION_TYPES = { entities, relations, modelSpecific };
export const ACTION_TYPES = { entities, relations, modelSpecific, resets };
238 changes: 238 additions & 0 deletions assets/src/data/eventespresso/core/actions/reset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
/**
* External imports
*/
import {
singularModelName,
pluralModelName,
} from '@eventespresso/model';
import { some, keys } from 'lodash';
import { isModelEntityOfModel } from '@eventespresso/validators';
import { select as dataSelect } from '@wordpress/data';

/**
* Internal imports
*/
import { dispatch, select } from '../../base-controls';
import { ACTION_TYPES } from './action-types';
import { REDUCER_KEY } from '../constants';
import * as modelSpecificSelectors from '../model/model-selectors-index';

const { resets: types } = ACTION_TYPES;

/**
* Resets the entire state to its default for the store.
*/
export function* resetAllState() {
// action for resetting the entire state.
yield {
type: types.RESET_ALL_STATE,
};

// get resolvers from core/data and dispatch invalidation of each resolver.
const resolvers = yield select(
'core/data',
'getCachedResolvers',
REDUCER_KEY
);

if ( invalidateActionsAvailable() ) {
yield dispatch(
'core/data',
'invalidateResolutionForStore',
REDUCER_KEY,
);
return;
}

// dispatch invalidation of the cached resolvers
for ( const selector in resolvers ) {
for ( const entry of resolvers[ selector ]._map ) {
yield dispatch(
'core/data',
'invalidateResolution',
REDUCER_KEY,
selector,
entry[ 0 ]
);
}
}
}

/**
* Resets all state related to the given modelName
*
* Note: This does not reset any state in the modelSpecific tree as there is no
* way to know what applies to the current model.
*
* @param {string} modelName
*/
export function* resetStateForModel( modelName ) {
yield {
type: types.RESET_STATE_FOR_MODEL,
modelName,
};

// get resolvers from core/data
const resolvers = yield select(
'core/data',
'getCachedResolvers',
REDUCER_KEY
);

// dispatch invalidation of the cached resolvers for any resolver that
// has a variation of modelName in the selector name or in the args for the
// cached resolver.
for ( const selector in resolvers ) {
for ( const entry of resolvers[ selector ]._map ) {
if (
(
modelNameInSelector( selector, modelName ) ||
modelNameInArgs( entry[ 0 ], modelName )
) &&
! selectorIsModelSpecific( selector )
) {
yield dispatch(
'core/data',
'invalidateResolution',
REDUCER_KEY,
selector,
entry[ 0 ],
);
}
}
}
}

/**
* Helper for determining whether the given modelName is found in the given
* selectorName.
*
* @param {string} selectorName
* @param {string} modelName
*
* @return {boolean} True means it is present, false means it isn't
*/
const modelNameInSelector = ( selectorName, modelName ) => {
const singularName = singularModelName( modelName );
const pluralName = pluralModelName( modelName );
selectorName = selectorName.toLowerCase();
return selectorName.indexOf( singularName ) > -1 ||
selectorName.indexOf( pluralName ) > -1;
};

/**
* Helper for determining whether the given modelName is found in the given
* set of args.
*
* This also considers if any of the args are an instance of BaseEntity and
* if that BaseEntity instance is for the given model.
*
* @param {Array} args
* @param {string} modelName
*
* @return {boolean} True means it is present, false means it isn't.
*/
const modelNameInArgs = ( args, modelName ) => {
const singularName = singularModelName( modelName );
const pluralName = pluralModelName( modelName );
const hasModelName = args.indexOf( singularName ) > -1 ||
args.indexOf( pluralName ) > -1;
if ( hasModelName ) {
return true;
}

// it's possible one of the args is an instance of BaseEntity. If so,
// then let's compare against the modelName on the entity instance.
return some(
args,
( arg ) => {
return isModelEntityOfModel( arg, singularName ) ||
isModelEntityOfModel( arg, pluralName );
}
);
};

/**
* For the given selector name and (optional) selectorsToInvalidate, this
* returns whether the selectorName is a match for the selectors to invalidate.
*
* @param {string} selectorName
* @param {Array|null?} selectorsToInvalidate If null, then the match array will
* be obtained from the registered modelSpecificSelectors imported for the
* module
*
* @return {boolean} True means there is a match, false means there is not.
*/
const selectorIsModelSpecific = (
selectorName,
selectorsToInvalidate = null
) => {
selectorsToInvalidate = selectorsToInvalidate === null ?
keys( modelSpecificSelectors ) :
selectorsToInvalidate;
return selectorsToInvalidate.indexOf( selectorName ) > -1;
};

/**
* Resets all model specific state.
*/
export function* resetAllModelSpecific() {
yield {
type: types.RESET_ALL_MODEL_SPECIFIC,
};

// get resolvers
const resolvers = yield select(
'core/data',
'getCachedResolvers',
REDUCER_KEY
);

const selectorsToInvalidate = keys( modelSpecificSelectors );

// dispatch invalidation of the cached resolvers for model specific selector
for ( const selector in resolvers ) {
for ( const entry of resolvers[ selector ]._map ) {
if ( selectorIsModelSpecific( selector, selectorsToInvalidate ) ) {
yield dispatch(
'core/data',
'invalidateResolution',
REDUCER_KEY,
selector,
entry[ 0 ],
);
}
}
}
}

/**
* Resets all state for a given model specific selector and its args
*
* @param {string} selectorName
* @param {Array} args
*/
export function* resetModelSpecificForSelector( selectorName, ...args ) {
yield {
type: types.RESET_MODEL_SPECIFIC_FOR_SELECTOR,
selectorName,
args,
};

yield dispatch(
'core/data',
'invalidateResolution',
REDUCER_KEY,
selectorName,
args,
);
}

/**
* Helper for determining if actions are available in the `core/data` package.
*
* @return {boolean} True means additional invalidation actions available.
*/
const invalidateActionsAvailable = () => {
return dataSelect( 'core/data' ).invalidateResolutionForStore !== undefined;
};
Loading