diff --git a/public/app/core/redux/reducerFactory.ts b/public/app/core/redux/reducerFactory.ts index c70d91e5e5f..50eb6ccd4c6 100644 --- a/public/app/core/redux/reducerFactory.ts +++ b/public/app/core/redux/reducerFactory.ts @@ -1,4 +1,4 @@ -import { ActionOf, ActionCreator } from './actionCreatorFactory'; +import { ActionOf, ActionCreator, actionCreatorFactory } from './actionCreatorFactory'; import { Reducer } from 'redux'; export type Mapper = (state: State, action: ActionOf) => State; @@ -43,3 +43,95 @@ export const reducerFactory = (initialState: State): AddMapper => return instance; }; + +/** Another type of fluent reducerFactory */ + +export interface FilterWith { + filterWith: (actionCreator: ActionCreator) => MapTo; +} + +export interface OrFilterWith { + orFilterWith: (actionCreator: ActionCreator) => MapTo; +} + +export interface MapTo { + mapTo: (mapper: Mapper) => CreateReducerEx; +} + +export interface CreateReducerEx extends OrFilterWith { + create: () => Reducer>; +} + +export const reducerFactoryEx = (initialState: State): FilterWith => { + const allMapperConfigs: Array> = []; + + const innerMapTo = (actionCreator: ActionCreator, mapper: Mapper): CreateReducerEx => { + allMapperConfigs.filter(config => config.filter.type === actionCreator.type)[0].mapper = mapper; + + return instance; + }; + + const filterWith = (actionCreator: ActionCreator): MapTo => { + if (allMapperConfigs.some(c => c.filter.type === actionCreator.type)) { + throw new Error(`There is already a mapper defined with the type ${actionCreator.type}`); + } + + allMapperConfigs.push({ filter: actionCreator, mapper: null }); + + const mapTo = (mapper: Mapper): CreateReducerEx => { + innerMapTo(actionCreator, mapper); + + return instance; + }; + + return { mapTo }; + }; + + const orFilterWith = (actionCreator: ActionCreator): MapTo => { + if (allMapperConfigs.some(c => c.filter.type === actionCreator.type)) { + throw new Error(`There is already a mapper defined with the type ${actionCreator.type}`); + } + + allMapperConfigs.push({ filter: actionCreator, mapper: null }); + + const mapTo = (mapper: Mapper): CreateReducerEx => { + innerMapTo(actionCreator, mapper); + + return instance; + }; + + return { mapTo }; + }; + + const create = (): Reducer> => (state: State = initialState, action: ActionOf): State => { + const mapperConfig = allMapperConfigs.filter(config => config.filter.type === action.type)[0]; + + if (mapperConfig) { + return mapperConfig.mapper(state, action); + } + + return state; + }; + + const instance = { filterWith, orFilterWith, create }; + + return instance; +}; + +interface TestState { + data: string[]; +} + +const initialState: TestState = { + data: [], +}; + +const dummyActionCreator = actionCreatorFactory('dummyActionCreator').create(); +const dummyActionCreator2 = actionCreatorFactory('dummyActionCreator2').create(); + +export const reducerFactoryExReducer = reducerFactoryEx(initialState) + .filterWith(dummyActionCreator) + .mapTo((state, action) => ({ ...state, data: state.data.concat(action.payload) })) + .orFilterWith(dummyActionCreator2) + .mapTo((state, action) => ({ ...state, data: state.data.concat(`${action.payload}`) })) + .create();