nodester 0.0.8 → 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.
Files changed (37) hide show
  1. package/Readme.md +18 -59
  2. package/lib/application/index.js +28 -7
  3. package/lib/controllers/methods/index.js +34 -10
  4. package/lib/controllers/mixins/index.js +14 -5
  5. package/lib/database/connection.js +34 -0
  6. package/lib/database/migration.js +42 -0
  7. package/lib/database/utils.js +19 -0
  8. package/lib/facades/methods/index.js +173 -0
  9. package/lib/facades/mixins/index.js +111 -0
  10. package/lib/middlewares/formidable/index.js +37 -0
  11. package/lib/middlewares/ql/sequelize/interpreter/ModelsTree.js +2 -2
  12. package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +3 -3
  13. package/lib/models/associate.js +17 -0
  14. package/lib/models/define.js +50 -1
  15. package/lib/models/mixins.js +81 -72
  16. package/lib/params/Params.js +10 -7
  17. package/lib/queries/Colander.js +84 -0
  18. package/lib/queries/traverse.js +311 -0
  19. package/lib/router/handlers.util.js +22 -2
  20. package/lib/router/index.js +96 -75
  21. package/lib/router/markers.js +78 -0
  22. package/lib/router/route.js +4 -4
  23. package/lib/router/routes.util.js +35 -5
  24. package/lib/router/utils.js +30 -0
  25. package/package.json +20 -7
  26. package/tests/nql.test.js +3 -3
  27. package/lib/_/n_controllers/Controller.js +0 -474
  28. package/lib/_/n_controllers/JWTController.js +0 -240
  29. package/lib/_/n_controllers/ServiceController.js +0 -109
  30. package/lib/_/n_controllers/WebController.js +0 -75
  31. package/lib/_facades/Facade.js +0 -388
  32. package/lib/_facades/FacadeParams.js +0 -11
  33. package/lib/_facades/ServiceFacade.js +0 -17
  34. package/lib/_facades/jwt.facade.js +0 -273
  35. package/lib/models/DisabledRefreshToken.js +0 -68
  36. package/lib/models/Extractor.js +0 -320
  37. package/lib/utils/forms.util.js +0 -22
