redux-tiles
Version:
Library to create and easily compose redux pieces together in less verbose manner
122 lines (105 loc) • 3.42 kB
text/typescript
import { createType, ensureArray } from "../helpers";
import { get, isString } from "../utils";
import { ICreateSelectorsTypes, IData, ISelectors, SyncData } from "./types";
export let DEFAULT_REDUCER: string = "";
export function changeDefaultReducer(newReducer: string): void {
DEFAULT_REDUCER = newReducer;
}
export function getTopReducer(): string {
return DEFAULT_REDUCER;
}
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 })
};
}