-
Notifications
You must be signed in to change notification settings - Fork 19
/
redux-object.js
108 lines (82 loc) · 2.69 KB
/
redux-object.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* eslint no-use-before-define: [1, 'nofunc'] */
function uniqueId(objectName, id) {
if (!id) {
return null;
}
return `${objectName}${id}`;
}
function buildRelationship(reducer, target, relationship, options, cache) {
const { ignoreLinks } = options;
const rel = target.relationships[relationship];
if (typeof rel.data !== 'undefined') {
if (Array.isArray(rel.data)) {
return rel.data.map(child => build(reducer, child.type, child.id, options, cache) || child);
} else if (rel.data === null) {
return null;
}
return build(reducer, rel.data.type, rel.data.id, options, cache) || rel.data;
} else if (!ignoreLinks && rel.links) {
throw new Error('Remote lazy loading is not supported (see: https://github.com/yury-dymov/json-api-normalizer/issues/2). To disable this error, include option \'ignoreLinks: true\' in the build function like so: build(reducer, type, id, { ignoreLinks: true })');
}
return undefined;
}
export default function build(reducer, objectName, id = null, providedOpts = {}, cache = {}) {
const defOpts = { eager: false, ignoreLinks: false, includeType: false };
const options = Object.assign({}, defOpts, providedOpts);
const { eager, includeType } = options;
if (!reducer[objectName]) {
return null;
}
if (id === null || Array.isArray(id)) {
const idList = id || Object.keys(reducer[objectName]);
return idList.map(e => build(reducer, objectName, e, options, cache));
}
const ids = id.toString();
const uuid = uniqueId(objectName, ids);
const cachedObject = cache[uuid];
if (cachedObject) {
return cachedObject;
}
const ret = {};
const target = reducer[objectName][ids];
if (!target) {
return null;
}
if (target.id) {
ret.id = target.id;
}
Object.keys(target.attributes).forEach((key) => { ret[key] = target.attributes[key]; });
if (target.meta) {
ret.meta = target.meta;
}
if (includeType && !ret.type) {
ret.type = objectName;
}
cache[uuid] = ret;
if (target.relationships) {
Object.keys(target.relationships).forEach((relationship) => {
if (eager) {
ret[relationship] = buildRelationship(reducer, target, relationship, options, cache);
} else {
Object.defineProperty(
ret,
relationship,
{
get: () => {
const field = `__${relationship}`;
if (ret[field]) {
return ret[field];
}
ret[field] = buildRelationship(reducer, target, relationship, options, cache);
return ret[field];
},
},
);
}
});
}
if (typeof ret.id === 'undefined') {
ret.id = ids;
}
return ret;
}