@@ -1,388 +0,0 @@
1
- const Params = require('nodester/facades/FacadeParams');
2
- // Utils:
3
- const { lowerCaseFirstLetter } = require('nodester/utils/strings.util');
4
- const { parseIncludesQuery } = require('nodester/services/includes.service');
5
- const { parseQueryParams } = require('nodester/utils/queries.util');
6
-
7
-
8
- module.exports = class Facade {
9
- constructor(modelDefinition) {
10
- if (!modelDefinition)
11
- throw new Error('"modelDefinition" argument is invalid.');
12
-
13
- this.model = modelDefinition;
14
- this.nameSingular = lowerCaseFirstLetter(modelDefinition?.options?.name?.singular);
15
- this.namePlural = lowerCaseFirstLetter(modelDefinition?.options?.name?.plural);
16
- }
17
-
18
- /*
19
- * @param <Object> data
20
- */
21
- async createOne(params) {
22
- try {
23
- const {
24
- data,
25
- includes,
26
- } = Params(params, {
27
- data: null,
28
- includes: null,
29
- });
30
-
31
- // Parse includes string to array.
32
- const _includes = typeof includes === 'string' ? parseIncludesQuery(this.model, includes) : null;
33
-
34
- const instance = await this.model.create({ ...data }, {
35
- include: this.model.getIncludesList(data)
36
- });
37
-
38
- // If includes are set, "find" this record with includes:
39
- if (!!_includes && _includes?.length > 0) {
40
- await instance.reload({ include: _includes });
41
- }
42
-
43
- const result = {
44
- [this.nameSingular]: instance,
45
- count: 1
46
- };
47
-
48
- // Call after create.
49
- await this.afterCreate(instance, params, result);
50
-
51
- // Send output.
52
- return Promise.resolve(result);
53
- }
54
- catch(error) {
55
- return Promise.reject(error);
56
- }
57
- }
58
-
59
- /*
60
- * @param <Object> data
61
- */
62
- async getOrCreateOne(params) {
63
- try {
64
- const {
65
- id,
66
- query,
67
- data,
68
- includes,
69
- } = Params(params, {
70
- id: null,
71
- query: null,
72
- data: null,
73
- includes: null,
74
- });
75
-
76
- // Parse includes string to array.
77
- const _includes = typeof includes === 'string' ? parseIncludesQuery(this.model, includes) : null;
78
-
79
- let instance, isNewRecord;
80
-
81
- if (!!id) {
82
- const [ _instance, _isNewRecord ] = await this.model.findOrCreate({
83
- where: {
84
- id: parseInt(id)
85
- },
86
- defaults: data
87
- });
88
-
89
- // Find this model again with passed includes.
90
- instance = await this.model.findById(id, _includes);
91
-
92
- isNewRecord = _isNewRecord;
93
- }
94
- else if (!!query) {
95
- // New sequilize query.
96
- const modelQuery = {};
97
-
98
- // If includes are set:
99
- if (!!_includes) {
100
- modelQuery.include = [ ..._includes ];
101
- }
102
-
103
- parseQueryParams(query, modelQuery);
104
-
105
- let _instance = await this.model.findOne(modelQuery);
106
-
107
- // Define "isNewRecord".
108
- isNewRecord = !instance;
109
-
110
- // If no record in DB, create new one:
111
- if (!_instance) {
112
- _instance = await this.model.create({ ...data }, {
113
- include: this.model.getIncludesList(data)
114
- });
115
-
116
- instance = _instance;
117
-
118
- // If includes are set, "find" this record with includes:
119
- if (!!_includes && _includes?.length > 0) {
120
- await instance.reload({ include: _includes });
121
- }
122
- }
123
- else {
124
- instance = _instance;
125
- }
126
- }
127
-
128
- const result = {
129
- [this.nameSingular]: instance,
130
- count: 1,
131
- isNewRecord: isNewRecord
132
- };
133
-
134
- // If new record, call "after create":
135
- if (!!isNewRecord) {
136
- await this.afterCreate(instance, params, result);
137
- }
138
-
139
- // Send output.
140
- return Promise.resolve(result);
141
- }
142
- catch(error) {
143
- return Promise.reject(error);
144
- }
145
- }
146
-
147
- /*
148
- * @param <ModelInstance> instance
149
- * @param <Array> params
150
- */
151
- async afterCreate(
152
- instance,
153
- params,
154
- result
155
- ) {
156
- // This method is empty, as it should be overwritten.
157
- return Promise.resolve();
158
- }
159
-
160
- /*
161
- * @param <UInt> id
162
- * @param <Object> query
163
- * @param <Array> includes
164
- */
165
- async getOne(params) {
166
- try {
167
- const {
168
- id,
169
- query,
170
- includes,
171
- } = Params(params, {
172
- id: null,
173
- query: null,
174
- includes: null,
175
- });
176
-
177
- // Parse includes string to array.
178
- const _includes = typeof includes === 'string' ? parseIncludesQuery(this.model, includes) : null;
179
-
180
- let instance = null;
181
-
182
- if (!!id || !!query?.id) {
183
- instance = await this.model.findById(( id ?? query.id ), _includes);
184
- }
185
- else if (!!query) {
186
- // New sequilize query.
187
- const modelQuery = {};
188
-
189
- // If includes are set:
190
- if (!!_includes) {
191
- modelQuery.include = [ ..._includes ];
192
- }
193
-
194
- parseQueryParams(query, modelQuery);
195
-
196
- instance = await this.model.findOne(modelQuery);
197
- }
198
-
199
- const result = {
200
- [this.nameSingular]: instance,
201
- count: !!instance ? 1 : 0
202
- };
203
-
204
- // Send output.
205
- return Promise.resolve(result);
206
- }
207
- catch(error) {
208
- return Promise.reject(error);
209
- }
210
- }
211
-
212
- /*
213
- * @param <Object> query
214
- * @param <Array> includes
215
- */
216
- async getMany(params) {
217
- try {
218
- const {
219
- query,
220
- includes,
221
- } = Params(params, {
222
- query: {},
223
- includes: null
224
- });
225
-
226
- // Parse includes string to array.
227
- const _includes = typeof includes === 'string' ? parseIncludesQuery(this.model, includes) : null;
228
-
229
- // New sequilize query.
230
- const modelQuery = {};
231
-
232
- // If includes are set:
233
- if (!!_includes) {
234
- modelQuery.include = [ ..._includes ];
235
- }
236
-
237
- parseQueryParams(query, modelQuery);
238
-
239
- // Get instances for current limits
240
- // and total number (Int) of such instances.
241
- const [
242
- instances,
243
- totalCount
244
- ] = await Promise.all([
245
- this.model.findAll(modelQuery),
246
- this.model.count(modelQuery)
247
- ]);
248
-
249
- const result = {
250
- [this.namePlural]: instances,
251
-
252
- count: instances.length,
253
- total_count: totalCount,
254
-
255
- limit: modelQuery.limit,
256
- skip: modelQuery.offset
257
- };
258
-
259
- // Send output.
260
- return Promise.resolve(result);
261
- }
262
- catch(error) {
263
- return Promise.reject(error);
264
- }
265
- }
266
-
267
- /*
268
- * @param <UInt> id
269
- * @param <Object> data
270
- * @param <Array> includes
271
- */
272
- async updateOne(params) {
273
- try {
274
- const {
275
- id,
276
- query,
277
- data,
278
- includes,
279
- } = Params(params, {
280
- id: null,
281
- query: {},
282
- data: null,
283
- includes: null,
284
- });
285
-
286
- // Parse includes string to array.
287
- const _includes = typeof includes === 'string' ? parseIncludesQuery(this.model, includes) : null;
288
-
289
- let updateResult = null;
290
-
291
- if (!!id || !!query.id) {
292
- updateResult = await this.model.updateById(( id ?? query.id ), data, _includes);
293
- }
294
- else {
295
- // New sequilize query.
296
- const modelQuery = {};
297
- parseQueryParams(query, modelQuery);
298
-
299
- updateResult = await this.model.updateOne(modelQuery.where, data, _includes);
300
- }
301
-
302
- const [ isNewRecord, instance ] = updateResult;
303
-
304
- const result = {
305
- success: isNewRecord === false,
306
- [this.nameSingular]: instance
307
- };
308
-
309
- // Send output.
310
- return Promise.resolve(result);
311
- }
312
- catch(error) {
313
- return Promise.reject(error);
314
- }
315
- }
316
-
317
- // TODO: finish updateMany:
318
- /*
319
- * @param <UInt> id
320
- * @param <Object> data
321
- * @param <Array> includes
322
- */
323
- // async updateMany(params) {
324
- // try {
325
- // const {
326
- // query,
327
- // data,
328
- // includes,
329
- // } = Params(params, {
330
- // query: {},
331
- // data: null,
332
- // includes: null,
333
- // });
334
-
335
- // const _includes = typeof includes === 'string' ? parseIncludesQuery(this.model, includes) : null;
336
-
337
- // let updateResult = null;
338
-
339
- // if (!!query.id) {
340
- // updateResult = await this.model.updateById(query.id, data, _includes);
341
- // }
342
- // else {
343
- // // New sequilize query.
344
- // const modelQuery = {};
345
- // parseQueryParams(query, modelQuery);
346
-
347
- // updateResult = await this.model.update(modelQuery.where, data, _includes);
348
-
349
- // console.log({ updateResult });
350
- // }
351
-
352
- // const result = {
353
- // success:isNewRecord === false,
354
- // [this.nameSingular]:instance
355
- // };
356
-
357
- // // Send output.
358
- // return Promise.resolve(result);
359
- // }
360
- // catch(error) {
361
- // return Promise.reject(error);
362
- // }
363
- // }
364
-
365
- /*
366
- * @param <UInt> id
367
- */
368
- async deleteOne(params) {
369
- try {
370
- const { id } = Params(params, {
371
- id: null
372
- });
373
-
374
- const count = await this.model.deleteById(id);
375
-
376
- const result = {
377
- success: count > 0,
378
- count: count
379
- };
380
-
381
- // Send output.
382
- return Promise.resolve(result);
383
- }
384
- catch(error) {
385
- return Promise.reject(error);
386
- }
387
- }
388
- }
@@ -1,11 +0,0 @@
1
- const Params = require('nodester/utils/params.util');
2
-
3
-
4
- module.exports = FacadeParams;
5
-
6
- function FacadeParams(
7
- sourceObject={},
8
- defaultValuesList={}
9
- ) {
10
- return Params(sourceObject, defaultValuesList);
11
- }
@@ -1,17 +0,0 @@
1
- // Utils:
2
- const { lowerCaseFirstLetter } = require('nodester/utils/strings.util');
3
-
4
-
5
- module.exports = class ServiceFacade {
6
- constructor(
7
- nameSingular,
8
- namePlural,
9
- ) {
10
- if (!nameSingular || !namePlural) {
11
- throw new Error('"nameSingular" and "namePlural" arguments must be set.');
12
- }
13
-
14
- this.nameSingular = lowerCaseFirstLetter(nameSingular);
15
- this.namePlural = lowerCaseFirstLetter(namePlural);
16
- }
17
- }
@@ -1,273 +0,0 @@
1
- // Access to database.
2
- const Sequelize = require('sequelize');
3
- // JWT service.
4
- const JWT = require('nodester/services/jwt.service');
5
- // Utils:
6
- const { lowerCaseFirstLetter } = require('nodester/utils/strings.util');
7
- const { addSeconds } = require('nodester/utils/dates.util');
8
- const Params = require('nodester/facades/FacadeParams');
9
-
10
-
11
- module.exports = class JWTFacade {
12
- constructor(
13
- disabledRefreshToken,
14
- roleModels=[],
15
- accessTokenConfigs=null,
16
- refreshTokenConfigs=null
17
- ) {
18
- if (!disabledRefreshToken)
19
- throw new Erroror('"disabledRefreshToken" argument is invalid.');
20
-
21
- this.disabledRefreshToken = disabledRefreshToken;
22
-
23
- this.roleModels = {};
24
- roleModels.forEach(model => {
25
- const name = lowerCaseFirstLetter(model?.options?.name?.singular);
26
- this.roleModels[name] = model;
27
- });
28
-
29
- this.service = new JWT(accessTokenConfigs, refreshTokenConfigs);
30
- }
31
-
32
- async login(params) {
33
- try {
34
- const {
35
- email,
36
- password,
37
- role
38
- } = Params(params, {
39
- email: null,
40
- password: null,
41
- role: null
42
- });
43
-
44
- if (Object.keys(this.roleModels).indexOf(role) === -1)
45
- throw new Error();
46
-
47
- // Extract model difinition of this type.
48
- const modelDefinition = this.roleModels[role];
49
- const instance = await modelDefinition?.findOneByEmail(email);
50
-
51
- if (!instance)
52
- throw new Error();
53
-
54
- const compareResult = await instance?.comparePasswords(password);
55
-
56
- if (compareResult === false)
57
- throw new Error();
58
-
59
- const result = {
60
- role: role,
61
- [role]: instance.toJSON(),
62
- tokens: await this.issueTokens({ modelInstance: instance, modelName: role })
63
- }
64
-
65
- // Send output.
66
- return Promise.resolve(result);
67
- }
68
- catch(error) {
69
- console.error(error);
70
-
71
- // Unauthorized on any error:
72
- const err = new Error();
73
- err.name = 'Unauthorized';
74
- return Promise.reject(err);
75
- }
76
- }
77
-
78
- async issueAccessToken(params) {
79
- try {
80
- const {
81
- parsedRefreshToken,
82
- modelInstance,
83
- modelName
84
- } = Params(params, {
85
- parsedRefreshToken: null,
86
- modelInstance: null,
87
- modelName: null,
88
- });
89
-
90
- let newAccessToken = null;
91
-
92
- if (!modelName && !parsedRefreshToken.role) {
93
- const err = new Error('No "modelName" provided for JWT issue.');
94
- err.name = "ValidationError";
95
- err.status = 403;
96
- throw err;
97
- }
98
-
99
- // If parsed refresh token was provided:
100
- if (!!parsedRefreshToken) {
101
- const payload = {
102
- id: parsedRefreshToken?.id,
103
- role: parsedRefreshToken.role,
104
- };
105
- newAccessToken = await this.service.issueAccessToken(payload);
106
- }
107
- // If modelInstance was provided:
108
- else if (!!modelInstance) {
109
- const payload = {
110
- id: modelInstance?.id,
111
- role: modelName
112
- };
113
- newAccessToken = await this.service.issueAccessToken(payload);
114
- }
115
- else {
116
- const err = new Error('No "modelInstance" or "parsedRefreshToken" provided for JWT issue.');
117
- err.name = "ValidationError";
118
- err.status = 403;
119
- throw err;
120
- }
121
-
122
- // Check if issue was successful.
123
- if (!newAccessToken) {
124
- const err = new Error("Could not issue new access token.");
125
- err.status = 401;
126
- throw err;
127
- }
128
-
129
- // Send output.
130
- return Promise.resolve(newAccessToken);
131
- }
132
- catch(error) {
133
- return Promise.reject(error);
134
- }
135
- }
136
-
137
- async issueTokens(params) {
138
- try {
139
- const {
140
- modelInstance,
141
- modelName,
142
- noAccessToken,
143
- noRefreshToken
144
- } = Params(params, {
145
- modelInstance: null,
146
- modelName: null,
147
- noAccessToken: false,
148
- noRefreshToken: false
149
- });
150
-
151
- // Prepare payload container.
152
- let payload = {};
153
-
154
- if (!!modelInstance && !!modelName) {
155
- payload = {
156
- id: modelInstance?.id,
157
- role: modelName
158
- };
159
- }
160
- else {
161
- const err = new Error('No "modelInstance" and "modelName" provided for JWT issue.');
162
- err.name = "ValidationError";
163
- err.status = 403;
164
- throw err;
165
- }
166
-
167
- const accessToken = await this.service.issueAccessToken(payload);
168
- const refreshToken = await this.service.issueRefreshToken(payload);
169
-
170
- // Prepare output,
171
- const tokens = {
172
- accessToken,
173
- refreshToken
174
- };
175
-
176
- if (noAccessToken)
177
- delete tokens.accessToken;
178
-
179
- if (noRefreshToken)
180
- delete tokens.refreshToken;
181
-
182
- // Send output.
183
- return Promise.resolve(tokens);
184
- }
185
- catch(error) {
186
- return Promise.reject(error);
187
- }
188
- }
189
-
190
- async refreshAccessToken(params) {
191
- try {
192
- const {
193
- refreshToken,
194
- parsedRefreshToken
195
- } = Params(params, {
196
- refreshToken: null,
197
- parsedRefreshToken: null
198
- });
199
-
200
- // Check if token is not blocked:
201
- const isActive = await this.isRefreshTokenActive({ refreshToken });
202
- if (!isActive) {
203
- const err = new Error('Invalid Token!');
204
- err.name = 'InvalidToken';
205
- throw err;
206
- }
207
-
208
- // Issue new access token, based on refresh token:
209
- const accessToken = await this.issueAccessToken({ parsedRefreshToken });
210
-
211
- // Send output.
212
- return Promise.resolve(accessToken);
213
- }
214
- catch(error) {
215
- return Promise.reject(error);
216
- }
217
- }
218
-
219
- async isRefreshTokenActive(params) {
220
- try {
221
- const {
222
- refreshToken
223
- } = Params(params, {
224
- refreshToken: null
225
- });
226
-
227
- const foundTokens = await this.disabledRefreshToken.selectAll({ token: refreshToken });
228
-
229
- // Prepare output. Check if provided token was not disabled.
230
- const isActive = foundTokens.length === 0;
231
-
232
- // Send output.
233
- return Promise.resolve(isActive);
234
- }
235
- catch(error) {
236
- return Promise.reject(error);
237
- }
238
- }
239
-
240
- async disableRefreshToken(params) {
241
- try {
242
- const {
243
- refreshToken,
244
- parsedToken
245
- } = Params(params, {
246
- refreshToken: null,
247
- parsedToken: null
248
- });
249
-
250
- // Unwrap nessessary data.
251
- const { id, role } = parsedToken;
252
-
253
- // Find or create:
254
- const cofParams = {
255
- [`${ role }_id`]: id,
256
- token: refreshToken
257
- };
258
- const [ disabledRefreshToken, created ] = await this.disabledRefreshToken.createOrFind(cofParams);
259
-
260
- // Check result,
261
- const createdStatus = created === true || !!disabledRefreshToken;
262
-
263
- // Send output.
264
- const result = {
265
- status: createdStatus
266
- }
267
- return Promise.resolve(result);
268
- }
269
- catch(error) {
270
- return Promise.reject(error);
271
- }
272
- }
273
- }