摘要 開發復雜的應用時,不可避免會有一些數據相互引用。建議你盡可能地把 state 范式化,不存在嵌套。把所有數據放到一個對象裡,每個數據以 ID 為主鍵,不同數據相互引用時通過 ID 來查找。把 應用的 state 想像成數據庫 。這種方法在 normalizr 文檔裡有詳細闡述。 normalizr...
開發復雜的應用時,不可避免會有一些數據相互引用。建議你盡可能地把 state
范式化,不存在嵌套。把所有數據放到一個對象裡,每個數據以 ID 為主鍵,不同數據相互引用時通過 ID 來查找。把 應用的 state 想像成數據庫 。這種方法在 normalizr 文檔裡有詳細闡述。
normalizr:將嵌套的JSON格式扁平化,方便被Redux利用;
我們的目標是將:
[{
id: 1,
title: 'Some Article',
author: {
id: 1,
name: 'Dan'
}
}, {
id: 2,
title: 'Other Article',
author: {
id: 1,
name: 'Dan'
}
}]
我們描述上述的結構: - 返回的是一個數組(array) - 數組的對象中包含另外一個schema —— user
應該比較合理的,應該是轉換成:
{
result: [1, 2],
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 1
},
2: {
id: 2,
title: 'Other Article',
author: 1
}
},
users: {
1: {
id: 1,
name: 'Dan'
}
}
}
}
觀看示例最好的,就是官方的測試文件:https://github.com/gaearon/normalizr/blob/master/test/index.js
先引入 normalizr
:
import { normalize, Schema, arrayOf } from 'normalizr';
定義schema
:
var article = new Schema('articles'),
user = new Schema('users'),
collection = new Schema('collections'),
feedSchema,
input;
定義規則:
article.define({
author: user,
collections: arrayOf(collection)
});
collection.define({
curator: user
});
feedSchema = {
feed: arrayOf(article)
};
測試:
input = {
feed: [{
id: 1,
title: 'Some Article',
author: {
id: 3,
name: 'Mike Persson'
},
collections: [{
id: 1,
title: 'Awesome Writing',
curator: {
id: 4,
name: 'Andy Warhol'
}
}, {
id: 7,
title: 'Even Awesomer',
curator: {
id: 100,
name: 'T.S. Eliot'
}
}]
}, {
id: 2,
title: 'Other Article',
collections: [{
id: 2,
title: 'Neverhood',
curator: {
id: 120,
name: 'Ada Lovelace'
}
}],
author: {
id: 2,
name: 'Pete Hunt'
}
}]
};
Object.freeze(input);
normalize(input, feedSchema).should.eql({
result: {
feed: [1, 2]
},
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 3,
collections: [1, 7]
},
2: {
id: 2,
title: 'Other Article',
author: 2,
collections: [2]
}
},
collections: {
1: {
id: 1,
title: 'Awesome Writing',
curator: 4
},
2: {
id: 2,
title: 'Neverhood',
curator: 120
},
7: {
id: 7,
title: 'Even Awesomer',
curator: 100
}
},
users: {
2: {
id: 2,
name: 'Pete Hunt'
},
3: {
id: 3,
name: 'Mike Persson'
},
4: {
id: 4,
name: 'Andy Warhol'
},
100: {
id: 100,
name: 'T.S. Eliot'
},
120: {
id: 120,
name: 'Ada Lovelace'
}
}
}
});
假定請求 /articles
返回的數據的schema如下:
articles: article*
article: {
author: user,
likers: user*
primary_collection: collection?
collections: collection*
}
collection: {
curator: user
}
如果不做范式化,store需要事先知道API的各種結構,比如UserStore
會包含很多樣板代碼來獲取新用戶,諸如下面那樣:
switch (action.type) {
case ActionTypes.RECEIVE_USERS:
mergeUsers(action.rawUsers);
break;
case ActionTypes.RECEIVE_ARTICLES:
action.rawArticles.forEach(rawArticle => {
mergeUsers([rawArticle.user]);
mergeUsers(rawArticle.likers);
mergeUsers([rawArticle.primaryCollection.curator]);
rawArticle.collections.forEach(rawCollection => {
mergeUsers(rawCollection.curator);
});
});
UserStore.emitChange();
break;
}
store表示累覺不愛啊!! 每個store都要對返回的 進行各種foreach 才能獲取想要的數據。
來一個范式吧:
const article = new Schema('articles');
const user = new Schema('users');
article.define({
author: user,
contributors: arrayOf(user),
meta: {
likes: arrayOf({
user: user
})
}
});
// ...
const json = getArticleArray();
const normalized = normalize(json, arrayOf(article));
經過范式整頓之後,你愛理或者不愛理,users對象總是在 action.entities.users
中:
const { action } = payload;
if (action.response && action.response.entities && action.response.entities.users) {
mergeUsers(action.response.entities.users);
UserStore.emitChange();
break;
}
var article = new Schema('articles'),
input;
input = {
id: 1,
title: 'Some Article',
isFavorite: false
};
Object.freeze(input);
normalize(input, article).should.eql({
result: 1,
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
isFavorite: false
}
}
}
});
有時候後端接口會返回很多額外的字段,甚至會有重復的字段;比如下方示例中 typeId
和 type.id
是重復的;注意方法中 形參key
是經過artcle.define
定義過的。
var article = new Schema('articles'),
type = new Schema('types'),
input;
// 定義內嵌規則
article.define({
type: type
});
input = {
id: 1,
title: 'Some Article',
isFavorite: false,
typeId: 1,
type: {
id: 1,
}
};
Object.freeze(input);
// assignEntity刪除後端返回額外數據的
var options = {
assignEntity: function(obj, key, val) {
obj[key] = val;
delete obj[key + 'Id'];
}
};
normalize(input, article, options).should.eql({
result: 1,
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
isFavorite: false,
type: 1
}
},
types: {
1: {
id: 1
}
}
}
});
和上個示例相反的是,mergeIntoEntity
用於將多份同質數據不同信息融合到一起,用於解決沖突。
下方示例中,author
和 reviewer
是同一個人,只是前者留下的聯系方式是手機,後者留下的聯系方式是郵箱,但無論如何都是同一個人;
此時就可以使用 mergeIntoEntity
將兩份數據融合到一起;(注意這裡是用 valueOf
規則 )
var author = new Schema('authors'),
input;
input = {
author: {
id: 1,
name: 'Ada Lovelace',
contact: {
phone: '555-0100'
}
},
reviewer: {
id: 1,
name: 'Ada Lovelace',
contact: {
email: '[email protected]'
}
}
}
Object.freeze(input);
var options = {
mergeIntoEntity: function(entityA, entityB, entityKey) {
var key;
for (key in entityB) {
if (!entityB.hasOwnProperty(key)) {
continue;
}
if (!entityA.hasOwnProperty(key) || isEqual(entityA[key], entityB[key])) {
entityA[key] = entityB[key];
continue;
}
if (isObject(entityA[key]) && isObject(entityB[key])) {
merge(entityA[key], entityB[key])
continue;
}
console.warn('Unequal data!');
}
}
};
normalize(input, valuesOf(author), options).should.eql({
result: {
author: 1,
reviewer: 1
},
entities: {
authors: {
1: {
id: 1,
name: 'Ada Lovelace',
contact: {
phone: '555-0100',
email: '[email protected]'
}
}
}
}
});
有時候對象沒有 id
屬性,或者我們並不想按 id
屬性規范化,可以使用 idAttribute 指定;
下面的例子,就是使用slug
作為規范化的key:
var article = new Schema('articles', { idAttribute: 'slug' }),
input;
input = {
id: 1,
slug: 'some-article',
title: 'Some Article',
isFavorite: false
};
Object.freeze(input);
normalize(input, article).should.eql({
result: 'some-article',
entities: {
articles: {
'some-article': {
id: 1,
slug: 'some-article',
title: 'Some Article',
isFavorite: false
}
}
}
});
有時候想自己創建一個key,雖然今天和去年創建的文章名稱都是Happy
,但明顯是不一樣的,為了按時間區分出來,可以 使用自定義函數生成想要的key 。
function makeSlug(article) {
var posted = article.posted,
title = article.title.toLowerCase().replace(' ', '-');
return [title, posted.year, posted.month, posted.day].join('-');
}
var article = new Schema('articles', { idAttribute: makeSlug }),
input;
input = {
id: 1,
title: 'Some Article',
isFavorite: false,
posted: {
day: 12,
month: 3,
year: 1983
}
};
Object.freeze(input);
normalize(input, article).should.eql({
result: 'some-article-1983-3-12',
entities: {
articles: {
'some-article-1983-3-12': {
id: 1,
title: 'Some Article',
isFavorite: false,
posted: {
day: 12,
month: 3,
year: 1983
}
}
}
}
});
後端返回的數據往往是一串數組居多,此時規范化起到很大的作用,規范化的同時將數據壓縮了一遍;
var article = new Schema('articles'),
input;
input = [{
id: 1,
title: 'Some Article'
}, {
id: 2,
title: 'Other Article'
}];
Object.freeze(input);
normalize(input, arrayOf(article)).should.eql({
result: [1, 2],
entities: {
articles: {
1: {
id: 1,
title: 'Some Article'
},
2: {
id: 2,
title: 'Other Article'
}
}
}
});
上面講的情形比較簡單,只涉及抽出結果是單個schema的情形;現實中,你往往想抽象出多個schema,比如下方,我想抽離出 tutorials
(教程) 和articles
(文章)兩個 schema,此時需要 通過 schemaAttribute 選項指定區分這兩個 schema 的字段 :
var article = new Schema('articles'),
tutorial = new Schema('tutorials'),
articleOrTutorial = { articles: article, tutorials: tutorial },
input;
input = [{
id: 1,
type: 'articles',
title: 'Some Article'
}, {
id: 1,
type: 'tutorials',
title: 'Some Tutorial'
}];
Object.freeze(input);
normalize(input, arrayOf(articleOrTutorial, { schemaAttribute: 'type' })).should.eql({
result: [
{id: 1, schema: 'articles'},
{id: 1, schema: 'tutorials'}
],
entities: {
articles: {
1: {
id: 1,
type: 'articles',
title: 'Some Article'
}
},
tutorials: {
1: {
id: 1,
type: 'tutorials',
title: 'Some Tutorial'
}
}
}
});
這個示例中,雖然文章的id都是1,但很明顯它們是不同的文章,因為一篇是普通文章,一篇是教程文章;因此要按schema維度抽離數據;
這裡的 arrayOf(articleOrTutorial)
中的 articleOrTutorial
是包含多個屬性的對象,這表示 input
應該是 articleOrTutorial
中的一種情況;
有時候原始數據屬性 和 我們定義的有些差別,此時可以將 schemaAttribute
的值設成函數,將原始屬性經過適當加工;比如原始屬性是tutorial
, 而抽離出的 schema 名字為 tutorials
,相差一個s
:
function guessSchema(item) {
return item.type + 's';
}
var article = new Schema('articles'),
tutorial = new Schema('tutorials'),
articleOrTutorial = { articles: article, tutorials: tutorial },
input;
input = [{
id: 1,
type: 'article',
title: 'Some Article'
}, {
id: 1,
type: 'tutorial',
title: 'Some Tutorial'
}];
Object.freeze(input);
normalize(input, arrayOf(articleOrTutorial, { schemaAttribute: guessSchema })).should.eql({
result: [
{ id: 1, schema: 'articles' },
{ id: 1, schema: 'tutorials' }
],
entities: {
articles: {
1: {
id: 1,
type: 'article',
title: 'Some Article'
}
},
tutorials: {
1: {
id: 1,
type: 'tutorial',
title: 'Some Tutorial'
}
}
}
});
上述是數組情況,針對普通的對象也是可以的,將規則 改成 valueOf 即可:
var article = new Schema('articles'),
tutorial = new Schema('tutorials'),
articleOrTutorial = { articles: article, tutorials: tutorial },
input;
input = {
one: {
id: 1,
type: 'articles',
title: 'Some Article'
},
two: {
id: 2,
type: 'articles',
title: 'Another Article'
},
three: {
id: 1,
type: 'tutorials',
title: 'Some Tutorial'
}
};
Object.freeze(input);
normalize(input, valuesOf(articleOrTutorial, { schemaAttribute: 'type' })).should.eql({
result: {
one: {id: 1, schema: 'articles'},
two: {id: 2, schema: 'articles'},
three: {id: 1, schema: 'tutorials'}
},
entities: {
articles: {
1: {
id: 1,
type: 'articles',
title: 'Some Article'
},
2: {
id: 2,
type: 'articles',
title: 'Another Article'
}
},
tutorials: {
1: {
id: 1,
type: 'tutorials',
title: 'Some Tutorial'
}
}
}
});
schemaAttribute 是函數的情況就不列舉了,和上述一致;
上面的對象比較簡單,原本就是扁平化的;如果對象格式稍微復雜一些,比如每篇文章有多個作者的情形。此時需要使用 define 事先聲明 schema 之間的層級關系:
var article = new Schema('articles'),
user = new Schema('users'),
input;
article.define({
author: user
});
input = {
id: 1,
title: 'Some Article',
author: {
id: 3,
name: 'Mike Persson'
}
};
Object.freeze(input);
normalize(input, article).should.eql({
result: 1,
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 3
}
},
users: {
3: {
id: 3,
name: 'Mike Persson'
}
}
}
});
上面是不是覺得簡單了?那麼給你一個比較復雜的情形,萬變不離其宗。我們最終想抽離出 articles
、users
以及 collections
這三個 schema,所以只要定義這三個schema就行了,
然後使用 define 方法聲明這三個schema之間千絲萬縷的關系;
最外層的feed只是屬性,並不需要定義;
var article = new Schema('articles'),
user = new Schema('users'),
collection = new Schema('collections'),
feedSchema,
input;
article.define({
author: user,
collections: arrayOf(collection)
});
collection.define({
curator: user
});
feedSchema = {
feed: arrayOf(article)
};
input = {
feed: [{
id: 1,
title: 'Some Article',
author: {
id: 3,
name: 'Mike Persson'
},
collections: [{
id: 1,
title: 'Awesome Writing',
curator: {
id: 4,
name: 'Andy Warhol'
}
}, {
id: 7,
title: 'Even Awesomer',
curator: {
id: 100,
name: 'T.S. Eliot'
}
}]
}, {
id: 2,
title: 'Other Article',
collections: [{
id: 2,
title: 'Neverhood',
curator: {
id: 120,
name: 'Ada Lovelace'
}
}],
author: {
id: 2,
name: 'Pete Hunt'
}
}]
};
Object.freeze(input);
normalize(input, feedSchema).should.eql({
result: {
feed: [1, 2]
},
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 3,
collections: [1, 7]
},
2: {
id: 2,
title: 'Other Article',
author: 2,
collections: [2]
}
},
collections: {
1: {
id: 1,
title: 'Awesome Writing',
curator: 4
},
2: {
id: 2,
title: 'Neverhood',
curator: 120
},
7: {
id: 7,
title: 'Even Awesomer',
curator: 100
}
},
users: {
2: {
id: 2,
name: 'Pete Hunt'
},
3: {
id: 3,
name: 'Mike Persson'
},
4: {
id: 4,
name: 'Andy Warhol'
},
100: {
id: 100,
name: 'T.S. Eliot'
},
120: {
id: 120,
name: 'Ada Lovelace'
}
}
}
});
var article = new Schema('articles'),
tutorial = new Schema('tutorials'),
articleOrTutorial = { articles: article, tutorials: tutorial },
user = new Schema('users'),
collection = new Schema('collections'),
feedSchema,
input;
article.define({
author: user,
collections: arrayOf(collection)
});
tutorial.define({
author: user,
collections: arrayOf(collection)
});
collection.define({
curator: user
});
feedSchema = {
feed: arrayOf(articleOrTutorial, { schemaAttribute: 'type' })
};
input = {
feed: [{
id: 1,
type: 'articles',
title: 'Some Article',
author: {
id: 3,
name: 'Mike Persson'
},
collections: [{
id: 1,
title: 'Awesome Writing',
curator: {
id: 4,
name: 'Andy Warhol'
}
}, {
id: 7,
title: 'Even Awesomer',
curator: {
id: 100,
name: 'T.S. Eliot'
}
}]
}, {
id: 1,
type: 'tutorials',
title: 'Some Tutorial',
collections: [{
id: 2,
title: 'Neverhood',
curator: {
id: 120,
name: 'Ada Lovelace'
}
}],
author: {
id: 2,
name: 'Pete Hunt'
}
}]
};
Object.freeze(input);
normalize(input, feedSchema).should.eql({
result: {
feed: [
{ id: 1, schema: 'articles' },
{ id: 1, schema: 'tutorials' }
]
},
entities: {
articles: {
1: {
id: 1,
type: 'articles',
title: 'Some Article',
author: 3,
collections: [1, 7]
}
},
tutorials: {
1: {
id: 1,
type: 'tutorials',
title: 'Some Tutorial',
author: 2,
collections: [2]
}
},
collections: {
1: {
id: 1,
title: 'Awesome Writing',
curator: 4
},
2: {
id: 2,
title: 'Neverhood',
curator: 120
},
7: {
id: 7,
title: 'Even Awesomer',
curator: 100
}
},
users: {
2: {
id: 2,
name: 'Pete Hunt'
},
3: {
id: 3,
name: 'Mike Persson'
},
4: {
id: 4,
name: 'Andy Warhol'
},
100: {
id: 100,
name: 'T.S. Eliot'
},
120: {
id: 120,
name: 'Ada Lovelace'
}
}
}
});
看到下面的 valuesOf(arrayOf(user)) 了沒有,它表示該屬性是一個對象,對象裡面各個數組值是 User對象數組;
var article = new Schema('articles'),
user = new Schema('users'),
feedSchema,
input;
article.define({
collaborators: valuesOf(arrayOf(user))
});
feedSchema = {
feed: arrayOf(article),
suggestions: valuesOf(arrayOf(article))
};
input = {
feed: [{
id: 1,
title: 'Some Article',
collaborators: {
authors: [{
id: 3,
name: 'Mike Persson'
}],
reviewers: [{
id: 2,
name: 'Pete Hunt'
}]
}
}, {
id: 2,
title: 'Other Article',
collaborators: {
authors: [{
id: 2,
name: 'Pete Hunt'
}]
}
}, {
id: 3,
title: 'Last Article'
}],
suggestions: {
1: [{
id: 2,
title: 'Other Article',
collaborators: {
authors: [{
id: 2,
name: 'Pete Hunt'
}]
}
}, {
id: 3,
title: 'Last Article'
}]
}
};
Object.freeze(input);
normalize(input, feedSchema).should.eql({
result: {
feed: [1, 2, 3],
suggestions: {
1: [2, 3]
}
},
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
collaborators: {
authors: [3],
reviewers: [2]
}
},
2: {
id: 2,
title: 'Other Article',
collaborators: {
authors: [2]
}
},
3: {
id: 3,
title: 'Last Article'
}
},
users: {
2: {
id: 2,
name: 'Pete Hunt'
},
3: {
id: 3,
name: 'Mike Persson'
}
}
}
});
還有更加復雜的,這次用上 valuesOf(userOrGroup, { schemaAttribute: 'type' }) 了:
var article = new Schema('articles'),
user = new Schema('users'),
group = new Schema('groups'),
userOrGroup = { users: user, groups: group },
feedSchema,
input;
article.define({
collaborators: valuesOf(userOrGroup, { schemaAttribute: 'type' })
});
feedSchema = {
feed: arrayOf(article),
suggestions: valuesOf(arrayOf(article))
};
input = {
feed: [{
id: 1,
title: 'Some Article',
collaborators: {
author: {
id: 3,
type: 'users',
name: 'Mike Persson'
},
reviewer: {
id: 2,
type: 'groups',
name: 'Reviewer Group'
}
}
}, {
id: 2,
title: 'Other Article',
collaborators: {
author: {
id: 2,
type: 'users',
name: 'Pete Hunt'
}
}
}, {
id: 3,
title: 'Last Article'
}],
suggestions: {
1: [{
id: 2,
title: 'Other Article'
}, {
id: 3,
title: 'Last Article'
}]
}
};
Object.freeze(input);
normalize(input, feedSchema).should.eql({
result: {
feed: [1, 2, 3],
suggestions: {
1: [2, 3]
}
},
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
collaborators: {
author: { id: 3, schema: 'users' },
reviewer: { id: 2, schema: 'groups' }
}
},
2: {
id: 2,
title: 'Other Article',
collaborators: {
author: { id: 2, schema: 'users' }
}
},
3: {
id: 3,
title: 'Last Article'
}
},
users: {
2: {
id: 2,
type: 'users',
name: 'Pete Hunt'
},
3: {
id: 3,
type: 'users',
name: 'Mike Persson'
}
},
groups: {
2: {
id: 2,
type: 'groups',
name: 'Reviewer Group'
}
}
}
});
比如某某人關注了另外的人,用戶 寫了一系列文章,該文章 被其他用戶 訂閱就是這種情況:
var article = new Schema('articles'),
user = new Schema('users'),
collection = new Schema('collections'),
feedSchema,
input;
user.define({
articles: arrayOf(article)
});
article.define({
collections: arrayOf(collection)
});
collection.define({
subscribers: arrayOf(user)
});
feedSchema = {
feed: arrayOf(article)
};
input = {
feed: [{
id: 1,
title: 'Some Article',
collections: [{
id: 1,
title: 'Awesome Writing',
subscribers: [{
id: 4,
name: 'Andy Warhol',
articles: [{
id: 1,
title: 'Some Article'
}]
}, {
id: 100,
name: 'T.S. Eliot',
articles: [{
id: 1,
title: 'Some Article'
}]
}]
}, {
id: 7,
title: 'Even Awesomer',
subscribers: [{
id: 100,
name: 'T.S. Eliot',
articles: [{
id: 1,
title: 'Some Article'
}]
}]
}]
}]
};
Object.freeze(input);
normalize(input, feedSchema).should.eql({
result: {
feed: [1]
},
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
collections: [1, 7]
}
},
collections: {
1: {
id: 1,
title: 'Awesome Writing',
subscribers: [4, 100]
},
7: {
id: 7,
title: 'Even Awesomer',
subscribers: [100]
}
},
users: {
4: {
id: 4,
name: 'Andy Warhol',
articles: [1]
},
100: {
id: 100,
name: 'T.S. Eliot',
articles: [1]
}
}
}
});
上面還算好的,有些schema直接就遞歸聲明了,比如 兒女和父母 的關系:
var user = new Schema('users'),
input;
user.define({
parent: user
});
input = {
id: 1,
name: 'Andy Warhol',
parent: {
id: 7,
name: 'Tom Dale',
parent: {
id: 4,
name: 'Pete Hunt'
}
}
};
Object.freeze(input);
normalize(input, user).should.eql({
result: 1,
entities: {
users: {
1: {
id: 1,
name: 'Andy Warhol',
parent: 7
},
7: {
id: 7,
name: 'Tom Dale',
parent: 4
},
4: {
id: 4,
name: 'Pete Hunt'
}
}
}
});
在一個數組裡面,如果id屬性一致,會自動抽取並合屬性成一個:
var writer = new Schema('writers'),
book = new Schema('books'),
schema = arrayOf(writer),
input;
writer.define({
books: arrayOf(book)
});
input = [{
id: 3,
name: 'Jo Rowling',
isBritish: true,
location: {
x: 100,
y: 200,
nested: ['hello', {
world: true
}]
},
books: [{
id: 1,
soldWell: true,
name: 'Harry Potter'
}]
}, {
id: 3,
name: 'Jo Rowling',
bio: 'writer',
location: {
x: 100,
y: 200,
nested: ['hello', {
world: true
}]
},
books: [{
id: 1,
isAwesome: true,
name: 'Harry Potter'
}]
}];
normalize(input, schema).should.eql({
result: [3, 3],
entities: {
writers: {
3: {
id: 3,
isBritish: true,
name: 'Jo Rowling',
bio: 'writer',
books: [1],
location: {
x: 100,
y: 200,
nested: ['hello', {
world: true
}]
}
}
},
books: {
1: {
id: 1,
isAwesome: true,
soldWell: true,
name: 'Harry Potter'
}
}
}
});
如果合並過程中有沖突會有提示,並自動剔除沖突的屬性;比如下方同一個作者寫的書,一個對象裡描述“賣得好”,而在另外一個對象裡卻描述“賣得差”,明顯是有問題的:
var writer = new Schema('writers'),
book = new Schema('books'),
schema = arrayOf(writer),
input;
writer.define({
books: arrayOf(book)
});
input = [{
id: 3,
name: 'Jo Rowling',
books: [{
id: 1,
soldWell: true,
name: 'Harry Potter'
}]
}, {
id: 3,
name: 'Jo Rowling',
books: [{
id: 1,
soldWell: false,
name: 'Harry Potter'
}]
}];
var warnCalled = false,
realConsoleWarn;
function mockWarn() {
warnCalled = true;
}
realConsoleWarn = console.warn;
console.warn = mockWarn;
normalize(input, schema).should.eql({
result: [3, 3],
entities: {
writers: {
3: {
id: 3,
name: 'Jo Rowling',
books: [1]
}
},
books: {
1: {
id: 1,
soldWell: true,
name: 'Harry Potter'
}
}
}
});
warnCalled.should.eq(true);
console.warn = realConsoleWarn;
如果應用的schma規范不存在,你還傳入,就會創建一個新的父屬性:
var writer = new Schema('writers'),
schema = writer,
input;
input = {
id: 'constructor',
name: 'Constructor',
isAwesome: true
};
normalize(input, schema).should.eql({
result: 'constructor',
entities: {
writers: {
constructor: {
id: 'constructor',
name: 'Constructor',
isAwesome: true
}
}
}