nodester 0.0.1 → 0.0.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.
Files changed (68) hide show
  1. package/Readme.md +33 -39
  2. package/lib/application/index.js +110 -38
  3. package/lib/constants/Operations.js +23 -0
  4. package/lib/controllers/methods/index.js +194 -0
  5. package/lib/controllers/mixins/index.js +222 -0
  6. package/lib/database/connection.js +34 -0
  7. package/lib/database/migration.js +42 -0
  8. package/lib/database/utils.js +19 -0
  9. package/lib/enums/Enum.js +16 -0
  10. package/lib/facades/methods/index.js +173 -0
  11. package/lib/facades/mixins/index.js +111 -0
  12. package/lib/factories/errors/CustomError.js +7 -5
  13. package/lib/factories/responses/html.js +7 -2
  14. package/lib/factories/responses/rest.js +110 -0
  15. package/lib/http/codes/index.js +157 -0
  16. package/lib/{application/http → http}/request.js +6 -30
  17. package/lib/{application/http → http}/response.js +20 -53
  18. package/lib/middlewares/etag/index.js +62 -0
  19. package/lib/middlewares/ql/sequelize/index.js +34 -0
  20. package/lib/middlewares/ql/sequelize/interpreter/ModelsTree.js +121 -0
  21. package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +456 -0
  22. package/lib/models/associate.js +17 -0
  23. package/lib/models/define.js +56 -14
  24. package/lib/models/mixins.js +100 -78
  25. package/lib/params/Params.js +37 -0
  26. package/lib/queries/Colander.js +84 -0
  27. package/lib/queries/NodesterQueryParams.js +139 -0
  28. package/lib/queries/traverse.js +311 -0
  29. package/lib/router/handlers.util.js +61 -0
  30. package/lib/router/index.js +386 -0
  31. package/lib/router/route.js +124 -0
  32. package/lib/router/routes.util.js +66 -0
  33. package/lib/stacks/MarkersStack.js +35 -0
  34. package/lib/{application → stacks}/MiddlewareStack.js +47 -13
  35. package/lib/utils/path.util.js +3 -1
  36. package/lib/utils/types.util.js +51 -1
  37. package/lib/validators/dates.js +25 -0
  38. package/lib/validators/numbers.js +14 -0
  39. package/package.json +31 -4
  40. package/tests/index.test.js +7 -2
  41. package/tests/nql.test.js +277 -0
  42. package/docs/App.md +0 -13
  43. package/docs/Queries.md +0 -61
  44. package/docs/Readme.md +0 -2
  45. package/docs/Routing.md +0 -34
  46. package/examples/goal/index.js +0 -23
  47. package/examples/rest/index.js +0 -25
  48. package/examples/rest/node_modules/.package-lock.json +0 -40
  49. package/examples/rest/package-lock.json +0 -72
  50. package/examples/rest/package.json +0 -14
  51. package/lib/constants/ConstantsEnum.js +0 -13
  52. package/lib/controllers/Controller.js +0 -474
  53. package/lib/controllers/JWTController.js +0 -240
  54. package/lib/controllers/ServiceController.js +0 -109
  55. package/lib/controllers/WebController.js +0 -75
  56. package/lib/facades/Facade.js +0 -388
  57. package/lib/facades/FacadeParams.js +0 -11
  58. package/lib/facades/ServiceFacade.js +0 -17
  59. package/lib/facades/jwt.facade.js +0 -273
  60. package/lib/factories/responses/api.js +0 -90
  61. package/lib/models/DisabledRefreshToken.js +0 -68
  62. package/lib/models/Extractor.js +0 -320
  63. package/lib/routers/Default/index.js +0 -143
  64. package/lib/routers/Default/layer.js +0 -50
  65. package/lib/routers/Main/index.js +0 -10
  66. package/lib/routers/Roles/index.js +0 -81
  67. package/lib/utils/params.util.js +0 -19
  68. /package/lib/{application/http → http}/utils.js +0 -0
@@ -6,35 +6,50 @@ const {
6
6
  modelHasAssociations,
7
7
  getModelAssociationProps,
8
8
  compileModelAssociationData,
9
- } = require('nodester/utils/modelAssociations.util');
9
+ } = require('../utils/modelAssociations.util');
10
+
11
+ // Nodester query:
12
+ const NQLexer = require('../middlewares/ql/sequelize/interpreter/QueryLexer');
13
+ const traverseNQuery = require('../queries/traverse');
10
14
 
