nodester 0.4.2 → 0.4.4
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.
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const Enum = require('nodester/enum');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
module.exports = new Enum({
|
|
12
|
+
'%20': ' ',
|
|
13
|
+
'%22': '\\',
|
|
14
|
+
'%23': '#',
|
|
15
|
+
'%24': '$',
|
|
16
|
+
'%25': '%',
|
|
17
|
+
'%26': '&',
|
|
18
|
+
'%27': `'`,
|
|
19
|
+
"%28": '(',
|
|
20
|
+
"%29": ')',
|
|
21
|
+
|
|
22
|
+
'%2A': '*',
|
|
23
|
+
'%2B': '+',
|
|
24
|
+
'%2C': ',',
|
|
25
|
+
'%2D': '-',
|
|
26
|
+
'%2E': '.',
|
|
27
|
+
'%2F': '/',
|
|
28
|
+
|
|
29
|
+
'%3A': ':',
|
|
30
|
+
'%3B': ';',
|
|
31
|
+
'%3C': '<',
|
|
32
|
+
'%3D': '=',
|
|
33
|
+
'%3E': '>',
|
|
34
|
+
'%3F': '?',
|
|
35
|
+
|
|
36
|
+
'%40': '@',
|
|
37
|
+
|
|
38
|
+
'%5B': '[',
|
|
39
|
+
'%5D': ']',
|
|
40
|
+
'%5E': '^',
|
|
41
|
+
'%5F': '_',
|
|
42
|
+
|
|
43
|
+
'%60': '`',
|
|
44
|
+
|
|
45
|
+
'%7B': '{',
|
|
46
|
+
'%7D': '}',
|
|
47
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const ENCODES = require('./encodes');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
decodeQueryString: _decodeQueryString
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function _decodeQueryString(queryString='') {
|
|
16
|
+
let decoded = '';
|
|
17
|
+
|
|
18
|
+
// Token is a String, accumulated char-by-char.
|
|
19
|
+
let token = '';
|
|
20
|
+
|
|
21
|
+
let isEcodedChar = false;
|
|
22
|
+
let encodedCharsCount = 0;
|
|
23
|
+
|
|
24
|
+
for (let i=0; i < queryString.length; i++) {
|
|
25
|
+
const char = queryString[i];
|
|
26
|
+
|
|
27
|
+
if (char === '%') {
|
|
28
|
+
isEcodedChar = true;
|
|
29
|
+
decoded += token;
|
|
30
|
+
token = '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Continue accumulating token.
|
|
34
|
+
token += char;
|
|
35
|
+
|
|
36
|
+
if (isEcodedChar) {
|
|
37
|
+
encodedCharsCount++;
|
|
38
|
+
|
|
39
|
+
if (encodedCharsCount === 3) {
|
|
40
|
+
const decodedChar = ENCODES[token];
|
|
41
|
+
|
|
42
|
+
if (!decodedChar) {
|
|
43
|
+
const err = new Error(`Uknown token '${ token }' at index ${ i }.`);
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
decoded += decodedChar;
|
|
48
|
+
// Reset:
|
|
49
|
+
token = '';
|
|
50
|
+
isEcodedChar = false;
|
|
51
|
+
encodedCharsCount = 0;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Last chunk.
|
|
57
|
+
decoded += token;
|
|
58
|
+
|
|
59
|
+
return decoded;
|
|
60
|
+
}
|
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
HTTP_CODE_UNPROCESSABLE_ENTITY
|
|
10
10
|
} = require('nodester/http/codes');
|
|
11
11
|
|
|
12
|
+
const { decodeQueryString } = require('./decoder');
|
|
12
13
|
const QueryLexer = require('./interpreter/QueryLexer');
|
|
13
14
|
const { createErrorResponse } = require('nodester/factories/responses/rest');
|
|
14
15
|
|
|
@@ -34,7 +35,8 @@ function nqlHandle(req, res, next) {
|
|
|
34
35
|
try {
|
|
35
36
|
const queryString = req.url.split('?')[1];
|
|
36
37
|
|
|
37
|
-
const
|
|
38
|
+
const decoded = decodeQueryString(queryString);
|
|
39
|
+
const lexer = new QueryLexer(decoded);
|
|
38
40
|
|
|
39
41
|
// Go on!
|
|
40
42
|
req.nquery = lexer.query;
|
package/lib/models/define.js
CHANGED
|
@@ -106,7 +106,7 @@ function _getIncludesTree(data=null) {
|
|
|
106
106
|
for (const [ associationName, associationDefinition ] of associationEntries) {
|
|
107
107
|
const formatted = { association: associationName };
|
|
108
108
|
|
|
109
|
-
if (typeof data === 'object') {
|
|
109
|
+
if (!!data && typeof data === 'object') {
|
|
110
110
|
// If data (for example during create)
|
|
111
111
|
// is set, go deeper:
|
|
112
112
|
const keys = Object.keys( data );
|
|
@@ -34,10 +34,11 @@ module.exports = traverse;
|
|
|
34
34
|
* @param {ModelsTreeNode} queryNode
|
|
35
35
|
* @param {NodesterFilter} filter
|
|
36
36
|
* @param {Model} model
|
|
37
|
+
* @param {Object} association (optional)
|
|
37
38
|
*
|
|
38
39
|
* @access public
|
|
39
40
|
*/
|
|
40
|
-
function traverse(queryNode, filter=null, model=null) {
|
|
41
|
+
function traverse(queryNode, filter=null, model=null, association=null) {
|
|
41
42
|
const _model = model ?? filter.model;
|
|
42
43
|
|
|
43
44
|
try {
|
|
@@ -236,21 +237,25 @@ function traverse(queryNode, filter=null, model=null) {
|
|
|
236
237
|
const staticClausesEntries = Object.entries(filter.statics.clauses);
|
|
237
238
|
|
|
238
239
|
for (let entry of staticClausesEntries) {
|
|
239
|
-
const [clauseName, staticClauseValue] = entry;
|
|
240
|
+
const [ clauseName, staticClauseValue ] = entry;
|
|
240
241
|
|
|
241
242
|
switch(clauseName) {
|
|
242
243
|
case 'limit':
|
|
243
244
|
newQuery.limit = staticClauseValue;
|
|
244
245
|
continue;
|
|
246
|
+
|
|
245
247
|
case 'skip':
|
|
246
248
|
newQuery.offset = staticClauseValue;
|
|
247
249
|
continue;
|
|
250
|
+
|
|
248
251
|
case 'order':
|
|
249
252
|
order.order = staticClauseValue;
|
|
250
253
|
continue;
|
|
254
|
+
|
|
251
255
|
case 'order_by':
|
|
252
256
|
order.by = staticClauseValue;
|
|
253
257
|
continue;
|
|
258
|
+
|
|
254
259
|
default:
|
|
255
260
|
break;
|
|
256
261
|
}
|
|
@@ -378,7 +383,7 @@ function _traverseIncludes(includes, rootModel, filter, resultQuery) {
|
|
|
378
383
|
|
|
379
384
|
const includeModel = association.target;
|
|
380
385
|
// Build query for this include.
|
|
381
|
-
const associationQuery = traverse(include, filter.includes[includeName], includeModel);
|
|
386
|
+
const associationQuery = traverse(include, filter.includes[includeName], includeModel, association);
|
|
382
387
|
|
|
383
388
|
addAssociationQuery(associationQuery, includeName, resultQuery);
|
|
384
389
|
}
|