nodester 0.0.9 → 0.1.0
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 +14 -1
- package/lib/application/index.js +28 -7
- package/lib/controllers/methods/index.js +34 -10
- package/lib/controllers/mixins/index.js +14 -5
- 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 +173 -0
- package/lib/facades/mixins/index.js +111 -0
- package/lib/middlewares/formidable/index.js +37 -0
- package/lib/middlewares/ql/sequelize/interpreter/ModelsTree.js +2 -2
- package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +3 -3
- 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 +84 -0
- package/lib/queries/traverse.js +311 -0
- package/lib/router/handlers.util.js +22 -2
- package/lib/router/index.js +96 -75
- 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/package.json +19 -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/utils/forms.util.js +0 -22
package/Readme.md
CHANGED
|
@@ -28,9 +28,22 @@ app.listen(8080, function() {
|
|
|
28
28
|
|
|
29
29
|
## Documentation
|
|
30
30
|
|
|
31
|
+
|
|
31
32
|
### Core concepts
|
|
32
33
|
[Go to core concepts documentaion](docs/CoreConcepts.md)
|
|
33
34
|
|
|
35
|
+
### Queries & Querying - Nodester Query Language (NQR)
|
|
36
|
+
One of the main power points of nodester is it's query language. It's an extension of a REST API syntaxis for a broader integration with a database SQL. Read more about it in the documentation:
|
|
37
|
+
|
|
38
|
+
[Go to NQR documentaion](docs/Queries.md)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Database
|
|
42
|
+
Nodester is built upon a powerful [Sequelize](https://sequelize.org/).
|
|
43
|
+
Supported drivers:
|
|
44
|
+
- MySQL
|
|
45
|
+
- PostgreSQL
|
|
46
|
+
|
|
34
47
|
|
|
35
48
|
### Extending Application functionality
|
|
36
49
|
|
|
@@ -95,7 +108,7 @@ The Philosophy of `nodester` is to provide a developer with a tool that can buil
|
|
|
95
108
|
|
|
96
109
|
### Goal
|
|
97
110
|
|
|
98
|
-
The goal of `nodester` is to be a robust and flexible framework that makes
|
|
111
|
+
The goal of `nodester` is to be a robust and flexible framework that makes development in iteratations easy, and further scale possible.
|
|
99
112
|
|
|
100
113
|
|
|
101
114
|
## LICENSE
|
package/lib/application/index.js
CHANGED
|
@@ -7,17 +7,25 @@
|
|
|
7
7
|
|
|
8
8
|
const Emitter = require('events');
|
|
9
9
|
const DefaultRouter = require('../router');
|
|
10
|
+
|
|
10
11
|
// Server:
|
|
11
12
|
const http = require('http');
|
|
12
13
|
const request = require('../http/request');
|
|
13
14
|
const response = require('../http/response');
|
|
15
|
+
|
|
14
16
|
// Middlewares:
|
|
15
17
|
const nodesterQL = require('../middlewares/ql/sequelize');
|
|
18
|
+
const bodyParser = require('body-parser');
|
|
19
|
+
|
|
16
20
|
// Utils:
|
|
17
21
|
const {
|
|
18
22
|
typeOf,
|
|
19
23
|
isConstructor
|
|
20
24
|
} = require('../utils/types.util');
|
|
25
|
+
const {
|
|
26
|
+
associateModels
|
|
27
|
+
} = require('../database/utils');
|
|
28
|
+
|
|
21
29
|
const { merge } = require('../utils/objects.util');
|
|
22
30
|
const consl = require('../logger/console');
|
|
23
31
|
const debug = require('debug')('nodester:application');
|
|
@@ -52,6 +60,13 @@ module.exports = class Application extends Emitter {
|
|
|
52
60
|
beforeStart: ()=>{}
|
|
53
61
|
};
|
|
54
62
|
|
|
63
|
+
// Default middlewares:
|
|
64
|
+
const _withoutMiddlewares = opts?.middlewares?.without ?? [];
|
|
65
|
+
|
|
66
|
+
if (_withoutMiddlewares.indexOf('body-parser') === -1) {
|
|
67
|
+
this.use(bodyParser.json());
|
|
68
|
+
}
|
|
69
|
+
|
|
55
70
|
// Indicatorors.
|
|
56
71
|
this.isListening = false;
|
|
57
72
|
}
|
|
@@ -104,7 +119,7 @@ module.exports = class Application extends Emitter {
|
|
|
104
119
|
*
|
|
105
120
|
* @public
|
|
106
121
|
*/
|
|
107
|
-
setDatabase(sequilizeConnection, crashOnError=true) {
|
|
122
|
+
async setDatabase(sequilizeConnection, crashOnError=true) {
|
|
108
123
|
try {
|
|
109
124
|
if (!sequilizeConnection) {
|
|
110
125
|
const err = new TypeError('Connection to database (Sequilize) can not be null or undefined.');
|
|
@@ -116,10 +131,14 @@ module.exports = class Application extends Emitter {
|
|
|
116
131
|
throw err;
|
|
117
132
|
}
|
|
118
133
|
|
|
119
|
-
|
|
134
|
+
// Test connection.
|
|
135
|
+
const result = await sequilizeConnection.authenticate();
|
|
136
|
+
// Associate models.
|
|
137
|
+
await associateModels(sequilizeConnection.models);
|
|
138
|
+
// Set database.
|
|
120
139
|
this._database = sequilizeConnection;
|
|
121
140
|
|
|
122
|
-
return result;
|
|
141
|
+
return Promise.resolve(result);
|
|
123
142
|
}
|
|
124
143
|
catch(error) {
|
|
125
144
|
if (crashOnError === true) {
|
|
@@ -128,6 +147,8 @@ module.exports = class Application extends Emitter {
|
|
|
128
147
|
else {
|
|
129
148
|
consl.error(error);
|
|
130
149
|
}
|
|
150
|
+
|
|
151
|
+
return Promise.reject(error);
|
|
131
152
|
}
|
|
132
153
|
}
|
|
133
154
|
|
|
@@ -188,14 +209,14 @@ module.exports = class Application extends Emitter {
|
|
|
188
209
|
|
|
189
210
|
|
|
190
211
|
/*
|
|
191
|
-
* Proxy to .
|
|
212
|
+
* Proxy to router.use()
|
|
192
213
|
*
|
|
193
|
-
* @param {Function}
|
|
214
|
+
* @param {Function|NodesterRouter} fnOrRouter
|
|
194
215
|
*
|
|
195
216
|
* @api public
|
|
196
217
|
*/
|
|
197
|
-
use(
|
|
198
|
-
return this._router.
|
|
218
|
+
use(fnOrRouter) {
|
|
219
|
+
return this._router.use(fnOrRouter);
|
|
199
220
|
}
|
|
200
221
|
|
|
201
222
|
|
|
@@ -14,8 +14,13 @@ module.exports = {
|
|
|
14
14
|
*/
|
|
15
15
|
async function _getOne(req, res) {
|
|
16
16
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
const params = {
|
|
18
|
+
query: {
|
|
19
|
+
...req.query,
|
|
20
|
+
where: req.params
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const result = await this.facade.getOne(params);
|
|
19
24
|
|
|
20
25
|
if (this.afterGetOne) {
|
|
21
26
|
await this.afterGetOne(req, res, result);
|
|
@@ -26,7 +31,6 @@ async function _getOne(req, res) {
|
|
|
26
31
|
});
|
|
27
32
|
}
|
|
28
33
|
catch(error) {
|
|
29
|
-
console.error('getOne', error);
|
|
30
34
|
if (this.processError) {
|
|
31
35
|
return this.processError(error, req, res);
|
|
32
36
|
}
|
|
@@ -47,7 +51,10 @@ async function _getOne(req, res) {
|
|
|
47
51
|
*/
|
|
48
52
|
async function _getMany(req, res) {
|
|
49
53
|
try {
|
|
50
|
-
const
|
|
54
|
+
const params = {
|
|
55
|
+
query: req.query
|
|
56
|
+
}
|
|
57
|
+
const result = await this.facade.getMany(params);
|
|
51
58
|
|
|
52
59
|
if (this.afterGetMany) {
|
|
53
60
|
await this.afterGetMany(req, res, result);
|
|
@@ -78,8 +85,14 @@ async function _getMany(req, res) {
|
|
|
78
85
|
*/
|
|
79
86
|
async function _createOne(req, res) {
|
|
80
87
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
88
|
+
const params = {
|
|
89
|
+
query: {
|
|
90
|
+
...req.query,
|
|
91
|
+
where: req.params
|
|
92
|
+
},
|
|
93
|
+
data: req.body,
|
|
94
|
+
}
|
|
95
|
+
const result = await this.facade.createOne(params);
|
|
83
96
|
|
|
84
97
|
if (this.afterCreateOne) {
|
|
85
98
|
await this.afterCreateOne(req, res, result);
|
|
@@ -110,8 +123,14 @@ async function _createOne(req, res) {
|
|
|
110
123
|
*/
|
|
111
124
|
async function _updateOne(req, res) {
|
|
112
125
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
const params = {
|
|
127
|
+
query: {
|
|
128
|
+
...req.query,
|
|
129
|
+
where: req.params
|
|
130
|
+
},
|
|
131
|
+
data: req.body,
|
|
132
|
+
}
|
|
133
|
+
const result = await this.facade.updateOne(params);
|
|
115
134
|
|
|
116
135
|
if (this.afterUpdateOne) {
|
|
117
136
|
await this.afterUpdateOne(req, res, result);
|
|
@@ -142,8 +161,13 @@ async function _updateOne(req, res) {
|
|
|
142
161
|
*/
|
|
143
162
|
async function _deleteOne(req, res) {
|
|
144
163
|
try {
|
|
145
|
-
|
|
146
|
-
|
|
164
|
+
const params = {
|
|
165
|
+
query: {
|
|
166
|
+
...req.query,
|
|
167
|
+
where: req.params
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const result = await this.facade.deleteOne(params);
|
|
147
171
|
|
|
148
172
|
if (this.afterDeleteOn) {
|
|
149
173
|
await this.afterDeleteOne(req, res, result);
|
|
@@ -134,6 +134,7 @@ function _withDefaultErrorProcessing(controller, opts={}) {
|
|
|
134
134
|
|
|
135
135
|
// Set processError:
|
|
136
136
|
controller.processError = function (error, req, res) {
|
|
137
|
+
|
|
137
138
|
// Default error message.
|
|
138
139
|
let errorMessage = error?.message ?? 'Internal server error';
|
|
139
140
|
// Default HTTP status code.
|
|
@@ -169,23 +170,31 @@ function _withDefaultErrorProcessing(controller, opts={}) {
|
|
|
169
170
|
}
|
|
170
171
|
case('InternalValidationError'): {
|
|
171
172
|
statusCode = 500;
|
|
172
|
-
errorResponse.details = { message:'Error' };
|
|
173
|
+
errorResponse.details = { message: 'Error' };
|
|
173
174
|
break;
|
|
174
175
|
}
|
|
175
176
|
default: {
|
|
176
|
-
errorResponse.details = { message:errorMessage };
|
|
177
|
+
errorResponse.details = { message: errorMessage };
|
|
177
178
|
break;
|
|
178
179
|
}
|
|
179
180
|
}
|
|
180
181
|
|
|
181
|
-
// Send error response with provided status code
|
|
182
|
-
|
|
182
|
+
// Send error response with provided status code:
|
|
183
|
+
const data = {
|
|
183
184
|
error: {
|
|
184
185
|
...errorResponse,
|
|
185
186
|
code: statusCode
|
|
186
187
|
},
|
|
187
188
|
status: statusCode
|
|
188
|
-
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (!!this.respondNotOk) {
|
|
192
|
+
return this.respondNotOk(res, data);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Barebones response:
|
|
196
|
+
res.status(statusCode);
|
|
197
|
+
res.json(data);
|
|
189
198
|
}
|
|
190
199
|
|
|
191
200
|
return controller;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// ORM.
|
|
2
|
+
const Sequelize = require('sequelize');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
buildConnection: _buildConnection
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
function _buildConnection(opts={}) {
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
const dbName = opts.name;
|
|
13
|
+
const username = opts.username;
|
|
14
|
+
const password = opts.password;
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
const connection = new Sequelize(
|
|
18
|
+
dbName,
|
|
19
|
+
username,
|
|
20
|
+
password,
|
|
21
|
+
{
|
|
22
|
+
host: opts.host,
|
|
23
|
+
port: opts.port,
|
|
24
|
+
dialect: opts.dialect,
|
|
25
|
+
pool: opts.pool,
|
|
26
|
+
charset: opts.charset,
|
|
27
|
+
collate: opts.collate,
|
|
28
|
+
timestamps: opts.timestamps,
|
|
29
|
+
logging: opts.logging
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
return connection;
|
|
34
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { associateModels } = require('./utils');
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
migrate: _migrate
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async function _migrate(databaseConnection, force=false) {
|
|
9
|
+
try {
|
|
10
|
+
// Validation of 'force' parameter.
|
|
11
|
+
if (typeof force !== 'boolean') {
|
|
12
|
+
const err = new Error('Wrong "force" parameter; must be boolean.');
|
|
13
|
+
throw err;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Test connection.
|
|
17
|
+
await databaseConnection.authenticate();
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const models = databaseConnection.models;
|
|
21
|
+
const modelNames = Object.keys(models);
|
|
22
|
+
console.info('Models to sync:', modelNames);
|
|
23
|
+
console.info('Forcefully?', force);
|
|
24
|
+
console.info('Syncing...\n');
|
|
25
|
+
await associateModels(models);
|
|
26
|
+
await databaseConnection.sync({ force });
|
|
27
|
+
console.info('Successful migration!');
|
|
28
|
+
|
|
29
|
+
const output = {
|
|
30
|
+
synced: true,
|
|
31
|
+
modelNames: modelNames,
|
|
32
|
+
models: models
|
|
33
|
+
}
|
|
34
|
+
return Promise.resolve(output);
|
|
35
|
+
}
|
|
36
|
+
catch(error) {
|
|
37
|
+
console.error('Migration failed!');
|
|
38
|
+
console.error(error);
|
|
39
|
+
return Promise.reject(error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
module.exports = {
|
|
3
|
+
associateModels: _associateModels
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
async function _associateModels(models) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
try {
|
|
9
|
+
Object.keys(models).map(modelName => (
|
|
10
|
+
models[modelName].associate(models)
|
|
11
|
+
));
|
|
12
|
+
|
|
13
|
+
return resolve(models);
|
|
14
|
+
}
|
|
15
|
+
catch(error) {
|
|
16
|
+
reject(error);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
const Params = require('nodester/params');
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
getOne: _getOne,
|
|
6
|
+
getMany: _getMany,
|
|
7
|
+
createOne: _createOne,
|
|
8
|
+
updateOne: _updateOne,
|
|
9
|
+
deleteOne: _deleteOne
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} params
|
|
16
|
+
*
|
|
17
|
+
* @alias getOne
|
|
18
|
+
* @api public
|
|
19
|
+
*/
|
|
20
|
+
async function _getOne(params) {
|
|
21
|
+
try {
|
|
22
|
+
const {
|
|
23
|
+
query
|
|
24
|
+
} = Params(params, {
|
|
25
|
+
query: {}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const instance = await this.model.findOne(query);
|
|
29
|
+
|
|
30
|
+
const result = {
|
|
31
|
+
[this.modelName.singular]: instance,
|
|
32
|
+
count: 0 + instance !== null
|
|
33
|
+
}
|
|
34
|
+
return Promise.resolve(result);
|
|
35
|
+
}
|
|
36
|
+
catch(error) {
|
|
37
|
+
return Promise.reject(error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
*
|
|
44
|
+
* @param {Object} params
|
|
45
|
+
*
|
|
46
|
+
* @alias getMany
|
|
47
|
+
* @api public
|
|
48
|
+
*/
|
|
49
|
+
async function _getMany(params) {
|
|
50
|
+
try {
|
|
51
|
+
const {
|
|
52
|
+
query
|
|
53
|
+
} = Params(params, {
|
|
54
|
+
query: {}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const instances = await this.model.findAll(query);
|
|
58
|
+
|
|
59
|
+
const result = {
|
|
60
|
+
[this.modelName.plural]: instances,
|
|
61
|
+
count: instances.length
|
|
62
|
+
}
|
|
63
|
+
return Promise.resolve(result);
|
|
64
|
+
}
|
|
65
|
+
catch(error) {
|
|
66
|
+
return Promise.reject(error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
/*
|
|
72
|
+
*
|
|
73
|
+
* @param {Object} params
|
|
74
|
+
*
|
|
75
|
+
* @alias createOne
|
|
76
|
+
* @api public
|
|
77
|
+
*/
|
|
78
|
+
async function _createOne(params) {
|
|
79
|
+
try {
|
|
80
|
+
const {
|
|
81
|
+
data,
|
|
82
|
+
includes,
|
|
83
|
+
} = Params(params, {
|
|
84
|
+
data: null,
|
|
85
|
+
includes: null,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const instance = await this.model.create({ ...data }, {
|
|
89
|
+
include: this.model.getIncludesList(data)
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// If includes are set, "find" this record with includes:
|
|
93
|
+
if (!!includes && includes?.length > 0) {
|
|
94
|
+
await instance.reload({ include: includes });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const result = {
|
|
98
|
+
[this.modelName.singular]: instance,
|
|
99
|
+
count: instance === null ? 0 : 1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Call after create.
|
|
103
|
+
await this.afterCreateOne(instance, params, result);
|
|
104
|
+
|
|
105
|
+
return Promise.resolve(result);
|
|
106
|
+
}
|
|
107
|
+
catch(error) {
|
|
108
|
+
return Promise.reject(error);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
*
|
|
115
|
+
* @param {Object} params
|
|
116
|
+
*
|
|
117
|
+
* @alias updateOne
|
|
118
|
+
* @api public
|
|
119
|
+
*/
|
|
120
|
+
async function _updateOne(params) {
|
|
121
|
+
try {
|
|
122
|
+
const {
|
|
123
|
+
query,
|
|
124
|
+
data
|
|
125
|
+
} = Params(params, {
|
|
126
|
+
query: {},
|
|
127
|
+
data: null
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const updateResult = await this.model.updateOne(query.where, data);;
|
|
131
|
+
|
|
132
|
+
const [ isNewRecord, instance ] = updateResult;
|
|
133
|
+
|
|
134
|
+
const result = {
|
|
135
|
+
success: isNewRecord === false,
|
|
136
|
+
[this.modelName.singular]: instance,
|
|
137
|
+
count: !!instance ? 1 : 0
|
|
138
|
+
}
|
|
139
|
+
return Promise.resolve(result);
|
|
140
|
+
}
|
|
141
|
+
catch(error) {
|
|
142
|
+
return Promise.reject(error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
/*
|
|
148
|
+
*
|
|
149
|
+
* @param {Object} params
|
|
150
|
+
*
|
|
151
|
+
* @alias deleteOne
|
|
152
|
+
* @api public
|
|
153
|
+
*/
|
|
154
|
+
async function _deleteOne(params) {
|
|
155
|
+
try {
|
|
156
|
+
const {
|
|
157
|
+
query
|
|
158
|
+
} = Params(params, {
|
|
159
|
+
query: null
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const count = await this.model.deleteOne(query);
|
|
163
|
+
|
|
164
|
+
const result = {
|
|
165
|
+
success: count > 0,
|
|
166
|
+
count: count
|
|
167
|
+
};
|
|
168
|
+
return Promise.resolve(result);
|
|
169
|
+
}
|
|
170
|
+
catch(error) {
|
|
171
|
+
return Promise.reject(error);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -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,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
|
+
|
|
@@ -16,7 +16,7 @@ class ModelsTreeNode {
|
|
|
16
16
|
|
|
17
17
|
this.includes = opts.includes ?? [];
|
|
18
18
|
this.order = opts.order ?? 'asc';
|
|
19
|
-
this.
|
|
19
|
+
this.order_by = opts.order_by ?? 'id';
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
get hasParent() {
|
|
@@ -64,7 +64,7 @@ class ModelsTreeNode {
|
|
|
64
64
|
skip: this.skip,
|
|
65
65
|
limit: this.limit,
|
|
66
66
|
order: this.order,
|
|
67
|
-
|
|
67
|
+
order_by: this.order_by,
|
|
68
68
|
|
|
69
69
|
fields: this.fields,
|
|
70
70
|
|
|
@@ -378,7 +378,7 @@ module.exports = class QueryLexer {
|
|
|
378
378
|
return 'order';
|
|
379
379
|
case 'order_by':
|
|
380
380
|
case 'o_by':
|
|
381
|
-
return '
|
|
381
|
+
return 'order_by';
|
|
382
382
|
case 'fields':
|
|
383
383
|
case 'f':
|
|
384
384
|
return 'fields';
|
|
@@ -406,8 +406,8 @@ module.exports = class QueryLexer {
|
|
|
406
406
|
case 'order':
|
|
407
407
|
treeNode.order = token;
|
|
408
408
|
break;
|
|
409
|
-
case '
|
|
410
|
-
treeNode.
|
|
409
|
+
case 'order_by':
|
|
410
|
+
treeNode.order_by = token;
|
|
411
411
|
break;
|
|
412
412
|
case 'fields':
|
|
413
413
|
if (token)
|