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
@@ -4,12 +4,13 @@ const debug = require('debug')('nodester:MiddlewareStack');
4
4
 
5
5
 
6
6
  module.exports = class MiddlewareStack {
7
- constructor() {
7
+ constructor(opts={}) {
8
8
  // This array MUST stay flat!
9
9
  this.middlewares = [];
10
10
 
11
11
  // Indicates whether we can add more middlewares or no.
12
12
  this.isLocked = false;
13
+ this.finalhandlerEnabled = !!opts.finalhandlerEnabled;
13
14
 
14
15
 
15
16
  const env = process.env.NODE_ENV || 'development';
@@ -25,11 +26,12 @@ module.exports = class MiddlewareStack {
25
26
  * Add the given middleware `fn` to the stack.
26
27
  *
27
28
  * @param {Function} fn
29
+ * @param {Integer} index (0 or undefined)
28
30
  * @return {Integer} index of new middleware
29
31
  *
30
32
  * @api public
31
33
  */
32
- add(fn) {
34
+ add(fn, index) {
33
35
  if (this.isLocked) {
34
36
  const err = new Error(`Can't add more middlewares while stack is locked.`);
35
37
  throw err;
@@ -40,9 +42,23 @@ module.exports = class MiddlewareStack {
40
42
  throw err;
41
43
  }
42
44
 
43
- const index = this.middlewares.push(fn);
44
- debug(`added middleware (${ index })`);
45
- return index;
45
+ if (!!index && isNaN(index)) {
46
+ const err = new TypeError('"index" must be an Integer!');
47
+ throw err;
48
+ }
49
+
50
+ let pushedIndex = -1;
51
+
52
+ if (index === 0) {
53
+ this.middlewares.unshift(fn);
54
+ pushedIndex = 0;
55
+ }
56
+ else {
57
+ pushedIndex = this.middlewares.push(fn);
58
+ }
59
+
60
+ debug(`added middleware (${ pushedIndex })`);
61
+ return pushedIndex;
46
62
  }
47
63
 
48
64
 
@@ -65,7 +81,7 @@ module.exports = class MiddlewareStack {
65
81
  throw err;
66
82
  }
67
83
 
68
- this.middlewares.splice(middlewareIndex, 1);
84
+ this.middlewares.splice(index, 1);
69
85
  debug(`removed middleware (${ index })`);
70
86
  return this;
71
87
  }
@@ -77,8 +93,10 @@ module.exports = class MiddlewareStack {
77
93
  * @api public
78
94
  */
79
95
  lock() {
80
- // Add final handler to the stack.
81
- this.add((req, res)=>this.finalhandler(req, res)());
96
+ if (this.finalhandlerEnabled) {
97
+ // Add final handler to the stack.
98
+ this.add((req, res)=>this.finalhandler(req, res)());
99
+ }
82
100
 
83
101
  // Stack is ready.
84
102
  this.isLocked = true;
@@ -94,7 +112,10 @@ module.exports = class MiddlewareStack {
94
112
  */
95
113
  unlock() {
96
114
  this.isLocked = false;
97
- this.middlewares.pop();
115
+
116
+ if (this.finalhandlerEnabled) {
117
+ this.middlewares.pop();
118
+ }
98
119
 
99
120
  debug(`stack is unlocked`);
100
121
  }
@@ -105,21 +126,34 @@ module.exports = class MiddlewareStack {
105
126
  *
106
127
  * @api public
107
128
  */
108
- process(req, res) {
129
+ process(req, res, next) {
109
130
  let middlewareOffset = -1;
110
131
 
111
- const next = (...args) => {
132
+ const _next = (...args) => {
112
133
  middlewareOffset += 1;
113
134
  const fn = this.middlewares[middlewareOffset];
114
135
 
115
136
  try {
116
- return fn.call(null, req, res, next, ...args);
137
+ if (!fn && !next) {
138
+ const err = new TypeError(`Handler for ${ req.method } ${ req.url } is not defined.`);
139
+ throw err;
140
+ }
141
+ else if (!fn && !!next) {
142
+ return next.call(null, req, res, next, ...args);
143
+ }
144
+
145
+ return fn.call(null, req, res, _next, ...args);
117
146
  }
118
147
  catch(error) {
119
148
  return this.finalhandler(req, res)(error);
120
149
  }
121
150
  }
122
151
 
123
- return next();
152
+ return _next();
153
+ }
154
+
155
+
156
+ get length() {
157
+ return this.middlewares.length;
124
158
  }
125
159
  }
@@ -7,8 +7,10 @@ exports = module.exports = {
7
7
  * Check if `path` looks absolute.
8
8
  *
9
9
  * @param {String} path
10
+ *
10
11
  * @return {Boolean}
11
- * @api private
12
+ *
13
+ * @api public
12
14
  * @alias isAbsolute
13
15
  */
14
16
  function _isAbsolute(path) {
@@ -2,7 +2,10 @@ const objectRegExp = /^\[object (\S+)\]$/;
2
2
 
3
3
 
4
4
  module.exports = {
5
- typeOf: _typeOf
5
+ typeOf: _typeOf,
6
+ isAsync: _isAsync,
7
+ isRegExp: _isRegExp,
8
+ isConstructor: _isConstructor
6
9
  }
7
10
 
8
11
 
@@ -24,3 +27,50 @@ function _typeOf(obj) {
24
27
  .call(obj)
25
28
  .replace(objectRegExp, '$1');
26
29
  }
30
+
31
+
32
+ /**
33
+ *
34
+ * @alias isAsync
35
+ * @public
36
+ */
37
+ function _isAsync(fn) {
38
+ if (!fn) {
39
+ const err = new TypeError('"fn" is not defined.');
40
+ throw err;
41
+ }
42
+
43
+ return fn.constructor.name === 'AsyncFunction';
44
+ }
45
+
46
+
47
+ /**
48
+ *
49
+ * @alias isRegExp
50
+ * @public
51
+ */
52
+ function _isRegExp(obj) {
53
+ if (!obj) {
54
+ const err = new TypeError('"obj" is not defined.');
55
+ throw err;
56
+ }
57
+
58
+ return obj instanceof RegExp;
59
+ }
60
+
61
+
62
+ /**
63
+ *
64
+ * @alias isConstructor
65
+ * @public
66
+ */
67
+ function _isConstructor(fn) {
68
+ try {
69
+ new fn();
70
+ }
71
+ catch (err) {
72
+ return false;
73
+ }
74
+
75
+ return true;
76
+ }
@@ -0,0 +1,25 @@
1
+
2
+ module.exports = {
3
+ isValidDate: _isValidDate
4
+ }
5
+
6
+
7
+ /**
8
+ * @param {Any} dateToTest
9
+ *
10
+ * @alias isValidDate
11
+ * @api public
12
+ */
13
+ function _isValidDate(dateToTest) {
14
+ // If number:
15
+ if (!isNaN(dateToTest)) {
16
+ return false;
17
+ }
18
+
19
+ if (typeof dateToTest === 'string') {
20
+ const date = new Date(dateToTest);
21
+ return date.toString() !== 'Invalid Date';
22
+ }
23
+
24
+ return dateToTest instanceof Date;
25
+ }
@@ -0,0 +1,14 @@
1
+
2
+ module.exports = {
3
+ isValidNumber: _isValidNumber
4
+ }
5
+
6
+ /**
7
+ * @param {Any} numToTest
8
+ *
9
+ * @alias isValidNumber
10
+ * @api public
11
+ */
12
+ function _isValidNumber(numToTest){
13
+ return !isNaN(numToTest);
14
+ }
package/package.json CHANGED
@@ -1,9 +1,29 @@
1
1
  {
2
2
  "name": "nodester",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "A boilerplate framework for Node.js",
5
5
  "exports": {
6
- ".": "./lib/application/index.js"
6
+ ".": "./lib/application/index.js",
7
+ "./controllers/methods": "./lib/controllers/methods/index.js",
8
+ "./controllers/mixins": "./lib/controllers/mixins/index.js",
9
+ "./database/connection": "./lib/database/connection.js",
10
+ "./database/migration": "./lib/database/migration.js",
11
+ "./database/utils": "./lib/database/utils.js",
12
+ "./enum": "./lib/enums/Enum.js",
13
+ "./facades/methods": "./lib/facades/methods/index.js",
14
+ "./facades/mixins": "./lib/facades/mixins/index.js",
15
+ "./factories/errors": "./lib/factories/errors/index.js",
16
+ "./factories/responses/rest": "./lib/factories/responses/rest/index.js",
17
+ "./http/codes": "./lib/http/codes/index.js",
18
+ "./models/associate": "./lib/models/associate.js",
19
+ "./models/define": "./lib/models/define.js",
20
+ "./params": "./lib/params/Params.js",
21
+ "./ql/sequelize": "./lib/middlewares/ql/sequelize",
22
+ "./queries/Colander": "./lib/queries/Colander.js",
23
+ "./queries/traverse": "./lib/queries/traverse.js",
24
+ "./route": "./lib/router/route.js",
25
+ "./router": "./lib/router/index.js",
26
+ "./utils/strings": "./lib/utils/strings.util.js"
7
27
  },
8
28
  "directories": {
9
29
  "doc": "docs"
@@ -12,8 +32,8 @@
12
32
  "lib"
13
33
  ],
14
34
  "scripts": {
15
- "examples:rest": "node ./examples/rest/index.js",
16
- "test": "jest"
35
+ "test": "jest",
36
+ "examples:rest": "node ./examples/rest/index.js"
17
37
  },
18
38
  "author": "Mark Khramko <markkhramko@gmail.com>",
19
39
  "license": "MIT",
@@ -35,17 +55,24 @@
35
55
  "api"
36
56
  ],
37
57
  "dependencies": {
58
+ "@js-temporal/polyfill": "^0.4.3",
38
59
  "accepts": "^1.3.8",
60
+ "body-parser": "^1.20.2",
61
+ "common-js-file-extensions": "^1.0.4",
39
62
  "content-disposition": "^0.5.4",
40
63
  "content-type": "^1.0.5",
41
64
  "cookie": "^0.5.0",
42
65
  "cookie-signature": "^1.2.0",
43
66
  "debug": "^4.3.4",
67
+ "etag": "^1.8.1",
44
68
  "finalhandler": "^1.2.0",
45
69
  "formidable": "^1.2.6",
46
70
  "fresh": "^0.5.2",
47
71
  "http-errors": "^2.0.0",
48
72
  "inflection": "^2.0.1",
73
+ "mysql2": "^3.6.0",
74
+ "pg": "^8.11.3",
75
+ "pg-hstore": "^2.3.4",
49
76
  "proxy-addr": "^2.0.7",
50
77
  "qs": "^6.11.0",
51
78
  "range-parser": "^1.2.1",
@@ -1,4 +1,4 @@
1
- // Test utils:
1
+ // Test utils.
2
2
  const {
3
3
  describe,
4
4
  it,
@@ -24,11 +24,16 @@ describe('nodester application', () => {
24
24
  // app.setDatabase();
25
25
  // app.set.database();
26
26
 
27
- test('listening port', () => {
27
+ test('Application start', () => {
28
28
  app.listen(PORT, function() {
29
29
  expect(app.port).toBe(PORT);
30
+ expect(app.router._middlewares.isLocked).toBe(true);
31
+ expect(app.router._middlewares.length).toBe(2);
30
32
 
31
33
  app.stop();
34
+
35
+ expect(app.router._middlewares.length).toBe(0);
36
+ expect(app.router._middlewares.isLocked).toBe(false);
32
37
  expect(app.isListening).toBe(false);
33
38
  });
34
39
  });
@@ -0,0 +1,277 @@
1
+ // Test utils.
2
+ const {
3
+ describe,
4
+ it,
5
+ expect,
6
+ test
7
+ } = require('@jest/globals');
8
+
9
+ // Parser:
10
+ const { ModelsTree } = require('../lib/middlewares/ql/sequelize/interpreter/ModelsTree');
11
+ const QueryLexer = require('../lib/middlewares/ql/sequelize/interpreter/QueryLexer');
12
+
13
+ describe('nodester Query Language', () => {
14
+ const queryStrings = [
15
+ // Simple where.
16
+ 'id=10',
17
+ // All possible params.
18
+ 'id=10&position=4&limit=3&skip=10&order=desc&order_by=index&fields=id,content,position,created_at',
19
+ // Simple includes.
20
+ 'includes=comments&id=7',
21
+ // Include with All possible params.
22
+ 'includes=comments(id=10&position=4&limit=3&skip=10&order=desc&order_by=index&fields=id,content,position)',
23
+
24
+ // Subinclude horizontal.
25
+ 'includes=comments,users&id=1000',
26
+ // Subinclude horizontal (more entries).
27
+ 'includes=comments(order=desc),users,likes(order=rand),reposts&id=1000',
28
+ // Subinclude horizontal (+ syntaxis).
29
+ 'includes=comments(order=desc).users+likes(order=rand&order_by=position)&id=1000',
30
+
31
+ // Subinclude vertical.
32
+ 'includes=comments.users&id=1000',
33
+ // Subinclude vertical (more entries).
34
+ 'in=comments.users.avatars.sizes&position=200',
35
+
36
+ // Complex includes.
37
+ 'includes=comments.users.avatars(fields=id,content&order=rand)&id=7&limit=3',
38
+
39
+ // Broken includes.
40
+ 'includes=comments(order=rand)&id=7&limit=3&includes=users(fields=id,content)',
41
+
42
+ // OR simple.
43
+ 'or(index=2,position=5)',
44
+ // OR shortened.
45
+ '|(index=2,position=5)',
46
+
47
+ // NOT inside include.
48
+ 'includes=comments(id=not(7))',
49
+
50
+ // Like simple.
51
+ 'title=like(some_text)',
52
+ ];
53
+
54
+ it('query "Simple where"', () => {
55
+ const lexer = new QueryLexer( queryStrings[0] );
56
+ const result = lexer.query;
57
+
58
+ const tree = new ModelsTree();
59
+ tree.node.addWhere({ id: ['10'] });
60
+ const expected = tree.root.toObject();
61
+
62
+ expect(result).toMatchObject(expected);
63
+ });
64
+
65
+ test('query "All possible params"', () => {
66
+ const lexer = new QueryLexer( queryStrings[1] );
67
+ const result = lexer.query;
68
+
69
+
70
+ const tree = new ModelsTree();
71
+ tree.node.addWhere({ id: ['10'], position: ['4'] });
72
+ tree.node.fields = [ 'id', 'content', 'position', 'created_at' ];
73
+ tree.node.limit = 3;
74
+ tree.node.skip = 10;
75
+ tree.node.order = 'desc';
76
+ tree.node.order_by = 'index';
77
+ const expected = tree.root.toObject();
78
+
79
+ expect(result).toMatchObject(expected);
80
+ });
81
+
82
+ test('query "Simple includes"', () => {
83
+ const lexer = new QueryLexer( queryStrings[2] );
84
+ const result = lexer.query;
85
+
86
+
87
+ const tree = new ModelsTree();
88
+ tree.node.addWhere({ id: ['7'] });
89
+ tree.include('comments');
90
+ const expected = tree.root.toObject();
91
+
92
+ expect(result).toMatchObject(expected);
93
+ });
94
+
95
+ test('query "Include with all possible params"', () => {
96
+ const lexer = new QueryLexer( queryStrings[3] );
97
+ const result = lexer.query;
98
+
99
+ const tree = new ModelsTree();
100
+ tree.include('comments').use('comments');
101
+ tree.node.addWhere({ id: ['10'], position: ['4'] });
102
+ tree.node.fields = [ 'id', 'content', 'position' ];
103
+ tree.node.limit = 3;
104
+ tree.node.skip = 10;
105
+ tree.node.order = 'desc';
106
+ tree.node.order_by = 'index';
107
+ const expected = tree.root.toObject();
108
+
109
+ expect(result).toMatchObject(expected);
110
+ });
111
+
112
+
113
+ test('query "Subinclude horizontal"', () => {
114
+ const lexer = new QueryLexer( queryStrings[4] );
115
+ const result = lexer.query;
116
+
117
+
118
+ const tree = new ModelsTree();
119
+ tree.node.addWhere({ id: ['1000'] });
120
+ tree.include('comments');
121
+ tree.include('users');
122
+ const expected = tree.root.toObject();
123
+
124
+ expect(result).toMatchObject(expected);
125
+ });
126
+
127
+ test('query "Subinclude horizontal (complex)"', () => {
128
+ const lexer = new QueryLexer( queryStrings[5] );
129
+ const result = lexer.query;
130
+
131
+
132
+ const tree = new ModelsTree();
133
+ tree.node.addWhere({ id: ['1000'] });
134
+ tree.include('comments').use('comments');
135
+ tree.node.order = 'desc';
136
+ tree.up();
137
+ tree.include('users');
138
+ tree.include('likes') && tree.use('likes');
139
+ tree.node.order = 'rand';
140
+ tree.up();
141
+ tree.include('reposts');
142
+ const expected = tree.root.toObject();
143
+
144
+ expect(result).toMatchObject(expected);
145
+ });
146
+
147
+
148
+ test('query "Subinclude horizontal (+ syntaxis)"', () => {
149
+ const lexer = new QueryLexer( queryStrings[6] );
150
+ const result = lexer.query;
151
+
152
+
153
+ const tree = new ModelsTree();
154
+ tree.node.addWhere({ id: ['1000'] });
155
+ tree.include('comments').use('comments');
156
+ tree.node.order = 'desc';
157
+ tree.include('users');
158
+ tree.include('likes') && tree.use('likes');
159
+ tree.node.order = 'rand';
160
+ tree.node.order_by = 'position';
161
+ tree.up();
162
+ const expected = tree.root.toObject();
163
+
164
+ expect(result).toMatchObject(expected);
165
+ });
166
+
167
+
168
+ test('query "Subinclude vertical"', () => {
169
+ const lexer = new QueryLexer( queryStrings[7] );
170
+ const result = lexer.query;
171
+
172
+
173
+ const tree = new ModelsTree();
174
+ tree.node.addWhere({ id: ['1000'] });
175
+ tree.include('comments').use('comments');
176
+ tree.include('users');
177
+ const expected = tree.root.toObject();
178
+
179
+ expect(result).toMatchObject(expected);
180
+ });
181
+
182
+ test('query "Subinclude vertical (complex)"', () => {
183
+ const lexer = new QueryLexer( queryStrings[8] );
184
+ const result = lexer.query;
185
+
186
+
187
+ const tree = new ModelsTree();
188
+ tree.node.addWhere({ position: ['200'] });
189
+ tree.include('comments').use('comments');
190
+ tree.include('users').use('users');
191
+ tree.include('avatars').use('avatars');
192
+ tree.include('sizes').use('sizes');
193
+ const expected = tree.root.toObject();
194
+
195
+ expect(result).toMatchObject(expected);
196
+ });
197
+
198
+ test('query "Complex includes"', () => {
199
+ const lexer = new QueryLexer( queryStrings[9] );
200
+ const result = lexer.query;
201
+
202
+ const tree = new ModelsTree();
203
+ tree.node.addWhere({ id: ['7'] });
204
+ tree.node.limit = 3;
205
+ tree.include('comments').use('comments');
206
+ tree.include('users').use('users');
207
+ tree.include('avatars').use('avatars');
208
+ tree.node.fields = [ 'id', 'content' ];
209
+ tree.node.order = 'rand';
210
+ const expected = tree.root.toObject();
211
+
212
+ expect(result).toMatchObject(expected);
213
+ });
214
+
215
+ test('query "Broken includes"', () => {
216
+ const lexer = new QueryLexer( queryStrings[10] );
217
+ const result = lexer.query;
218
+
219
+ const tree = new ModelsTree();
220
+ tree.node.addWhere({ id: ['7'] });
221
+ tree.node.limit = 3;
222
+ tree.include('comments').use('comments');
223
+ tree.node.order = 'rand';
224
+ tree.up();
225
+ tree.include('users').use('users');
226
+ tree.node.fields = [ 'id', 'content' ];
227
+ const expected = tree.root.toObject();
228
+
229
+ expect(result).toMatchObject(expected);
230
+ });
231
+
232
+ test('Token "OR" simple', () => {
233
+ const lexer = new QueryLexer( queryStrings[11] );
234
+ const result = lexer.query;
235
+
236
+ const tree = new ModelsTree();
237
+ tree.node.addWhere({ or: [ { index: ['2'] }, { position: ['5'] } ] });
238
+ const expected = tree.root.toObject();
239
+
240
+ expect(result).toMatchObject(expected);
241
+ });
242
+
243
+ test('Token "OR" shortened', () => {
244
+ const lexer = new QueryLexer( queryStrings[12] );
245
+ const result = lexer.query;
246
+
247
+ const tree = new ModelsTree();
248
+ tree.node.addWhere({ or: [ { index: ['2'] }, { position: ['5'] } ] });
249
+ const expected = tree.root.toObject();
250
+
251
+ expect(result).toMatchObject(expected);
252
+ });
253
+
254
+ test('Token "NOT"', () => {
255
+ const lexer = new QueryLexer( queryStrings[13] );
256
+ const result = lexer.query;
257
+
258
+ const tree = new ModelsTree();
259
+ tree.include('comments').use('comments');
260
+ tree.node.addWhere({ id: { not: ['7'] }});
261
+ const expected = tree.root.toObject();
262
+
263
+ expect(result).toMatchObject(expected);
264
+ });
265
+
266
+
267
+ test('Token "Like" simple', () => {
268
+ const lexer = new QueryLexer( queryStrings[14] );
269
+ const result = lexer.query;
270
+
271
+ const tree = new ModelsTree();
272
+ tree.node.addWhere({ title: { like: ['some_text'] }});
273
+ const expected = tree.root.toObject();
274
+
275
+ expect(result).toMatchObject(expected);
276
+ });
277
+ });
package/docs/App.md DELETED
@@ -1,13 +0,0 @@
1
- # nodester Application
2
-
3
- ## Init
4
-
5
- ```js
6
- const nodester = require('nodester');
7
-
8
- const app = new nodester();
9
-
10
- app.listen(8080, function() {
11
- console.log('listening on port', app.port);
12
- });
13
- ```
package/docs/Queries.md DELETED
@@ -1,61 +0,0 @@
1
- # nodester Queries API
2
-
3
- ## Like value
4
-
5
- To emulate MySQL's `like %value% ` query in URL,
6
- pass `?key=like(value)` in the query.
7
-
8
- * Example:
9
- `http://localhost:5001/api/v1/countries?name=like(Engl)`
10
-
11
-
12
- ## NotLike value
13
-
14
- * Example:
15
- `http://localhost:5001/api/v1/countries?name=notLike(Engl)`
16
-
17
-
18
- ## Or
19
-
20
- To emulate MySQL's `where key=value or key=value` query in URL,
21
- pass `?key=or(value1,value2)` in the query.
22
- * ! Note: don't use `spaces` between values.
23
-
24
- * Example:
25
- `http://localhost:5001/api/v1/countries?name=or(England,Germany)`
26
-
27
-
28
- ## Count
29
-
30
- MySQL's `select count(value)` query is run by default in facade's `getMany` function
31
-
32
- * Response Example:
33
- ```JSON
34
- {
35
- "count": 10,
36
- "countries": [ ... ],
37
- "limit": 10,
38
- "skip": 0,
39
- "total_count": 195
40
- }
41
- ```
42
-
43
- ## Order (Sorting)
44
-
45
-
46
- #### Top level
47
-
48
- `order_by` & `order` arguments can be set in `query`
49
- `http://localhost:5001/api/v1/countries?order_by=id&order=desc`
50
-
51
- Above `query` will sort Countries[] by it's id.
52
-
53
-
54
- #### Nested (Includes)
55
-
56
- `http://localhost:5001/api/v1/countries?includes=cities(order_by=id&order=desc)`
57
-
58
- Above `query` will sort Cities[] by it's id inside every Country object.
59
-
60
- It can also do this:
61
- `http://localhost:5001/api/v1/countries?includes=cities(order_by=id&order=desc).areas`
package/docs/Readme.md DELETED
@@ -1,2 +0,0 @@
1
- # nodester API description
2
-