@@ -17,6 +17,7 @@ module.exports = function MongoQS(opts) {
1717 this . string . toNumber = opts . string . toNumber || true ;
1818
1919 this . keyRegex = opts . keyRegex || / ^ [ a - z æ ø å 0 - 9 - _ .] + $ / i;
20+ this . valRegex = opts . valRegex || / [ ^ a - z æ ø å 0 - 9 - _ .* ] / i;
2021 this . arrRegex = opts . arrRegex || / ^ [ a - z æ ø å 0 - 9 - _ .] + ( \[ \] ) ? $ / i;
2122
2223 for ( var param in this . custom ) {
@@ -117,20 +118,86 @@ module.exports.prototype.customAfter = function(field) {
117118 } ;
118119} ;
119120
120- module . exports . prototype . parseString = function ( string ) {
121+ module . exports . prototype . parseString = function ( string , array ) {
122+ var op = string [ 0 ] || '' ;
123+ var eq = string [ 1 ] === '=' ;
124+ var org = string . substr ( eq ? 2 : 1 ) || '' ;
125+ var val = this . parseStringVal ( org ) ;
126+
127+ var ret = { op : op , org : org , value : val } ;
128+
129+ switch ( op ) {
130+ case '!' :
131+ if ( array ) {
132+ ret . field = '$nin' ;
133+ } else if ( org === '' ) {
134+ ret . field = '$exists' ;
135+ ret . value = false ;
136+ } else {
137+ ret . field = '$ne' ;
138+ }
139+ break ;
140+ case '>' :
141+ ret . field = eq ? '$gte' : '$gt' ;
142+ break ;
143+ case '<' :
144+ ret . field = eq ? '$lte' : '$lt' ;
145+ break ;
146+ case '^' :
147+ case '$' :
148+ case '~' :
149+ ret . field = '$regex' ;
150+ ret . options = 'i' ;
151+ ret . value = org . replace ( this . valReqex , '' ) ;
152+
153+ switch ( op ) {
154+ case '^' :
155+ ret . value = '^' + val ;
156+ break ;
157+ case '$' :
158+ ret . value = val + '$' ;
159+ break ;
160+ }
161+ break ;
162+ default :
163+ ret . org = org = op + org ;
164+ ret . op = op = '' ;
165+ ret . value = this . parseStringVal ( org ) ;
166+
167+ if ( array ) {
168+ ret . field = '$in' ;
169+ } else if ( org === '' ) {
170+ ret . field = '$exists' ;
171+ ret . value = true ;
172+ } else {
173+ ret . field = '$eq' ;
174+ }
175+ }
176+
177+ ret . parsed = { } ;
178+ ret . parsed [ ret . field ] = ret . value ;
179+
180+ if ( ret . options ) {
181+ ret . parsed . $options = ret . options ;
182+ }
183+
184+ return ret ;
185+ } ;
186+
187+ module . exports . prototype . parseStringVal = function ( string ) {
121188 if ( this . string . toBoolean && string . toLowerCase ( ) === 'true' ) {
122189 return true ;
123190 } else if ( this . string . toBoolean && string . toLowerCase ( ) === 'false' ) {
124191 return false ;
125- } else if ( this . string . toNumber && ! isNaN ( string ) ) {
192+ } else if ( this . string . toNumber && ! isNaN ( parseFloat ( string , 10 ) ) ) {
126193 return parseFloat ( string , 10 ) ;
127194 } else {
128195 return string ;
129196 }
130197} ;
131198
132199module . exports . prototype . parse = function ( query ) {
133- var op , val ;
200+ var val ;
134201 var res = { } ;
135202
136203 for ( var key in query ) {
@@ -161,71 +228,55 @@ module.exports.prototype.parse = function(query) {
161228 if ( this . ops . indexOf ( '$in' ) >= 0 && val . length > 0 ) {
162229 // remove [] at end of key name (unless it has already been removed)
163230 key = key . replace ( / \[ \] $ / , '' ) ;
164-
165- // $in query
166- if ( val [ 0 ] [ 0 ] !== '!' ) {
167- res [ key ] = { $in : val . filter ( function ( element ) {
168- return element [ 0 ] !== '!' ;
169- } ) . map ( function ( element ) {
170- return this . parseString ( element ) ;
171- } . bind ( this ) ) } ;
172-
173- // $nin query
174- } else {
175- res [ key ] = { $nin : val . filter ( function ( element ) {
176- return element [ 0 ] === '!' ;
177- } ) . map ( function ( element ) {
178- return this . parseString ( element . substr ( 1 ) ) ;
179- } . bind ( this ) ) } ;
231+ res [ key ] = { } ;
232+
233+ for ( var i = 0 ; i < val . length ; i ++ ) {
234+ if ( this . ops . indexOf ( val [ i ] [ 0 ] ) >= 0 ) {
235+ var parsed = this . parseString ( val [ i ] , true ) ;
236+
237+ switch ( parsed . field ) {
238+ case '$in' :
239+ case '$nin' :
240+ res [ key ] [ parsed . field ] = res [ key ] [ parsed . field ] || [ ] ;
241+ res [ key ] [ parsed . field ] . push ( parsed . value ) ;
242+ break ;
243+ case '$regex' :
244+ res [ key ] . $regex = parsed . value ;
245+ res [ key ] . $options = parsed . options ;
246+ break ;
247+ default :
248+ res [ key ] [ parsed . field ] = parsed . value ;
249+ }
250+ } else {
251+ res [ key ] . $in = res [ key ] . $in || [ ] ;
252+ res [ key ] . $in . push ( this . parseStringVal ( val [ i ] ) ) ;
253+ }
180254 }
181255 }
182256
183257 continue ;
184258 }
185259
260+ // value must be a string
186261 if ( typeof val !== 'string' ) {
187262 continue ;
188263 }
189264
265+ // custom functions
190266 if ( typeof this . custom [ key ] === 'function' ) {
191267 this . custom [ key ] ( res , val ) ;
192268
269+ // field exists query
193270 } else if ( ! val ) {
194271 res [ key ] = { $exists : true } ;
195272
273+ // query operators
196274 } else if ( this . ops . indexOf ( val [ 0 ] ) >= 0 ) {
197- op = val . charAt ( 0 ) ;
198- val = val . substr ( 1 ) ;
199-
200- res [ key ] = ( function ( ) {
201- var hasEqual = ( val . charAt ( 0 ) === '=' ) ;
202- var output = parseFloat ( ( hasEqual ? val . substr ( 1 ) : val ) , 10 ) ;
203- switch ( op ) {
204- case '!' :
205- if ( val ) {
206- return { $ne : this . parseString ( val ) } ;
207- } else {
208- return { $exists : false } ;
209- }
210- break ;
211- case '>' :
212- return output ? hasEqual ? { $gte : output } : { $gt : output } : { } ;
213- case '<' :
214- return output ? hasEqual ? { $lte : output } : { $lt : output } : { } ;
215- default :
216- val = val . replace ( / [ ^ a - z æ ø å 0 - 9 - _ .* ] / i, '' ) ;
217- switch ( op ) {
218- case '^' :
219- return { $regex : '^' + val , $options : 'i' } ;
220- case '$' :
221- return { $regex : val + '$' , $options : 'i' } ;
222- default :
223- return { $regex : val , $options : 'i' } ;
224- }
225- }
226- } . bind ( this ) ) ( ) ;
275+ res [ key ] = this . parseString ( val ) . parsed ;
276+
277+ // equal operator (no operator)
227278 } else {
228- res [ key ] = this . parseString ( val ) ;
279+ res [ key ] = this . parseStringVal ( val ) ;
229280 }
230281 }
231282 return res ;
0 commit comments