docs: function createRootReducer (model, name) {
    const handlers = {}
    const initialState = model.state
    // auto-generated reducers
    if (isNotNullObject(initialState)) {
      for (const key of Object.keys(initialState)) {
        handlers[addSetPrefix(name)(key)] = (state, action) => includeKey(action, 'payload') ? { ...state, [key]: action.payload } : state
      }
    }
    // reducer for updating multiple field of the state in one action
    // or replace the state directly
    handlers[addPrefix(name)('merge')] = (state, action) => {
      if (!includeKey(action, 'payload')) {
        return state
      }
      const payload = action.payload
      if (isNotArrayObject(state)) {
        // if (includeNewKeys(state, payload)) {
        //   return pureMerge(state, payload)
        // } else {
        //   return { ...state, ...payload }
        // }
        return pureMerge(state, payload)
      } else {
        return payload
      }
    }
    // user defined reducers
    for (const r of Object.keys(model.reducers || {})) {
      const reducer = model.reducers[r]
      let finalReducer
      if (typeof reducer === 'function') {
        finalReducer = (state, action) => reducer(state, action)
      } else {
        finalReducer = (state) => state
      }
      // notice the reducer override occurs here
      handlers[addPrefix(name)(r)] = finalReducer
    }
    return (state = initialState, action) => (handlers[action.type] ? handlers[action.type](state, action) : state)
  }