nodester 0.0.9 → 0.1.4
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 +16 -2
- package/lib/application/index.js +29 -8
- package/lib/constants/ErrorCodes.js +19 -0
- package/lib/constants/Operations.js +1 -1
- package/lib/controllers/methods/index.js +34 -10
- package/lib/controllers/mixins/index.js +72 -24
- package/lib/database/connection.js +34 -0
- package/lib/database/migration.js +42 -0
- package/lib/database/utils.js +19 -0
- package/lib/facades/methods/index.js +180 -0
- package/lib/facades/mixins/index.js +111 -0
- 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/loggers/dev.js +28 -0
- package/lib/middlewares/formidable/index.js +37 -0
- package/lib/middlewares/ql/sequelize/interpreter/ModelsTree.js +26 -3
- package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +67 -15
- package/lib/models/define.js +49 -1
- package/lib/models/mixins.js +76 -67
- package/lib/params/Params.js +10 -7
- package/lib/queries/Colander.js +107 -0
- package/lib/queries/NodesterQueryParams.js +6 -0
- package/lib/queries/traverse.js +381 -0
- package/lib/router/handlers.util.js +22 -2
- package/lib/router/index.js +97 -76
- package/lib/router/markers.js +78 -0
- package/lib/router/route.js +4 -4
- package/lib/router/routes.util.js +35 -5
- package/lib/router/utils.js +30 -0
- package/lib/stacks/MarkersStack.js +1 -1
- package/lib/stacks/MiddlewareStack.js +1 -1
- package/lib/utils/models.js +14 -0
- package/package.json +36 -7
- package/tests/nql.test.js +3 -3
- package/lib/_/n_controllers/Controller.js +0 -474
- package/lib/_/n_controllers/JWTController.js +0 -240
- package/lib/_/n_controllers/ServiceController.js +0 -109
- package/lib/_/n_controllers/WebController.js +0 -75
- package/lib/_facades/Facade.js +0 -388
- package/lib/_facades/FacadeParams.js +0 -11
- package/lib/_facades/ServiceFacade.js +0 -17
- package/lib/_facades/jwt.facade.js +0 -273
- package/lib/models/Extractor.js +0 -320
- package/lib/preprocessors/IncludesPreprocessor.js +0 -55
- package/lib/preprocessors/QueryPreprocessor.js +0 -64
- package/lib/utils/forms.util.js +0 -22
- /package/lib/{logger → loggers}/console.js +0 -0
package/lib/params/Params.js
CHANGED
|
@@ -10,10 +10,9 @@ module.exports = Params;
|
|
|
10
10
|
* @param {Object} sourceObj
|
|
11
11
|
* @param {Object} defaultValuesList
|
|
12
12
|
*
|
|
13
|
-
* @return {
|
|
13
|
+
* @return {Object} result
|
|
14
14
|
*
|
|
15
15
|
* @api public
|
|
16
|
-
* @alias withDefaultCRUD
|
|
17
16
|
*/
|
|
18
17
|
function Params(
|
|
19
18
|
sourceObj={},
|
|
@@ -23,11 +22,15 @@ function Params(
|
|
|
23
22
|
|
|
24
23
|
const keys = Object.keys(defaultValuesList);
|
|
25
24
|
for (const key of keys) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
|
|
26
|
+
// If value is not set,
|
|
27
|
+
// use default one from 'defaultValuesList':
|
|
28
|
+
if (sourceObj[key] === undefined) {
|
|
29
|
+
result[key] = defaultValuesList[key];
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
result[key] = sourceObj[key];
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
return result;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const CLAUSES = ['limit', 'skip', 'order', 'order_by'];
|
|
8
|
+
|
|
9
|
+
const { isModel } = require('../utils/models');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
module.exports = class Colander {
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
*
|
|
16
|
+
* @param {Object|Model} optsOrModelDefinition
|
|
17
|
+
@ - @param {Model} model
|
|
18
|
+
* - @param {Array} fields
|
|
19
|
+
* - @param {Array} clauses
|
|
20
|
+
* - @param {Object} includes
|
|
21
|
+
* - @param {Object} statics
|
|
22
|
+
* -- @param {Object} attributes
|
|
23
|
+
* -- @param {Object} clauses
|
|
24
|
+
*
|
|
25
|
+
* @param {Boolean} noLimit
|
|
26
|
+
*
|
|
27
|
+
*/
|
|
28
|
+
constructor(optsOrModelDefinition, noLimit=false) {
|
|
29
|
+
this._fields = [];
|
|
30
|
+
this._clauses = [];
|
|
31
|
+
this._includes = {};
|
|
32
|
+
|
|
33
|
+
this._statics = {
|
|
34
|
+
attributes: {},
|
|
35
|
+
clauses: {
|
|
36
|
+
limit: 3
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (noLimit === true) {
|
|
40
|
+
delete this._statics.clauses.limit;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// If model:
|
|
44
|
+
if (isModel(optsOrModelDefinition)) {
|
|
45
|
+
this._fields = Object.keys(optsOrModelDefinition.tableAttributes);
|
|
46
|
+
this._clauses = CLAUSES;
|
|
47
|
+
}
|
|
48
|
+
// If options:
|
|
49
|
+
else {
|
|
50
|
+
const {
|
|
51
|
+
model,
|
|
52
|
+
fields,
|
|
53
|
+
clauses,
|
|
54
|
+
includes,
|
|
55
|
+
statics,
|
|
56
|
+
} = optsOrModelDefinition;
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// If fields are array:
|
|
60
|
+
if (Array.isArray(fields)) {
|
|
61
|
+
this._fields = fields;
|
|
62
|
+
}
|
|
63
|
+
// If fields were not provided,
|
|
64
|
+
// but we have full model definition:
|
|
65
|
+
else if (isModel(model)) {
|
|
66
|
+
this._fields = Object.keys(model.tableAttributes);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
if (Array.isArray(clauses)) {
|
|
71
|
+
this._clauses = clauses;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof includes === 'object') {
|
|
75
|
+
this._includes = includes;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (typeof statics === 'object') {
|
|
79
|
+
if (typeof statics.attributes === 'object') {
|
|
80
|
+
this._statics.attributes = statics.attributes;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (typeof statics.clauses === 'object') {
|
|
84
|
+
this._statics.clauses = statics.clauses;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Getters:
|
|
91
|
+
get fields() {
|
|
92
|
+
return this._fields;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get clauses() {
|
|
96
|
+
return this._clauses;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get includes() {
|
|
100
|
+
return this._includes;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get statics() {
|
|
104
|
+
return this._statics;
|
|
105
|
+
}
|
|
106
|
+
// Getters\
|
|
107
|
+
}
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const { Op } = require('sequelize');
|
|
8
|
+
const NQueryError = require('../factories/errors/NodesterQueryError');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
module.exports = traverse;
|
|
12
|
+
|
|
13
|
+
function traverse(queryNode, colander=null, model) {
|
|
14
|
+
|
|
15
|
+
const sequelize = model.sequelize;
|
|
16
|
+
const fieldsAvailable = Object.keys(model.tableAttributes);
|
|
17
|
+
const includesAvailable = model.getIncludesList();
|
|
18
|
+
|
|
19
|
+
const newQuery = {
|
|
20
|
+
attributes: [],
|
|
21
|
+
where: {},
|
|
22
|
+
include: []
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
where,
|
|
27
|
+
includes,
|
|
28
|
+
fields,
|
|
29
|
+
functions,
|
|
30
|
+
clauses,
|
|
31
|
+
} = _disassembleQueryNode(queryNode);
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
// Fields:
|
|
35
|
+
//
|
|
36
|
+
// If Colander is not set,
|
|
37
|
+
// use every available field:
|
|
38
|
+
if (colander === null) {
|
|
39
|
+
for (let field of fieldsAvailable) {
|
|
40
|
+
// If no query filter or field is requested:
|
|
41
|
+
if (fields.length === 0 || fields.indexOf(field) > -1) {
|
|
42
|
+
newQuery.attributes.push(field);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Colander is present:
|
|
48
|
+
else {
|
|
49
|
+
// If no query fields were set,
|
|
50
|
+
// use the ones from Colander,
|
|
51
|
+
// If query fields were set,
|
|
52
|
+
// put them through Colander:
|
|
53
|
+
for (let field of colander.fields) {
|
|
54
|
+
if (fieldsAvailable.indexOf(field) === -1) {
|
|
55
|
+
const err = new TypeError(`field ${ field } is not present in model.`);
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// If field is not in available set:
|
|
60
|
+
// if (colander.fields.indexOf(field) === -1) {
|
|
61
|
+
// continue;
|
|
62
|
+
// }
|
|
63
|
+
|
|
64
|
+
// If no query filter or field is requested:
|
|
65
|
+
if (fields.length === 0 || fields.indexOf(field) > -1) {
|
|
66
|
+
newQuery.attributes.push(field);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// At least 1 field is mandatory:
|
|
73
|
+
if (newQuery.attributes.length === 0) {
|
|
74
|
+
const err = new TypeError(`No fields were selected.`);
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
// Fields\
|
|
78
|
+
|
|
79
|
+
// Functions:
|
|
80
|
+
for (const fnParams of functions) {
|
|
81
|
+
|
|
82
|
+
// If COUNT() is requested:
|
|
83
|
+
if (fnParams.fn === 'count') {
|
|
84
|
+
const countParams = fnParams.args;
|
|
85
|
+
|
|
86
|
+
const [ countTarget ] = countParams;
|
|
87
|
+
const RootModelName = model.options.name;
|
|
88
|
+
// Count can be requested for this model,
|
|
89
|
+
// or for any of the available uncludes.
|
|
90
|
+
const isForRootModel = countTarget === RootModelName.plural.toLowerCase();
|
|
91
|
+
|
|
92
|
+
// Compile request:
|
|
93
|
+
// Example:
|
|
94
|
+
// `(SELECT COUNT(*) FROM comments WHERE comments.morph_id=Morph.id)`
|
|
95
|
+
|
|
96
|
+
// Params for attribute:
|
|
97
|
+
let rawSQL = '(SELECT COUNT(*) FROM ';
|
|
98
|
+
let countAttribute = '_count';
|
|
99
|
+
|
|
100
|
+
// If request to count one of includes:
|
|
101
|
+
if (!isForRootModel) {
|
|
102
|
+
// Check if it's available:
|
|
103
|
+
if (
|
|
104
|
+
!colander
|
|
105
|
+
||
|
|
106
|
+
!colander?.includes[countTarget]
|
|
107
|
+
||
|
|
108
|
+
model.associations[countTarget] === undefined
|
|
109
|
+
) {
|
|
110
|
+
const err = new NQueryError(`Count for ${ countTarget } is not available.`);
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const {
|
|
115
|
+
foreignKey,
|
|
116
|
+
sourceKey
|
|
117
|
+
} = model.associations[countTarget];
|
|
118
|
+
rawSQL += `${ countTarget } where ${ countTarget }.${ foreignKey }=${ RootModelName.singular }.${ sourceKey })`;
|
|
119
|
+
countAttribute = `${ countTarget }_count`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
newQuery.attributes.push(
|
|
123
|
+
[sequelize.literal(rawSQL), countAttribute]
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Functions\
|
|
128
|
+
|
|
129
|
+
// Clauses:
|
|
130
|
+
const order = {};
|
|
131
|
+
|
|
132
|
+
const clausesEntries = Object.entries(clauses);
|
|
133
|
+
for (let [clauseName, value] of clausesEntries) {
|
|
134
|
+
// If clause is not available:
|
|
135
|
+
if (colander != null) {
|
|
136
|
+
if (colander.clauses.indexOf(clauseName) === -1)
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
switch(clauseName) {
|
|
141
|
+
case 'limit':
|
|
142
|
+
// Do not set if -1:
|
|
143
|
+
if (value === -1)
|
|
144
|
+
continue;
|
|
145
|
+
|
|
146
|
+
newQuery.limit = value;
|
|
147
|
+
continue;
|
|
148
|
+
|
|
149
|
+
case 'skip':
|
|
150
|
+
// Do not set if 0:
|
|
151
|
+
if (value === 0)
|
|
152
|
+
continue;
|
|
153
|
+
|
|
154
|
+
newQuery.offset = value;
|
|
155
|
+
continue;
|
|
156
|
+
|
|
157
|
+
case 'order':
|
|
158
|
+
order.order = value;
|
|
159
|
+
continue;
|
|
160
|
+
|
|
161
|
+
case 'order_by':
|
|
162
|
+
order.by = value;
|
|
163
|
+
continue;
|
|
164
|
+
|
|
165
|
+
default:
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// "statics" override or set any query Clause:
|
|
171
|
+
if (colander !== null) {
|
|
172
|
+
const staticClausesEntries = Object.entries(colander.statics.clauses);
|
|
173
|
+
for (let entry of staticClausesEntries) {
|
|
174
|
+
const [clauseName, staticClauseValue] = entry;
|
|
175
|
+
|
|
176
|
+
switch(clauseName) {
|
|
177
|
+
case 'limit':
|
|
178
|
+
newQuery.limit = staticClauseValue;
|
|
179
|
+
continue;
|
|
180
|
+
case 'skip':
|
|
181
|
+
newQuery.offset = staticClauseValue;
|
|
182
|
+
continue;
|
|
183
|
+
case 'order':
|
|
184
|
+
order.order = staticClauseValue;
|
|
185
|
+
continue;
|
|
186
|
+
case 'order_by':
|
|
187
|
+
order.by = staticClauseValue;
|
|
188
|
+
continue;
|
|
189
|
+
default:
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Clauses\
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
// Order:
|
|
198
|
+
if ( ['rand', 'random'].indexOf(order.order) > -1) {
|
|
199
|
+
newQuery.order = sequelize.random();
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
const column = sequelize.col( order.by );
|
|
203
|
+
switch (order.order) {
|
|
204
|
+
// MAX/MIN:
|
|
205
|
+
case 'max-asc':
|
|
206
|
+
case 'max':
|
|
207
|
+
case 'min-desc':
|
|
208
|
+
newQuery.order = sequelize.fn('max', column);
|
|
209
|
+
break;
|
|
210
|
+
case 'min':
|
|
211
|
+
case 'min-asc':
|
|
212
|
+
case 'max-desc':
|
|
213
|
+
newQuery.order = [ sequelize.fn('max', column), 'DESC' ];
|
|
214
|
+
break;
|
|
215
|
+
// MAX/MIN\
|
|
216
|
+
|
|
217
|
+
case null:
|
|
218
|
+
case undefined:
|
|
219
|
+
newQuery.order = [ ['id', 'desc'] ];
|
|
220
|
+
break;
|
|
221
|
+
|
|
222
|
+
default:
|
|
223
|
+
newQuery.order = [ [order.by, order.order] ];
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Order\
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
// Includes:
|
|
231
|
+
// If requested includes are not available:
|
|
232
|
+
const leftIncludes = includesAvailable.map(i => i.association);
|
|
233
|
+
for (let include of includes) {
|
|
234
|
+
const includeName = include.model;
|
|
235
|
+
|
|
236
|
+
const includeIndex = leftIncludes.indexOf(includeName);
|
|
237
|
+
if (includeIndex === -1) {
|
|
238
|
+
const err = new TypeError(`No include named ${ includeName }`);
|
|
239
|
+
throw err;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
leftIncludes.splice(includeIndex, 1);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
_traverseIncludes(includes, model, colander, newQuery)
|
|
246
|
+
// Includes\
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
// Where:
|
|
250
|
+
const whereEntries = Object.entries(where);
|
|
251
|
+
for (let [attribute, value] of whereEntries) {
|
|
252
|
+
_parseWhereEntry(attribute, value, newQuery.where, colander.statics.attributes);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// If "where" was not set:
|
|
256
|
+
if (whereEntries.length === 0) {
|
|
257
|
+
delete newQuery.where;
|
|
258
|
+
}
|
|
259
|
+
// Where\
|
|
260
|
+
|
|
261
|
+
return newQuery;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
function _traverseIncludes(includes, model, colander, resultQuery) {
|
|
266
|
+
// If no Colander:
|
|
267
|
+
if (colander === null) {
|
|
268
|
+
for (let include of includes) {
|
|
269
|
+
const includeName = include.model;
|
|
270
|
+
const association = model.associations[includeName];
|
|
271
|
+
|
|
272
|
+
// If no such association:
|
|
273
|
+
if (!association) {
|
|
274
|
+
const err = new TypeError(`No include ${ includeName }`);
|
|
275
|
+
throw err;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const includeModel = association.target;
|
|
279
|
+
// Build query for this include.
|
|
280
|
+
const associationQuery = traverse(include, null, includeModel);
|
|
281
|
+
|
|
282
|
+
_addAssociationQuery(associationQuery, includeName, resultQuery);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Colander is present:
|
|
286
|
+
else {
|
|
287
|
+
const colanderIncludeEntries = Object.entries(colander.includes);
|
|
288
|
+
for (let [includeName, includeColander] of colanderIncludeEntries) {
|
|
289
|
+
const association = model.associations[includeName];
|
|
290
|
+
// If no such association:
|
|
291
|
+
if (!association) {
|
|
292
|
+
const err = new TypeError(`No include ${ includeName }`);
|
|
293
|
+
throw err;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// If include was not requested:
|
|
297
|
+
const include = includes.find(({ model }) => model === includeName);
|
|
298
|
+
if (!include)
|
|
299
|
+
continue;
|
|
300
|
+
|
|
301
|
+
const includeModel = association.target;
|
|
302
|
+
// Build query for this include.
|
|
303
|
+
const associationQuery = traverse(include, colander.includes[includeName], includeModel);
|
|
304
|
+
|
|
305
|
+
_addAssociationQuery(associationQuery, includeName, resultQuery);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
function _addAssociationQuery(associationQuery, includeName, resultQuery) {
|
|
312
|
+
|
|
313
|
+
// Add all association info into query.
|
|
314
|
+
resultQuery.include.push({
|
|
315
|
+
association: includeName,
|
|
316
|
+
...associationQuery
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
function _parseWhereEntry(attribute, value, whereHolder, staticAttributes) {
|
|
322
|
+
let _value = value;
|
|
323
|
+
const staticAttribute = staticAttributes[attribute];
|
|
324
|
+
|
|
325
|
+
// If attribute is Op (not, like, or, etc.):
|
|
326
|
+
if (attribute in Op) {
|
|
327
|
+
// Parse value:
|
|
328
|
+
_value = _parseValue(_value, attribute);
|
|
329
|
+
|
|
330
|
+
const op = Op[attribute];
|
|
331
|
+
whereHolder[op] = _value;
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Static value overrides any other:
|
|
336
|
+
if (!!staticAttribute) {
|
|
337
|
+
whereHolder[attribute] = staticAttribute;
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
whereHolder[attribute] = _parseValue(_value, attribute);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function _disassembleQueryNode(queryNode) {
|
|
345
|
+
// Disassemble current query node:
|
|
346
|
+
const {
|
|
347
|
+
where,
|
|
348
|
+
includes,
|
|
349
|
+
fields,
|
|
350
|
+
functions,
|
|
351
|
+
...clauses
|
|
352
|
+
} = queryNode;
|
|
353
|
+
// delete queryNode.model;
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
where: where ?? {},
|
|
357
|
+
includes: includes ?? [],
|
|
358
|
+
fields: fields ?? [],
|
|
359
|
+
functions: functions ?? [],
|
|
360
|
+
clauses: clauses ?? []
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function _parseValue(value, attribute) {
|
|
365
|
+
// If value is Object:
|
|
366
|
+
if (typeof value === 'object' && Array.isArray(value) === false) {
|
|
367
|
+
const [opKey, rawValue] = (Object.entries(value))[0];
|
|
368
|
+
|
|
369
|
+
// If operation is "in":
|
|
370
|
+
if (opKey === 'in') {
|
|
371
|
+
// Unwrap rawValue.
|
|
372
|
+
return rawValue[0][attribute];
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
const op = Op[opKey];
|
|
376
|
+
return { [op]: rawValue };
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return value;
|
|
381
|
+
}
|
|
@@ -26,19 +26,24 @@ function _parseRouteHandler(routeHandler={}) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const result = {
|
|
29
|
+
actionName: undefined,
|
|
29
30
|
before: null,
|
|
30
31
|
controllerName: undefined,
|
|
31
|
-
|
|
32
|
+
providerName: undefined
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
const {
|
|
36
|
+
action,
|
|
35
37
|
before,
|
|
36
38
|
|
|
37
39
|
controller,
|
|
38
40
|
controlledBy,
|
|
39
|
-
|
|
41
|
+
|
|
42
|
+
provider,
|
|
43
|
+
providedBy,
|
|
40
44
|
} = routeHandler;
|
|
41
45
|
|
|
46
|
+
// Controllers:
|
|
42
47
|
if (!!controlledBy) {
|
|
43
48
|
const parts = controlledBy.split('.');
|
|
44
49
|
const controllerName = parts[0];
|
|
@@ -49,6 +54,21 @@ function _parseRouteHandler(routeHandler={}) {
|
|
|
49
54
|
else if (!!controller) {
|
|
50
55
|
result.controllerName = `${ controller }`;
|
|
51
56
|
}
|
|
57
|
+
// Controllers\
|
|
58
|
+
|
|
59
|
+
// Providers:
|
|
60
|
+
else if (!!providedBy) {
|
|
61
|
+
const parts = providedBy.split('.');
|
|
62
|
+
const providerName = parts[0];
|
|
63
|
+
const actionName = parts[1];
|
|
64
|
+
result.providerName = providerName;
|
|
65
|
+
result.actionName = actionName;
|
|
66
|
+
}
|
|
67
|
+
else if (!!provider) {
|
|
68
|
+
result.providerName = `${ provider }`;
|
|
69
|
+
}
|
|
70
|
+
// Providers\
|
|
71
|
+
|
|
52
72
|
else if (!!action) {
|
|
53
73
|
result.actionName = `${ action }`;
|
|
54
74
|
}
|