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

Commit

Permalink
Merge pull request #9 from mschipperheyn/0.0.3
Browse files Browse the repository at this point in the history
0.0.3
  • Loading branch information
mschipperheyn committed May 15, 2016
2 parents 7be0c79 + 6468af0 commit 09f1a3e
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 79 deletions.
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@ We recommend reading the documentation for Normalizr and Immutable first, to get

### Installation
```
npm install normalizr-immutable
npm install --save normalizr-immutable
```

### Changes to API!
Based on user feedback I decided to make some changes to the API:
* `reducerKey` is now an attribute for Schema. This makes it possible to reference entities that are stored in other reducers.

It does mean that if you receive different levels of detail for a single type of entity across REST endpoints, or you want to maintain the original functionality of referencing entities within one reducer, you may need to maintain different Schema definitions for that entity.

If you do want to maintain entities across reducers, you have to be careful not to reference a reducer through the Proxy that has not been hydrated yet.

### What does Normalizr-Immutable do?
It normalizes a deeply nested json structure according to a schema for Redux apps and makes the resulting object immutable.
It does this in a way that preserves the ability to reference objects using traditional javascript object notation.
Expand Down Expand Up @@ -169,6 +177,13 @@ new Article({
In order to use the proxy, you will need to give it access to the actual object structure. We have developed this feature testing against Redux, so we pass it the getState function reference and the reference to the reducer inside the state structure.

```javascript
const schemas = {
article : new Schema('articles', { idAttribute: 'id', record: Article, reducerKey: 'articleReducer' }),
user : new Schema('users', { idAttribute: 'id', record: User, reducerKey: 'userReducer' }),
tag : new Schema('tags', { idAttribute: 'id', record: Tag, reducerKey: 'tagReducer' })
};


const normalized = normalize(json.articles.items, arrayOf(schemas.article),{
getState,
reducerKey:'articleReducer'
Expand All @@ -195,9 +210,6 @@ export function loadArticles(){

`articleReducer` in this case, is the name of the reducer. Currently we assume that the `result` and `entitites` keys are available in the root of the referenced reducer. This will be made more flexible in future versions.

### Examples
I still have to write examples, but for now check out the tests to get an idea of how it works.

### Browser support
This library has currently only been tested against React-Native, so I would like to hear about experiences in the browser. For a list of browsers with appropriate Proxy support [http://caniuse.com/#feat=proxy](http://caniuse.com/#feat=proxy).

Expand All @@ -208,6 +220,8 @@ The way I turn a list of entities into Records (the ValueStructure Record) is a

This library has been developed as part of [Ology](https://www.ology.com.br), the social network for physicians.

I removed harmony-reflect because it's a rather big library and more recent versions of v8 don't need it. I'm just maintaining the harmony-proxy shim.

### TODO
* API description
* Examples
Expand Down
27 changes: 0 additions & 27 deletions npm-debug.log

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"immutable": "^3.7.6",
"lodash": "^4.2.1",
"lodash-es": "^4.2.1",
"normalizr": "^2.0.1"
"normalizr": "^2.0.2"
},
"devDependencies": {
"babel-cli": "^6.8.0",
Expand Down
7 changes: 6 additions & 1 deletion src/RecordEntitySchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ export default class RecordEntitySchema extends Schema{
this._getId = typeof idAttribute === 'function' ? idAttribute : x => x[idAttribute];
this._idAttribute = idAttribute;
this._record = options.record;
this._reducerKey = options.reducerKey;
}

getRecord() {
return this._record;
}

getReducerKey() {
return this._reducerKey;
}

toString(){
return `EntitySchema, key: ${this._key}, idAttribute: ${this._idAttribute}`;
return `EntitySchema, key: ${this._key}, idAttribute: ${this._idAttribute}, reducerKey: ${this._reducerKey}`;
}
}
48 changes: 24 additions & 24 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
// Based on Normalizr 2.0.1
'use strict';

// import { arrayOf, valuesOf, unionOf } from 'normalizr';
import { Record, Map, List, Iterable } from 'immutable';

//Shim for new Proxy instead of Proxy.create
import Proxy from 'harmony-proxy';
//Should patch proxy to work properly
import Reflect from 'harmony-reflect';
// import Reflect from 'harmony-reflect';

import RecordEntitySchema from './RecordEntitySchema';
import IterableSchema from './IterableSchema';
import UnionSchema from './UnionSchema';
import lodashIsEqual from 'lodash/isEqual';
import lodashIsObject from 'lodash/isObject';

const NormalizedRecord = new Record({entities:null, result: new List()});
const NormalizedRecord = new Record({entities:null, result: null});
const PolymorphicMapper = new Record({id:null, schema: null});

function defaultAssignEntity(normalized, key, entity) {
Expand All @@ -26,27 +25,19 @@ function proxy(id, schema, bag, options){
/**
* if options contains getState reference and reducer key we can create a proxyHandler
*/
if(typeof Proxy === 'undefined')
return id;

return new Proxy({id: id, key: schema.getKey()},{
get(target, name, receiver) {
// if(name === 'toJSON'){
// console.log(`WARN: use toJSON in stead of JSON.stringify on immutable data structures: ${key}`);
// }
//toString methods create recursive issues
// if(name === 'toJSON' || name === 'toString')
// return () => target;
// if (name === 'valueOf')
// return target[name];
//this method can get called before the normalization process has completed.
//We can always expect entities to be a record, so we can defensively check for existence
//We want to be able to return the id before the state has been initialized

if(name === 'id')
return target.id;

const state = options.getState();

if(state[options.reducerKey].entities){
const ref = Reflect.get(state[options.reducerKey].entities[schema.getKey()][target.id],name);
if(state[schema.getReducerKey()].entities){
const ref = state[schema.getReducerKey()].entities[schema.getKey()][target.id][name];
return ref;
}
return undefined;
Expand All @@ -55,7 +46,7 @@ function proxy(id, schema, bag, options){
throw new Error('Not supported');
},
has(name){
return options.getState()[options.reducerKey].entities[schema.getKey()][id].has(name);
return options.getState()[schema.getReducerKey()].entities[schema.getKey()][id].has(name);
},
valueOf : function () {
return 0;
Expand Down Expand Up @@ -221,19 +212,28 @@ function normalize(obj, schema, options = {}) {
throw new Error('Normalize accepts an object for schema.');
}

if(options.getState && typeof Proxy === 'undefined'){
console.warn('Proxies not supported in this environment');
}

let bag = {};
let entityStructure = {};
let keyStructure = {};
let results = [];

//This will either return a sequence, an id or a Proxy object
let result = visit(obj, schema, bag, options);

//we are now assuming that the returned "ids" are actually proxies if there is a getState method
results = options.getState?
result.map(function(val){
return val.id;
})
:
result;
if(options.getState){
results = result instanceof List?
result.map(function(val){
return val.id;
}) :
result.id
}else{
results = result;
}

for(let schemaKey in bag){
keyStructure[schemaKey] = null;
Expand All @@ -245,7 +245,7 @@ function normalize(obj, schema, options = {}) {

return new NormalizedRecord({
entities: new EntityStructure(entityStructure),
result: new List(results)
result: results
});
}

Expand Down
36 changes: 36 additions & 0 deletions test/mocks/article_comments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"id" : 49443,
"txt" : "Testing Normalizr",
"user" : {
"nickName" : "Marc",
"id" : 192
},
"tags": [{
"id" : 5,
"label" : "React"
},
{
"id" : 6,
"label" : "Normalizr"
}
],
"comments" : [
{
"user" : {
"nickName" : "Diogenes",
"id" : 193
},
"id" : 50001,
"txt" : "bla"
},
{
"user" : {
"nickName" : "Marc",
"id" : 192
},
"id" : 50002,
"txt" : "bla die bla 2"
}
],
"resultCount" : 114
}
12 changes: 12 additions & 0 deletions test/mocks/users.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"users":[
{
"nickName" : "Diogenes",
"id" : 193
},
{
"nickName" : "Marc",
"id" : 192
}
]
}
Loading

0 comments on commit 09f1a3e

Please sign in to comment.