redux-tiles
Version:
Library to create and easily compose redux pieces together in less verbose manner
97 lines (81 loc) • 3.27 kB
text/typescript
import { get, isString } from 'lodash';
import { createType, ensureArray } from '../helpers';
import { ICreateSelectorsTypes, IData, ISelectors, SyncData } from './types';
export let DEFAULT_REDUCER: string = '';
export function changeDefaultReducer(newReducer: string): void {
DEFAULT_REDUCER = newReducer;
}
function checkValue(result: any, defaultValue?: any): {} {
return result === undefined || result === null ? defaultValue : result;
}
interface ILookupParams {
selectorFallback: any;
state: Object;
params: any;
nesting: ((params: any) => string[])|undefined;
tileName: string|string[];
}
/**
* @overview Deep lookup inside state
* @param {Object} state – current redux state object
* @param {Any} params – argument with which action was dispatched
* @param {Function} nesting – function to create nested data inside store
* @param {String} tileName – string to access module data
* @return {Object} – stored data
*/
function lookup({ state, params, nesting, tileName, selectorFallback }: ILookupParams): IData|SyncData {
let path: string[] = [];
const topReducer: string = DEFAULT_REDUCER;
if (nesting) {
path = nesting(params);
}
const nestedNames: string[] = ensureArray(tileName);
const topReducerArray: string[] = Boolean(topReducer) ? [topReducer] : [];
return checkValue(get(state, [...topReducerArray, ...nestedNames, ...path]), selectorFallback);
}
interface ICheckArgumentsParams {
state: {};
params: any;
tileName: string|string[];
fn: Function;
}
/**
* @overview check passed arguments to the Selector function.
* The single purpose is for readability, to throw sane error
* @param {Object} state – redux state
* @param {Any} params – argument with which action was dispatched
* @param {String} tileName – string to access module data
* @param {Function} fn – function to invoke if check was passed
* @return {Any} – result of function invokation
*/
function checkArguments({ state, params, tileName, fn }: ICheckArgumentsParams): {} {
if (!state) {
throw new Error(`
Error in Redux-Tiles Selector – you have to provide
state as a first argument!. Error in "${createType({ type: tileName })}" tile.`
);
}
return fn(state, params);
}
/**
* @overview function to create selectors for modules
* @param {String} tileName – string to access module data
* @param {Function} nesting – function to create nested data inside store
* @return {Object} – object with selectors for all and specific data
*/
export function createSelectors(
{ tileName, nesting, selectorFallback }: ICreateSelectorsTypes
): ISelectors {
const getAll: Function = (state: any): any => {
const topReducerArray: string[] = Boolean(DEFAULT_REDUCER) ? [DEFAULT_REDUCER] : [];
return checkValue(get(state, [...topReducerArray, ...ensureArray(tileName)]));
};
const getSpecific: Function = (state: {}, params: any): IData|SyncData =>
lookup({ state, params, nesting, tileName, selectorFallback });
return {
getAll: (state: any): {} =>
checkArguments({ state, tileName, fn: getAll } as any),
get: (state: any, params?: any): IData|SyncData =>
checkArguments({ state, params, tileName, fn: getSpecific })
};
}