Skip to content
This repository was archived by the owner on May 1, 2025. It is now read-only.

Commit 873e92a

Browse files
committed
Merge pull request #11 from Turistforeningen/feat/boolean-strings
Parse Boolean Strings
2 parents c32f938 + 6330344 commit 873e92a

File tree

3 files changed

+108
-21
lines changed

3 files changed

+108
-21
lines changed

README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ useful when building an API and accepting various user specificed queries.
2323
* `$nin`
2424
* `$exists`
2525
* `$regex`
26+
* Parse string integers and floats to numbers
27+
* Parse string boolean to ture/false booleans
2628

2729
| operation | query string | query object |
2830
|-----------|---------------|--------------|
@@ -69,11 +71,16 @@ var MongoQS = require('mongo-querystring');
6971

7072
### new MongoQS(`object` options)
7173

72-
* `Array` ops - list of supported operators
73-
* `object` alias - query param aliases
74-
* `object` blacklist - blacklisted query params
75-
* `object` whitelist - whitelisted query params
76-
* `object` custom - custom query params
74+
* `Array` ops - list of supported operators (default: `['!', '^', '$', '~', '>', '<', '$in']`)
75+
* `object` alias - query param aliases (default: `{}`)
76+
* `object` blacklist - blacklisted query params (default: `{}`)
77+
* `object` whitelist - whitelisted query params (default: `{}`)
78+
* `object` custom - custom query params (default: `{}`)
79+
* `object` string - string parsing
80+
* `boolean` toBoolean - parse `"true"`, `"false"` string to booleans (default: `true`)
81+
* `boolean` toNumber - parse string integer and float values to numbers (default: `true`)
82+
* `regexp` keyRegex - allowed key names (default: `/^[a-zæøå0-9-_.]+$/i`)
83+
* `regexp` arrRegex - allowed array key names (default: `/^[a-zæøå0-9-_.]+(\[\])?$/i`)
7784

7885
#### Bult in custom queries
7986

index.js

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ module.exports = function MongoQS(opts) {
1010
this.whitelist = opts.whitelist || {};
1111
this.custom = opts.custom || {};
1212

13+
// String Value Parsing
14+
opts.string = opts.string || {};
15+
this.string = opts.string || {};
16+
this.string.toBoolean = opts.string.toBoolean || true;
17+
this.string.toNumber = opts.string.toNumber || true;
18+
1319
this.keyRegex = opts.keyRegex || /^[a-zæøå0-9-_.]+$/i;
1420
this.arrRegex = opts.arrRegex || /^[a-zæøå0-9-_.]+(\[\])?$/i;
1521

@@ -100,6 +106,18 @@ module.exports.prototype.customAfter = function(field) {
100106
};
101107
};
102108

109+
module.exports.prototype.parseString = function(string) {
110+
if (this.string.toBoolean && string.toLowerCase() === 'true') {
111+
return true;
112+
} else if (this.string.toBoolean && string.toLowerCase() === 'false') {
113+
return false;
114+
} else if (this.string.toNumber && !isNaN(string)) {
115+
return parseFloat(string, 10);
116+
} else {
117+
return string;
118+
}
119+
};
120+
103121
module.exports.prototype.parse = function(query) {
104122
var op, val;
105123
var res = {};
@@ -138,17 +156,16 @@ module.exports.prototype.parse = function(query) {
138156
res[key] = {$in: val.filter(function(element) {
139157
return element[0] !== '!';
140158
}).map(function(element) {
141-
return isNaN(element) ? element : parseFloat(element, 10);
142-
})};
159+
return this.parseString(element);
160+
}.bind(this))};
143161

144162
// $nin query
145163
} else {
146164
res[key] = {$nin: val.filter(function(element) {
147165
return element[0] === '!';
148166
}).map(function(element) {
149-
element = element.substr(1);
150-
return isNaN(element) ? element : parseFloat(element, 10);
151-
})};
167+
return this.parseString(element.substr(1));
168+
}.bind(this))};
152169
}
153170
}
154171

@@ -173,7 +190,7 @@ module.exports.prototype.parse = function(query) {
173190
switch (op) {
174191
case '!':
175192
if (val) {
176-
return { $ne: isNaN(val) ? val : parseFloat(val, 10) };
193+
return { $ne: this.parseString(val) };
177194
} else {
178195
return { $exists: false };
179196
}
@@ -193,9 +210,9 @@ module.exports.prototype.parse = function(query) {
193210
return { $regex: val, $options: 'i' };
194211
}
195212
}
196-
})();
213+
}.bind(this))();
197214
} else {
198-
res[key] = isNaN(val) ? val : parseFloat(val, 10);
215+
res[key] = this.parseString(val);
199216
}
200217
}
201218
return res;

test.js

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,47 @@ describe('customAfter()', function() {
100100
});
101101
});
102102

