Skip to content

Commit 5b1eef7

Browse files
committed
ADD: default limit to query
Closes #4
1 parent bd45596 commit 5b1eef7

File tree

2 files changed

+101
-97
lines changed

2 files changed

+101
-97
lines changed

.prettierrc.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"semi": true,
3+
"singleQuote": true,
4+
"arrowParens": "always",
5+
"printWidth": 160,
6+
"tabWidth": 4,
7+
"endOfLine": "auto",
8+
"trailingComma": "none"
9+
}

sequelizeQueryParser.js

Lines changed: 92 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
* Author: Twaha Mukammel (t.mukammel@gmail.com)
55
*/
66

7-
'use strict'
7+
'use strict';
88

99
const Promise = require('bluebird');
1010

1111
/**
1212
* Pass `db` connection object which has `Sequelize.Op`
13-
* @param {*} db
13+
* @param {*} db
1414
* @returns object {parse}
1515
*/
1616
module.exports = function (db) {
@@ -24,115 +24,110 @@ module.exports = function (db) {
2424
ne: Op.ne,
2525
eq: Op.eq,
2626
not: Op.not,
27-
like: Op.like, // LIKE '%hat'
28-
notLike: Op.notLike, // NOT LIKE '%hat'
27+
like: Op.like, // LIKE '%hat'
28+
notLike: Op.notLike, // NOT LIKE '%hat'
2929
// iLike: Op.iLike, // ILIKE '%hat' (case insensitive) (PG only)
3030
// notILike: Op.notILike, // NOT ILIKE '%hat' (PG only)
31-
regexp: Op.regexp, // REGEXP/~ '^[h|a|t]' (MySQL/PG only)
32-
notRegexp: Op.notRegexp, // NOT REGEXP/!~ '^[h|a|t]' (MySQL/PG only)
31+
regexp: Op.regexp, // REGEXP/~ '^[h|a|t]' (MySQL/PG only)
32+
notRegexp: Op.notRegexp, // NOT REGEXP/!~ '^[h|a|t]' (MySQL/PG only)
3333
// iRegexp: Op.iRegexp, // ~* '^[h|a|t]' (PG only)
3434
// notIRegexp: Op.notIRegexp // !~* '^[h|a|t]' (PG only)
35-
and: Op.and, // AND (a = 5)
36-
or: Op.or, // (a = 5 OR a = 6)
37-
between: Op.between, // BETWEEN 6 AND 10
38-
notBetween: Op.notBetween, // NOT BETWEEN 11 AND 15
39-
in: Op.in, // IN [1, 2]
40-
notIn: Op.notIn, // NOT IN [1, 2]
35+
and: Op.and, // AND (a = 5)
36+
or: Op.or, // (a = 5 OR a = 6)
37+
between: Op.between, // BETWEEN 6 AND 10
38+
notBetween: Op.notBetween, // NOT BETWEEN 11 AND 15
39+
in: Op.in, // IN [1, 2]
40+
notIn: Op.notIn // NOT IN [1, 2]
4141
// overlap: Op.overlap, // && [1, 2] (PG array overlap operator)
4242
// contains: Op.contains, // @> [1, 2] (PG array contains operator)
4343
// contained: Op.contained, // <@ [1, 2] (PG array contained by operator)
4444
// col: Op.col // = "user"."organization_id", with dialect specific column identifiers, PG in this example
4545
// any: Op.any // ANY ARRAY[2, 3]::INTEGER (PG only)
46-
}
47-
46+
};
47+
4848
/**
4949
* Split '.' or ',' seperated strings to array
50-
* @param {JSON} obj
51-
* @param {array} array
50+
* @param {JSON} obj
51+
* @param {array} array
5252
*/
5353
const splitStringAndBuildArray = (obj, array) => {
5454
let elements = obj.split(',');
55-
55+
5656
if (elements && elements.length > 0) {
57-
elements.forEach(element => {
57+
elements.forEach((element) => {
5858
var fields = element.split('.');
5959
if (fields && fields.length > 0) {
60-
array.push(fields)
60+
array.push(fields);
6161
}
6262
});
6363
}
64-
}
65-
64+
};
65+
6666
/**
6767
* Parse query params
6868
* @param {string|Array} query
6969
* @returns {Array} sequelize formatted DB query array
7070
*/
7171
const parseFields = (query) => {
7272
let array = null;
73-
73+
7474
if (query !== null) {
7575
array = [];
76-
76+
7777
if (Array.isArray(query) == true) {
78-
query.forEach(obj => {
78+
query.forEach((obj) => {
7979
splitStringAndBuildArray(obj, array);
8080
});
81-
}
82-
else {
81+
} else {
8382
splitStringAndBuildArray(query, array);
8483
}
8584
}
86-
85+
8786
return array;
88-
}
89-
87+
};
88+
9089
/**
9190
* Replaces operator (json object key) with Sequelize operator.
92-
* @param {JSON} json
93-
* @param {string} key
91+
* @param {JSON} json
92+
* @param {string} key
9493
* @param {Sequelize.op} op
9594
*/
9695
const replaceKeyWithOperator = (json, key, op) => {
9796
let value = json[key];
9897
delete json[key];
9998
json[op] = value;
100-
}
101-
99+
};
100+
102101
/**
103102
* Iteratively replace json keys with Sequelize formated query operators.
104103
* @param {JSON} json next json
105104
*/
106105
const iterativeReplace = (json) => {
107106
Object.keys(json).forEach(function (key) {
108107
if (json[key] !== null && typeof json[key] === 'object') {
109-
110108
// console.debug("key: ", key);
111109
let op = operators[key];
112110
// console.debug("operation: ", op);
113-
111+
114112
if (op) {
115113
replaceKeyWithOperator(json, key, op);
116114
// console.debug("next: ", JSON.stringify(json[op], null, 4));
117115
iterativeReplace(json[op]);
118-
}
119-
else {
116+
} else {
120117
// console.debug("next: ", JSON.stringify(json[key], null, 4));
121118
iterativeReplace(json[key]);
122119
}
123-
}
124-
else if (key == 'model' && db[json[key]] != null) {
120+
} else if (key == 'model' && db[json[key]] != null) {
125121
// json['as'] = json[key].replace(/^./, char => char.toLowerCase());// /^\w/
126122
json['model'] = db[json[key]];
127-
}
128-
else {
123+
} else {
129124
let op = operators[key];
130125
if (op) replaceKeyWithOperator(json, key, op);
131126
}
132-
127+
133128
// console.debug("After Key:", key, " Query fields: ", JSON.stringify(json, null, 4))
134129
});
135-
}
130+
};
136131

