@@ -320,7 +320,8 @@ private Condition mapCondition(Criteria criteria, MutableBindings bindings, Tabl
320
320
typeHint = actualType .getType ();
321
321
}
322
322
323
- return createCondition (column , mappedValue , typeHint , bindings , criteria .getComparator ());
323
+ return createCondition (column , mappedValue , typeHint , bindings , criteria .getComparator (),
324
+ criteria .isIgnoreCase ());
324
325
}
325
326
326
327
/**
@@ -370,7 +371,7 @@ protected MappingContext<? extends RelationalPersistentEntity<?>, RelationalPers
370
371
}
371
372
372
373
private Condition createCondition (Column column , @ Nullable Object mappedValue , Class <?> valueType ,
373
- MutableBindings bindings , Comparator comparator ) {
374
+ MutableBindings bindings , Comparator comparator , boolean ignoreCase ) {
374
375
375
376
if (comparator .equals (Comparator .IS_NULL )) {
376
377
return column .isNull ();
@@ -380,6 +381,19 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, C
380
381
return column .isNotNull ();
381
382
}
382
383
384
+ if (comparator == Comparator .IS_TRUE ) {
385
+ return column .isEqualTo (SQL .literalOf ((Object ) ("TRUE" )));
386
+ }
387
+
388
+ if (comparator == Comparator .IS_FALSE ) {
389
+ return column .isEqualTo (SQL .literalOf ((Object ) ("FALSE" )));
390
+ }
391
+
392
+ Expression columnExpression = column ;
393
+ if (ignoreCase && String .class == valueType ) {
394
+ columnExpression = new Upper (column );
395
+ }
396
+
383
397
if (comparator == Comparator .NOT_IN || comparator == Comparator .IN ) {
384
398
385
399
Condition condition ;
@@ -395,14 +409,14 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, C
395
409
expressions .add (bind (o , valueType , bindings , bindMarker ));
396
410
}
397
411
398
- condition = column .in (expressions .toArray (new Expression [0 ]));
412
+ condition = Conditions .in (columnExpression , expressions .toArray (new Expression [0 ]));
399
413
400
414
} else {
401
415
402
416
BindMarker bindMarker = bindings .nextMarker (column .getName ().getReference ());
403
417
Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
404
418
405
- condition = column .in (expression );
419
+ condition = Conditions .in (columnExpression , expression );
406
420
}
407
421
408
422
if (comparator == Comparator .NOT_IN ) {
@@ -413,23 +427,40 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, C
413
427
}
414
428
415
429
BindMarker bindMarker = bindings .nextMarker (column .getName ().getReference ());
416
- Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
417
430
418
431
switch (comparator ) {
419
- case EQ :
420
- return column .isEqualTo (expression );
421
- case NEQ :
422
- return column .isNotEqualTo (expression );
423
- case LT :
432
+ case EQ : {
433
+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker , ignoreCase );
434
+ return Conditions .isEqual (columnExpression , expression );
435
+ }
436
+ case NEQ : {
437
+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker , ignoreCase );
438
+ return Conditions .isEqual (columnExpression , expression ).not ();
439
+ }
440
+ case LT : {
441
+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
424
442
return column .isLess (expression );
425
- case LTE :
443
+ }
444
+ case LTE : {
445
+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
426
446
return column .isLessOrEqualTo (expression );
427
- case GT :
447
+ }
448
+ case GT : {
449
+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
428
450
return column .isGreater (expression );
429
- case GTE :
451
+ }
452
+ case GTE : {
453
+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
430
454
return column .isGreaterOrEqualTo (expression );
431
- case LIKE :
432
- return column .like (expression );
455
+ }
456
+ case LIKE : {
457
+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker , ignoreCase );
458
+ return Conditions .like (columnExpression , expression );
459
+ }
460
+ case NOT_LIKE : {
461
+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker , ignoreCase );
462
+ return NotLike .create (columnExpression , expression );
463
+ }
433
464
default :
434
465
throw new UnsupportedOperationException ("Comparator " + comparator + " not supported" );
435
466
}
@@ -459,14 +490,20 @@ Class<?> getTypeHint(@Nullable Object mappedValue, Class<?> propertyType, Settab
459
490
460
491
private Expression bind (@ Nullable Object mappedValue , Class <?> valueType , MutableBindings bindings ,
461
492
BindMarker bindMarker ) {
493
+ return bind (mappedValue , valueType , bindings , bindMarker , false );
494
+ }
495
+
496
+ private Expression bind (@ Nullable Object mappedValue , Class <?> valueType , MutableBindings bindings ,
497
+ BindMarker bindMarker , boolean ignoreCase ) {
462
498
463
499
if (mappedValue != null ) {
464
500
bindings .bind (bindMarker , mappedValue );
465
501
} else {
466
502
bindings .bindNull (bindMarker , valueType );
467
503
}
468
504
469
- return SQL .bindMarker (bindMarker .getPlaceholder ());
505
+ return ignoreCase ? new Upper (SQL .bindMarker (bindMarker .getPlaceholder ()))
506
+ : SQL .bindMarker (bindMarker .getPlaceholder ());
470
507
}
471
508
472
509
/**
@@ -665,4 +702,89 @@ public String toString() {
665
702
return toSql (IdentifierProcessing .ANSI );
666
703
}
667
704
}
705
+
706
+ // TODO: include support of NOT LIKE operator into spring-data-relational
707
+ /**
708
+ * Negated LIKE {@link Condition} comparing two {@link Expression}s.
709
+ * <p/>
710
+ * Results in a rendered condition: {@code <left> NOT LIKE <right>}.
711
+ */
712
+ private static class NotLike implements Segment , Condition {
713
+ private final Comparison delegate ;
714
+
715
+ private NotLike (Expression leftColumnOrExpression , Expression rightColumnOrExpression ) {
716
+ this .delegate = Comparison .create (leftColumnOrExpression , "NOT LIKE" , rightColumnOrExpression );
717
+ }
718
+
719
+ /**
720
+ * Creates new instance of this class with the given {@link Expression}s.
721
+ *
722
+ * @param leftColumnOrExpression the left {@link Expression}
723
+ * @param rightColumnOrExpression the right {@link Expression}
724
+ * @return {@link NotLike} condition
725
+ */
726
+ public static NotLike create (Expression leftColumnOrExpression , Expression rightColumnOrExpression ) {
727
+ Assert .notNull (leftColumnOrExpression , "Left expression must not be null!" );
728
+ Assert .notNull (rightColumnOrExpression , "Right expression must not be null!" );
729
+ return new NotLike (leftColumnOrExpression , rightColumnOrExpression );
730
+ }
731
+
732
+ @ Override
733
+ public void visit (Visitor visitor ) {
734
+ Assert .notNull (visitor , "Visitor must not be null!" );
735
+ delegate .visit (visitor );
736
+ }
737
+
738
+ @ Override
739
+ public String toString () {
740
+ return delegate .toString ();
741
+ }
742
+ }
743
+
744
+ // TODO: include support of functions in WHERE conditions into spring-data-relational
745
+ /**
746
+ * Models the ANSI SQL {@code UPPER} function.
747
+ * <p>
748
+ * Results in a rendered function: {@code UPPER(<expression>)}.
749
+ */
750
+ private class Upper implements Expression {
751
+ private Literal <Object > delegate ;
752
+
753
+ /**
754
+ * Creates new instance of this class with the given expression. Only expressions of type {@link Column} and
755
+ * {@link org.springframework.data.relational.core.sql.BindMarker} are supported.
756
+ *
757
+ * @param expression expression to be uppercased (must not be {@literal null})
758
+ */
759
+ private Upper (Expression expression ) {
760
+ Assert .notNull (expression , "Expression must not be null!" );
761
+ String functionArgument ;
762
+ if (expression instanceof org .springframework .data .relational .core .sql .BindMarker ) {
763
+ functionArgument = expression instanceof Named ? ((Named ) expression ).getName ().getReference ()
764
+ : expression .toString ();
765
+ } else if (expression instanceof Column ) {
766
+ functionArgument = "" ;
767
+ Table table = ((Column ) expression ).getTable ();
768
+ if (table != null ) {
769
+ functionArgument = toSql (table .getName ()) + "." ;
770
+ }
771
+ functionArgument += toSql (((Column ) expression ).getName ());
772
+ } else {
773
+ throw new IllegalArgumentException ("Unable to ignore case expression of type " + expression .getClass ().getName ()
774
+ + ". Only " + Column .class .getName () + " and "
775
+ + org .springframework .data .relational .core .sql .BindMarker .class .getName () + " types are supported" );
776
+ }
777
+ this .delegate = SQL .literalOf ((Object ) ("UPPER(" + functionArgument + ")" ));
778
+ }
779
+
780
+ @ Override
781
+ public void visit (Visitor visitor ) {
782
+ delegate .visit (visitor );
783
+ }
784
+
785
+ @ Override
786
+ public String toString () {
787
+ return delegate .toString ();
788
+ }
789
+ }
668
790
}
0 commit comments