11
15
 
12
16
  module.exports = {
13
17
  implementsCRUD: _implementsCRUD
14
18
  }
15
19
 
16
- function _implementsCRUD(modelDefinition) {
17
- if (!!modelDefinition) {
18
20
 
19
- // Create.
20
- modelDefinition.createWithIncludes = _createWithIncludes.bind(modelDefinition);
21
+ /**
22
+ * Sets all of CRUD methods to Model.
23
+ *
24
+ * @param {Object} modelDefinition
25
+ *
26
+ *
27
+ * @api public
28
+ * @alias implementsCRUD
29
+ */
30
+ function _implementsCRUD(modelDefinition) {
31
+ if (!modelDefinition) {
32
+ const err = new TypeError(`"modelDefinition" argument is not provided.`);
33
+ throw err;
34
+ }
21
35
 
22
- // Read:
23
- modelDefinition.findById = _findById.bind(modelDefinition);
24
- modelDefinition.findOneWithIncludes = _findOneWithIncludes.bind(modelDefinition);
36
+ // Create.
37
+ modelDefinition.createWithIncludes = _createWithIncludes.bind(modelDefinition);
25
38
 
26
- // Update:
27
- modelDefinition.updateOne = _updateOne.bind(modelDefinition);
28
- modelDefinition.updateById = _updateById.bind(modelDefinition);
39
+ // Read:
40
+ modelDefinition.findById = _findById.bind(modelDefinition);
41
+ modelDefinition.findMany = _findMany.bind(modelDefinition);
29
42
 
30
- // Delete.
31
- modelDefinition.deleteById = _deleteById.bind(modelDefinition);
43
+ // Update:
44
+ modelDefinition.updateOne = _updateOne.bind(modelDefinition);
45
+ modelDefinition.updateById = _updateById.bind(modelDefinition);
32
46
 
33
- // Associations:
34
- modelDefinition.getIncludesList = _getIncludesList.bind(modelDefinition);
35
- }
47
+ // Delete:
48
+ modelDefinition.deleteOne = _deleteOne.bind(modelDefinition);
49
+ modelDefinition.deleteById = _deleteById.bind(modelDefinition);
36
50
  }
37
51
 
52
+
38
53
  /* Main mixinis: */
39
54
  async function _createWithIncludes(
40
55
  data={}
@@ -101,37 +116,76 @@ async function _createWithIncludes(
101
116
 
102
117
  function _findById(
103
118
  id=null,
104
- include=[],
105
- paranoid=true
119
+ opts={}
106
120
  ) {
107
- const query = {
108
- where: { id },
109
- include: include,
110
- paranoid: !!paranoid
111
- };
112
- return this.findOne(query);
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);
113
148
  }
114
149
 
115
- function _findOneWithIncludes(
116
- where={},
117
- include=[],
118
- paranoid=true
119
- ) {
120
- const query = {
121
- where: where,
122
- include: include,
123
- paranoid: !!paranoid
124
- };
125
- return this.findOne(query);
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);
126
179
  }
127
180
 
181
+
128
182
  async function _updateOne(
129
183
  where,
130
184
  data,
131
185
  include=[]
132
186
  ) {
133
187
  try {
134
- const instance = await this.findOneWithIncludes(where, include);
188
+ const instance = await this.findOne({ where, include });
135
189
 
136
190
  if (!instance) {
137
191
  const err = new Error(`Model not found`);
@@ -188,7 +242,7 @@ async function _updateOne(
188
242
 
189
243
  // Select this instance again, if includes was set:
190
244
  if (include?.length > 0) {
191
- const updatedInstance = await this.findOneWithIncludes(where, include);
245
+ const updatedInstance = await this.findOne({ where, include });
192
246
  fullInstanceData = updatedInstance.toJSON();
193
247
  }
194
248
 
@@ -212,6 +266,15 @@ async function _updateById(
212
266
  );
213
267
  }
214
268
 
269
+
270
+ function _deleteOne(query={}) {
271
+ const _query = {
272
+ ...query,
273
+ limit: 1
274
+ }
275
+ return this.destroy(_query);
276
+ }
277
+
215
278
  function _deleteById(
216
279
  id=null
217
280
  ) {
@@ -222,47 +285,6 @@ function _deleteById(
222
285
  }
223
286
  /* Main mixinis\ */
224
287
 
225
- /* Association mixins: */
226
- function _getIncludesList(facadeData=null) {
227
- // console.log({ facadeData, model: this });
228
-
229
- const result = [];
230
-
231
- const associations = this.associations;
232
- const associationEntries = Object.entries(associations);
233
-
234
- associationEntries.forEach(([
235
- associationName,
236
- associationDefinition
237
- ]) => {
238
- const a = { association: associationName };
239
-
240
- if (!!facadeData) {
241
- // If facade data is set, go deeper:
242
- const keys = Object.keys( facadeData );
243
- if (keys.indexOf(associationName) > 0) {
244
- const associationModel = associationDefinition.target;
245
-
246
- const a = { association: associationName };
247
- if (Object.entries(associationModel.associations).length > 0) {
248
- const deepData = facadeData[ associationName ];
249
- a.include = associationModel.getIncludesList(Array.isArray(deepData) ? deepData[0] : deepData);
250
- }
251
-
252
- result.push( a );
253
- }
254
- }
255
- else {
256
- result.push( a );
257
- }
258
- });
259
-
260
- // console.log('getIncludesList', result);
261
-
262
- return result;
263
- }
264
- /* Association mixins\ */
265
-
266
288
  /* Subfunctions: */
267
289
  async function _updateOrCreateOrDelete(
268
290
  modelDefinition,
@@ -0,0 +1,37 @@
1
+
2
+ module.exports = Params;
3
+
4
+ /**
5
+ * Extracts only values in second argument
6
+ * from first argument.
7
+ * If such values is missing in first atgument,
8
+ * will fallback to the value in second argument.
9
+ *
10
+ * @param {Object} sourceObj
11
+ * @param {Object} defaultValuesList
12
+ *
13
+ * @return {Object} result
14
+ *
15
+ * @api public
16
+ */
17
+ function Params(
18
+ sourceObj={},
19
+ defaultValuesList={}
20
+ ) {
21
+ const result = {};
22
+
23
+ const keys = Object.keys(defaultValuesList);
24
+ for (const key of keys) {
25
+
26
+ // If value is not set,
27
+ // use default one from 'defaultValuesList':
28
+ if (sourceObj[key] === undefined) {
29
+ result[key] = defaultValuesList[key];
30
+ continue;
31
+ }
32
+
33
+ result[key] = sourceObj[key];
34
+ }
35
+
36
+ return result;
37
+ }
@@ -0,0 +1,84 @@
1
+ const CLAUSES = ['limit', 'skip', 'order', 'order_by'];
2
+
3
+
4
+ module.exports = class Colander {
5
+
6
+ /*
7
+ *
8
+ * @param {Object|Model} optsOrModelDefinition
9
+ * - @param {Array} fields
10
+ * - @param {Array} clauses
11
+ * - @param {Object} includes
12
+ * - @param {Object} statics
13
+ * -- @param {Object} attributes
14
+ * -- @param {Object} clauses
15
+ *
16
+ */
17
+ constructor(optsOrModelDefinition) {
18
+ this._fields = [];
19
+ this._clauses = [];
20
+ this._includes = {};
21
+
22
+ this._statics = {
23
+ attributes: {},
24
+ clauses: {
25
+ limit: 3
26
+ }
27
+ }
28
+
29
+ // If model:
30
+ if (!!optsOrModelDefinition.tableName && typeof optsOrModelDefinition._schema === 'object') {
31
+ this._fields = Object.keys(optsOrModelDefinition.tableAttributes);
32
+ this._clauses = CLAUSES;
33
+ }
34
+ // If options:
35
+ else {
36
+ const {
37
+ fields,
38
+ clauses,
39
+ includes,
40
+ statics,
41
+ } = optsOrModelDefinition;
42
+
43
+ if (Array.isArray(fields)) {
44
+ this._fields = fields;
45
+ }
46
+
47
+ if (Array.isArray(clauses)) {
48
+ this._clauses = clauses;
49
+ }
50
+
51
+ if (typeof includes === 'object') {
52
+ this._includes = includes;
53
+ }
54
+
55
+ if (typeof statics === 'object') {
56
+ if (typeof statics.attributes === 'object') {
57
+ this._statics.attributes = statics.attributes;
58
+ }
59
+
60
+ if (typeof statics.clauses === 'object') {
61
+ this._statics.clauses = statics.clauses;
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ // Getters:
68
+ get fields() {
69
+ return this._fields;
70
+ }
71
+
72
+ get clauses() {
73
+ return this._clauses;
74
+ }
75
+
76
+ get includes() {
77
+ return this._includes;
78
+ }
79
+
80
+ get statics() {
81
+ return this._statics;
82
+ }
83
+ // Getters\
84
+ }
@@ -0,0 +1,139 @@
1
+ // Dictionary of unsafe characters:
2
+ const NOT_ALLOWED = [
3
+ '{',
4
+ '}',
5
+ // `\`,
6
+ '^',
7
+ '~',
8
+ '[',
9
+ ']',
10
+ '`'
11
+ ];
12
+
13
+ const util = require('util');
14
+
15
+ /*
16
+ * NodesterQueryParams is a ready-to-use replacement for URLSearchParams.
17
+ * The only difference is that NodesterQueryParams
18
+ * respects nested "&" during parsing.
19
+ */
20
+ module.exports = class NodesterQueryParams {
21
+ constructor(queryString='') {
22
+ // Type validateion:
23
+ if (typeof queryString !== 'string') {
24
+ const err = new TypeError(`'query' must be a String.`);
25
+ throw err;
26
+ }
27
+
28
+ // You never know if it's encoded or not.
29
+ const decoded = decodeURI(queryString);
30
+
31
+ // Indicates, how deep the char is inside different ().
32
+ let deep = 0;
33
+
34
+ const paramLevels = {};
35
+
36
+ // Current query parameter.
37
+ let param = '';
38
+
39
+ // Current query token.
40
+ let token = '';
41
+
42
+ this._map = new Map();
43
+
44
+ for (let i=0; i < decoded.length; i++) {
45
+ const char = decoded[i];
46
+
47
+ // Validate char:
48
+ if (NOT_ALLOWED.indexOf(char) > -1) {
49
+ const err = new TypeError(`Invalid query token at ${ i }: '${ char }'`);
50
+ throw err;
51
+ }
52
+
53
+ if (char === '(') {
54
+ // Error If there is nothing behind:
55
+ if (param.length === 0) {
56
+ const err = new TypeError(`Invalid query token at ${ i }: '${ char }'`);
57
+ throw err;
58
+ }
59
+
60
+ // If not special token, go deeper:
61
+ if (['and', 'or', 'xor', 'not', '!', '|', 'like'].indexOf(token) === -1) {
62
+ this.append(param, token);
63
+ deep++;
64
+ }
65
+
66
+ // will set ( in token later.
67
+ }
68
+
69
+ if (char === ')') {
70
+ // If sub-level:
71
+ if (deep > 0) {
72
+ deep--
73
+ }
74
+ }
75
+
76
+ // & can mean the end of key=value pair:
77
+ if (char === '&') {
78
+ // If top-level:
79
+ if (deep === 0) {
80
+ this.append(param, token);
81
+ param = '';
82
+ token = '';
83
+ continue;
84
+ }
85
+
86
+ // If sub-level do nothing.
87
+ }
88
+
89
+ // = can mean the end of param name:
90
+ if (char === '=') {
91
+ // If top-level:
92
+ if (deep === 0) {
93
+ param = token;
94
+ token = '';
95
+ }
96
+ }
97
+
98
+ // Continue building token:
99
+ if (char !== '=' || deep > 0 ) {
100
+ token += char;
101
+ }
102
+
103
+ // If last char:
104
+ if (i === decoded.length-1) {
105
+ // Validate:
106
+ if (deep > 0) {
107
+ const err = new TypeError(`Missing ')' at ${ i }`);
108
+ throw err;
109
+ }
110
+
111
+ this.append(param, token);
112
+ }
113
+ }
114
+ }
115
+
116
+ append(...args) {
117
+ return this._map.set(...args);
118
+ }
119
+
120
+ get(...args) {
121
+ return this._map.get(...args);
122
+ }
123
+
124
+ delete(...args) {
125
+ return this._map.delete(...args);
126
+ }
127
+
128
+ entries(...args) {
129
+ return this._map.entries(...args);
130
+ }
131
+
132
+ toString() {
133
+ return this._map.toString();
134
+ }
135
+
136
+ [util.inspect.custom](depth, opts) {
137
+ return this._map;
138
+ }
139
+ }