nodester 0.0.1 → 0.0.6

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 (58) hide show
  1. package/Readme.md +61 -26
  2. package/lib/application/index.js +86 -35
  3. package/lib/constants/Operations.js +23 -0
  4. package/lib/controllers/methods/index.js +170 -0
  5. package/lib/controllers/mixins/index.js +213 -0
  6. package/lib/enums/Enum.js +16 -0
  7. package/lib/factories/errors/CustomError.js +7 -5
  8. package/lib/factories/responses/html.js +7 -2
  9. package/lib/factories/responses/rest.js +110 -0
  10. package/lib/http/codes/index.js +157 -0
  11. package/lib/{application/http → http}/request.js +6 -30
  12. package/lib/{application/http → http}/response.js +20 -53
  13. package/lib/middlewares/etag/index.js +62 -0
  14. package/lib/middlewares/ql/sequelize/index.js +34 -0
  15. package/lib/middlewares/ql/sequelize/interpreter/ModelsTree.js +121 -0
  16. package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +456 -0
  17. package/lib/models/define.js +6 -13
  18. package/lib/models/mixins.js +28 -15
  19. package/lib/params/Params.js +34 -0
  20. package/lib/queries/NodesterQueryParams.js +139 -0
  21. package/lib/router/handlers.util.js +61 -0
  22. package/lib/router/index.js +386 -0
  23. package/lib/router/route.js +124 -0
  24. package/lib/router/routes.util.js +66 -0
  25. package/lib/stacks/MarkersStack.js +35 -0
  26. package/lib/{application → stacks}/MiddlewareStack.js +47 -13
  27. package/lib/utils/path.util.js +3 -1
  28. package/lib/utils/types.util.js +51 -1
  29. package/lib/validators/dates.js +25 -0
  30. package/lib/validators/numbers.js +14 -0
  31. package/package.json +16 -2
  32. package/tests/index.test.js +7 -2
  33. package/tests/nql.test.js +277 -0
  34. package/docs/App.md +0 -13
  35. package/docs/Queries.md +0 -61
  36. package/docs/Readme.md +0 -2
  37. package/docs/Routing.md +0 -34
  38. package/examples/goal/index.js +0 -23
  39. package/examples/rest/index.js +0 -25
  40. package/examples/rest/node_modules/.package-lock.json +0 -40
  41. package/examples/rest/package-lock.json +0 -72
  42. package/examples/rest/package.json +0 -14
  43. package/lib/constants/ConstantsEnum.js +0 -13
  44. package/lib/factories/responses/api.js +0 -90
  45. package/lib/routers/Default/index.js +0 -143
  46. package/lib/routers/Default/layer.js +0 -50
  47. package/lib/routers/Main/index.js +0 -10
  48. package/lib/routers/Roles/index.js +0 -81
  49. package/lib/utils/params.util.js +0 -19
  50. /package/lib/{controllers/Controller.js → _/n_controllers/Controller.js"} +0 -0
  51. /package/lib/{controllers/JWTController.js → _/n_controllers/JWTController.js"} +0 -0
  52. /package/lib/{controllers/ServiceController.js → _/n_controllers/ServiceController.js"} +0 -0
  53. /package/lib/{controllers/WebController.js → _/n_controllers/WebController.js"} +0 -0
  54. /package/lib/{facades → _facades}/Facade.js +0 -0
  55. /package/lib/{facades → _facades}/FacadeParams.js +0 -0
  56. /package/lib/{facades → _facades}/ServiceFacade.js +0 -0
  57. /package/lib/{facades → _facades}/jwt.facade.js +0 -0
  58. /package/lib/{application/http → http}/utils.js +0 -0
@@ -12,7 +12,7 @@ const contentDisposition = require('content-disposition');
12
12
  const createError = require('http-errors')
13
13
  const encodeUrl = require('encodeurl');
14
14
  const escapeHtml = require('escape-html');
15
- const http = require('http');
15
+ const { ServerResponse } = require('http');
16
16
  const onFinished = require('on-finished');
17
17
  const statuses = require('statuses')
18
18
  const sign = require('cookie-signature').sign;
@@ -28,10 +28,10 @@ const {
28
28
  const path = require('path');
29
29
  const extname = path.extname;
30
30
  const resolve = path.resolve;
31
- const { isAbsolute } = require('../../utils/path.util');
31
+ const { isAbsolute } = require('../utils/path.util');
32
32
 
33
33
 
34
- const res = http.ServerResponse.prototype;
34
+ const res = ServerResponse.prototype;
35
35
  module.exports = res;
36
36
 
37
37
  /**
@@ -135,53 +135,26 @@ res.send = function send(body) {
135
135
  }
136
136
  }
137
137
 
138
- // determine if ETag should be generated
139
- const etagFn = app.get('etag fn')
140
- const generateETag = !this.get('ETag') && typeof etagFn === 'function'
141
-
142
- // populate Content-Length
143
- let bufferLength = undefined;
144
- if (chunk !== undefined) {
145
- if (Buffer.isBuffer(chunk)) {
146
- // Get length of the Buffer.
147
- bufferLength = chunk.length
148
- }
149
- else if (!generateETag && chunk.length < 1000) {
150
- // Just calculate length when no ETag + small chunk.
151
- bufferLength = Buffer.byteLength(chunk, encoding)
152
- }
153
- else {
154
- // Convert chunk to Buffer and calculate:
155
- chunk = Buffer.from(chunk, encoding)
156
- encoding = undefined;
157
- bufferLength = chunk.length
158
- }
159
-
160
- this.set('Content-Length', bufferLength);
161
- }
162
-
163
- // Populate ETag
164
- let etag = undefined;
165
- if (generateETag && bufferLength !== undefined) {
166
- if ((etag = etagFn(chunk, encoding))) {
167
- this.set('ETag', etag);
168
- }
169
- }
170
-
171
138
  // freshness:
172
- if (req.fresh) {
173
- this.statusCode = 304;
174
- }
175
-
176
- // strip irrelevant headers
177
- if (204 === this.statusCode || 304 === this.statusCode) {
139
+ // if (req.fresh) {
140
+ // this.statusCode = 304;
141
+ // }
142
+
143
+ // Strip irrelevant headers for:
144
+ // - 204 (No Content)
145
+ // - 303 (Not Modified)
146
+ if (
147
+ this.statusCode === 204
148
+ ||
149
+ this.statusCode === 304
150
+ ) {
178
151
  this.removeHeader('Content-Type');
179
152
  this.removeHeader('Content-Length');
180
153
  this.removeHeader('Transfer-Encoding');
181
154
  chunk = '';
182
155
  }
183
156
 
184
- // alter headers for 205
157
+ // Alter headers for 205 (Reset Content):
185
158
  if (this.statusCode === 205) {
186
159
  this.set('Content-Length', '0')
187
160
  this.removeHeader('Transfer-Encoding')
@@ -189,11 +162,11 @@ res.send = function send(body) {
189
162
  }
190
163
 
191
164
  if (req.method === 'HEAD') {
192
- // skip body for HEAD
165
+ // skip body for HEAD.
193
166
  this.end();
194
167
  }
195
168
  else {
196
- // respond
169
+ // Respond.
197
170
  this.end(chunk, encoding);
198
171
  }
199
172
 
@@ -214,19 +187,13 @@ res.send = function send(body) {
214
187
  * @public
215
188
  */
216
189
  res.json = function json(obj) {
217
- const app = this.app;
218
-
219
- // Settings:
220
- const escape = app.get('json escape')
221
- const replacer = app.get('json replacer');
222
- const spaces = app.get('json spaces');
223
- const body = stringify(obj, replacer, spaces, escape)
224
190
 
225
- // content-type
191
+ // If content-type not set:
226
192
  if (!this.get('Content-Type')) {
227
193
  this.set('Content-Type', 'application/json');
228
194
  }
229
195
 
196
+ const body = JSON.stringify(obj);
230
197
  return this.send(body);
231
198
  };
232
199
 
@@ -0,0 +1,62 @@
1
+ 'use strict'
2
+
3
+ const calculate = require('etag');
4
+ const Stream = require('stream');
5
+ const promisify = require('util').promisify;
6
+ const fs = require('fs');
7
+
8
+ const getFileStats = promisify(fs.stat);
9
+
10
+ /**
11
+ * Expose `etag` middleware.
12
+ *
13
+ * Add ETag header field.
14
+ * @param {object} [options] see https://github.com/jshttp/etag#options
15
+ * @param {boolean} [options.weak]
16
+ * @return {Function}
17
+ * @api public
18
+ */
19
+ module.exports = function etag (options) {
20
+ return async function(req, res, next) {
21
+ await next()
22
+ const entity = await getResponseEntity(req, res)
23
+ setEtag(res, entity, options);
24
+ }
25
+ }
26
+
27
+
28
+ async function getResponseEntity (res) {
29
+ // If body is not defined:
30
+ const { body } = res;
31
+ if (!body || res.get('etag'))
32
+ return;
33
+
34
+ // Status code.
35
+ const status = res.status / 100 | 0;
36
+
37
+ // 2xx
38
+ if (status !== 2)
39
+ return;
40
+
41
+ if (body instanceof Stream) {
42
+ if (!body.path)
43
+ return;
44
+
45
+ const stats = await getFileStats(body.path);
46
+ return stats;
47
+ }
48
+ else if ((typeof body === 'string') || Buffer.isBuffer(body)) {
49
+ return body;
50
+ }
51
+ else {
52
+ return JSON.stringify(body);
53
+ }
54
+ }
55
+
56
+
57
+ function setEtag (res, entity, options) {
58
+ if (!entity)
59
+ return;
60
+
61
+ res.etag = calculate(entity, options);
62
+ }
@@ -0,0 +1,34 @@
1
+ const QueryLexer = require('./interpreter/QueryLexer');
2
+
3
+
4
+ module.exports = NodesterQL;
5
+
6
+ async function NodesterQL(req, res, next) {
7
+ // Object, which will be populated with parsed query.
8
+ req.nquery = {};
9
+
10
+ // Unwrap neccessary params.
11
+ const {
12
+ url
13
+ } = req;
14
+
15
+ // If no query, skip:
16
+ if (url.indexOf('?') === -1) {
17
+ return next();
18
+ }
19
+
20
+ try {
21
+ // Convert to URLSearchParams.
22
+ const queryString = req.url.split('?')[1];
23
+
24
+ const lexer = new QueryLexer(queryString);
25
+
26
+ // Go on!
27
+ req.nquery = lexer.query;
28
+ next();
29
+ }
30
+ catch(error) {
31
+ res.status(422);
32
+ res.json({ error: error.toString() });
33
+ }
34
+ }
@@ -0,0 +1,121 @@
1
+ const debug = require('debug')('nodester:interpreter:ModelsTree');
2
+
3
+
4
+ class ModelsTreeNode {
5
+ constructor(model, parent=null, opts={}) {
6
+ this.model = model;
7
+ this.parent = parent;
8
+ this.activeParam = null;
9
+ this.op = null;
10
+
11
+ // for override:
12
+ this.fields = [];
13
+ this._where = {};
14
+ this.skip = 0;
15
+ this.limit = -1; // No limit
16
+
17
+ this.includes = opts.includes ?? [];
18
+ this.order = opts.order ?? 'asc';
19
+ this.orderBy = opts.orderBy ?? 'id';
20
+ }
21
+
22
+ get hasParent() {
23
+ return this.parent !== null;
24
+ }
25
+
26
+ get includesCount() {
27
+ return Object.values(this.includes).length;
28
+ }
29
+
30
+ get hasIncludes() {
31
+ return this.includesCount > 0;
32
+ }
33
+
34
+ get where() {
35
+ return this._where;
36
+ }
37
+
38
+ resetActiveParam() {
39
+ this.activeParam = null;
40
+ }
41
+
42
+ resetOP() {
43
+ this.op = null;
44
+ }
45
+
46
+ addWhere(condition={}) {
47
+ this._where = {
48
+ ...this.where,
49
+ ...condition
50
+ }
51
+ }
52
+
53
+ include(modelTreeNode) {
54
+ modelTreeNode.parent = this;
55
+ this.includes.push(modelTreeNode);
56
+ return modelTreeNode;
57
+ }
58
+
59
+ toObject() {
60
+ return {
61
+ model: this.model,
62
+
63
+ where: this.where,
64
+ skip: this.skip,
65
+ limit: this.limit,
66
+ order: this.order,
67
+ orderBy: this.orderBy,
68
+
69
+ fields: this.fields,
70
+
71
+ includes: this.includes.map(i => i.toObject())
72
+ }
73
+ }
74
+ }
75
+
76
+ class ModelsTree {
77
+ constructor() {
78
+ this.root = new ModelsTreeNode('root', null);
79
+ this.node = this.root;
80
+ }
81
+
82
+ include(model, opts={}) {
83
+ debug('include', model);
84
+
85
+ const node = new ModelsTreeNode(model, this.node, opts);
86
+ this.node.include(node);
87
+ return this;
88
+ }
89
+
90
+ use(model) {
91
+ let foundOne = null;
92
+ // Dirty search:
93
+ for (const include of this.node.includes) {
94
+ if (include.model === model) {
95
+ foundOne = this.node = include;
96
+ break;
97
+ }
98
+ }
99
+
100
+ debug('use', model, !!foundOne ? '' : '-> failed.');
101
+
102
+ return foundOne;
103
+ }
104
+
105
+ up() {
106
+ if (this.node.hasParent) {
107
+ this.node = this.node.parent;
108
+ }
109
+
110
+ debug('go up to', this.node.model);
111
+ }
112
+
113
+ upToRoot() {
114
+ this.node = this.root;
115
+
116
+ debug('go up to root');
117
+ }
118
+ }
119
+
120
+ exports.ModelsTreeNode = ModelsTreeNode;
121
+ exports.ModelsTree = ModelsTree;