nodester 0.1.0 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +3 -2
- package/lib/application/index.js +1 -1
- package/lib/body/extract.js +78 -0
- package/lib/constants/ErrorCodes.js +19 -0
- package/lib/constants/Operations.js +1 -1
- package/lib/controllers/mixins/index.js +59 -20
- package/lib/facades/methods/index.js +16 -10
- package/lib/factories/errors/CustomError.js +7 -0
- package/lib/factories/errors/NodesterQueryError.js +23 -0
- package/lib/factories/errors/index.js +10 -3
- package/lib/{queries/Colander.js → filters/Filter.js} +37 -12
- package/lib/http/codes/descriptions.js +82 -0
- package/lib/http/codes/index.js +70 -145
- package/lib/http/codes/symbols.js +82 -0
- package/lib/loggers/dev.js +28 -0
- package/lib/middlewares/ql/sequelize/index.js +2 -2
- package/lib/middlewares/ql/sequelize/interpreter/ModelsTree.js +24 -1
- package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +67 -15
- package/lib/models/define.js +7 -4
- package/lib/models/mixins.js +1 -1
- package/lib/{queries → query}/traverse.js +108 -30
- package/lib/router/index.js +3 -3
- package/lib/router/routes.util.js +5 -1
- package/lib/stacks/MarkersStack.js +1 -1
- package/lib/stacks/MiddlewareStack.js +1 -1
- package/lib/utils/models.js +14 -0
- package/package.json +28 -4
- package/lib/preprocessors/BodyPreprocessor.js +0 -61
- package/lib/preprocessors/IncludesPreprocessor.js +0 -55
- package/lib/preprocessors/QueryPreprocessor.js +0 -64
- package/lib/queries/NodesterQueryParams.js +0 -139
- /package/lib/{logger → loggers}/console.js +0 -0
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
1
7
|
const { Op } = require('sequelize');
|
|
8
|
+
const NQueryError = require('../factories/errors/NodesterQueryError');
|
|
9
|
+
const httpCodes = require('nodester/http/codes');
|
|
2
10
|
|
|
3
11
|
|
|
4
12
|
module.exports = traverse;
|
|
5
13
|
|
|
6
|
-
function traverse(queryNode,
|
|
14
|
+
function traverse(queryNode, filter=null, model) {
|
|
7
15
|
|
|
16
|
+
const sequelize = model.sequelize;
|
|
8
17
|
const fieldsAvailable = Object.keys(model.tableAttributes);
|
|
9
18
|
const includesAvailable = model.getIncludesList();
|
|
10
19
|
|
|
@@ -18,15 +27,16 @@ function traverse(queryNode, colander=null, model) {
|
|
|
18
27
|
where,
|
|
19
28
|
includes,
|
|
20
29
|
fields,
|
|
30
|
+
functions,
|
|
21
31
|
clauses,
|
|
22
32
|
} = _disassembleQueryNode(queryNode);
|
|
23
33
|
|
|
24
34
|
|
|
25
35
|
// Fields:
|
|
26
36
|
//
|
|
27
|
-
// If
|
|
37
|
+
// If Filter is not set,
|
|
28
38
|
// use every available field:
|
|
29
|
-
if (
|
|
39
|
+
if (filter === null) {
|
|
30
40
|
for (let field of fieldsAvailable) {
|
|
31
41
|
// If no query filter or field is requested:
|
|
32
42
|
if (fields.length === 0 || fields.indexOf(field) > -1) {
|
|
@@ -35,20 +45,21 @@ function traverse(queryNode, colander=null, model) {
|
|
|
35
45
|
}
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
|
-
//
|
|
48
|
+
// Filter is present:
|
|
39
49
|
else {
|
|
40
50
|
// If no query fields were set,
|
|
41
|
-
// use the ones from
|
|
51
|
+
// use the ones from Filter,
|
|
42
52
|
// If query fields were set,
|
|
43
|
-
// put them through
|
|
44
|
-
for (let field of
|
|
53
|
+
// put them through Filter:
|
|
54
|
+
for (let field of filter.fields) {
|
|
45
55
|
if (fieldsAvailable.indexOf(field) === -1) {
|
|
46
|
-
const err = new TypeError(`
|
|
56
|
+
const err = new TypeError(`Field '${ field }' is not present in model.`);
|
|
57
|
+
err.status = httpCodes.NOT_ACCEPTABLE;
|
|
47
58
|
throw err;
|
|
48
59
|
}
|
|
49
60
|
|
|
50
61
|
// If field is not in available set:
|
|
51
|
-
// if (
|
|
62
|
+
// if (filter.fields.indexOf(field) === -1) {
|
|
52
63
|
// continue;
|
|
53
64
|
// }
|
|
54
65
|
|
|
@@ -63,10 +74,61 @@ function traverse(queryNode, colander=null, model) {
|
|
|
63
74
|
// At least 1 field is mandatory:
|
|
64
75
|
if (newQuery.attributes.length === 0) {
|
|
65
76
|
const err = new TypeError(`No fields were selected.`);
|
|
77
|
+
err.status = httpCodes.NOT_ACCEPTABLE;
|
|
66
78
|
throw err;
|
|
67
79
|
}
|
|
68
80
|
// Fields\
|
|
69
81
|
|
|
82
|
+
// Functions:
|
|
83
|
+
for (const fnParams of functions) {
|
|
84
|
+
|
|
85
|
+
// If COUNT() is requested:
|
|
86
|
+
if (fnParams.fn === 'count') {
|
|
87
|
+
const countParams = fnParams.args;
|
|
88
|
+
|
|
89
|
+
const [ countTarget ] = countParams;
|
|
90
|
+
const RootModelName = model.options.name;
|
|
91
|
+
// Count can be requested for this model,
|
|
92
|
+
// or for any of the available uncludes.
|
|
93
|
+
const isForRootModel = countTarget === RootModelName.plural.toLowerCase();
|
|
94
|
+
|
|
95
|
+
// Compile request:
|
|
96
|
+
// Example:
|
|
97
|
+
// `(SELECT COUNT(*) FROM comments WHERE comments.morph_id=Morph.id)`
|
|
98
|
+
|
|
99
|
+
// Params for attribute:
|
|
100
|
+
let rawSQL = '(SELECT COUNT(*) FROM ';
|
|
101
|
+
let countAttribute = '_count';
|
|
102
|
+
|
|
103
|
+
// If request to count one of includes:
|
|
104
|
+
if (!isForRootModel) {
|
|
105
|
+
// Check if it's available:
|
|
106
|
+
if (
|
|
107
|
+
!filter
|
|
108
|
+
||
|
|
109
|
+
!filter?.includes[countTarget]
|
|
110
|
+
||
|
|
111
|
+
model.associations[countTarget] === undefined
|
|
112
|
+
) {
|
|
113
|
+
const err = new NQueryError(`Count for '${ countTarget }' is not available.`);
|
|
114
|
+
err.status = httpCodes.NOT_ACCEPTABLE;
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const {
|
|
119
|
+
foreignKey,
|
|
120
|
+
sourceKey
|
|
121
|
+
} = model.associations[countTarget];
|
|
122
|
+
rawSQL += `${ countTarget } where ${ countTarget }.${ foreignKey }=${ RootModelName.singular }.${ sourceKey })`;
|
|
123
|
+
countAttribute = `${ countTarget }_count`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
newQuery.attributes.push(
|
|
127
|
+
[sequelize.literal(rawSQL), countAttribute]
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Functions\
|
|
70
132
|
|
|
71
133
|
// Clauses:
|
|
72
134
|
const order = {};
|
|
@@ -74,8 +136,8 @@ function traverse(queryNode, colander=null, model) {
|
|
|
74
136
|
const clausesEntries = Object.entries(clauses);
|
|
75
137
|
for (let [clauseName, value] of clausesEntries) {
|
|
76
138
|
// If clause is not available:
|
|
77
|
-
if (
|
|
78
|
-
if (
|
|
139
|
+
if (filter != null) {
|
|
140
|
+
if (filter.clauses.indexOf(clauseName) === -1)
|
|
79
141
|
continue;
|
|
80
142
|
}
|
|
81
143
|
|
|
@@ -87,6 +149,7 @@ function traverse(queryNode, colander=null, model) {
|
|
|
87
149
|
|
|
88
150
|
newQuery.limit = value;
|
|
89
151
|
continue;
|
|
152
|
+
|
|
90
153
|
case 'skip':
|
|
91
154
|
// Do not set if 0:
|
|
92
155
|
if (value === 0)
|
|
@@ -94,20 +157,27 @@ function traverse(queryNode, colander=null, model) {
|
|
|
94
157
|
|
|
95
158
|
newQuery.offset = value;
|
|
96
159
|
continue;
|
|
160
|
+
|
|
97
161
|
case 'order':
|
|
98
162
|
order.order = value;
|
|
99
163
|
continue;
|
|
164
|
+
|
|
100
165
|
case 'order_by':
|
|
101
166
|
order.by = value;
|
|
102
167
|
continue;
|
|
168
|
+
|
|
103
169
|
default:
|
|
104
170
|
continue;
|
|
105
171
|
}
|
|
106
172
|
}
|
|
107
173
|
|
|
108
174
|
// "statics" override or set any query Clause:
|
|
109
|
-
if (
|
|
110
|
-
|
|
175
|
+
if (filter !== null) {
|
|
176
|
+
const staticClausesEntries = Object.entries(filter.statics.clauses);
|
|
177
|
+
|
|
178
|
+
for (let entry of staticClausesEntries) {
|
|
179
|
+
const [clauseName, staticClauseValue] = entry;
|
|
180
|
+
|
|
111
181
|
switch(clauseName) {
|
|
112
182
|
case 'limit':
|
|
113
183
|
newQuery.limit = staticClauseValue;
|
|
@@ -130,7 +200,6 @@ function traverse(queryNode, colander=null, model) {
|
|
|
130
200
|
|
|
131
201
|
|
|
132
202
|
// Order:
|
|
133
|
-
const sequelize = model.sequelize;
|
|
134
203
|
if ( ['rand', 'random'].indexOf(order.order) > -1) {
|
|
135
204
|
newQuery.order = sequelize.random();
|
|
136
205
|
}
|
|
@@ -150,6 +219,11 @@ function traverse(queryNode, colander=null, model) {
|
|
|
150
219
|
break;
|
|
151
220
|
// MAX/MIN\
|
|
152
221
|
|
|
222
|
+
case null:
|
|
223
|
+
case undefined:
|
|
224
|
+
newQuery.order = [ ['id', 'desc'] ];
|
|
225
|
+
break;
|
|
226
|
+
|
|
153
227
|
default:
|
|
154
228
|
newQuery.order = [ [order.by, order.order] ];
|
|
155
229
|
break;
|
|
@@ -166,21 +240,22 @@ function traverse(queryNode, colander=null, model) {
|
|
|
166
240
|
|
|
167
241
|
const includeIndex = leftIncludes.indexOf(includeName);
|
|
168
242
|
if (includeIndex === -1) {
|
|
169
|
-
const err = new TypeError(`No include named ${ includeName }`);
|
|
243
|
+
const err = new TypeError(`No include named '${ includeName }'`);
|
|
244
|
+
err.status = httpCodes.NOT_ACCEPTABLE;
|
|
170
245
|
throw err;
|
|
171
246
|
}
|
|
172
247
|
|
|
173
248
|
leftIncludes.splice(includeIndex, 1);
|
|
174
249
|
}
|
|
175
250
|
|
|
176
|
-
_traverseIncludes(includes, model,
|
|
251
|
+
_traverseIncludes(includes, model, filter, newQuery)
|
|
177
252
|
// Includes\
|
|
178
253
|
|
|
179
254
|
|
|
180
255
|
// Where:
|
|
181
256
|
const whereEntries = Object.entries(where);
|
|
182
257
|
for (let [attribute, value] of whereEntries) {
|
|
183
|
-
_parseWhereEntry(attribute, value, newQuery.where,
|
|
258
|
+
_parseWhereEntry(attribute, value, newQuery.where, filter.statics.attributes);
|
|
184
259
|
}
|
|
185
260
|
|
|
186
261
|
// If "where" was not set:
|
|
@@ -189,21 +264,21 @@ function traverse(queryNode, colander=null, model) {
|
|
|
189
264
|
}
|
|
190
265
|
// Where\
|
|
191
266
|
|
|
192
|
-
|
|
193
267
|
return newQuery;
|
|
194
268
|
}
|
|
195
269
|
|
|
196
270
|
|
|
197
|
-
function _traverseIncludes(includes, model,
|
|
198
|
-
// If no
|
|
199
|
-
if (
|
|
271
|
+
function _traverseIncludes(includes, model, filter=null, resultQuery) {
|
|
272
|
+
// If no Filter:
|
|
273
|
+
if (filter === null) {
|
|
200
274
|
for (let include of includes) {
|
|
201
275
|
const includeName = include.model;
|
|
202
276
|
const association = model.associations[includeName];
|
|
203
277
|
|
|
204
278
|
// If no such association:
|
|
205
279
|
if (!association) {
|
|
206
|
-
const err = new TypeError(`No include ${ includeName }`);
|
|
280
|
+
const err = new TypeError(`No include '${ includeName }'`);
|
|
281
|
+
err.status = httpCodes.NOT_ACCEPTABLE;
|
|
207
282
|
throw err;
|
|
208
283
|
}
|
|
209
284
|
|
|
@@ -214,14 +289,15 @@ function _traverseIncludes(includes, model, colander, resultQuery) {
|
|
|
214
289
|
_addAssociationQuery(associationQuery, includeName, resultQuery);
|
|
215
290
|
}
|
|
216
291
|
}
|
|
217
|
-
//
|
|
292
|
+
// Filter is present:
|
|
218
293
|
else {
|
|
219
|
-
const
|
|
220
|
-
for (let [includeName,
|
|
294
|
+
const filterIncludeEntries = Object.entries(filter.includes);
|
|
295
|
+
for (let [includeName, includeFilter] of filterIncludeEntries) {
|
|
221
296
|
const association = model.associations[includeName];
|
|
222
297
|
// If no such association:
|
|
223
298
|
if (!association) {
|
|
224
299
|
const err = new TypeError(`No include ${ includeName }`);
|
|
300
|
+
err.status = httpCodes.NOT_ACCEPTABLE;
|
|
225
301
|
throw err;
|
|
226
302
|
}
|
|
227
303
|
|
|
@@ -232,7 +308,7 @@ function _traverseIncludes(includes, model, colander, resultQuery) {
|
|
|
232
308
|
|
|
233
309
|
const includeModel = association.target;
|
|
234
310
|
// Build query for this include.
|
|
235
|
-
const associationQuery = traverse(include,
|
|
311
|
+
const associationQuery = traverse(include, filter.includes[includeName], includeModel);
|
|
236
312
|
|
|
237
313
|
_addAssociationQuery(associationQuery, includeName, resultQuery);
|
|
238
314
|
}
|
|
@@ -252,9 +328,9 @@ function _addAssociationQuery(associationQuery, includeName, resultQuery) {
|
|
|
252
328
|
|
|
253
329
|
function _parseWhereEntry(attribute, value, whereHolder, staticAttributes) {
|
|
254
330
|
let _value = value;
|
|
255
|
-
const
|
|
331
|
+
const staticAttribute = staticAttributes[attribute];
|
|
256
332
|
|
|
257
|
-
// If attribute is Op (like, or,
|
|
333
|
+
// If attribute is Op (not, like, or, etc.):
|
|
258
334
|
if (attribute in Op) {
|
|
259
335
|
// Parse value:
|
|
260
336
|
_value = _parseValue(_value, attribute);
|
|
@@ -265,8 +341,8 @@ function _parseWhereEntry(attribute, value, whereHolder, staticAttributes) {
|
|
|
265
341
|
}
|
|
266
342
|
|
|
267
343
|
// Static value overrides any other:
|
|
268
|
-
if (!!
|
|
269
|
-
whereHolder[attribute] =
|
|
344
|
+
if (!!staticAttribute) {
|
|
345
|
+
whereHolder[attribute] = staticAttribute;
|
|
270
346
|
return;
|
|
271
347
|
}
|
|
272
348
|
|
|
@@ -279,6 +355,7 @@ function _disassembleQueryNode(queryNode) {
|
|
|
279
355
|
where,
|
|
280
356
|
includes,
|
|
281
357
|
fields,
|
|
358
|
+
functions,
|
|
282
359
|
...clauses
|
|
283
360
|
} = queryNode;
|
|
284
361
|
// delete queryNode.model;
|
|
@@ -287,6 +364,7 @@ function _disassembleQueryNode(queryNode) {
|
|
|
287
364
|
where: where ?? {},
|
|
288
365
|
includes: includes ?? [],
|
|
289
366
|
fields: fields ?? [],
|
|
367
|
+
functions: functions ?? [],
|
|
290
368
|
clauses: clauses ?? []
|
|
291
369
|
};
|
|
292
370
|
}
|
package/lib/router/index.js
CHANGED
|
@@ -22,7 +22,7 @@ const Path = require('path');
|
|
|
22
22
|
const fs = require('fs');
|
|
23
23
|
const commonExtensions = require('common-js-file-extensions');
|
|
24
24
|
// Debug & console:
|
|
25
|
-
const consl = require('
|
|
25
|
+
const consl = require('nodester/loggers/console');
|
|
26
26
|
const debug = require('debug')('nodester:router');
|
|
27
27
|
|
|
28
28
|
|
|
@@ -257,7 +257,7 @@ module.exports = class NodesterRouter {
|
|
|
257
257
|
const handlerType = typeOf(handler);
|
|
258
258
|
|
|
259
259
|
if (handlerType === 'Object' && !this.paths.controllers && !this.paths.providers) {
|
|
260
|
-
const msg = `Please set
|
|
260
|
+
const msg = `Please set 'controllersPath' or 'providersPath' during Router initialization.`;
|
|
261
261
|
const err = new TypeError(msg);
|
|
262
262
|
throw err;
|
|
263
263
|
}
|
|
@@ -396,7 +396,7 @@ module.exports = class NodesterRouter {
|
|
|
396
396
|
extend(key='', fnOrProperty) {
|
|
397
397
|
const keys = Object.keys(this);
|
|
398
398
|
if (keys.indexOf(key) > -1) {
|
|
399
|
-
const err = new TypeError(`Key ${ key } is already present in Router instance
|
|
399
|
+
const err = new TypeError(`Key '${ key }' is already present in Router instance.`);
|
|
400
400
|
throw err;
|
|
401
401
|
}
|
|
402
402
|
|
|
@@ -88,7 +88,11 @@ function _wrapRouteHandler(routeInstance, handler) {
|
|
|
88
88
|
await parsedHandler.before(req.nquery, req, res);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
// If response was not sent,
|
|
92
|
+
// perform action
|
|
93
|
+
if (res.headersSent === false) {
|
|
94
|
+
await providedAction(req, res);
|
|
95
|
+
}
|
|
92
96
|
}
|
|
93
97
|
};
|
|
94
98
|
|
package/package.json
CHANGED
|
@@ -1,30 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodester",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "A boilerplate framework for Node.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./lib/application/index.js",
|
|
7
|
+
|
|
8
|
+
"./body/extract": "./lib/body/extract.js",
|
|
9
|
+
|
|
10
|
+
"./constants/ErrorCodes": "./lib/constants/ErrorCodes.js",
|
|
11
|
+
|
|
7
12
|
"./controllers/methods": "./lib/controllers/methods/index.js",
|
|
8
13
|
"./controllers/mixins": "./lib/controllers/mixins/index.js",
|
|
14
|
+
|
|
9
15
|
"./database/connection": "./lib/database/connection.js",
|
|
10
16
|
"./database/migration": "./lib/database/migration.js",
|
|
11
17
|
"./database/utils": "./lib/database/utils.js",
|
|
18
|
+
|
|
12
19
|
"./enum": "./lib/enums/Enum.js",
|
|
20
|
+
|
|
13
21
|
"./facades/methods": "./lib/facades/methods/index.js",
|
|
14
22
|
"./facades/mixins": "./lib/facades/mixins/index.js",
|
|
23
|
+
|
|
15
24
|
"./factories/errors": "./lib/factories/errors/index.js",
|
|
16
25
|
"./factories/responses/rest": "./lib/factories/responses/rest/index.js",
|
|
26
|
+
|
|
27
|
+
"./filter": "./lib/filters/Filter.js",
|
|
28
|
+
|
|
17
29
|
"./http/codes": "./lib/http/codes/index.js",
|
|
30
|
+
"./http/codes/descriptions": "./lib/http/codes/descriptions.js",
|
|
31
|
+
"./http/codes/symbols": "./lib/http/codes/symbols.js",
|
|
32
|
+
|
|
33
|
+
"./loggers/console": "./lib/loggers/console.js",
|
|
34
|
+
"./loggers/dev": "./lib/loggers/dev.js",
|
|
35
|
+
|
|
18
36
|
"./middlewares/formidable": "./lib/middlewares/formidable/index.js",
|
|
37
|
+
|
|
19
38
|
"./models/associate": "./lib/models/associate.js",
|
|
20
39
|
"./models/define": "./lib/models/define.js",
|
|
40
|
+
|
|
21
41
|
"./params": "./lib/params/Params.js",
|
|
42
|
+
|
|
22
43
|
"./ql/sequelize": "./lib/middlewares/ql/sequelize",
|
|
23
|
-
"./
|
|
24
|
-
|
|
44
|
+
"./query/traverse": "./lib/query/traverse.js",
|
|
45
|
+
|
|
25
46
|
"./route": "./lib/router/route.js",
|
|
26
47
|
"./router": "./lib/router/index.js",
|
|
27
|
-
|
|
48
|
+
|
|
49
|
+
"./utils/sql": "./lib/utils/sql.util.js",
|
|
50
|
+
"./utils/strings": "./lib/utils/strings.util.js",
|
|
51
|
+
"./utils/sanitizations": "./lib/utils/sanitizations.util.js"
|
|
28
52
|
},
|
|
29
53
|
"directories": {
|
|
30
54
|
"doc": "docs"
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// Constants.
|
|
2
|
-
const VISITOR = 'visitor';
|
|
3
|
-
|
|
4
|
-
// Custom error.
|
|
5
|
-
const { Err } = require('nodester/factories/errors');
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
module.exports = class BodyPreprocessor {
|
|
9
|
-
constructor(
|
|
10
|
-
availableParamsForRoles,
|
|
11
|
-
staticParamsForRoles,
|
|
12
|
-
customProcessFunction
|
|
13
|
-
) {
|
|
14
|
-
this.availableParamsForRoles = availableParamsForRoles ?? {};
|
|
15
|
-
this.staticParamsForRoles = staticParamsForRoles ?? {};
|
|
16
|
-
|
|
17
|
-
this.customProcessFunction = customProcessFunction ? customProcessFunction : ()=>{};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async extract(
|
|
21
|
-
req,
|
|
22
|
-
role
|
|
23
|
-
) {
|
|
24
|
-
try {
|
|
25
|
-
const requestBody = req.body;
|
|
26
|
-
|
|
27
|
-
if (!requestBody || typeof requestBody !== 'object') {
|
|
28
|
-
const err = new Err();
|
|
29
|
-
err.name = 'ValidationError';
|
|
30
|
-
throw err;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Get role or set "visitor"
|
|
34
|
-
const _role = typeof role === 'string' && role.length > 1 ? role : VISITOR;
|
|
35
|
-
|
|
36
|
-
const resultBody = {};
|
|
37
|
-
|
|
38
|
-
const params = this.availableParamsForRoles[_role] ?? [];
|
|
39
|
-
const staticValues = this.staticParamsForRoles[_role] ?? {};
|
|
40
|
-
|
|
41
|
-
params.forEach((param) => {
|
|
42
|
-
// If such param is set in body:
|
|
43
|
-
if (!!requestBody[param]) {
|
|
44
|
-
resultBody[param] = staticValues[param] ?? requestBody[param];
|
|
45
|
-
}
|
|
46
|
-
// If such param is not set, but we have a "static" for it:
|
|
47
|
-
else if (!requestBody[param] && !!staticValues[param]) {
|
|
48
|
-
resultBody[param] = staticValues[param];
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Make further preprocessing using customly defined function.
|
|
53
|
-
await this.customProcessFunction.call(this, req, role, resultBody);
|
|
54
|
-
|
|
55
|
-
return Promise.resolve(resultBody);
|
|
56
|
-
}
|
|
57
|
-
catch(error) {
|
|
58
|
-
return Promise.reject(error);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// Constants:
|
|
2
|
-
const VISITOR = 'visitor';
|
|
3
|
-
const DefaultAvailableParamsForRoles = { [VISITOR]: [] };
|
|
4
|
-
const DefaultStaticParamsForRoles = { [VISITOR]: [] };
|
|
5
|
-
|
|
6
|
-
// Custom error.
|
|
7
|
-
const { Err } = require('nodester/factories/errors');
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
module.exports = class IncludesPreprocessor {
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
availableParamsForRoles,
|
|
14
|
-
staticParamsForRoles,
|
|
15
|
-
customProcessFunction=()=>{}
|
|
16
|
-
) {
|
|
17
|
-
this.availableParamsForRoles = availableParamsForRoles ?? DefaultAvailableParamsForRoles;
|
|
18
|
-
this.staticParamsForRoles = staticParamsForRoles ?? DefaultStaticParamsForRoles;
|
|
19
|
-
|
|
20
|
-
this.customProcessFunction = customProcessFunction ? customProcessFunction : ()=>{};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async extract(
|
|
24
|
-
req,
|
|
25
|
-
role
|
|
26
|
-
) {
|
|
27
|
-
const requestIncludes = req.query?.includes ?? [];
|
|
28
|
-
|
|
29
|
-
if (!requestQuery || typeof requestQuery !== 'object') {
|
|
30
|
-
const err = new Err();
|
|
31
|
-
err.name = 'ValidationError';
|
|
32
|
-
throw err;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Get role or set "visitor"
|
|
36
|
-
const _role = typeof role === 'string' && role.length > 1 ? role : VISITOR;
|
|
37
|
-
|
|
38
|
-
const resultIncludes = [];
|
|
39
|
-
|
|
40
|
-
const params = this.availableParamsForRoles[_role] ?? [];
|
|
41
|
-
const staticValues = this.staticParamsForRoles[_role] ?? [];
|
|
42
|
-
|
|
43
|
-
params.forEach((param) => {
|
|
44
|
-
// If such param is set in query:
|
|
45
|
-
if (requestIncludes.indexOf(param) !== -1) {
|
|
46
|
-
resultIncludes.push(param);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// Make further preprocessing using custom defined function.
|
|
51
|
-
await this.customProcessFunction.call(this, req, role, resultIncludes);
|
|
52
|
-
|
|
53
|
-
return resultIncludes;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// Constants:
|
|
2
|
-
const VISITOR = 'visitor';
|
|
3
|
-
const DefaultAvailableParamsForRoles = { [VISITOR]: [ 'skip', 'limit', 'order' ] };
|
|
4
|
-
const DefaultStaticParamsForRoles = { [VISITOR]: { limit: 50 } };
|
|
5
|
-
|
|
6
|
-
// Custom error.
|
|
7
|
-
const { Err } = require('nodester/factories/errors');
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
module.exports = class QueryPreprocessor {
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
availableParamsForRoles,
|
|
14
|
-
staticParamsForRoles,
|
|
15
|
-
customProcessFunction
|
|
16
|
-
) {
|
|
17
|
-
this.availableParamsForRoles = availableParamsForRoles ?? DefaultAvailableParamsForRoles;
|
|
18
|
-
this.staticParamsForRoles = staticParamsForRoles ?? DefaultStaticParamsForRoles;
|
|
19
|
-
|
|
20
|
-
this.customProcessFunction = customProcessFunction ? customProcessFunction : ()=>{};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async extract(
|
|
24
|
-
req,
|
|
25
|
-
role
|
|
26
|
-
) {
|
|
27
|
-
try {
|
|
28
|
-
const requestQuery = req.query;
|
|
29
|
-
|
|
30
|
-
if (!requestQuery || typeof requestQuery !== 'object') {
|
|
31
|
-
const err = new Err();
|
|
32
|
-
err.name = 'ValidationError';
|
|
33
|
-
throw err;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Get role or set "visitor"
|
|
37
|
-
const _role = typeof role === 'string' && role.length > 1 ? role : [VISITOR];
|
|
38
|
-
|
|
39
|
-
const resultQuery = {};
|
|
40
|
-
|
|
41
|
-
const params = this.availableParamsForRoles[_role] ?? [];
|
|
42
|
-
const staticValues = this.staticParamsForRoles[_role] ?? {};
|
|
43
|
-
|
|
44
|
-
params.forEach((param) => {
|
|
45
|
-
// If such param is set in query:
|
|
46
|
-
if (!!requestQuery[param]) {
|
|
47
|
-
resultQuery[param] = staticValues[param] ?? requestQuery[param];
|
|
48
|
-
}
|
|
49
|
-
// If such param is not set, but we have a "static" for it:
|
|
50
|
-
else if (!requestQuery[param] && !!staticValues[param]) {
|
|
51
|
-
resultQuery[param] = staticValues[param];
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// Make further preprocessing using customly defined function.
|
|
56
|
-
await this.customProcessFunction.call(this, req, role, resultQuery);
|
|
57
|
-
|
|
58
|
-
return Promise.resolve(resultQuery);
|
|
59
|
-
}
|
|
60
|
-
catch(error) {
|
|
61
|
-
return Promise.reject(error);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|