Skip to content
This repository has been archived by the owner on Feb 8, 2024. It is now read-only.

Commit

Permalink
feat: add createSymbioteFetcher, handleFnFetching. deprecate handleFe…
Browse files Browse the repository at this point in the history
…tchingF
  • Loading branch information
sergeysova committed Jun 21, 2018
1 parent d240ee4 commit 49db390
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 115 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Expand Up @@ -51,5 +51,8 @@
"eslint-plugin-import": "^2.10.0",
"nyc": "^11.6.0",
"redux-symbiote": "^2.0.3"
},
"dependencies": {
"deprecated": "0.0.2"
}
}
130 changes: 130 additions & 0 deletions src/advanced.js
@@ -0,0 +1,130 @@
const deprecate = require('deprecated')
const { fetchStatus } = require('./status')


/**
* @typedef {Object} Action
* @prop {string} type
*/


function createSymbioteFetcher({ propStatus = 'status', propError = 'error' } = {}) {
/**
* @example
* const initialState = {
* status: initialFetching,
* }
*/
const initialFetching = {
[propStatus]: fetchStatus.initial,
[propError]: null,
}

/**
* @param {string} stateProperty
* @return {{ start: Function, finish: Function, fail: Function }}
* @example
* createSymbiote(initialState, {
* fetching: createFetching('status'),
* })
*/
const createFetching = (stateProperty) => ({
start: (state) => ({
...state,
[stateProperty]: { [propStatus]: fetchStatus.loading, [propError]: null },
}),
finish: (state) => ({
...state,
[stateProperty]: { [propStatus]: fetchStatus.ready, [propError]: null },
}),
fail: (state, error) => ({
...state,
[stateProperty]: { [propStatus]: fetchStatus.failed, [propError]: error },
}),
})

/**
* @param {{ start: () => Action, finish: () => Action, fail: (error: Error) => Action }} actions
* @param {{ before?: Function, run: Function, fail?: Function, noThrow: boolean }} fetcherObject
* @example
* export const fetchData = (id) => handleFetching(actions.fetching, {
* noThrow: true,
* prepareError: (error) => error.message,
* async before(dispatch) {
* return await dispatch(someEffect())
* },
* async run(dispatch, getState, { api }) {
* const result = await api.get(`/data/${id}`)
*s
* dispatch(actions.setData(result.data))
* },
* })
*/
const handleFetching = (actions, fetcherObject) => (
async (dispatch, getState, extra) => {
let beforeResult

dispatch(actions.start())

if (fetcherObject.before) {
beforeResult = await fetcherObject.before(dispatch, getState, extra)
}

try {
const result = await fetcherObject.run(dispatch, getState, extra, beforeResult)

dispatch(actions.finish())
return result
}
catch (error) {
if (fetcherObject.fail) {
fetcherObject.fail(error, dispatch, getState, extra, beforeResult)
}

dispatch(actions.fail(fetcherObject.prepareError
? fetcherObject.prepareError(error)
: error))

if (fetcherObject.noThrow) {
return undefined
}

throw error
}
}
)

const handleFnFetching = (actions, runFn) => (
async (dispatch, getState, extra) => {
try {
dispatch(actions.start())
const result = await runFn(dispatch, getState, extra)

dispatch(actions.finish())
return result
}
catch (error) {
dispatch(actions.fail(error))
return undefined
}
}
)

const handleFetchingF = deprecate.method(
'handleFetchingF is deprecated. Use handleFnFetching',
console.log, // eslint-disable-line no-console
handleFnFetching
)

return {
initialFetching,
createFetching,
handleFetching,
handleFetchingF,
handleFnFetching,
}
}

module.exports = {
createSymbioteFetcher,
}
123 changes: 8 additions & 115 deletions src/index.js
@@ -1,124 +1,17 @@
const { fetchStatus } = require('./status')
const { createSymbioteFetcher } = require('./advanced')

const fetchStatus = {
failed: -1,
initial: 0,
loading: 1,
ready: 2,
}

const propStatus = 'status'
const propError = 'error'

/**
* @example
* const initialState = {
* status: initialFetching,
* }
*/
const initialFetching = {
[propStatus]: fetchStatus.initial,
[propError]: null,
}

/**
* @param {string} stateProperty
* @return {{ start: Function, finish: Function, fail: Function }}
* @example
* createSymbiote(initialState, {
* fetching: createFetching('status'),
* })
*/
const createFetching = (stateProperty) => ({
start: (state) => ({
...state,
[stateProperty]: { [propStatus]: fetchStatus.loading, [propError]: null },
}),
finish: (state) => ({
...state,
[stateProperty]: { [propStatus]: fetchStatus.ready, [propError]: null },
}),
fail: (state, error) => ({
...state,
[stateProperty]: { [propStatus]: fetchStatus.failed, [propError]: error },
}),
})

/**
* @typedef {Object} Action
* @prop {string} type
*/

/**
* @param {{ start: () => Action, finish: () => Action, fail: (error: Error) => Action }} actions
* @param {{ before?: Function, run: Function, fail?: Function, noThrow: boolean }} fetcherObject
* @example
* export const fetchData = (id) => handleFetching(actions.fetching, {
* noThrow: true,
* prepareError: (error) => error.message,
* async before(dispatch) {
* return await dispatch(someEffect())
* },
* async run(dispatch, getState, { api }) {
* const result = await api.get(`/data/${id}`)
*s
* dispatch(actions.setData(result.data))
* },
* })
*/
const handleFetching = (actions, fetcherObject) => (
async (dispatch, getState, extra) => {
let beforeResult

dispatch(actions.start())

if (fetcherObject.before) {
beforeResult = await fetcherObject.before(dispatch, getState, extra)
}

try {
const result = await fetcherObject.run(dispatch, getState, extra, beforeResult)

dispatch(actions.finish())
return result
}
catch (error) {
if (fetcherObject.fail) {
fetcherObject.fail(error, dispatch, getState, extra, beforeResult)
}

dispatch(actions.fail(fetcherObject.prepareError
? fetcherObject.prepareError(error)
: error))

if (fetcherObject.noThrow) {
return undefined
}

throw error
}
}
)

const handleFetchingF = (actions, runFn) => (
async (dispatch, getState, extra) => {
try {
dispatch(actions.start())
const result = await runFn(dispatch, getState, extra)

dispatch(actions.finish())
return result
}
catch (error) {
dispatch(actions.fail(error))
return undefined
}
}
)
// TODO: remove deprecated handleFetchingF
const {
initialFetching, createFetching, handleFetching, handleFetchingF, handleFnFetching,
} = createSymbioteFetcher()

module.exports = {
fetchStatus,
createSymbioteFetcher,
initialFetching,
createFetching,
handleFetching,
handleFetchingF,
handleFnFetching,
}
11 changes: 11 additions & 0 deletions src/status.js
@@ -0,0 +1,11 @@

const fetchStatus = {
failed: -1,
initial: 0,
loading: 1,
ready: 2,
}

module.exports = {
fetchStatus,
}

0 comments on commit 49db390

Please sign in to comment.