nodester 0.2.1 → 0.2.2

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 CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  > **nodester** is a modern and versatile Node.js framework designed to streamline the development of robust and scalable web applications.
7
7
 
8
- **nodester Query Language (NQL):** The main reason of nodester's existence is the [nodester Query Language (NQL)](docs/Queries.md), an extension of standard REST API syntax, it lets you craft complex queries with hierarchical associations.
8
+ The main reason of nodester's existence is the [nodester Query Language (NQL)](docs/Queries.md), an extension of standard REST API syntax, it lets you craft complex queries with hierarchical associations.
9
9
 
10
10
 
11
11
  ## Installation
@@ -30,7 +30,7 @@ const {
30
30
  const { merge } = require('../utils/objects.util');
31
31
 
32
32
  // Arguments validator.
33
- const { ensure } = require('../validators/arguments');
33
+ const { ensure } = require('nodester/validators/arguments');
34
34
 
35
35
  // Console:
36
36
  const consl = require('nodester/loggers/console');
@@ -24,7 +24,7 @@ const {
24
24
  } = require('../methods');
25
25
 
26
26
  // Arguments validator.
27
- const { ensure } = require('../../validators/arguments');
27
+ const { ensure } = require('nodester/validators/arguments');
28
28
 
29
29
 
30
30
  module.exports = {
@@ -7,6 +7,9 @@
7
7
 
8
8
  const { associateModels } = require('nodester/models/associate');
9
9
 
10
+ // Arguments validator.
11
+ const { ensure } = require('nodester/validators/arguments');
12
+
10
13
 
11
14
  module.exports = {
12
15
  migrate: _migrate
@@ -14,11 +17,7 @@ module.exports = {
14
17
 
15
18
  async function _migrate(databaseConnection, force=false) {
16
19
  try {
17
- // Validation of 'force' parameter.
18
- if (typeof force !== 'boolean') {
19
- const err = new Error('Wrong "force" parameter; must be boolean.');
20
- throw err;
21
- }
20
+ ensure(force, 'boolean', 'force');
22
21
 
23
22
  // Test connection.
24
23
  await databaseConnection.authenticate();
@@ -44,7 +43,7 @@ async function _migrate(databaseConnection, force=false) {
44
43
  return Promise.resolve(output);
45
44
  }
46
45
  catch(error) {
47
- console.error(' Migration failed!');
46
+ console.error('Migration failed!');
48
47
  console.error(error);
49
48
  return Promise.reject(error);
50
49
  }
@@ -0,0 +1,18 @@
1
+ /*!
2
+ * /nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
8
+
9
+ module.exports = class NodesterError extends Error {
10
+ constructor(message, status) {
11
+ super(message);
12
+
13
+ this.name = this.constructor.name;
14
+ this.status = status;
15
+
16
+ Error.captureStackTrace(this, this.constructor);
17
+ }
18
+ }
@@ -8,16 +8,19 @@
8
8
  const {
9
9
  NODESTER_QUERY_ERROR,
10
10
  } = require('nodester/constants/ErrorCodes');
11
+ const {
12
+ NOT_ACCEPTABLE
13
+ } = require('nodester/http/codes');
14
+
15
+ const NodesterError = require('./NodesterError');
11
16
 
12
17
 
13
- module.exports = class NodesterQueryError extends Error {
18
+ module.exports = class NodesterQueryError extends NodesterError {
14
19
  constructor(message) {
15
20
  super(message);
16
21
 
17
- this.name = NODESTER_QUERY_ERROR;
18
- this.status = 422;
22
+ this.status = NOT_ACCEPTABLE;
19
23
 
20
- // Remove constructor info from stack.
21
24
  Error.captureStackTrace(this, this.constructor);
22
25
  }
23
26
  }
@@ -7,10 +7,12 @@
7
7
 
8
8
 
9
9
  const Err = require('./CustomError');
10
+ const NodesterError = require('./NodesterError');
10
11
  const NodesterQueryError = require('./NodesterQueryError');
11
12
 
12
13
 
13
14
  module.exports = {
14
15
  Err,
16
+ NodesterError,
15
17
  NodesterQueryError
16
18
  }
@@ -21,7 +21,8 @@ module.exports = {
21
21
 
22
22
  /*
23
23
  *
24
- * @param {Object} params
24
+ * @param {Object} [params]
25
+ * @param {Object} params.query
25
26
  *
26
27
  * @alias getOne
27
28
  * @api public
@@ -40,6 +41,10 @@ async function _getOne(params) {
40
41
  [this.outputName.singular]: instance,
41
42
  count: 0 + (instance !== null)
42
43
  }
44
+
45
+ // Hook (checkout facades/mixins).
46
+ await this.afterGetOne(instance, params, result);
47
+
43
48
  return Promise.resolve(result);
44
49
  }
45
50
  catch(error) {
@@ -51,7 +56,8 @@ async function _getOne(params) {
51
56
 
52
57
  /*
53
58
  *
54
- * @param {Object} params
59
+ * @param {Object} [params]
60
+ * @param {Object} params.query
55
61
  *
56
62
  * @alias getMany
57
63
  * @api public
@@ -70,6 +76,10 @@ async function _getMany(params) {
70
76
  [this.outputName.plural]: instances,
71
77
  count: instances.length
72
78
  }
79
+
80
+ // Hook (checkout facades/mixins).
81
+ await this.afterGetMany(instances, params, result);
82
+
73
83
  return Promise.resolve(result);
74
84
  }
75
85
  catch(error) {
@@ -81,7 +91,8 @@ async function _getMany(params) {
81
91
 
82
92
  /*
83
93
  *
84
- * @param {Object} params
94
+ * @param {Object} [params]
95
+ * @param {Object} params.data
85
96
  *
86
97
  * @alias createOne
87
98
  * @api public
@@ -103,7 +114,7 @@ async function _createOne(params) {
103
114
  count: 0 + (instance !== null)
104
115
  }
105
116
 
106
- // Call after create.
117
+ // Hook (checkout facades/mixins).
107
118
  await this.afterCreateOne(instance, params, result);
108
119
 
109
120
  return Promise.resolve(result);
@@ -117,7 +128,9 @@ async function _createOne(params) {
117
128
 
118
129
  /*
119
130
  *
120
- * @param {Object} params
131
+ * @param {Object} [params]
132
+ * @param {Object} params.query
133
+ * @param {Object} params.data
121
134
  *
122
135
  * @alias updateOne
123
136
  * @api public
@@ -141,6 +154,10 @@ async function _updateOne(params) {
141
154
  [this.outputName.singular]: instance,
142
155
  count: 0 + (instance !== null)
143
156
  }
157
+
158
+ // Hook (checkout facades/mixins).
159
+ await this.afterUpdateOne(instance, params, result);
160
+
144
161
  return Promise.resolve(result);
145
162
  }
146
163
  catch(error) {
@@ -152,7 +169,8 @@ async function _updateOne(params) {
152
169
 
153
170
  /*
154
171
  *
155
- * @param {Object} params
172
+ * @param {Object} [params]
173
+ * @param {Object} params.query
156
174
  *
157
175
  * @alias deleteOne
158
176
  * @api public
@@ -171,6 +189,10 @@ async function _deleteOne(params) {
171
189
  success: count > 0,
172
190
  count: count
173
191
  };
192
+
193
+ // Hook (checkout facades/mixins).
194
+ await this.afterDeleteOne(null, params, result);
195
+
174
196
  return Promise.resolve(result);
175
197
  }
176
198
  catch(error) {
@@ -18,7 +18,7 @@ const { Sequelize } = require('sequelize');
18
18
  const { lowerCaseFirstLetter } = require('nodester/utils/strings');
19
19
 
20
20
  // Arguments validator.
21
- const { ensure } = require('../../validators/arguments');
21
+ const { ensure } = require('nodester/validators/arguments');
22
22
 
23
23
 
24
24
  module.exports = {
@@ -70,6 +70,7 @@ function _withDefaultCRUD(facade, options={}) {
70
70
  },
71
71
  writable: false
72
72
  });
73
+ // Model info\
73
74
 
74
75
  // Set name of this facade:
75
76
  Object.defineProperty(facade, 'name', {
@@ -138,7 +139,7 @@ function _withDefaultCRUD(facade, options={}) {
138
139
  facade.afterGetMany = async () => {};
139
140
  facade.afterCreateOne = async () => {};
140
141
  facade.afterUpdateOne = async () => {};
141
- facade.afterDeleteOe = async () => {};
142
+ facade.afterDeleteOne = async () => {};
142
143
  }
143
144
 
144
145
  return facade;
@@ -8,8 +8,8 @@
8
8
  /*
9
9
  * REST response factory.
10
10
  */
11
-
12
- const ResponseFormats = require('../../constants/ResponseFormats');
11
+ const Params = require('nodester/params');
12
+ const { NodesterError } = require('nodester/errors');
13
13
 
14
14
 
15
15
  module.exports = {
@@ -26,52 +26,83 @@ module.exports = {
26
26
  * }
27
27
  * Status code is sent in header.
28
28
  *
29
- * If error is not present, error should be null.
29
+ * If error is not present, error must be null.
30
30
  * If error is present, content can be null (But it's not required).
31
31
  *
32
32
  * @param {ServerResponse} res
33
- * @param {Object} options
33
+ * @param {Object} [options]
34
34
  * @param {Object} options.error
35
35
  * @param {Object} options.content (optional)
36
36
  * @param {Int} options.status
37
- * @param {String} options.format
38
37
  *
39
38
  * @alias createGenericResponse
40
39
  * @api public
41
40
  */
42
- function _createGenericResponse(
43
- res,
44
- options = {
45
- status: 200,
46
- content: {},
47
- error: null,
48
- format: ResponseFormats.JSON
49
- }
50
- ) {
41
+ function _createGenericResponse(res, options) {
51
42
  try {
43
+ let {
44
+ status,
45
+ content,
46
+ error
47
+ } = Params(options, {
48
+ status: 200,
49
+ content: {},
50
+ error: null
51
+ });
52
+
52
53
  const data = {
53
54
  content: options?.content ?? null,
54
- error: options?.error ?? null
55
+ error: null,
55
56
  };
56
57
 
57
- switch(options?.format) {
58
- case ResponseFormats.JSON: {
59
- return res.json(data);
58
+ if (!!error) {
59
+ const details = {
60
+ message: error?.message
60
61
  }
61
- case ResponseFormats.XML: {
62
- // TODO: format data into XML.
63
- return res.send(data);
62
+
63
+ switch(error.name) {
64
+ case 'Unauthorized': {
65
+ statusCode = 401;
66
+ break;
67
+ }
68
+ case 'NotFound': {
69
+ statusCode = 404;
70
+ break;
71
+ }
72
+ case 'ValidationError': {
73
+ statusCode = 422;
74
+ break;
75
+ }
76
+ case 'ConflictError': {
77
+ statusCode = 409;
78
+ break;
79
+ }
80
+ case 'SequelizeUniqueConstraintError': {
81
+ statusCode = 409;
82
+ details.errors = error?.errors;
83
+ break;
84
+ }
85
+ default:
86
+ statusCode = status;
87
+
88
+ if (!!error?.errors) {
89
+ details.errors = error?.errors;
90
+ }
91
+ break;
64
92
  }
65
- default: {
66
- const err = new TypeError("No format specified.");
67
- throw err;
93
+
94
+ data.error = {
95
+ details: details,
96
+ code: error.name
68
97
  }
69
98
  }
99
+
100
+ res.status(status);
101
+ return res.json(data);
70
102
  }
71
103
  catch(error) {
72
- const err = new Error(`Could not create generic response: ${error.message}`);
73
- err.name = error?.name;
74
- err.code = error?.code;
104
+ const err = new NodesterError(`Could not create generic response: ${ error.message }`);
105
+ Error.captureStackTrace(err, _createGenericResponse);
75
106
  throw err;
76
107
  }
77
108
  }
@@ -82,8 +113,9 @@ function _createGenericResponse(
82
113
  * Should be called on all successful respones.
83
114
  *
84
115
  * @param {ServerResponse} res
116
+ * @param {Object} [options]
85
117
  * @param {Object} options.content (optional)
86
- * @param {String} options.format
118
+ * @param {Object} options.status (optional)
87
119
  *
88
120
  * @alias createOKResponse
89
121
  * @api public
@@ -92,8 +124,7 @@ function _createOKResponse(res, options={}) {
92
124
 
93
125
  return this.createGenericResponse(res, {
94
126
  ...options,
95
- status: 200,
96
- format: options?.format ?? ResponseFormats.JSON
127
+ status: options?.status ?? 200,
97
128
  });
98
129
  }
99
130
 
@@ -103,11 +134,10 @@ function _createOKResponse(res, options={}) {
103
134
  * Should be called on all failed respones.
104
135
  *
105
136
  * @param {ServerResponse} res
106
- * @param {Object} options
137
+ * @param {Object} [options]
107
138
  * @param {Object} options.error
108
139
  * @param {Object} options.content (optional)
109
140
  * @param {Int} options.status
110
- * @param {String} options.format
111
141
  *
112
142
  * @alias createErrorResponse
113
143
  * @api public
@@ -117,6 +147,5 @@ function _createErrorResponse(res, options) {
117
147
  return this.createGenericResponse(res, {
118
148
  ...options,
119
149
  status: options?.status ?? 500,
120
- format: options?.format ?? ResponseFormats.JSON
121
150
  });
122
151
  }
@@ -79,4 +79,5 @@ module.exports = new Enum({
79
79
  LOOP_DETECTED: 508,
80
80
  NOT_EXTENDED: 510,
81
81
  NETWORK_AUTHENTICATION_REQUIRED: 511,
82
- });
82
+ })
83
+ .withKeyPrefix('HTTP_CODE_');
@@ -5,9 +5,15 @@
5
5
 
6
6
  'use strict';
7
7
 
8
+ const {
9
+ HTTP_CODE_UNPROCESSABLE_ENTITY
10
+ } = require('nodester/http/codes');
11
+
8
12
  const cookie = require('cookie');
9
13
  const cookieSignature = require('cookie-signature');
10
14
 
15
+ const { createErrorResponse } = require('nodester/factories/responses/rest');
16
+
11
17
 
12
18
  module.exports = function initCookiesMiddleware(options={}) {
13
19
  const context = {
@@ -26,19 +32,12 @@ function cookiesHandle(req, res, next) {
26
32
  const cookies = cookie.parse(req.headers.cookie);
27
33
  req.cookies = cookies;
28
34
 
29
- next();
35
+ return next();
30
36
  }
31
37
  catch(error) {
32
- console.error(error);
33
-
34
- const statusCode = error.status || 406;
35
- res.status(statusCode);
36
- res.json({
37
- error: {
38
- message: error.message,
39
- code: statusCode
40
- },
41
- status: statusCode
38
+ return createErrorResponse(res, {
39
+ error: error,
40
+ status: error.status ?? HTTP_CODE_UNPROCESSABLE_ENTITY
42
41
  });
43
42
  }
44
43
  }
@@ -5,8 +5,14 @@
5
5
 
6
6
  'use strict';
7
7
 
8
+ const {
9
+ HTTP_CODE_NOT_ACCEPTABLE
10
+ } = require('nodester/http/codes');
11
+
8
12
  const { formidable } = require('formidable');
9
13
 
14
+ const { createErrorResponse } = require('nodester/factories/responses/rest');
15
+
10
16
 
11
17
  module.exports = function initFormidableMiddleware(formidableOptions={}) {
12
18
  const context = {
@@ -26,17 +32,12 @@ async function formidableHandle(req, res, next) {
26
32
  files
27
33
  };
28
34
 
29
- next();
35
+ return next();
30
36
  }
31
37
  catch(error) {
32
- const statusCode = error.status || 406;
33
- res.status(statusCode);
34
- res.json({
35
- error: {
36
- message: error.message,
37
- code: statusCode
38
- },
39
- status: statusCode
40
- });
38
+ return createErrorResponse(res, {
39
+ error: error,
40
+ status: error.status ?? HTTP_CODE_NOT_ACCEPTABLE
41
+ })
41
42
  }
42
43
  }
@@ -5,8 +5,12 @@
5
5
 
6
6
  'use strict';
7
7
 
8
+ const {
9
+ HTTP_CODE_UNPROCESSABLE_ENTITY
10
+ } = require('nodester/http/codes');
11
+
8
12
  const QueryLexer = require('./interpreter/QueryLexer');
9
- const httpCodes = require('nodester/http/codes');
13
+ const { createErrorResponse } = require('nodester/factories/responses/rest');
10
14
 
11
15
 
12
16
  module.exports = function initNodesterQL() {
@@ -34,10 +38,12 @@ async function nqlHandle(req, res, next) {
34
38
 
35
39
  // Go on!
36
40
  req.nquery = lexer.query;
37
- next();
41
+ return next();
38
42
  }
39
43
  catch(error) {
40
- res.status(error.status ?? httpCodes.UNPROCESSABLE_ENTITY);
41
- res.json({ error: error.toString() });
44
+ return createErrorResponse(res, {
45
+ error: error,
46
+ status: error.status ?? HTTP_CODE_UNPROCESSABLE_ENTITY
47
+ });
42
48
  }
43
49
  }
@@ -2,6 +2,7 @@
2
2
  * /nodester
3
3
  * MIT Licensed
4
4
  */
5
+
5
6
  'use strict';
6
7
 
7
8
  const debug = require('debug')('nodester:interpreter:ModelsTree');
@@ -22,15 +23,27 @@ class ModelsTreeNode {
22
23
  this.skip = 0;
23
24
  this.limit = -1; // No limit
24
25
 
25
- this.includes = opts.includes ?? [];
26
+ this._includes = opts.includes ?? [];
26
27
  this.order = opts.order ?? 'asc';
27
28
  this.order_by = opts.order_by ?? 'id';
28
29
  }
29
30
 
31
+ get where() {
32
+ return this._where;
33
+ }
34
+
35
+ get functions() {
36
+ return this._functions;
37
+ }
38
+
30
39
  get hasParent() {
31
40
  return this.parent !== null;
32
41
  }
33
42
 
43
+ get includes() {
44
+ return this._includes;
45
+ }
46
+
34
47
  get includesCount() {
35
48
  return Object.values(this.includes).length;
36
49
  }
@@ -39,14 +52,6 @@ class ModelsTreeNode {
39
52
  return this.includesCount > 0;
40
53
  }
41
54
 
42
- get where() {
43
- return this._where;
44
- }
45
-
46
- get functions() {
47
- return this._functions;
48
- }
49
-
50
55
  resetActiveParam() {
51
56
  this.activeParam = null;
52
57
  }
@@ -72,7 +77,7 @@ class ModelsTreeNode {
72
77
 
73
78
  include(modelTreeNode) {
74
79
  modelTreeNode.parent = this;
75
- this.includes.push(modelTreeNode);
80
+ this._includes.push(modelTreeNode);
76
81
  return modelTreeNode;
77
82
  }
78
83
 
@@ -383,7 +383,7 @@ module.exports = class QueryLexer {
383
383
  const param = this.parseParamFromToken(token);
384
384
 
385
385
  if (isSubQuery === true && param === 'includes') {
386
- const err = new TypeError(`'include' is forbidden inside subquery (position ${ i }). Use: 'model.model1' or 'model.model1+model2'.`);
386
+ const err = new TypeError(`'include' is forbidden inside subquery (position ${ i }). Use: 'model.submodel' or 'model.submodel1+submodel2'.`);
387
387
  throw err;
388
388
  }
389
389
 
@@ -8,10 +8,10 @@
8
8
  const BOUNDS = require('../constants/Bounds');
9
9
 
10
10
  const { Op } = require('sequelize');
11
- const NQueryError = require('../factories/errors/NodesterQueryError');
11
+ const { NodesterQueryError } = require('nodester/errors');
12
12
  const httpCodes = require('nodester/http/codes');
13
13
 
14
- const { ensure } = require('../validators/arguments');
14
+ const { ensure } = require('nodester/validators/arguments');
15
15
 
16
16
 
17
17
  module.exports = traverse;
@@ -73,8 +73,8 @@ function traverse(queryNode, filter=null, model=null) {
73
73
  // put them through Filter:
74
74
  for (let field of filter.fields) {
75
75
  if (fieldsAvailable.indexOf(field) === -1) {
76
- const err = new TypeError(`Field '${ field }' is not present in model.`);
77
- err.status = httpCodes.NOT_ACCEPTABLE;
76
+ const err = new NodesterQueryError(`Field '${ field }' is not present in model.`);
77
+ Error.captureStackTrace(err, traverse);
78
78
  throw err;
79
79
  }
80
80
 
@@ -93,8 +93,8 @@ function traverse(queryNode, filter=null, model=null) {
93
93
 
94
94
  // At least 1 field is mandatory:
95
95
  if (newQuery.attributes.length === 0) {
96
- const err = new TypeError(`No fields were selected.`);
97
- err.status = httpCodes.NOT_ACCEPTABLE;
96
+ const err = new NodesterQueryError(`No fields were selected.`);
97
+ Error.captureStackTrace(err, traverse);
98
98
  throw err;
99
99
  }
100
100
  // Fields\
@@ -119,7 +119,7 @@ function traverse(queryNode, filter=null, model=null) {
119
119
  let rawSQL = '(SELECT COUNT(*) FROM ';
120
120
  let countAttribute = '_count';
121
121
 
122
- // If request to count one of includes:
122
+ // If request to count one of the includes:
123
123
  if (!isForRootModel) {
124
124
  // Check if it's available:
125
125
  if (
@@ -129,8 +129,8 @@ function traverse(queryNode, filter=null, model=null) {
129
129
  ||
130
130
  rootModelAssociations[countTarget] === undefined
131
131
  ) {
132
- const err = new NQueryError(`Count for '${ countTarget }' is not available.`);
133
- err.status = httpCodes.NOT_ACCEPTABLE;
132
+ const err = new NodesterQueryError(`Count for '${ countTarget }' is not available.`);
133
+ Error.captureStackTrace(err, traverse);
134
134
  throw err;
135
135
  }
136
136
 
@@ -266,8 +266,7 @@ function traverse(queryNode, filter=null, model=null) {
266
266
  const includeName = include.model;
267
267
 
268
268
  if (rootModelAssociations[includeName] === undefined) {
269
- const err = new NQueryError(`No include named '${ includeName }'`);
270
- err.status = httpCodes.NOT_ACCEPTABLE;
269
+ const err = new NodesterQueryError(`No include named '${ includeName }'`);
271
270
  Error.captureStackTrace(err, traverse);
272
271
  throw err;
273
272
  }
@@ -301,8 +300,7 @@ function _traverseIncludes(includes, model, filter, resultQuery) {
301
300
 
302
301
  // If no such association:
303
302
  if (!association) {
304
- const err = new NQueryError(`No include named '${ includeName }'`);
305
- err.status = httpCodes.NOT_ACCEPTABLE;
303
+ const err = new NodesterQueryError(`No include named '${ includeName }'`);
306
304
  Error.captureStackTrace(err, _traverseIncludes);
307
305
  throw err;
308
306
  }
@@ -25,7 +25,7 @@ const fs = require('fs');
25
25
  const commonExtensions = require('common-js-file-extensions');
26
26
 
27
27
  // Arguments validator.
28
- const { ensure } = require('../validators/arguments');
28
+ const { ensure } = require('nodester/validators/arguments');
29
29
 
30
30
  // Console:
31
31
  const consl = require('nodester/loggers/console');
@@ -9,7 +9,7 @@
9
9
  const { typeOf } = require('../utils/types.util');
10
10
 
11
11
  // Arguments validator.
12
- const { ensure } = require('../validators/arguments');
12
+ const { ensure } = require('nodester/validators/arguments');
13
13
 
14
14
 
15
15
  module.exports = class NodesterRoute {
@@ -6,7 +6,7 @@
6
6
  'use strict';
7
7
 
8
8
  // Arguments validator.
9
- const { ensure } = require('../validators/arguments');
9
+ const { ensure } = require('nodester/validators/arguments');
10
10
 
11
11
  // Console:
12
12
  const consl = require('nodester/loggers/console');
@@ -8,7 +8,7 @@
8
8
  const finalhandler = require('finalhandler');
9
9
 
10
10
  // Arguments validator.
11
- const { ensure } = require('../validators/arguments');
11
+ const { ensure } = require('nodester/validators/arguments');
12
12
 
13
13
  // Console:
14
14
  const consl = require('nodester/loggers/console');
@@ -175,17 +175,17 @@ module.exports = class MiddlewaresStack {
175
175
  process(req, res, next) {
176
176
  let middlewareOffset = -1;
177
177
 
178
- const _next = (...args) => {
178
+ const _next = async (...args) => {
179
179
  middlewareOffset += 1;
180
180
  const fn = this._middlewares[middlewareOffset];
181
181
 
182
182
  try {
183
183
  if (!fn && !!next) {
184
- // Middleware stack is finished:
184
+ // Middlewares stack is finished:
185
185
  return next.call(null, req, res, next, ...args);
186
186
  }
187
187
  else if (!!fn) {
188
- return fn.call(null, req, res, _next, ...args);
188
+ return await fn.call(null, req, res, _next, ...args);
189
189
  }
190
190
  }
191
191
  catch(error) {
@@ -9,7 +9,7 @@ const BOUNDS = require('../constants/Bounds');
9
9
  const CLAUSES = require('../constants/Clauses');
10
10
 
11
11
  const { isModel } = require('../utils/models');
12
- const { ensure } = require('../validators/arguments');
12
+ const { ensure } = require('nodester/validators/arguments');
13
13
 
14
14
 
15
15
  module.exports = class NodesterFilter {
@@ -0,0 +1,45 @@
1
+ /*!
2
+ * /nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
8
+
9
+ module.exports = {
10
+ toAST_ModelsTreeNode: _toAST_ModelsTreeNode
11
+ }
12
+
13
+ function _toAST_ModelsTreeNode(node, spacing=0) {
14
+ let spaces = '';
15
+ for (let i = 0; i < spacing; i++) {
16
+ spaces += ' ';
17
+ }
18
+
19
+ let ast = `${ spaces }[TreeNode]\n`;
20
+
21
+ spaces += ' ';
22
+
23
+ ast += `${ spaces }model: ${ node.model }\n\n`;
24
+
25
+ ast += `${ spaces }fields: [\n${ node.fields.map(f => ` • ${ f },\n`) }`;
26
+ ast += `${ spaces }]\n\n`;
27
+
28
+ ast += `${ spaces }functions: [\n${ node.functions.map(f => ` • ${ f },\n`) }`;
29
+ ast += `${ spaces }]\n\n`;
30
+
31
+ ast += `${ spaces }where: ${ JSON.stringify(node.where) }\n\n`;
32
+
33
+ ['skip','limit','order','order_by'].map(
34
+ c => ast += `${ spaces }${ c }: ${ node[c] }\n\n`
35
+ );
36
+
37
+ ast += `${ spaces }includes: [\n`
38
+ node.includes.map(n => ast += _toAST_ModelsTreeNode(n, spacing + 2));
39
+ ast += `${ spaces }]\n`;
40
+
41
+ spaces.slice(-1);
42
+ ast += `${ spaces }[TreeNode END]\n\n`;
43
+
44
+ return ast;
45
+ }
@@ -6,7 +6,7 @@
6
6
  'use strict';
7
7
 
8
8
  // Arguments validator.
9
- const { ensure } = require('../validators/arguments');
9
+ const { ensure } = require('nodester/validators/arguments');
10
10
 
11
11
 
12
12
  module.exports = {
@@ -17,7 +17,7 @@ module.exports = {
17
17
  * @param {String} rules
18
18
  * @param {String} argumentName
19
19
  *
20
- * @api private
20
+ * @api public
21
21
  * @alias ensure
22
22
  */
23
23
  function _ensure(argument, rules, argumentName) {
@@ -40,7 +40,9 @@ function _ensure(argument, rules, argumentName) {
40
40
 
41
41
  if (rule === 'required') {
42
42
  if (argument === undefined || argument === null) {
43
- throw new Error(`${ name } is required.`);
43
+ const err = new TypeError(`${ name } is required.`);
44
+ Error.captureStackTrace(err, _ensure);
45
+ throw err;
44
46
  }
45
47
 
46
48
  isRequired = true;
@@ -61,7 +63,9 @@ function _ensure(argument, rules, argumentName) {
61
63
  }
62
64
 
63
65
  if (mismatchedTypesCount === types.length && argument !== undefined) {
64
- throw new TypeError(`${ name } must be of type ${ types.join('|') }.`);
66
+ const err = new TypeError(`${ name } must be of type ${ types.join('|') }.`);
67
+ Error.captureStackTrace(err, _ensure);
68
+ throw err;
65
69
  }
66
70
 
67
71
  return true;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nodester",
3
- "version": "0.2.1",
4
- "description": "A boilerplate framework for Node.js",
3
+ "version": "0.2.2",
4
+ "description": "A versatile REST framework for Node.js",
5
5
  "exports": {
6
6
  ".": "./lib/application/index.js",
7
7
 
@@ -18,11 +18,12 @@
18
18
 
19
19
  "./enum": "./lib/structures/Enum.js",
20
20
 
21
+ "./errors": "./lib/errors/index.js",
22
+
21
23
  "./facades/methods": "./lib/facades/methods/index.js",
22
24
  "./facades/mixins": "./lib/facades/mixins/index.js",
23
25
 
24
- "./factories/errors": "./lib/factories/errors/index.js",
25
- "./factories/responses/rest": "./lib/factories/responses/rest/index.js",
26
+ "./factories/responses/rest": "./lib/factories/responses/rest.js",
26
27
 
27
28
  "./filter": "./lib/structures/Filter.js",
28
29
 
@@ -53,10 +54,14 @@
53
54
 
54
55
  "./utils/sql": "./lib/utils/sql.util.js",
55
56
  "./utils/strings": "./lib/utils/strings.util.js",
56
- "./utils/sanitizations": "./lib/utils/sanitizations.util.js"
57
+ "./utils/sanitizations": "./lib/utils/sanitizations.util.js",
58
+
59
+ "./validators/arguments": "./lib/validators/arguments.js"
57
60
  },
58
61
  "directories": {
59
- "doc": "docs"
62
+ "docs": "docs",
63
+ "lib": "lib",
64
+ "tests": "tests"
60
65
  },
61
66
  "source": [
62
67
  "lib"
@@ -67,7 +72,10 @@
67
72
  },
68
73
  "author": "Mark Khramko <markkhramko@gmail.com>",
69
74
  "license": "MIT",
70
- "repository": "MarkKhramko/nodester",
75
+ "repository": {
76
+ "type": "git",
77
+ "url": "git+https://github.com/MarkKhramko/nodester.git"
78
+ },
71
79
  "private": false,
72
80
  "bugs": {
73
81
  "url": "https://github.com/MarkKhramko/nodester/issues"
@@ -0,0 +1,16 @@
1
+ const { ModelsTree } = require('../lib/middlewares/ql/sequelize/interpreter/ModelsTree');
2
+ const { toAST_ModelsTreeNode } = require('../lib/tools/nql.tool');
3
+
4
+ const tree = new ModelsTree();
5
+ tree.node.addWhere({ id: ['1000'] });
6
+ tree.include('comments').use('comments');
7
+ tree.node.order = 'desc';
8
+ tree.up();
9
+ tree.include('users');
10
+ tree.include('likes') && tree.use('likes');
11
+ tree.node.order = 'rand';
12
+ tree.up();
13
+ tree.include('reposts');
14
+
15
+ console.debug(toAST_ModelsTreeNode(tree.root));
16
+
File without changes