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
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const {
|
|
2
|
+
getOne,
|
|
3
|
+
getMany,
|
|
4
|
+
createOne,
|
|
5
|
+
updateOne,
|
|
6
|
+
deleteOne
|
|
7
|
+
} = require('../methods');
|
|
8
|
+
// Utils,
|
|
9
|
+
const { lowerCaseFirstLetter } = require('nodester/utils/strings');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
withDefaultCRUD: _withDefaultCRUD,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Sets one of or all of CRUD methods to Facade.
|
|
18
|
+
*
|
|
19
|
+
* @param {Function|Object} facade
|
|
20
|
+
* @param {Object} opts
|
|
21
|
+
* - @param {Function|Object} model
|
|
22
|
+
* - @param {String} name
|
|
23
|
+
* - @param {Array} only
|
|
24
|
+
*
|
|
25
|
+
* @return {Function|Object} facade
|
|
26
|
+
*
|
|
27
|
+
* @api public
|
|
28
|
+
* @alias withDefaultCRUD
|
|
29
|
+
*/
|
|
30
|
+
function _withDefaultCRUD(facade, opts={}) {
|
|
31
|
+
const {
|
|
32
|
+
model,
|
|
33
|
+
|
|
34
|
+
// Optional:
|
|
35
|
+
name,
|
|
36
|
+
only
|
|
37
|
+
} = opts;
|
|
38
|
+
|
|
39
|
+
if (!facade) {
|
|
40
|
+
const err = new TypeError(`'facade' argument is not provided.`);
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Set model info:
|
|
45
|
+
// Set model:
|
|
46
|
+
Object.defineProperty(facade, 'model', {
|
|
47
|
+
value: model,
|
|
48
|
+
writable: false
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Model name:
|
|
52
|
+
const modelName = model.options.name;
|
|
53
|
+
Object.defineProperty(facade, 'modelName', {
|
|
54
|
+
value: {
|
|
55
|
+
singular: lowerCaseFirstLetter(modelName.singular),
|
|
56
|
+
plural: lowerCaseFirstLetter(modelName.plural)
|
|
57
|
+
},
|
|
58
|
+
writable: false
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// Set name of this facade:
|
|
63
|
+
Object.defineProperty(facade, 'name', {
|
|
64
|
+
value: name ?? `${ modelName.plural ?? facade.name }Facade`,
|
|
65
|
+
writable: false
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
// If only certain methods should be set:
|
|
70
|
+
if (!!only) {
|
|
71
|
+
for (const selectedMethod of only) {
|
|
72
|
+
switch(selectedMethod) {
|
|
73
|
+
case 'getOne':
|
|
74
|
+
facade.getOne = getOne.bind(facade);
|
|
75
|
+
break;
|
|
76
|
+
case 'getMany':
|
|
77
|
+
facade.getMany = getMany.bind(facade);
|
|
78
|
+
break;
|
|
79
|
+
case 'createOne':
|
|
80
|
+
facade.createOne = createOne.bind(facade);
|
|
81
|
+
break;
|
|
82
|
+
case 'updateOne':
|
|
83
|
+
facade.updateOne = updateOne.bind(facade);
|
|
84
|
+
break;
|
|
85
|
+
case 'deleteOne':
|
|
86
|
+
facade.deleteOne = deleteOne.bind(facade);
|
|
87
|
+
break;
|
|
88
|
+
|
|
89
|
+
default:
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Or set all methods:
|
|
95
|
+
else {
|
|
96
|
+
facade.getOne = getOne.bind(facade);
|
|
97
|
+
facade.getMany = getMany.bind(facade);
|
|
98
|
+
facade.createOne = createOne.bind(facade);
|
|
99
|
+
facade.updateOne = updateOne.bind(facade);
|
|
100
|
+
facade.deleteOne = deleteOne.bind(facade);
|
|
101
|
+
|
|
102
|
+
// Set empty hooks:
|
|
103
|
+
facade.afterGetOne = async () => {};
|
|
104
|
+
facade.afterGetMany = async () => {};
|
|
105
|
+
facade.afterCreateOne = async () => {};
|
|
106
|
+
facade.afterUpdateOne = async () => {};
|
|
107
|
+
facade.afterDeleteOe = async () => {};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return facade;
|
|
111
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
NODESTER_QUERY_ERROR,
|
|
10
|
+
} = require('nodester/constants/ErrorCodes');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
module.exports = class NodesterQueryError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
|
|
17
|
+
this.name = NODESTER_QUERY_ERROR;
|
|
18
|
+
this.status = 422;
|
|
19
|
+
|
|
20
|
+
// Remove constructor info from stack.
|
|
21
|
+
Error.captureStackTrace(this, this.constructor);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
3
4
|
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
|
|
4
9
|
const Err = require('./CustomError');
|
|
10
|
+
const NodesterQueryError = require('./NodesterQueryError');
|
|
5
11
|
|
|
6
12
|
|
|
7
13
|
module.exports = {
|
|
8
|
-
Err
|
|
14
|
+
Err,
|
|
15
|
+
NodesterQueryError
|
|
9
16
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
exports = module.exports = {
|
|
10
|
+
error: _error
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Log error using console.error.
|
|
15
|
+
*
|
|
16
|
+
* @param {Array} args
|
|
17
|
+
*
|
|
18
|
+
* @alias error
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
function _error(...args) {
|
|
23
|
+
const activeEnv = process.env.NODE_ENV
|
|
24
|
+
|
|
25
|
+
if (activeEnv === 'development' || activeEnv === 'testing') {
|
|
26
|
+
console.error(...args);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const { formidable } = require('formidable');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
module.exports = function FormidableMiddleware(formidableOptions={}) {
|
|
11
|
+
return async function(req, res, next) {
|
|
12
|
+
try {
|
|
13
|
+
const form = formidable(formidableOptions);
|
|
14
|
+
const [fields, files] = await form.parse(req);
|
|
15
|
+
|
|
16
|
+
// Add to request:
|
|
17
|
+
req.form = {
|
|
18
|
+
fields,
|
|
19
|
+
files
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
next();
|
|
23
|
+
}
|
|
24
|
+
catch(error) {
|
|
25
|
+
const statusCode = error.status || 406;
|
|
26
|
+
res.status(statusCode);
|
|
27
|
+
res.json({
|
|
28
|
+
error: {
|
|
29
|
+
message: error.message,
|
|
30
|
+
code: statusCode
|
|
31
|
+
},
|
|
32
|
+
status: statusCode
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
1
7
|
const debug = require('debug')('nodester:interpreter:ModelsTree');
|
|
2
8
|
|
|
3
9
|
|
|
@@ -7,16 +13,18 @@ class ModelsTreeNode {
|
|
|
7
13
|
this.parent = parent;
|
|
8
14
|
this.activeParam = null;
|
|
9
15
|
this.op = null;
|
|
16
|
+
this.fn = null;
|
|
10
17
|
|
|
11
18
|
// for override:
|
|
12
19
|
this.fields = [];
|
|
13
20
|
this._where = {};
|
|
21
|
+
this._functions = [];
|
|
14
22
|
this.skip = 0;
|
|
15
23
|
this.limit = -1; // No limit
|
|
16
24
|
|
|
17
25
|
this.includes = opts.includes ?? [];
|
|
18
26
|
this.order = opts.order ?? 'asc';
|
|
19
|
-
this.
|
|
27
|
+
this.order_by = opts.order_by ?? 'id';
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
get hasParent() {
|
|
@@ -35,6 +43,10 @@ class ModelsTreeNode {
|
|
|
35
43
|
return this._where;
|
|
36
44
|
}
|
|
37
45
|
|
|
46
|
+
get functions() {
|
|
47
|
+
return this._functions;
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
resetActiveParam() {
|
|
39
51
|
this.activeParam = null;
|
|
40
52
|
}
|
|
@@ -43,6 +55,10 @@ class ModelsTreeNode {
|
|
|
43
55
|
this.op = null;
|
|
44
56
|
}
|
|
45
57
|
|
|
58
|
+
resetFN() {
|
|
59
|
+
this.fn = null;
|
|
60
|
+
}
|
|
61
|
+
|
|
46
62
|
addWhere(condition={}) {
|
|
47
63
|
this._where = {
|
|
48
64
|
...this.where,
|
|
@@ -50,6 +66,10 @@ class ModelsTreeNode {
|
|
|
50
66
|
}
|
|
51
67
|
}
|
|
52
68
|
|
|
69
|
+
addFunction(fnParams={}) {
|
|
70
|
+
this._functions.push(fnParams);
|
|
71
|
+
}
|
|
72
|
+
|
|
53
73
|
include(modelTreeNode) {
|
|
54
74
|
modelTreeNode.parent = this;
|
|
55
75
|
this.includes.push(modelTreeNode);
|
|
@@ -60,13 +80,16 @@ class ModelsTreeNode {
|
|
|
60
80
|
return {
|
|
61
81
|
model: this.model,
|
|
62
82
|
|
|
83
|
+
fields: this.fields,
|
|
84
|
+
functions: this.functions,
|
|
85
|
+
|
|
63
86
|
where: this.where,
|
|
87
|
+
|
|
64
88
|
skip: this.skip,
|
|
65
89
|
limit: this.limit,
|
|
66
90
|
order: this.order,
|
|
67
|
-
|
|
91
|
+
order_by: this.order_by,
|
|
68
92
|
|
|
69
|
-
fields: this.fields,
|
|
70
93
|
|
|
71
94
|
includes: this.includes.map(i => i.toObject())
|
|
72
95
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
|
|
1
8
|
const Enum = require('../../../../enums/Enum');
|
|
2
9
|
const { ModelsTree, ModelsTreeNode } = require('./ModelsTree');
|
|
3
10
|
const util = require('util');
|
|
@@ -21,6 +28,10 @@ const OP_TOKENS = new Enum({
|
|
|
21
28
|
LOWER_OR_EQUAL: 'lte'
|
|
22
29
|
});
|
|
23
30
|
|
|
31
|
+
const FN_TOKENS = new Enum({
|
|
32
|
+
COUNT: 'count',
|
|
33
|
+
});
|
|
34
|
+
|
|
24
35
|
|
|
25
36
|
module.exports = class QueryLexer {
|
|
26
37
|
constructor(queryString='') {
|
|
@@ -71,22 +82,29 @@ module.exports = class QueryLexer {
|
|
|
71
82
|
token = '';
|
|
72
83
|
continue;
|
|
73
84
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
|
|
86
|
+
// If FN token:
|
|
87
|
+
if (FN_TOKENS.asArray.indexOf(token) > -1) {
|
|
88
|
+
// Set function token.
|
|
89
|
+
tree.node.fn = token;
|
|
78
90
|
token = '';
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
79
93
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
94
|
+
// If model subquery:
|
|
95
|
+
const model = token;
|
|
96
|
+
tree.use(model) ?? tree.include(model).use(model);
|
|
97
|
+
token = '';
|
|
84
98
|
|
|
85
|
-
|
|
86
|
-
|
|
99
|
+
// Process subquery:
|
|
100
|
+
i++;
|
|
101
|
+
const [ charsCount ] = this.parseIsolatedQuery(queryString, i, tree);
|
|
102
|
+
i += charsCount;
|
|
87
103
|
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
previousActive = model;
|
|
105
|
+
tree.up();
|
|
106
|
+
|
|
107
|
+
continue;
|
|
90
108
|
}
|
|
91
109
|
|
|
92
110
|
// ) can mean end of OP token params,
|
|
@@ -126,6 +144,40 @@ module.exports = class QueryLexer {
|
|
|
126
144
|
continue;
|
|
127
145
|
}
|
|
128
146
|
|
|
147
|
+
// If end of FN token:
|
|
148
|
+
if (!!tree.node.fn) {
|
|
149
|
+
// If token is empty, error:
|
|
150
|
+
if (token === '') {
|
|
151
|
+
const err = UnexpectedCharError(i, char);
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let fnParams = {};
|
|
156
|
+
switch (tree.node.fn) {
|
|
157
|
+
case 'count':
|
|
158
|
+
fnParams = {
|
|
159
|
+
fn: 'count',
|
|
160
|
+
args: [token]
|
|
161
|
+
};
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
fnParams = {
|
|
165
|
+
fn: [tree.node.fn],
|
|
166
|
+
args: [token]
|
|
167
|
+
};
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
tree.node.addFunction(fnParams);
|
|
172
|
+
|
|
173
|
+
// Reset:
|
|
174
|
+
tree.node.resetFN();
|
|
175
|
+
tree.node.activeParam = 'includes';
|
|
176
|
+
token = '';
|
|
177
|
+
value = [];
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
|
|
129
181
|
// If end of subquery:
|
|
130
182
|
if (!!tree.node.activeParam && tree.node.activeParam !== 'includes') {
|
|
131
183
|
// Set value.
|
|
@@ -378,7 +430,7 @@ module.exports = class QueryLexer {
|
|
|
378
430
|
return 'order';
|
|
379
431
|
case 'order_by':
|
|
380
432
|
case 'o_by':
|
|
381
|
-
return '
|
|
433
|
+
return 'order_by';
|
|
382
434
|
case 'fields':
|
|
383
435
|
case 'f':
|
|
384
436
|
return 'fields';
|
|
@@ -406,8 +458,8 @@ module.exports = class QueryLexer {
|
|
|
406
458
|
case 'order':
|
|
407
459
|
treeNode.order = token;
|
|
408
460
|
break;
|
|
409
|
-
case '
|
|
410
|
-
treeNode.
|
|
461
|
+
case 'order_by':
|
|
462
|
+
treeNode.order_by = token;
|
|
411
463
|
break;
|
|
412
464
|
case 'fields':
|
|
413
465
|
if (token)
|
package/lib/models/define.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
const { implementsCRUD } = require('./mixins');
|
|
3
3
|
// ORM.
|
|
4
4
|
const { DataTypes } = require('sequelize');
|
|
5
|
+
// NQL.
|
|
6
|
+
const Colander = require('../queries/Colander');
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
module.exports = defineModel;
|
|
@@ -41,10 +43,19 @@ function defineModel(
|
|
|
41
43
|
const model = databaseConnection.define(modelName, definitionObject, _options);
|
|
42
44
|
|
|
43
45
|
if (options.noCRUD !== true) {
|
|
44
|
-
// Add
|
|
46
|
+
// Add:
|
|
47
|
+
// - createWithIncludes;
|
|
48
|
+
// - findById;
|
|
49
|
+
// - updateById;
|
|
50
|
+
// - deleteById;
|
|
51
|
+
// - etc.
|
|
45
52
|
implementsCRUD(model);
|
|
46
53
|
}
|
|
47
54
|
|
|
55
|
+
// Association helpers:
|
|
56
|
+
model.associate = (models) => {};
|
|
57
|
+
model.getIncludesList = _getIncludesList.bind(model);
|
|
58
|
+
|
|
48
59
|
// Instance methods:
|
|
49
60
|
model.prototype.toJSON = function() {
|
|
50
61
|
const values = { ...this.get() };
|
|
@@ -54,3 +65,40 @@ function defineModel(
|
|
|
54
65
|
|
|
55
66
|
return model;
|
|
56
67
|
}
|
|
68
|
+
|
|
69
|
+
/* Association mixins: */
|
|
70
|
+
function _getIncludesList(facadeData=null) {
|
|
71
|
+
const result = [];
|
|
72
|
+
|
|
73
|
+
const associations = this.associations;
|
|
74
|
+
const associationEntries = Object.entries(associations);
|
|
75
|
+
|
|
76
|
+
associationEntries.forEach(([
|
|
77
|
+
associationName,
|
|
78
|
+
associationDefinition
|
|
79
|
+
]) => {
|
|
80
|
+
const a = { association: associationName };
|
|
81
|
+
|
|
82
|
+
if (!!facadeData) {
|
|
83
|
+
// If facade data is set, go deeper:
|
|
84
|
+
const keys = Object.keys( facadeData );
|
|
85
|
+
if (keys.indexOf(associationName) > 0) {
|
|
86
|
+
const associationModel = associationDefinition.target;
|
|
87
|
+
|
|
88
|
+
const a = { association: associationName };
|
|
89
|
+
if (Object.entries(associationModel.associations).length > 0) {
|
|
90
|
+
const deepData = facadeData[ associationName ];
|
|
91
|
+
a.include = associationModel.getIncludesList(Array.isArray(deepData) ? deepData[0] : deepData);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
result.push( a );
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
result.push( a );
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
/* Association mixins\ */
|
package/lib/models/mixins.js
CHANGED
|
@@ -8,6 +8,10 @@ const {
|
|
|
8
8
|
compileModelAssociationData,
|
|
9
9
|
} = require('../utils/modelAssociations.util');
|
|
10
10
|
|
|
11
|
+
// Nodester query:
|
|
12
|
+
const NQLexer = require('../middlewares/ql/sequelize/interpreter/QueryLexer');
|
|
13
|
+
const traverseNQuery = require('../queries/traverse');
|
|
14
|
+
|
|
11
15
|
|
|
12
16
|
module.exports = {
|
|
13
17
|
implementsCRUD: _implementsCRUD
|
|
@@ -34,17 +38,15 @@ function _implementsCRUD(modelDefinition) {
|
|
|
34
38
|
|
|
35
39
|
// Read:
|
|
36
40
|
modelDefinition.findById = _findById.bind(modelDefinition);
|
|
37
|
-
modelDefinition.
|
|
41
|
+
modelDefinition.findMany = _findMany.bind(modelDefinition);
|
|
38
42
|
|
|
39
43
|
// Update:
|
|
40
44
|
modelDefinition.updateOne = _updateOne.bind(modelDefinition);
|
|
41
45
|
modelDefinition.updateById = _updateById.bind(modelDefinition);
|
|
42
46
|
|
|
43
|
-
// Delete
|
|
47
|
+
// Delete:
|
|
48
|
+
modelDefinition.deleteOne = _deleteOne.bind(modelDefinition);
|
|
44
49
|
modelDefinition.deleteById = _deleteById.bind(modelDefinition);
|
|
45
|
-
|
|
46
|
-
// Associations:
|
|
47
|
-
modelDefinition.getIncludesList = _getIncludesList.bind(modelDefinition);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
|
|
@@ -114,37 +116,76 @@ async function _createWithIncludes(
|
|
|
114
116
|
|
|
115
117
|
function _findById(
|
|
116
118
|
id=null,
|
|
117
|
-
|
|
118
|
-
paranoid=true
|
|
119
|
+
opts={}
|
|
119
120
|
) {
|
|
120
|
-
const query =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
121
|
+
const { query } = opts;
|
|
122
|
+
|
|
123
|
+
let _query = {};
|
|
124
|
+
|
|
125
|
+
if (typeof query === 'string') {
|
|
126
|
+
const lexer = new NQLexer(query);
|
|
127
|
+
const nquery = lexer.query;
|
|
128
|
+
_query = traverseNQuery(nquery, null, this);
|
|
129
|
+
_query.where = {
|
|
130
|
+
..._query.where,
|
|
131
|
+
id: id
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const {
|
|
136
|
+
include,
|
|
137
|
+
paranoid
|
|
138
|
+
} = opts;
|
|
139
|
+
|
|
140
|
+
_query = {
|
|
141
|
+
where: { id },
|
|
142
|
+
include: include,
|
|
143
|
+
paranoid: !!paranoid
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return this.findOne(_query);
|
|
126
148
|
}
|
|
127
149
|
|
|
128
|
-
function
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
150
|
+
function _findMany(opts={}) {
|
|
151
|
+
const { query } = opts;
|
|
152
|
+
|
|
153
|
+
let _query = {};
|
|
154
|
+
|
|
155
|
+
if (typeof query === 'string') {
|
|
156
|
+
const lexer = new NQLexer(query);
|
|
157
|
+
const nquery = lexer.query;
|
|
158
|
+
_query = traverseNQuery(nquery, null, this);
|
|
159
|
+
_query.where = {
|
|
160
|
+
..._query.where,
|
|
161
|
+
id: id
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
const {
|
|
166
|
+
include,
|
|
167
|
+
paranoid
|
|
168
|
+
} = opts;
|
|
169
|
+
|
|
170
|
+
_query = {
|
|
171
|
+
where: { id },
|
|
172
|
+
include: include,
|
|
173
|
+
paranoid: !!paranoid
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
return this.findAll(_query);
|
|
139
179
|
}
|
|
140
180
|
|
|
181
|
+
|
|
141
182
|
async function _updateOne(
|
|
142
183
|
where,
|
|
143
184
|
data,
|
|
144
185
|
include=[]
|
|
145
186
|
) {
|
|
146
187
|
try {
|
|
147
|
-
const instance = await this.
|
|
188
|
+
const instance = await this.findOne({ where, include });
|
|
148
189
|
|
|
149
190
|
if (!instance) {
|
|
150
191
|
const err = new Error(`Model not found`);
|
|
@@ -201,7 +242,7 @@ async function _updateOne(
|
|
|
201
242
|
|
|
202
243
|
// Select this instance again, if includes was set:
|
|
203
244
|
if (include?.length > 0) {
|
|
204
|
-
const updatedInstance = await this.
|
|
245
|
+
const updatedInstance = await this.findOne({ where, include });
|
|
205
246
|
fullInstanceData = updatedInstance.toJSON();
|
|
206
247
|
}
|
|
207
248
|
|
|
@@ -225,6 +266,15 @@ async function _updateById(
|
|
|
225
266
|
);
|
|
226
267
|
}
|
|
227
268
|
|
|
269
|
+
|
|
270
|
+
function _deleteOne(query={}) {
|
|
271
|
+
const _query = {
|
|
272
|
+
...query,
|
|
273
|
+
limit: 1
|
|
274
|
+
}
|
|
275
|
+
return this.destroy(_query);
|
|
276
|
+
}
|
|
277
|
+
|
|
228
278
|
function _deleteById(
|
|
229
279
|
id=null
|
|
230
280
|
) {
|
|
@@ -235,47 +285,6 @@ function _deleteById(
|
|
|
235
285
|
}
|
|
236
286
|
/* Main mixinis\ */
|
|
237
287
|
|
|
238
|
-
/* Association mixins: */
|
|
239
|
-
function _getIncludesList(facadeData=null) {
|
|
240
|
-
// console.log({ facadeData, model: this });
|
|
241
|
-
|
|
242
|
-
const result = [];
|
|
243
|
-
|
|
244
|
-
const associations = this.associations;
|
|
245
|
-
const associationEntries = Object.entries(associations);
|
|
246
|
-
|
|
247
|
-
associationEntries.forEach(([
|
|
248
|
-
associationName,
|
|
249
|
-
associationDefinition
|
|
250
|
-
]) => {
|
|
251
|
-
const a = { association: associationName };
|
|
252
|
-
|
|
253
|
-
if (!!facadeData) {
|
|
254
|
-
// If facade data is set, go deeper:
|
|
255
|
-
const keys = Object.keys( facadeData );
|
|
256
|
-
if (keys.indexOf(associationName) > 0) {
|
|
257
|
-
const associationModel = associationDefinition.target;
|
|
258
|
-
|
|
259
|
-
const a = { association: associationName };
|
|
260
|
-
if (Object.entries(associationModel.associations).length > 0) {
|
|
261
|
-
const deepData = facadeData[ associationName ];
|
|
262
|
-
a.include = associationModel.getIncludesList(Array.isArray(deepData) ? deepData[0] : deepData);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
result.push( a );
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
else {
|
|
269
|
-
result.push( a );
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
// console.log('getIncludesList', result);
|
|
274
|
-
|
|
275
|
-
return result;
|
|
276
|
-
}
|
|
277
|
-
/* Association mixins\ */
|
|
278
|
-
|
|
279
288
|
/* Subfunctions: */
|
|
280
289
|
async function _updateOrCreateOrDelete(
|
|
281
290
|
modelDefinition,
|