103+
describe('parseString()', function() {
104+
it('returns boolean true for "true" string', function() {
105+
assert.equal(qs.parseString('true'), true);
106+
});
107+
108+
it('returns string "true" when boolean parsing is disabled', function() {
109+
qs.string.toBoolean = false;
110+
assert.equal(qs.parseString('true'), 'true');
111+
});
112+
113+
it('returns boolean false for "flase" string', function() {
114+
assert.equal(qs.parseString('false'), false);
115+
});
116+
117+
it('returns string "false" when boolean parsing is disabled', function() {
118+
qs.string.toBoolean = false;
119+
assert.equal(qs.parseString('false'), 'false');
120+
});
121+
122+
it('returns number for parseable integer', function() {
123+
assert.equal(qs.parseString('100'), 100);
124+
});
125+
126+
it('returns string number when number parsing is disabled', function() {
127+
qs.string.toNumber = false;
128+
assert.equal(qs.parseString('100'), '100');
129+
});
130+
131+
it('returns number for zero padded parseable integer', function() {
132+
assert.equal(qs.parseString('000100'), 100);
133+
});
134+
135+
it('returns number for parseable float', function() {
136+
assert.equal(qs.parseString('10.123'), 10.123);
137+
});
138+
139+
it('returns number for zero padded parseable float', function() {
140+
assert.equal(qs.parseString('00010.123'), 10.123);
141+
});
142+
});
143+
103144
describe('parse()', function() {
104145
describe('parsing', function() {
105146
describe('key value validation', function() {
@@ -143,6 +184,17 @@ describe('parse()', function() {
143184
});
144185
});
145186

187+
it('return string boolean as boolean', function() {
188+
query = qs.parse({
189+
foo: 'true',
190+
bar: 'false'
191+
});
192+
assert.deepEqual(query, {
193+
foo: true,
194+
bar: false
195+
});
196+
});
197+
146198
it('returns string integer as number', function() {
147199
query = qs.parse({
148200
navn: '10'
@@ -185,6 +237,17 @@ describe('parse()', function() {
185237
});
186238
});
187239

240+
it('return string boolean as boolean', function() {
241+
query = qs.parse({
242+
foo: '!true',
243+
bar: '!false'
244+
});
245+
assert.deepEqual(query, {
246+
foo: {$ne: true},
247+
bar: {$ne: false}
248+
});
249+
});
250+
188251
it('returns string integer as number', function() {
189252
query = qs.parse({
190253
navn: '!10'
@@ -289,23 +352,23 @@ describe('parse()', function() {
289352

290353
describe('$in / $nin operator', function() {
291354
it('returns in array query', function() {
292-
var string = 'foo[]=10&foo[]=10.011&foo[]=bar';
355+
var string = 'foo[]=10&foo[]=10.011&foo[]=bar&foo[]=true';
293356
var params = require('querystring').parse(string);
294357

295358
assert.deepEqual(qs.parse(params), {
296359
foo: {
297-
$in: [10, 10.011, 'bar']
360+
$in: [10, 10.011, 'bar', true]
298361
}
299362
});
300363
});
301364

302365
it('returns in array query with "qs" parser (GH-06)', function() {
303-
var string = 'foo[]=10&foo[]=10.011&foo[]=bar';
366+
var string = 'foo[]=10&foo[]=10.011&foo[]=bar&foo[]=true';
304367
var params = require('qs').parse(string);
305368

306369
assert.deepEqual(qs.parse(params), {
307370
foo: {
308-
$in: [10, 10.011, 'bar']
371+
$in: [10, 10.011, 'bar', true]
309372
}
310373
});
311374
});
@@ -322,23 +385,23 @@ describe('parse()', function() {
322385
});
323386

324387
it('returns not in array query', function() {
325-
var string = 'foo[]=!10&foo[]=!10.011&foo[]=!bar';
388+
var string = 'foo[]=!10&foo[]=!10.011&foo[]=!bar&foo[]=!false';
326389
var params = require('querystring').parse(string);
327390

328391
assert.deepEqual(qs.parse(params), {
329392
foo: {
330-
$nin: [10, 10.011, 'bar']
393+
$nin: [10, 10.011, 'bar', false]
331394
}
332395
});
333396
});
334397

335398
it('returns not in array query with "gs" parser (GH-06)', function() {
336-
var string = 'foo[]=!10&foo[]=!10.011&foo[]=!bar';
399+
var string = 'foo[]=!10&foo[]=!10.011&foo[]=!bar&foo[]=!false';
337400
var params = require('qs').parse(string);
338401

339402
assert.deepEqual(qs.parse(params), {
340403
foo: {
341-
$nin: [10, 10.011, 'bar']
404+
$nin: [10, 10.011, 'bar', false]
342405
}
343406
});
344407
});

0 commit comments

Comments
 (0)