20
20
import java .util .Collection ;
21
21
import java .util .LinkedHashMap ;
22
22
import java .util .List ;
23
+ import java .util .regex .Pattern ;
23
24
25
+ import org .bson .BSON ;
24
26
import org .bson .types .BasicBSONList ;
25
27
import org .springframework .data .mongodb .InvalidMongoDbApiUsageException ;
26
28
import org .springframework .data .mongodb .core .geo .Circle ;
27
29
import org .springframework .data .mongodb .core .geo .Point ;
28
30
import org .springframework .data .mongodb .core .geo .Shape ;
29
31
import org .springframework .util .Assert ;
30
- import org .springframework .util .StringUtils ;
31
32
32
33
import com .mongodb .BasicDBObject ;
33
34
import com .mongodb .DBObject ;
@@ -97,13 +98,17 @@ public Criteria is(Object o) {
97
98
throw new InvalidMongoDbApiUsageException (
98
99
"Multiple 'is' values declared. You need to use 'and' with multiple criteria" );
99
100
}
100
- if (this . criteria . size () > 0 && "$not" . equals ( this . criteria . keySet (). toArray ()[ this . criteria . size () - 1 ] )) {
101
+ if (lastOperatorWasNot ( )) {
101
102
throw new InvalidMongoDbApiUsageException ("Invalid query: 'not' can't be used with 'is' - use 'ne' instead." );
102
103
}
103
104
this .isValue = o ;
104
105
return this ;
105
106
}
106
107
108
+ private boolean lastOperatorWasNot () {
109
+ return this .criteria .size () > 0 && "$not" .equals (this .criteria .keySet ().toArray ()[this .criteria .size () - 1 ]);
110
+ }
111
+
107
112
/**
108
113
* Creates a criterion using the $ne operator
109
114
*
@@ -269,7 +274,11 @@ public Criteria type(int t) {
269
274
* @return
270
275
*/
271
276
public Criteria not () {
272
- criteria .put ("$not" , null );
277
+ return not (null );
278
+ }
279
+
280
+ private Criteria not (Object value ) {
281
+ criteria .put ("$not" , value );
273
282
return this ;
274
283
}
275
284
@@ -280,8 +289,7 @@ public Criteria not() {
280
289
* @return
281
290
*/
282
291
public Criteria regex (String re ) {
283
- criteria .put ("$regex" , re );
284
- return this ;
292
+ return regex (re , null );
285
293
}
286
294
287
295
/**
@@ -292,13 +300,32 @@ public Criteria regex(String re) {
292
300
* @return
293
301
*/
294
302
public Criteria regex (String re , String options ) {
295
- criteria .put ("$regex" , re );
296
- if (StringUtils .hasText (options )) {
297
- criteria .put ("$options" , options );
303
+ return regex (toPattern (re , options ));
304
+ }
305
+
306
+ /**
307
+ * Syntactical sugar for {@link #is(Object)} making obvious that we create a regex predicate.
308
+ *
309
+ * @param pattern
310
+ * @return
311
+ */
312
+ public Criteria regex (Pattern pattern ) {
313
+
314
+ Assert .notNull (pattern );
315
+
316
+ if (lastOperatorWasNot ()) {
317
+ return not (pattern );
298
318
}
319
+
320
+ this .isValue = pattern ;
299
321
return this ;
300
322
}
301
323
324
+ private Pattern toPattern (String regex , String options ) {
325
+ Assert .notNull (regex );
326
+ return Pattern .compile (regex , options == null ? 0 : BSON .regexFlags (options ));
327
+ }
328
+
302
329
/**
303
330
* Creates a geospatial criterion using a $within $center operation. This is only available for Mongo 1.7 and higher.
304
331
*
@@ -426,16 +453,17 @@ protected DBObject getSingleCriteriaObject() {
426
453
DBObject dbo = new BasicDBObject ();
427
454
boolean not = false ;
428
455
for (String k : this .criteria .keySet ()) {
456
+ Object value = this .criteria .get (k );
429
457
if (not ) {
430
458
DBObject notDbo = new BasicDBObject ();
431
- notDbo .put (k , this . criteria . get ( k ) );
459
+ notDbo .put (k , value );
432
460
dbo .put ("$not" , notDbo );
433
461
not = false ;
434
462
} else {
435
- if ("$not" .equals (k )) {
463
+ if ("$not" .equals (k ) && value == null ) {
436
464
not = true ;
437
465
} else {
438
- dbo .put (k , this . criteria . get ( k ) );
466
+ dbo .put (k , value );
439
467
}
440
468
}
441
469
}
0 commit comments