Skip to content
This repository was archived by the owner on Mar 20, 2022. It is now read-only.

Commit 7d527b6

Browse files
timhwang21Tim Hwang
authored and
Tim Hwang
committed
Can normalize entities keyed with their ID
1 parent 0389142 commit 7d527b6

File tree

4 files changed

+63
-16
lines changed

4 files changed

+63
-16
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,12 @@ const article = new Schema('articles', { idAttribute: 'slug' });
248248
function generateSlug(entity) { /* ... */ }
249249
const article = new Schema('articles', { idAttribute: generateSlug });
250250

251+
// The function is passed both the current value and its key
252+
// This is helpful in occasions where your data is keyed by id, but doesn't contain id inside the value
253+
const keyedByIdJson = { 1: { ... }, 2: { ... }, 3: { ... } };
254+
function generateSlug(entity, id) { return id; }
255+
const article = new Schema('articles', { idAttribute: generateSlug });
256+
251257
// You can also specify meta properties to be used for customizing the output in assignEntity (see below)
252258
const article = new Schema('articles', { idAttribute: 'slug', meta: { removeProps: ['publisher'] }});
253259

src/EntitySchema.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ export default class EntitySchema {
2222
return this._key;
2323
}
2424

25-
getId(entity) {
26-
return this._getId(entity);
25+
getId(entity, key) {
26+
return this._getId(entity, key);
2727
}
2828

2929
getIdAttribute() {

src/index.js

+21-13
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function defaultAssignEntity(normalized, key, entity) {
88
normalized[key] = entity;
99
}
1010

11-
function visitObject(obj, schema, bag, options) {
11+
function visitObject(obj, schema, bag, options, collectionKey) {
1212
const { assignEntity = defaultAssignEntity } = options;
1313

1414
const defaults = schema && schema.getDefaults && schema.getDefaults();
@@ -17,7 +17,7 @@ function visitObject(obj, schema, bag, options) {
1717
for (let key in obj) {
1818
if (obj.hasOwnProperty(key)) {
1919
const resolvedSchema = typeof schema[key] === 'function' ? schema[key].call(null, obj) : schema[key];
20-
const entity = visit(obj[key], resolvedSchema, bag, options);
20+
const entity = visit(obj[key], resolvedSchema, bag, options, collectionKey);
2121
assignEntity.call(null, normalized, key, entity, obj, schema);
2222
if (schemaAssignEntity) {
2323
schemaAssignEntity.call(null, normalized, key, entity, obj, schema);
@@ -28,13 +28,13 @@ function visitObject(obj, schema, bag, options) {
2828
}
2929

3030
function defaultMapper(iterableSchema, itemSchema, bag, options) {
31-
return (obj) => visit(obj, itemSchema, bag, options);
31+
return (obj, key) => visit(obj, itemSchema, bag, options, key);
3232
}
3333

3434
function polymorphicMapper(iterableSchema, itemSchema, bag, options) {
35-
return (obj) => {
35+
return (obj, key) => {
3636
const schemaKey = iterableSchema.getSchemaKey(obj);
37-
const result = visit(obj, itemSchema[schemaKey], bag, options);
37+
const result = visit(obj, itemSchema[schemaKey], bag, options, key);
3838
return { id: result, schema: schemaKey };
3939
};
4040
}
@@ -47,7 +47,7 @@ function visitIterable(obj, iterableSchema, bag, options) {
4747
return obj.map(curriedItemMapper);
4848
} else {
4949
return Object.keys(obj).reduce(function (objMap, key) {
50-
objMap[key] = curriedItemMapper(obj[key]);
50+
objMap[key] = curriedItemMapper(obj[key], key);
5151
return objMap;
5252
}, {});
5353
}
@@ -76,11 +76,11 @@ function defaultMergeIntoEntity(entityA, entityB, entityKey) {
7676
}
7777
}
7878

79-
function visitEntity(entity, entitySchema, bag, options) {
79+
function visitEntity(entity, entitySchema, bag, options, collectionKey) {
8080
const { mergeIntoEntity = defaultMergeIntoEntity } = options;
8181

8282
const entityKey = entitySchema.getKey();
83-
const id = entitySchema.getId(entity);
83+
const id = entitySchema.getId(entity, collectionKey);
8484

8585
if (!bag.hasOwnProperty(entityKey)) {
8686
bag[entityKey] = {};
@@ -91,28 +91,35 @@ function visitEntity(entity, entitySchema, bag, options) {
9191
}
9292

9393
let stored = bag[entityKey][id];
94-
let normalized = visitObject(entity, entitySchema, bag, options);
94+
let normalized = visitObject(entity, entitySchema, bag, options, collectionKey);
9595
mergeIntoEntity(stored, normalized, entityKey);
9696

9797
return id;
9898
}
9999

100-
function visit(obj, schema, bag, options) {
100+
function visit(obj, schema, bag, options, collectionKey) {
101101
if (!isObject(obj) || !isObject(schema)) {
102102
return obj;
103103
}
104104

105105
if (schema instanceof EntitySchema) {
106-
return visitEntity(obj, schema, bag, options);
106+
return visitEntity(obj, schema, bag, options, collectionKey);
107107
} else if (schema instanceof IterableSchema) {
108108
return visitIterable(obj, schema, bag, options);
109109
} else if (schema instanceof UnionSchema) {
110110
return visitUnion(obj, schema, bag, options);
111111
} else {
112-
return visitObject(obj, schema, bag, options);
112+
return visitObject(obj, schema, bag, options, collectionKey);
113113
}
114114
}
115115

116+
function normalizeResult(result) {
117+
if (isObject(result) && isEqual(Object.keys(result), Object.keys(result).map(key => result[key]))) {
118+
return Object.keys(result);
119+
}
120+
return result;
121+
}
122+
116123
export function arrayOf(schema, options) {
117124
return new IterableSchema(schema, options);
118125
}
@@ -139,8 +146,9 @@ export function normalize(obj, schema, options = {}) {
139146
let bag = {};
140147
let result = visit(obj, schema, bag, options);
141148

149+
142150
return {
143151
entities: bag,
144-
result
152+
result: normalizeResult(result)
145153
};
146154
}

test/index.js

+34-1
Original file line numberDiff line numberDiff line change
@@ -1950,4 +1950,37 @@ describe('normalizr', function () {
19501950
}).should.throw();
19511951
});
19521952

1953-
});
1953+
it('can normalize iterables keyed with their id', function () {
1954+
var user = new Schema('users', {
1955+
idAttribute: function(obj, key) {
1956+
return key;
1957+
}
1958+
})
1959+
1960+
var input = {
1961+
1: {
1962+
name: 'Adam'
1963+
},
1964+
4: {
1965+
name: 'Jeremy'
1966+
}
1967+
};
1968+
1969+
Object.freeze(input);
1970+
1971+
normalize(input, valuesOf(user)).should.eql({
1972+
result: ['1', '4'],
1973+
entities: {
1974+
users: {
1975+
'1': {
1976+
name: 'Adam'
1977+
},
1978+
'4': {
1979+
name: 'Jeremy'
1980+
}
1981+
}
1982+
}
1983+
});
1984+
});
1985+
1986+
});

0 commit comments

Comments
 (0)