137132
/**
138133
* Unescape escaped sequences in string.
@@ -143,32 +138,32 @@ module.exports = function (db) {
143138
const queryString = query.toString();
144139
const queryStringUnescaped = unescape(queryString);
145140
return queryStringUnescaped;
146-
}
147-
141+
};
142+
148143
/**
149144
* Parse and build Sequelize format query
150-
* @param {JSON} query
145+
* @param {JSON} query
151146
* @returns {JSON} sequelize formatted DB query params JSON
152147
*/
153148
const parseQueryFields = (query) => {
154149
let json = JSON.parse(unescapeEscapedQuery(query));
155150
iterativeReplace(json);
156151
// console.debug("Resultent query fields: ", json);
157152
return json;
158-
}
159-
153+
};
154+
160155
/**
161156
* Parse and build Sequelize format query
162-
* @param {JSON} query
157+
* @param {JSON} query
163158
* @returns {JSON} sequelize formatted DB include params JSON
164159
*/
165160
const parseIncludeFields = (query) => {
166161
let json = JSON.parse(unescapeEscapedQuery(query));
167162
iterativeReplace(json);
168163
// console.debug("Resultent include fields: ", json);
169164
return json;
170-
}
171-
165+
};
166+
172167
/**
173168
* Parse single query parameter
174169
* @param {string} query
@@ -179,122 +174,122 @@ module.exports = function (db) {
179174
// console.debug("Query param: ", JSON.stringify(elements, null, 4));
180175
if (elements && elements.length > 1) {
181176
var param = {};
182-
const elementsArray = elements[1].split(',')
183-
if (elementsArray){
184-
if (elementsArray.length > 1){
185-
param[operators[elements[0]]] = elementsArray
186-
}
187-
else {
188-
param[operators[elements[0]]] = elementsArray[0]
177+
const elementsArray = elements[1].split(',');
178+
if (elementsArray) {
179+
if (elementsArray.length > 1) {
180+
param[operators[elements[0]]] = elementsArray;
181+
} else {
182+
param[operators[elements[0]]] = elementsArray[0];
189183
}
190184
// console.debug("Query param: ", param);
191185
return param;
192186
}
193187
}
194188
// console.debug("Query param: ", elements[0]);
195189
return elements[0];
196-
}
197-
190+
};
191+
198192
// Max page size limit is set to 200
199193
const pageSizeLimit = 200;
200-
194+
201195
/**
202-
* Sequelize Query Parser is a very simple package that
196+
* Sequelize Query Parser is a very simple package that
203197
* turns your RESTful APIs into a basic set of Graph APIs.
204-
*
198+
*
205199
* Parses - filter, query, sorting, paging, group, relational object queries
206-
*
200+
*
207201
* fields=field01,field02...
208-
*
202+
*
209203
* limit=value&&offset=value
210-
*
204+
*
211205
* sort_by=field01.asc|field02.desc
212-
*
206+
*
213207
* group_by=field01,field02
214-
*
208+
*
215209
* query=JSON
216-
*
210+
*
217211
* include=JSON
218-
*
212+
*
219213
* filedName=unaryOperator:value
220-
*
214+
*
221215
* @param {JSON} req
222216
* @returns {JSON} sequelize formatted DB query
223217
*/
224218
function parse(req) {
225-
console.debug("Request query: ", req.query);
226-
219+
console.debug('Request query: ', req.query);
220+
227221
return new Promise((resolve, reject) => {
228222
try {
229-
var offset = 0, limit = pageSizeLimit;
223+
var offset = 0,
224+
limit = pageSizeLimit;
230225
var dbQuery = {
231-
where: {}
226+
where: {},
227+
offset,
228+
limit
232229
};
233-
const Op = db.Sequelize.Op;
234-
230+
235231
for (const key in req.query) {
236232
switch (key) {
237233
// Fields
238234
case 'fields':
239235
// split the field names (attributes) and assign to an array
240-
let fields = req.query.fields.split(",");
236+
let fields = req.query.fields.split(',');
241237
// assign fields array to .attributes
242238
if (fields && fields.length > 0) dbQuery.attributes = fields;
243239
break;
244-
240+
245241
// pagination page size
246242
case 'limit':
247243
dbQuery.limit = Math.min(Math.max(parseInt(req.query.limit), 1), pageSizeLimit);
248244
limit = dbQuery.limit;
249245
break;
250-
246+
251247
// pagination page offset
252248
case 'offset':
253249
offset = Math.max(parseInt(req.query.offset), 0);
254250
break;
255-
251+
256252
// Sort by field order
257253
case 'sort_by':
258254
dbQuery.order = parseFields(req.query.sort_by);
259255
break;
260-
256+
261257
// Group by field
262258
// TODO: Check array
263259
case 'group_by':
264260
dbQuery.group = parseFields(req.query.group_by);
265261
break;
266-
262+
267263
// JSON (nested) query
268264
case 'query':
269265
let parsed = parseQueryFields(req.query.query);
270266
dbQuery.where = { ...dbQuery.where, ...parsed };
271267
break;
272-
268+
273269
// include and query on associated tables
274270
case 'include':
275271
dbQuery.include = parseIncludeFields(req.query.include);
276272
break;
277-
273+
278274
// Simple filter query
279275
default:
280276
dbQuery.where[key] = parseQueryParam(req.query[key]);
281277
break;
282278
}
283279
}
284-
280+
285281
dbQuery.offset = offset * limit;
286-
287-
console.debug("Final sequelize query:");
282+
283+
console.debug('Final sequelize query:');
288284
console.debug(JSON.stringify(dbQuery, null, 4));
289-
285+
290286
resolve(dbQuery);
287+
} catch (error) {
288+
console.debug('Error: ', error.message);
289+
reject([{ msg: error.message }]);
291290
}
292-
catch(error) {
293-
console.debug("Error: ", error.message)
294-
reject([{msg: error.message}]);
295-
}
296-
})
291+
});
297292
}
298-
299-
return { parse }
300-
}
293+
294+
return { parse };
295+
};

0 commit comments

Comments
 (0)