nodester 0.4.6 → 0.4.8
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/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +1 -1
- package/lib/tools/nql.tool.js +4 -0
- package/package.json +3 -1
- package/tests/index.test.js +1 -1
- package/tests/nql.test.js +54 -19
- package/lib/constants/Operators.js +0 -23
- package/lib/middlewares/404/index.js +0 -38
- package/lib/middlewares/etag/index.js +0 -81
- package/lib/middlewares/render/index.js +0 -62
- package/tests/ast.js +0 -18
|
@@ -289,7 +289,7 @@ module.exports = class QueryLexer {
|
|
|
289
289
|
debug('char', char, { token, node: tree.node });
|
|
290
290
|
|
|
291
291
|
// Vertical include:
|
|
292
|
-
if (!!previousActive) {
|
|
292
|
+
if (!!previousActive && token.length === 0) {
|
|
293
293
|
tree.use(previousActive);
|
|
294
294
|
tree.node.activeParam = PARAM_TOKENS.INCLUDES;
|
|
295
295
|
token = '';
|
package/lib/tools/nql.tool.js
CHANGED
|
@@ -42,13 +42,17 @@ function _AST_ModelsTreeNode(node, spacing=0) {
|
|
|
42
42
|
ast += `${ spaces }┣ model: ${ node.model }\n`;
|
|
43
43
|
ast += `${ spaces }┃\n`;
|
|
44
44
|
|
|
45
|
+
if (!!node.fields) {
|
|
45
46
|
ast += `${ spaces }┣ fields (${ node.fields.length }): [\n${ node.fields.map(f => ` • ${ f },\n`) }`;
|
|
46
47
|
ast += `${ spaces }┃ ]\n`;
|
|
47
48
|
ast += `${ spaces }┃\n`;
|
|
49
|
+
}
|
|
48
50
|
|
|
51
|
+
if (!!node.functions) {
|
|
49
52
|
ast += `${ spaces }┣ functions (${ node.functions.length }): [\n${ node.functions.map(f => ` • ${ f },\n`) }`;
|
|
50
53
|
ast += `${ spaces }┃ ]\n`;
|
|
51
54
|
ast += `${ spaces }┃\n`;
|
|
55
|
+
}
|
|
52
56
|
|
|
53
57
|
ast += `${ spaces }┣ where: ${ JSON.stringify(node.where) }\n`;
|
|
54
58
|
ast += `${ spaces }┃\n`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodester",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "A versatile REST framework for Node.js",
|
|
5
5
|
"directories": {
|
|
6
6
|
"docs": "docs",
|
|
@@ -65,6 +65,8 @@
|
|
|
65
65
|
"./stacks/markers": "./lib/stacks/MarkersStack.js",
|
|
66
66
|
"./stacks/middlewares": "./lib/stacks/MiddlewaresStack.js",
|
|
67
67
|
|
|
68
|
+
"./tools/nql": "./lib/tools/nql.tool.js",
|
|
69
|
+
|
|
68
70
|
"./utils/dates": "./lib/utils/dates.js",
|
|
69
71
|
"./utils/sql": "./lib/utils/sql.util.js",
|
|
70
72
|
"./utils/strings": "./lib/utils/strings.util.js",
|
package/tests/index.test.js
CHANGED
package/tests/nql.test.js
CHANGED
|
@@ -64,26 +64,30 @@ describe('nodester Query Language', () => {
|
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
describe('includes', () => {
|
|
67
|
-
const queryStrings =
|
|
67
|
+
const queryStrings = {
|
|
68
68
|
// Simple includes.
|
|
69
|
-
'includes=comments&id=7',
|
|
70
|
-
// Include with
|
|
71
|
-
'includes=comments(id=10&position=4&limit=3&skip=10&order=desc&order_by=index&a=id,content,position)',
|
|
72
|
-
|
|
73
|
-
// 2 horizontals
|
|
74
|
-
'includes=comments,users&id=1000',
|
|
69
|
+
'simple-includes': 'includes=comments&id=7',
|
|
70
|
+
// Include with params.
|
|
71
|
+
'include-with-params': 'includes=comments(id=10&position=4&limit=3&skip=10&order=desc&order_by=index&a=id,content,position)',
|
|
72
|
+
|
|
73
|
+
// 2 horizontals.
|
|
74
|
+
'2-horizontals': 'includes=comments,users&id=1000',
|
|
75
|
+
// 4 horizontals with subquery.
|
|
76
|
+
'4-horizontals': 'in=categories,replies.users,comments(order_by=position&order=desc),users.avatars',
|
|
75
77
|
|
|
76
78
|
// Horizontals queried.
|
|
77
|
-
'includes=comments(order=desc),users,likes(order=rand),reposts&id=1000',
|
|
79
|
+
'horizontals-queried': 'includes=comments(order=desc),users,likes(order=rand),reposts&id=1000',
|
|
78
80
|
// Horizontals queried №2.
|
|
79
|
-
'in=comments(order_by=index&order=asc).users.karma',
|
|
81
|
+
'horizontals-queried-2': 'in=comments(order_by=index&order=asc).users.karma',
|
|
80
82
|
// Horizontals queried №3.
|
|
81
|
-
'in=reactions,comments(user_id=gte(4)&skip=10&limit=2).users,likes,reposts',
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
'horizontals-queried-3': 'in=reactions,comments(user_id=gte(4)&skip=10&limit=2).users,likes,reposts',
|
|
84
|
+
|
|
85
|
+
// Separated includes.
|
|
86
|
+
'separated-includes': 'includes=comments(order=rand)&id=7&limit=3&includes=users(a=id,content)',
|
|
87
|
+
};
|
|
84
88
|
|
|
85
89
|
test('Simple includes', () => {
|
|
86
|
-
const lexer = new QueryLexer( queryStrings[
|
|
90
|
+
const lexer = new QueryLexer( queryStrings['simple-includes'] );
|
|
87
91
|
const result = lexer.query;
|
|
88
92
|
|
|
89
93
|
|
|
@@ -96,7 +100,7 @@ describe('nodester Query Language', () => {
|
|
|
96
100
|
});
|
|
97
101
|
|
|
98
102
|
test('Include with all possible params', () => {
|
|
99
|
-
const lexer = new QueryLexer( queryStrings[
|
|
103
|
+
const lexer = new QueryLexer( queryStrings['include-with-params'] );
|
|
100
104
|
const result = lexer.query;
|
|
101
105
|
|
|
102
106
|
const tree = new ModelsTree();
|
|
@@ -113,7 +117,7 @@ describe('nodester Query Language', () => {
|
|
|
113
117
|
});
|
|
114
118
|
|
|
115
119
|
test('2 horizontals', () => {
|
|
116
|
-
const lexer = new QueryLexer( queryStrings[2] );
|
|
120
|
+
const lexer = new QueryLexer( queryStrings['2-horizontals'] );
|
|
117
121
|
const result = lexer.query;
|
|
118
122
|
|
|
119
123
|
|
|
@@ -126,8 +130,39 @@ describe('nodester Query Language', () => {
|
|
|
126
130
|
expect(result).toMatchObject(expected);
|
|
127
131
|
});
|
|
128
132
|
|
|
133
|
+
test('4 horizontals', () => {
|
|
134
|
+
// in=categories,replies.users,comments(order_by=position&order=desc),users.avatars
|
|
135
|
+
|
|
136
|
+
const lexer = new QueryLexer( queryStrings['4-horizontals'] );
|
|
137
|
+
const result = lexer.query;
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
const tree = new ModelsTree();
|
|
141
|
+
tree.include('categories');
|
|
142
|
+
tree.include('replies');
|
|
143
|
+
tree.include('comments');
|
|
144
|
+
tree.include('users');
|
|
145
|
+
|
|
146
|
+
tree.use('replies');
|
|
147
|
+
tree.include('users');
|
|
148
|
+
|
|
149
|
+
tree.up();
|
|
150
|
+
|
|
151
|
+
tree.use('comments');
|
|
152
|
+
tree.node.order = 'desc';
|
|
153
|
+
tree.node.order_by = 'position';
|
|
154
|
+
|
|
155
|
+
tree.up();
|
|
156
|
+
tree.use('users');
|
|
157
|
+
tree.include('avatars');
|
|
158
|
+
|
|
159
|
+
const expected = tree.root.toObject();
|
|
160
|
+
|
|
161
|
+
expect(result).toMatchObject(expected);
|
|
162
|
+
});
|
|
163
|
+
|
|
129
164
|
test('Horizontals queried', () => {
|
|
130
|
-
const lexer = new QueryLexer( queryStrings[
|
|
165
|
+
const lexer = new QueryLexer( queryStrings['horizontals-queried'] );
|
|
131
166
|
const result = lexer.query;
|
|
132
167
|
|
|
133
168
|
|
|
@@ -147,7 +182,7 @@ describe('nodester Query Language', () => {
|
|
|
147
182
|
});
|
|
148
183
|
|
|
149
184
|
test('Horizontals queried №2', () => {
|
|
150
|
-
const lexer = new QueryLexer( queryStrings[
|
|
185
|
+
const lexer = new QueryLexer( queryStrings['horizontals-queried-2'] );
|
|
151
186
|
const result = lexer.query;
|
|
152
187
|
|
|
153
188
|
const tree = new ModelsTree();
|
|
@@ -165,7 +200,7 @@ describe('nodester Query Language', () => {
|
|
|
165
200
|
});
|
|
166
201
|
|
|
167
202
|
test('Horizontals queried №3', () => {
|
|
168
|
-
const lexer = new QueryLexer( queryStrings[
|
|
203
|
+
const lexer = new QueryLexer( queryStrings['horizontals-queried-3'] );
|
|
169
204
|
const result = lexer.query;
|
|
170
205
|
|
|
171
206
|
const tree = new ModelsTree();
|
|
@@ -192,7 +227,7 @@ describe('nodester Query Language', () => {
|
|
|
192
227
|
});
|
|
193
228
|
|
|
194
229
|
test('Separated includes"', () => {
|
|
195
|
-
const lexer = new QueryLexer( queryStrings[
|
|
230
|
+
const lexer = new QueryLexer( queryStrings['separated-includes'] );
|
|
196
231
|
const result = lexer.query;
|
|
197
232
|
|
|
198
233
|
const tree = new ModelsTree();
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const Enum = require('nodester/enum');
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
module.exports = new Enum({
|
|
5
|
-
and: Symbol.for('and'),
|
|
6
|
-
between: Symbol.for('between'),
|
|
7
|
-
contains: Symbol.for('contains'),
|
|
8
|
-
eq: Symbol.for('eq'),
|
|
9
|
-
ne: Symbol.for('ne'),
|
|
10
|
-
gte: Symbol.for('gte'),
|
|
11
|
-
gt: Symbol.for('gt'),
|
|
12
|
-
lte: Symbol.for('lte'),
|
|
13
|
-
lt: Symbol.for('lt'),
|
|
14
|
-
not: Symbol.for('not'),
|
|
15
|
-
is: Symbol.for('is'),
|
|
16
|
-
in: Symbol.for('in'),
|
|
17
|
-
notIn: Symbol.for('notIn'),
|
|
18
|
-
like: Symbol.for('like'),
|
|
19
|
-
notLike: Symbol.for('notLike'),
|
|
20
|
-
notBetween: Symbol.for('notBetween'),
|
|
21
|
-
or: Symbol.for('or'),
|
|
22
|
-
xor: Symbol.for('xor'),
|
|
23
|
-
});
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* nodester
|
|
3
|
-
* MIT Licensed
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use strict';
|
|
7
|
-
|
|
8
|
-
const {
|
|
9
|
-
HTTP_CODE_NOT_FOUND
|
|
10
|
-
} = require('nodester/http/codes');
|
|
11
|
-
|
|
12
|
-
const { createErrorResponse } = require('nodester/factories/responses/rest');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Initialize `404` middleware.
|
|
17
|
-
*
|
|
18
|
-
* @param {Object} [options]
|
|
19
|
-
*
|
|
20
|
-
* @return {Function}
|
|
21
|
-
*
|
|
22
|
-
* @access public
|
|
23
|
-
*/
|
|
24
|
-
module.exports = function init404Middleware(options={}) {
|
|
25
|
-
const context = {
|
|
26
|
-
options
|
|
27
|
-
}
|
|
28
|
-
return handle.bind(context);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function handle(req, res, next) {
|
|
32
|
-
const err = new Error('Route not found');
|
|
33
|
-
|
|
34
|
-
return createErrorResponse(res, {
|
|
35
|
-
error: err,
|
|
36
|
-
status: HTTP_CODE_NOT_FOUND
|
|
37
|
-
});
|
|
38
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* nodester
|
|
3
|
-
* MIT Licensed
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use strict';
|
|
7
|
-
|
|
8
|
-
const calculate = require('etag');
|
|
9
|
-
const Stream = require('stream');
|
|
10
|
-
|
|
11
|
-
// Utils:
|
|
12
|
-
const promisify = require('util').promisify;
|
|
13
|
-
const fs = require('fs');
|
|
14
|
-
const getFileStats = promisify(fs.stat);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
module.exports = initETagMiddleware;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Initialize `etag` middleware.
|
|
21
|
-
*
|
|
22
|
-
* @param {Object} [options]
|
|
23
|
-
* @param {boolean} options.weak
|
|
24
|
-
*
|
|
25
|
-
* @return {Function}
|
|
26
|
-
*
|
|
27
|
-
* @access public
|
|
28
|
-
*/
|
|
29
|
-
function initETagMiddleware(options) {
|
|
30
|
-
const context = {
|
|
31
|
-
options
|
|
32
|
-
}
|
|
33
|
-
return handle.bind(context);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Add ETag header field.
|
|
38
|
-
*/
|
|
39
|
-
function handle(req, res, next) {
|
|
40
|
-
// console.log('e', req.headers);
|
|
41
|
-
return next();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async function _getResponseEntity(res) {
|
|
45
|
-
// If body is not defined:
|
|
46
|
-
const { body } = res;
|
|
47
|
-
if (!body || res.get('etag'))
|
|
48
|
-
return;
|
|
49
|
-
|
|
50
|
-
// Status code.
|
|
51
|
-
const status = res.statusCode / 100 | 0;
|
|
52
|
-
|
|
53
|
-
console.log('getResponseEntity', status, { tag: res.get('etag') });
|
|
54
|
-
|
|
55
|
-
// 2xx
|
|
56
|
-
if (status !== 2)
|
|
57
|
-
return;
|
|
58
|
-
|
|
59
|
-
if (body instanceof Stream) {
|
|
60
|
-
if (!body.path)
|
|
61
|
-
return;
|
|
62
|
-
|
|
63
|
-
const stats = await getFileStats(body.path);
|
|
64
|
-
return stats;
|
|
65
|
-
}
|
|
66
|
-
else if (typeof body === 'string' || Buffer.isBuffer(body)) {
|
|
67
|
-
return body;
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
return JSON.stringify(body);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function _setEtag(res, entity, options) {
|
|
75
|
-
console.log('setEtag', typeof res, entity);
|
|
76
|
-
|
|
77
|
-
if (!entity)
|
|
78
|
-
return;
|
|
79
|
-
|
|
80
|
-
res.etag = calculate(entity, options);
|
|
81
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* nodester
|
|
3
|
-
* MIT Licensed
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use strict';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
module.exports = function initRenderMiddleware() {
|
|
10
|
-
return handle;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
function handle(req, res, next) {
|
|
15
|
-
const context = { req, res, next };
|
|
16
|
-
res.render = _render.bind(context);
|
|
17
|
-
next();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Render `view` with the given `options` and optional callback `fn`.
|
|
23
|
-
* When a callback function is given a response will _not_ be made
|
|
24
|
-
* automatically, otherwise a response of _200_ and _text/html_ is given.
|
|
25
|
-
*
|
|
26
|
-
* Options:
|
|
27
|
-
*
|
|
28
|
-
* - `cache` boolean hinting to the engine it should cache
|
|
29
|
-
* - `filename` filename of the view being rendered
|
|
30
|
-
*
|
|
31
|
-
* @alias render
|
|
32
|
-
* @access public
|
|
33
|
-
*/
|
|
34
|
-
function _render(view, options, callback) {
|
|
35
|
-
const app = this.req.app;
|
|
36
|
-
let done = callback;
|
|
37
|
-
let opts = options || {};
|
|
38
|
-
|
|
39
|
-
const req = this.req;
|
|
40
|
-
const res = this.res;
|
|
41
|
-
const next = this.next;
|
|
42
|
-
|
|
43
|
-
// support callback function as second arg
|
|
44
|
-
if (typeof options === 'function') {
|
|
45
|
-
done = options;
|
|
46
|
-
opts = {};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// merge res.locals
|
|
50
|
-
opts._locals = res.locals;
|
|
51
|
-
|
|
52
|
-
// default callback to respond
|
|
53
|
-
done = done || function (err, str) {
|
|
54
|
-
if (err)
|
|
55
|
-
return next(err);
|
|
56
|
-
|
|
57
|
-
res.send(str);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
// render
|
|
61
|
-
app.render(view, opts, done);
|
|
62
|
-
};
|
package/tests/ast.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const { ModelsTree } = require('../lib/middlewares/ql/sequelize/interpreter/ModelsTree');
|
|
2
|
-
const { AST_ModelsTree } = 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(
|
|
16
|
-
AST_ModelsTree(tree)
|
|
17
|
-
);
|
|
18
|
-
|