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

Commit a545727

Browse files
author
Hans Kristian Flaatten
committed
Add initial version
1 parent 1080267 commit a545727

File tree

2 files changed

+255
-0
lines changed

2 files changed

+255
-0
lines changed

src/index.litcoffee

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
module.exports = MongoQS = (opts) ->
2+
@ops = opts?.ops or ['!', '^', '$', '~', '>', '<']
3+
@alias = opts?.alias or {}
4+
@ignore = opts?.ignore or {}
5+
@custom = opts?.custom or {}
6+
7+
for param, field of @custom
8+
switch param
9+
when 'bbox' then @custom.bbox = @customBBOX field
10+
when 'near' then @custom.near = @customNear field
11+
when 'after' then @custom.near = @customNear field
12+
13+
return @
14+
15+
MongoQS.prototype.customBBOX = (field) ->
16+
(res, bbox) ->
17+
bbox = bbox.split ','
18+
19+
if bbox.length is 4
20+
val = parseFloat(val) for val in bbox
21+
22+
res[field] = $geoWithin: $geometry:
23+
type: 'Polygon'
24+
coordinates: [[
25+
[bbox[0], bbox[1]]
26+
[bbox[2], bbox[1]]
27+
[bbox[2], bbox[3]]
28+
[bbox[0], bbox[3]]
29+
[bbox[0], bbox[1]]
30+
]]
31+
32+
return
33+
34+
MongoQS.prototype.customNear = (field) ->
35+
(query, input) ->
36+
input = input.split ','
37+
38+
if input.length is 2
39+
val = parseFloat(val) for val in input
40+
41+
query[field] = $near: $geometry:
42+
type: 'Point'
43+
coordinates: input
44+
45+
return
46+
47+
MongoQS.prototype.customAfter = (field) ->
48+
(query, input) ->
49+
50+
if not isNaN input
51+
input = input + '000' if (input + '').length is 10
52+
input = parseInt input
53+
54+
input = new Date input
55+
56+
if input.toString() isnt 'Invalid Date'
57+
query[field] = $gte: input.toISOString()
58+
59+
60+
MongoQS.prototype.parse = (query) ->
61+
res = {}
62+
63+
for key, val of query
64+
continue if @ignore[key]
65+
continue if typeof val isnt 'string'
66+
continue if not /^[a-zæøå0-9-_.]+$/i.test key
67+
68+
key = @alias[key] if @alias[key]
69+
70+
If the value is empty we treat the query parameter as an
71+
[$exists](http://docs.mongodb.org/manual/reference/operator/query/exists/)
72+
operator.
73+
74+
if not val
75+
res[key] = $exists: true
76+
77+
Check for supported operators in `@ops`. This is configured when
78+
instanciating `MongoQS` and the defaults are `!`, `^`, `$`, `~`, `>`, and `<`.
79+
80+
else if val.charAt(0) in @ops
81+
op = val.charAt(0)
82+
val = val.substr(1)
83+
84+
res[key] = switch op
85+
when '!'
86+
if val
87+
$ne: if isNaN(val) then val else parseFloat(val, 10)
88+
else
89+
$exists: false
90+
when '>' then $gt: parseFloat(val, 10)
91+
when '<' then $lt: parseFloat(val, 10)
92+
else
93+
val = val.replace /[^a-zæøå0-9-_.* ]/i, ''
94+
switch op
95+
when '^' then $regex: '^' + val, $options: 'i'
96+
when '$' then $regex: val + '$', $options: 'i'
97+
else $regex: val, $options: 'i'
98+
99+
else
100+
res[key] = if isNaN(val) then val else parseFloat(val, 10)
101+
102+
res
103+

test/suite.coffee

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
assert = require 'assert'
2+
MongoQS = require '../src/'
3+
4+
qs = query = null
5+
6+
beforeEach ->
7+
qs = new MongoQS()
8+
query = {}
9+
10+
describe 'customBBOX()', ->
11+
it 'should not genearate $geoWithin query for invalid bbox', ->
12+
for input in ['0123', '0,1,2']
13+
qs.customBBOX('geojson') query, input
14+
assert.deepEqual query, {}, "#{input} should not be valid BBOX input"
15+
16+
it 'should generate $geoWithin query for valid bbox', ->
17+
qs.customBBOX('geojson') query, '0,1,2,3'
18+
assert.deepEqual query, geojson: $geoWithin: $geometry:
19+
type: 'Polygon'
20+
coordinates: [[
21+
[0, 1]
22+
[2, 1]
23+
[2, 3]
24+
[0, 3]
25+
[0, 1]
26+
]]
27+
28+
describe 'customNear()', ->
29+
it 'should not genearate $near query for invalid point', ->
30+
for input in ['0123']
31+
qs.customNear('geojson') query, input
32+
assert.deepEqual query, {}, "#{input} should not be valid BBOX input"
33+
34+
it 'should generate $near query for valid point', ->
35+
qs.customNear('geojson') query, '0,1'
36+
assert.deepEqual query, geojson: $near: $geometry:
37+
type: 'Point'
38+
coordinates: [0, 1]
39+
40+
describe 'customAfter()', ->
41+
it 'should not generate after query for invalid date', ->
42+
for input in ['foo']
43+
qs.customAfter('endret') query, input
44+
assert.deepEqual query, {}, "#{input} should not be valid after date"
45+
46+
it 'should generate after query for ISO date', ->
47+
qs.customAfter('endret') query, '2014-09-22T11:50:37.843Z'
48+
assert.deepEqual query, endret: $gte: '2014-09-22T11:50:37.843Z'
49+
50+
it 'should generate after query for milliseconds timestamp', ->
51+
qs.customAfter('endret') query, '1411386637843'
52+
assert.deepEqual query, endret: $gte: '2014-09-22T11:50:37.843Z'
53+
54+
it 'should generate after query for unix timestamp', ->
55+
qs.customAfter('endret') query, '1411386637'
56+
assert.deepEqual query, endret: $gte: '2014-09-22T11:50:37.000Z'
57+
58+
describe 'parse()', ->
59+
describe 'parsing', ->
60+
describe 'key value validation', ->
61+
it 'should allow basic alpha num key names', ->
62+
assert.deepEqual qs.parse({'Abc.Æøå_123-456': 'bix'}), 'Abc.Æøå_123-456': "bix"
63+
64+
it 'should discard keys with special chars', ->
65+
assert.deepEqual qs.parse({'h4xor$': 'bix'}), {}
66+
67+
it 'should discard non-string values', ->
68+
assert.deepEqual qs.parse({'foo': []}), {}
69+
assert.deepEqual qs.parse({'foo': {}}), {}
70+
assert.deepEqual qs.parse({'foo': false}), {}
71+
72+
describe 'no operator', ->
73+
it 'should return empty query set', ->
74+
assert.deepEqual qs.parse({}), {}
75+
76+
it 'should return equal query', ->
77+
assert.deepEqual qs.parse({navn: 'foo'}), navn: 'foo'
78+
79+
it 'should parse float if applicable', ->
80+
query = qs.parse navn: '10'
81+
assert.deepEqual query, navn: 10
82+
assert.strictEqual query.navn, 10
83+
84+
it 'should return empty equal query', ->
85+
assert.deepEqual qs.parse({navn: ''}), navn: $exists: true
86+
87+
describe '! operator', ->
88+
it 'should return not equal query', ->
89+
assert.deepEqual qs.parse({navn: '!foo'}), navn: $ne: 'foo'
90+
91+
it 'should parse float if applicable', ->
92+
query = qs.parse navn: '!10'
93+
assert.deepEqual query, navn: $ne: 10
94+
assert.strictEqual query.navn.$ne, 10
95+
96+
it 'should return empty not equal query', ->
97+
assert.deepEqual qs.parse({navn: '!'}), navn: $exists: false
98+
99+
describe '> operator', ->
100+
it 'should return greater than query', ->
101+
query = qs.parse navn: '>10'
102+
assert.deepEqual query, navn: $gt: 10
103+
assert.strictEqual query.navn.$gt, 10
104+
105+
describe '< operator', ->
106+
it 'should return less than query', ->
107+
query = qs.parse navn: '<10'
108+
assert.deepEqual query, navn: $lt: 10
109+
assert.strictEqual query.navn.$lt, 10
110+
111+
describe '^ operator', ->
112+
it 'should return starts with query', ->
113+
assert.deepEqual qs.parse({navn: '^foo'}), navn: $regex: '^foo', $options: 'i'
114+
115+
describe '$ operator', ->
116+
it 'should return ends with query', ->
117+
assert.deepEqual qs.parse({navn: '$foo'}), navn: $regex: 'foo$', $options: 'i'
118+
119+
describe '~ operator', ->
120+
it 'should return contains query', ->
121+
assert.deepEqual qs.parse({navn: '~foo'}), navn: $regex: 'foo', $options: 'i'
122+
123+
it 'should parse multiple keys', ->
124+
query = qs.parse
125+
foo: ''
126+
bar: '!foo'
127+
'%foo': 'bar'
128+
'bix.bax': 'that'
129+
'foo-bar': 'bar-foo'
130+
131+
assert.deepEqual query,
132+
foo: $exists: true
133+
bar: $ne: 'foo'
134+
'bix.bax': 'that'
135+
'foo-bar': 'bar-foo'
136+
137+
describe 'aliasing', ->
138+
it 'should alias key', ->
139+
qs = new MongoQS alias: foo: 'bar'
140+
assert.deepEqual qs.parse({foo: 'bix'}), bar: 'bix'
141+
142+
it 'should alias multiple keys'
143+
144+
describe 'ignoring', ->
145+
it 'should ignore key', ->
146+
qs = new MongoQS ignore: foo: true
147+
assert.deepEqual qs.parse({foo: 'bar', bar: 'foo'}), bar: 'foo'
148+
149+
it 'should ingore multiple keys'
150+
151+
describe 'custom', ->
152+

0 commit comments

Comments
 (0)