-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathremoveUnusedAttributes.js
139 lines (139 loc) · 5.46 KB
/
removeUnusedAttributes.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
exports.__esModule = true;
var graphql_sequelize_1 = require("graphql-sequelize");
/**
* This functions returns the findOptions for a findAll/One with only the attributes required in the info.
* By default all attributes are always fetched.
*
* @param {*} findOptions
* @param {*} info
* @param {Array<string>} keep An array of all the attributes to keep
*/
function removeUnusedAttributes(findOptions, info, currentModel, models, keep) {
if (keep === void 0) { keep = []; }
var fieldNodes = info.fieldNodes;
if (!fieldNodes) {
return findOptions;
}
var ast = (0, graphql_sequelize_1.simplifyAST)(fieldNodes[0], info);
var linkFields = [];
/**
* This reduce is made to add the attributes required to fetch
* sub objects. This part of the code not responsible for the parents.
* For exemple if the "id" of car is not selected, it will not be handled here
* but on the next step.
*
* Example :
* user {
* id
* // carId
* car {
* id
* }
* }
*
* If carId is not asked in the GraphQL query, we must still include it so
* that the reconcilier can match the car with the user.
*
*/
var attributes = Object.keys(ast.fields).filter(function (attribute) {
// The typename field is a key metadata and must always be returned if asked
if (attribute === '__typename') {
return false;
}
// We check if the field is a leef or an entity
if (Object.keys(ast.fields[attribute].fields).length > 0) {
// If the field is an entity we check if we find the association
if (models[currentModel.name].associations[attribute]) {
var association = models[currentModel.name].associations[attribute];
// If so we add the foreignKey to the list of fields to fetch.
// Without it the sub-entities will not be fetched
if (['HasOne', 'HasMany', 'BelongsToMany'].includes(association.associationType)) {
linkFields.push(association.sourceKey);
}
else if (['BelongsTo'].includes(association.associationType)) {
linkFields.push(association.foreignKey);
}
else {
throw new Error("removeUnusedAttributes does not support his association: ".concat(association.associationType, " for entity ").concat(currentModel.name, "/").concat(association.as));
}
}
// In any case, the entity name as attribute is not returned.
return false;
}
return true;
});
/**
* This part of the code is in charge of adding information required to be fetched
* to match with the parent object.
*
* Example :
* user {
* id
* cars {
* id
* // userId
* }
* }
*
* If userId is not asked in the GraphQL query, we must still include it so
* that the reconcilier can match the cars with the user.
*
*/
var parentModelReferenceAttributes = [];
// The relation can be direct
if (currentModel.associations[info.parentType.name]) {
if (currentModel.associations[info.parentType.name].associationType ===
'BelongsTo') {
parentModelReferenceAttributes.push(currentModel.associations[info.parentType.name].foreignKey);
}
// @todo add more cases as they are used
}
// Or indirect
if (models[info.parentType.name] &&
models[info.parentType.name].associations[info.fieldName]) {
if (['HasMany', 'HasOne'].includes(models[info.parentType.name].associations[info.fieldName]
.associationType)) {
parentModelReferenceAttributes.push(models[info.parentType.name].associations[info.fieldName].foreignKey);
}
// @todo add more cases as they are used
}
return __assign(__assign({}, findOptions), { attributes: __spreadArray([], __read(new Set(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], __read(attributes), false), __read(linkFields), false), __read(parentModelReferenceAttributes), false), __read(keep), false))), false) });
}
exports["default"] = removeUnusedAttributes;