Skip to content

Commit

Permalink
New vesion 1.0.0, updated dependencies, added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Anton Petrov committed Sep 7, 2016
1 parent 76e5de0 commit dc9673c
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 48 deletions.
5 changes: 2 additions & 3 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
"stage": 0,
"loose": "all"
}
"presets": ["es2015", "stage-1"]
}
19 changes: 3 additions & 16 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
{
"extends": "eslint-config-airbnb",
"env": {
"mocha": true,
"node": true
},
"globals": {
"expect": true
},
"rules": {
"padded-blocks": 0,
"no-use-before-define": [2, "nofunc"],
"no-unused-expressions": 0,
"indent": [2, 4],
"comma-dangle": 0
}
}
"parser": "babel-eslint",
"extends": "eslint:recommended"
}
5 changes: 4 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
language: node_js
node_js:
- "4"
- "4"
script:
- npm run eslint
- npm run test
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![build status](https://img.shields.io/travis/itsmepetrov/redux-entities/master.svg?style=flat-square)](https://travis-ci.org/itsmepetrov/redux-entities)
[![npm version](https://img.shields.io/npm/v/redux-entities.svg?style=flat-square)](https://www.npmjs.com/package/redux-entities)

Higher-order reducer for store entities received from gaearon's [normalizr](https://github.com/gaearon/normalizr) and makes it easy to handle them.
Higher-order reducer for store entities received from [normalizr](https://github.com/paularmstrong/normalizr) and makes it easy to handle them.

### Installation

Expand All @@ -19,7 +19,7 @@ WIP
```js
import { combineReducers } from 'redux';
import { entitiesReducer } from 'redux-entities';
import omit from 'lodash/object/omit';
import omit from 'lodash/omit';

function contacts(state = {}, action) {

Expand Down
23 changes: 14 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"name": "redux-entities",
"version": "0.0.4",
"description": "Higher-order reducer for store entities received from gaearon's normalizr and makes it easy to handle them.",
"version": "1.0.0",
"description": "Higher-order reducer for store entities received from normalizr and makes it easy to handle them.",
"main": "lib/index.js",
"scripts": {
"test": "eslint ./src/*.js",
"test": "mocha --compilers js:babel-core/register --recursive",
"eslint": "eslint ./src/*.js",
"build": "babel src --out-dir lib",
"clean": "rimraf lib",
"prepublish": "npm run clean && npm run test && npm run build"
Expand All @@ -27,14 +28,18 @@
},
"homepage": "https://github.com/itsmepetrov/redux-entities#readme",
"devDependencies": {
"babel": "^5.8.29",
"babel-eslint": "^4.1.3",
"eslint": "^1.7.3",
"eslint-config-airbnb": "^0.1.0",
"eslint-plugin-react": "^3.6.3",
"babel-cli": "^6.14.0",
"babel-core": "^6.14.0",
"babel-eslint": "^6.1.2",
"babel-preset-es2015": "^6.14.0",
"babel-preset-stage-1": "^6.13.0",
"babel-register": "^6.14.0",
"chai": "^3.5.0",
"eslint": "^3.4.0",
"mocha": "^3.0.2",
"rimraf": "^2.4.3"
},
"dependencies": {
"lodash": "^3.10.1"
"lodash": "^4.11.2"
}
}
38 changes: 21 additions & 17 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
import isFunction from 'lodash/lang/isFunction';
import mapValues from 'lodash/object/mapValues';
import isFunction from 'lodash/isFunction'
import mapValues from 'lodash/mapValues'
import get from 'lodash/get'

function selectEntities(action, name) {
if (action.payload && action.payload.entities && action.payload.entities[name]) {
return action.payload.entities[name];
}
const entities = get(action, `payload.entities.${name}`)
if (entities) {
return entities;
}
}

export function entitiesReducer(reducer, entitiesName) {
return (state, action) => {
let newState = state;
const entities = isFunction(entitiesName) ? entitiesName(action) : selectEntities(action, entitiesName);
return (state, action) => {
let newState = state;
const entities = isFunction(entitiesName) ?
entitiesName(action) : selectEntities(action, entitiesName);

if (entities) {
newState = Object.assign({}, newState, entities);
}
if (entities) {
newState = Object.assign({}, newState, entities);
}

return reducer(newState, action);
};
return reducer(newState, action);
};
}

export function combineEntitiesReducers(reducers) {
const entitiesReducers = mapValues(reducers, entitiesReducer);
return (state = {}, action) => mapValues(entitiesReducers,
(reducer, key) => reducer(state[key], action)
);
const entitiesReducers = mapValues(reducers, entitiesReducer);
return (state = {}, action) => mapValues(
entitiesReducers,
(reducer, key) => reducer(state[key], action)
);
}
128 changes: 128 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* eslint-env mocha */
import { expect } from 'chai';
import { entitiesReducer, combineEntitiesReducers } from '../src';

describe('redux-entities', () => {
const normalizedObject = {
entities: {
contacts: {
1: {
id: 1,
name: 'Anton'
},
2: {
id: 2,
name: 'Sergey'
}
},
notes: {
10: {
id: 10,
title: 'Run tests'
},
20: {
id: 20,
title: 'Run lint'
}
}
}
}

const fillEntitiesAction = {
type: 'FILL_ENTITIES',
payload: normalizedObject
}

const fillEntitiesNestedAction = {
type: 'FILL_ENTITIES',
payload: {
nested: normalizedObject
}
}

const updateContactAction = {
type: 'UPDATE_CONTACT',
payload: {
id: 1,
name: 'Andrey'
}
}

const contactsReducer = (state = {}) => state;
const notesReducer = (state = {}) => state;
const contactsWithUpdateReducer = (state = {}, action) => {
const { type, payload } = action;
if (type === 'UPDATE_CONTACT') {
const { id, ...rest } = payload
return {
...state,
[id]: {
...state[id],
...rest
}
}
}
return state
}

describe('entitiesReducer', () => {
it('should return named entities object', () => {
const reducer = entitiesReducer(
contactsReducer,
'contacts'
)

const state = reducer({}, fillEntitiesAction)

expect(state).to.deep.equal(normalizedObject.entities.contacts)
})

it('can extract entities by custom path', () => {
const reducer = entitiesReducer(
contactsReducer,
(action) => action.payload.nested.entities.contacts
)

const state = reducer({}, fillEntitiesNestedAction)

expect(state).to.deep.equal(normalizedObject.entities.contacts)
})

it('can update specific entitie', () => {
const reducer = entitiesReducer(
contactsWithUpdateReducer,
'contacts'
)

const state = reducer({}, fillEntitiesAction)
const updatedState = reducer(state, updateContactAction)

expect(updatedState[1]).to.deep.equal({ id: 1, name: 'Andrey' })
})
})

describe('combineEntitiesReducers', () => {
it('should return entities object', () => {
const reducer = combineEntitiesReducers({
contacts: contactsReducer,
notes: notesReducer,
})

const state = reducer({}, fillEntitiesAction)

expect(state).to.deep.equal(normalizedObject.entities)
})

it('can update specific entitie', () => {
const reducer = combineEntitiesReducers({
contacts: contactsWithUpdateReducer,
notes: notesReducer,
})

const state = reducer({}, fillEntitiesAction)
const updatedState = reducer(state, updateContactAction)

expect(updatedState.contacts[1]).to.deep.equal({ id: 1, name: 'Andrey' })
})
})
})

0 comments on commit dc9673c

Please sign in to comment.