Skip to content

Commit

Permalink
Merge pull request #49 from blueflag/feature/multi-hocks
Browse files Browse the repository at this point in the history
Create MultiHock factories
  • Loading branch information
allanhortle committed Dec 14, 2017
2 parents af3f441 + 97d5064 commit 877c5fb
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 7 deletions.
24 changes: 19 additions & 5 deletions src/EntityApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import EntityStoreFactory from './EntityStoreFactory';
import {fromJS, Map} from 'immutable';

import type {SelectOptions} from './definitions';
import type {SideEffect} from './definitions';

/**
The Entity Api is the main access point for your data. It allows you to define the link between your views
Expand Down Expand Up @@ -39,7 +40,7 @@ function reduceActionMap(branch: Map<string, any>, parentKey: string = ''): Map<
// @param {function} sideEffect Promise returning side effect to call after fetch action.
// @return {array} list of action creators and action types
// @memberof module:Api
function createRequestAction(fetchAction: string, recieveAction: string, errorAction: string, sideEffect: Function): Function {
export function createRequestAction(fetchAction: string, recieveAction: string, errorAction: string, sideEffect: SideEffect): Function {
function action(aa: string): Function {
return createAction(aa, (payload) => payload, (payload, meta) => meta);
}
Expand Down Expand Up @@ -67,6 +68,18 @@ function createRequestAction(fetchAction: string, recieveAction: string, errorAc
};
}

export function createAllRequestAction(fetchAction: string, recieveAction: string, errorAction: string, sideEffectList: Array<SideEffect>): Function {
function sideEffect(requestPayload: *, meta: Object): Promise<*> {
return Promise
// call all sideeffects
.all(sideEffectList.map(effect => effect(requestPayload, meta)))
// merge them back to one object
.then(payloads => payloads.reduce((out, payload) => Object.assign(out, payload), {}))
;
}
return createRequestAction(fetchAction, recieveAction, errorAction, sideEffect);
}


/**
* Constructs an Entity Api based off a schema and an object of promise returning functions.
Expand Down Expand Up @@ -109,7 +122,7 @@ function createRequestAction(fetchAction: string, recieveAction: string, errorAc
*/
export default function EntityApi(schema: Object, actionMap: Object, selectOptions: SelectOptions = {}): Object {
return reduceActionMap(fromJS(actionMap))
.reduce((state: Map<string, any>, sideEffect: Function, action: string): Map<string, any> => {
.reduce((state: Map<string, any>, sideEffect: SideEffect, action: string): Map<string, any> => {

const snakeAction = action.toUpperCase();

Expand Down Expand Up @@ -143,18 +156,19 @@ export default function EntityApi(schema: Object, actionMap: Object, selectOptio
// ACTION_RECIEVE: schema
// ...
// }
const actionMap = api
const schemaMap = api
.get('actionTypes')
.filter((action, key) => /_RECEIVE$/g.test(key))
.reduce((actionMap, key) => actionMap.set(key, schema), Map())
.reduce((schemaMap, key) => schemaMap.set(key, schema), Map())
.set(selectOptions.schemaKey || 'ENTITY_RECEIVE', schema)
.toObject()
;

const reducer = EntityReducerFactory({schemaMap: actionMap});
const reducer = EntityReducerFactory({schemaMap});

return api
.set('EntityReducer', reducer)
.set('sideEffects', actionMap)
.set('EntityStore', EntityStoreFactory(reducer));
})
.toJS();
Expand Down
2 changes: 1 addition & 1 deletion src/EntityMutationHockFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import type {SelectOptions} from './definitions';
* @returns {MutationHock}
* @memberof module:Factories
*/
export default function EntityMutationHockFactory(actionCreator: Function, selectOptions: SelectOptions): Function {
export default function EntityMutationHockFactory(actionCreator: Function, selectOptions?: SelectOptions): Function {

/**
* Mutation is used to request or change data in response to user interaction.
Expand Down
20 changes: 20 additions & 0 deletions src/MultiMutationHockFactory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//@flow
import EntityMutationHockFactory from './EntityMutationHockFactory';
import {createAllRequestAction} from './EntityApi';
import type {SelectOptions} from './definitions';
import type {SideEffect} from './definitions';

/**
*
* @param {function} sideEffect
* @returns {EntityMutationHock}
* @memberof module:Factories
*/
export default function MultiMutationHockFactory(sideEffectList: Array<SideEffect>, selectOptions?: SelectOptions): Function {
const actionPrefix = 'ENTITY';
const FETCH = `${actionPrefix}_FETCH`;
const RECEIVE = `${actionPrefix}_RECEIVE`;
const ERROR = `${actionPrefix}_ERROR`;

return EntityMutationHockFactory(createAllRequestAction(FETCH, RECEIVE, ERROR, sideEffectList), selectOptions);
}
21 changes: 21 additions & 0 deletions src/MultiQueryHockFactory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//@flow
import EntityQueryHockFactory from './EntityQueryHockFactory';
import {createAllRequestAction} from './EntityApi';
import type {SelectOptions} from './definitions';
import type {SideEffect} from './definitions';


/**
*
* @param {function} sideEffect
* @returns {EntityQueryHock}
* @memberof module:Factories
*/
export default function MultiQueryHockFactory(sideEffectList: Array<SideEffect>, selectOptions?: SelectOptions): Function {
const actionPrefix = 'ENTITY';
const FETCH = `${actionPrefix}_FETCH`;
const RECEIVE = `${actionPrefix}_RECEIVE`;
const ERROR = `${actionPrefix}_ERROR`;

return EntityQueryHockFactory(createAllRequestAction(FETCH, RECEIVE, ERROR, sideEffectList), selectOptions);
}
26 changes: 26 additions & 0 deletions src/__tests__/EntityApi-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import test from 'ava';
import sinon from 'sinon';
import EntityApi from '../EntityApi';
import {createAllRequestAction} from '../EntityApi';

const RESOLVE = (aa) => Promise.resolve(aa);
const REJECT = (aa) => Promise.reject(aa);
Expand Down Expand Up @@ -54,3 +55,28 @@ test('ERROR action resultKey defaults to ERROR action name', (t: Object): Promis
t.is('REJECT_ERROR', dispatch.secondCall.args[0].type);
});
});



// Create Multi ActionCreator

test('createAllRequestAction will call all sideffects', (t: Object): Promise<any> => {
var aa = sinon.spy();
var bb = sinon.spy();

return createAllRequestAction('a', 'a', 'a', [aa,bb])()(sinon.spy())
.then(() => {
t.is(aa.callCount, 1);
t.is(bb.callCount, 1);
})
});

test('createAllRequestAction will merge resulting objects', (t: Object): Promise<any> => {
var aa = async () => ({aa: 'aa'});
var bb = async () => ({bb: 'bb'});

return createAllRequestAction('a', 'a', 'a', [aa,bb])()(dd => dd)
.then((data) => {
t.deepEqual(data.payload, {aa: 'aa', bb: 'bb'});
})
});
15 changes: 15 additions & 0 deletions src/__tests__/MultiMutationHockFactory-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//@flow
import test from 'ava';
import sinon from 'sinon';
import MultiMutationHockFactory from '../MultiMutationHockFactory';

const RESOLVE = (aa) => Promise.resolve(aa);
const REJECT = (aa) => Promise.reject(aa);


test('MultiMutationHockFactory will return a MutationHock', (t: Object) => {
var aa = async () => ({aa: 'aa'});
var bb = async () => ({bb: 'bb'});

t.is(MultiMutationHockFactory([aa,bb]).name, 'EntityMutationHock');
});
15 changes: 15 additions & 0 deletions src/__tests__/MultiQueryHockFactory-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//@flow
import test from 'ava';
import sinon from 'sinon';
import MultiQueryHockFactory from '../MultiQueryHockFactory';

const RESOLVE = (aa) => Promise.resolve(aa);
const REJECT = (aa) => Promise.reject(aa);


test('MultiQueryHockFactory will return a QueryHock', (t: Object) => {
var aa = async () => ({aa: 'aa'});
var bb = async () => ({bb: 'bb'});

t.is(MultiQueryHockFactory([aa,bb]).name, 'EntityQueryHock');
});
2 changes: 2 additions & 0 deletions src/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ export type SelectOptions = {
schemaKey?: string,
stateKey?: string
};

export type SideEffect = (*, Object) => Promise<*>;
4 changes: 3 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ export {
} from './RequestStateSelector';

// Misc
export {default as EntityQueryHockFactory} from './EntityQueryHockFactory';
export {default as EntityMutationHockFactory} from './EntityMutationHockFactory';
export {default as EntityQueryHockFactory} from './EntityQueryHockFactory';
export {default as EntityReducerFactory} from './EntityReducerFactory';
export {default as MultiMutationHockFactory} from './MultiMutationHockFactory';
export {default as MultiQueryHockFactory} from './MultiQueryHockFactory';

export {
EmptyState,
Expand Down

0 comments on commit 877c5fb

Please sign in to comment.