Skip to content

Commit 501aca0

Browse files
fixes, tidy up options and added testing on new features
1 parent cb0c6ae commit 501aca0

File tree

3 files changed

+95
-21
lines changed

3 files changed

+95
-21
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ const { Op } = require('sequelize');
7979

8080
const minimumAgeHandler = (column, value, options) => {
8181
return {
82-
'age': [Op.gte]: value
82+
'age': {
83+
[Op.gte]: value
84+
}
8385
}
8486
};
8587

index.js

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,38 @@ class SequelizeQS {
2121
};
2222

2323
constructor(options) {
24+
// check and configure all the options are okay
2425
this.opt = options || {}
25-
this.ops = this.opt.ops || Object.keys(this.#opMaps);
26-
this.alias = this.opt.alias || {};
27-
this.blacklist = this.opt.blacklist || [];
28-
this.customHandlers = this.opt.custom || {};
29-
this.defaultPaginationLimit = this.opt.defaultPaginationLimit || 25;
30-
this.maximumPageSize = this.opt.maximumPageSize || 100;
31-
32-
if (!this.opt.dateFields) {
26+
27+
if (!this.opt.ops || !Array.isArray(this.opt.ops)) {
28+
this.opt.ops = Object.keys(this.#opMaps);
29+
}
30+
31+
if (!this.opt.alias || typeof(this.opt.alias) !== 'object') {
32+
this.opt.alias = {};
33+
}
34+
35+
if (!this.opt.blacklist || !Array.isArray(this.opt.blacklist)) {
36+
this.opt.blacklist = [];
37+
}
38+
39+
if (!this.opt.customHandlers || typeof(this.opt.customHandlers) !== 'object') {
40+
this.opt.customHandlers = {};
41+
}
42+
43+
if (!this.opt.defaultPaginationLimit || isNaN(this.opt.defaultPaginationLimit)) {
44+
this.opt.defaultPaginationLimit = 25;
45+
}
46+
47+
if (!this.opt.maximumPageSize || isNaN(this.opt.maximumPageSize)) {
48+
this.opt.maximumPageSize = 100;
49+
}
50+
51+
if (!this.opt.dateFields || !Array.isArray(this.opt.dateFields)) {
3352
this.opt.dateFields = ['createdAt', 'updatedAt'];
3453
}
3554

36-
if (!(typeof(this.opt.dateOnlyCompare) === 'boolean')) {
55+
if (!this.opt.dateOnlyCompare || typeof(this.opt.dateOnlyCompare) !== 'boolean') {
3756
this.opt.dateOnlyCompare = false;
3857
}
3958
}
@@ -62,8 +81,10 @@ class SequelizeQS {
6281
}
6382

6483
#parsePagination(page, limit) {
84+
const { defaultPaginationLimit, maximumPageSize } = this.opt;
85+
6586
let realPage = page || 1;
66-
let realLimit = limit || this.defaultPaginationLimit;
87+
let realLimit = limit || defaultPaginationLimit;
6788

6889
// prevent negative page number
6990
try {
@@ -79,12 +100,12 @@ class SequelizeQS {
79100
// prevent negative limit value or trying to get too many
80101
try {
81102
realLimit = parseInt(limit);
82-
if (isNaN(realLimit) || realLimit < 1 || (this.maximumPageSize && realLimit > this.maximumPageSize)) {
83-
realLimit = this.defaultPaginationLimit;
103+
if (isNaN(realLimit) || realLimit < 1 || (maximumPageSize && realLimit > maximumPageSize)) {
104+
realLimit = defaultPaginationLimit;
84105
}
85106
}
86107
catch {
87-
realLimit = this.defaultPaginationLimit;
108+
realLimit = defaultPaginationLimit;
88109
}
89110

90111
return { page: realPage, limit: realLimit };
@@ -113,22 +134,23 @@ class SequelizeQS {
113134
#parseWhereProperties(properties) {
114135
let where = {};
115136
let columns = Object.keys(properties);
137+
const { alias, blacklist, customHandlers, ops } = this.opt;
116138

117139
for (const column of columns) {
118-
let key = this.alias[column] || column; // handles an alias
119-
let value = properties[key];
140+
let key = alias[column] || column; // handles an alias
141+
let value = properties[column];
120142

121143
// check the blacklist
122-
if (this.blacklist.some(el => el === key)) {
144+
if (blacklist.some(el => el === key)) {
123145
break;
124146
}
125147

126148
// TODO: do we need to check for whitelist & let more dangerous query run?
127149

128150
// handles a custom function when we want to override the base functionality
129-
if (this.customHandlers[key] && typeof(this.customHandlers[key]) === 'function') {
151+
if (customHandlers[key] && typeof(customHandlers[key]) === 'function') {
130152
// call the custom handler function and get the operation to apply
131-
let customOperation = this.customHandlers[key](key, value, this.opt);
153+
let customOperation = customHandlers[key](key, value, this.opt);
132154
where = {
133155
...where,
134156
...customOperation
@@ -160,8 +182,8 @@ class SequelizeQS {
160182
}
161183

162184
// check if we have an operator to handle a special type (not a basic `=` equals basically)
163-
if (typeof(value) === 'string' && this.ops.some(op => value.startsWith(op))) {
164-
let op = this.ops.find(op => value.startsWith(op));
185+
if (typeof(value) === 'string' && ops.some(op => value.startsWith(op))) {
186+
let op = ops.find(op => value.startsWith(op));
165187
let fn = this.#opMaps[op];
166188

167189
if (!fn || !typeof (fn) === 'function') {

tests/test.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,43 @@
11
const connect = require('./db');
22
const assert = require('assert');
3+
const { Op } = require('sequelize');
34
const SequelizeQS = require('../index');
45

56
let models = null;
67
let sequelize = null;
78
let sequelizeQS = null;
89
let sequelizeDateQS = null;
10+
let sequelizeCustomQS = null;
911

1012
before(async () => {
1113
sequelize = await connect();
1214
models = sequelize.models;
1315
});
1416

1517
beforeEach(() => {
18+
// setup a basic parser
1619
sequelizeQS = new SequelizeQS();
20+
21+
// setup a parser that handlers dates as DATEONLY basically
1722
sequelizeDateQS = new SequelizeQS({
1823
dateOnlyCompare: true,
1924
dateFields: ['createdAt', 'updatedAt', 'lastLogin']
2025
});
26+
27+
// setup a parser that handlers blacklists, aliases and custom handlers
28+
sequelizeCustomQS = new SequelizeQS({
29+
blacklist: ['isActive'],
30+
alias: { 'customerAge': 'age' },
31+
customHandlers: {
32+
minAge: (column, value, options) => {
33+
return {
34+
'age': {
35+
[Op.gte]: value
36+
}
37+
}
38+
}
39+
}
40+
});
2141
});
2242

2343
describe('Basic Operations', () => {
@@ -324,6 +344,36 @@ describe('Operations - Date Only', () => {
324344
});
325345
});
326346

347+
describe('Alias', () => {
348+
it('should return 4', async () => {
349+
let options = sequelizeCustomQS.parse({
350+
customerAge: '|20|30'
351+
});
352+
let countResult = await models.customers.count(options);
353+
assert.equal(countResult, 4);
354+
});
355+
});
356+
357+
describe('Blacklist', () => {
358+
it('should return 10', async () => {
359+
let options = sequelizeCustomQS.parse({
360+
isActive: false
361+
});
362+
let countResult = await models.customers.count(options);
363+
assert.equal(countResult, 10);
364+
});
365+
});
366+
367+
describe('Custom Handlers', () => {
368+
it('should return 4', async () => {
369+
let options = sequelizeCustomQS.parse({
370+
minAge: 30
371+
});
372+
let countResult = await models.customers.count(options);
373+
assert.equal(countResult, 4);
374+
});
375+
});
376+
327377
describe('Pagination', () => {
328378
// no limit defined
329379
describe('No Limits', () => {

0 commit comments

Comments
 (0)