@@ -320,7 +320,8 @@ private Condition mapCondition(Criteria criteria, MutableBindings bindings, Tabl
320320 typeHint = actualType .getType ();
321321 }
322322
323- return createCondition (column , mappedValue , typeHint , bindings , criteria .getComparator ());
323+ return createCondition (column , mappedValue , typeHint , bindings , criteria .getComparator (),
324+ criteria .isIgnoreCase ());
324325 }
325326
326327 /**
@@ -370,7 +371,7 @@ protected MappingContext<? extends RelationalPersistentEntity<?>, RelationalPers
370371 }
371372
372373 private Condition createCondition (Column column , @ Nullable Object mappedValue , Class <?> valueType ,
373- MutableBindings bindings , Comparator comparator ) {
374+ MutableBindings bindings , Comparator comparator , boolean ignoreCase ) {
374375
375376 if (comparator .equals (Comparator .IS_NULL )) {
376377 return column .isNull ();
@@ -380,6 +381,19 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, C
380381 return column .isNotNull ();
381382 }
382383
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+
383397 if (comparator == Comparator .NOT_IN || comparator == Comparator .IN ) {
384398
385399 Condition condition ;
@@ -395,14 +409,14 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, C
395409 expressions .add (bind (o , valueType , bindings , bindMarker ));
396410 }
397411
398- condition = column .in (expressions .toArray (new Expression [0 ]));
412+ condition = Conditions .in (columnExpression , expressions .toArray (new Expression [0 ]));
399413
400414 } else {
401415
402416 BindMarker bindMarker = bindings .nextMarker (column .getName ().getReference ());
403417 Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
404418
405- condition = column .in (expression );
419+ condition = Conditions .in (columnExpression , expression );
406420 }
407421
408422 if (comparator == Comparator .NOT_IN ) {
@@ -413,23 +427,40 @@ private Condition createCondition(Column column, @Nullable Object mappedValue, C
413427 }
414428
415429 BindMarker bindMarker = bindings .nextMarker (column .getName ().getReference ());
416- Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
417430
418431 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 );
424442 return column .isLess (expression );
425- case LTE :
443+ }
444+ case LTE : {
445+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
426446 return column .isLessOrEqualTo (expression );
427- case GT :
447+ }
448+ case GT : {
449+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
428450 return column .isGreater (expression );
429- case GTE :
451+ }
452+ case GTE : {
453+ Expression expression = bind (mappedValue , valueType , bindings , bindMarker );
430454 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+ }
433464 default :
434465 throw new UnsupportedOperationException ("Comparator " + comparator + " not supported" );
435466 }
@@ -459,14 +490,20 @@ Class<?> getTypeHint(@Nullable Object mappedValue, Class<?> propertyType, Settab
459490
460491 private Expression bind (@ Nullable Object mappedValue , Class <?> valueType , MutableBindings bindings ,
461492 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 ) {
462498
463499 if (mappedValue != null ) {
464500 bindings .bind (bindMarker , mappedValue );
465501 } else {
466502 bindings .bindNull (bindMarker , valueType );
467503 }
468504
469- return SQL .bindMarker (bindMarker .getPlaceholder ());
505+ return ignoreCase ? new Upper (SQL .bindMarker (bindMarker .getPlaceholder ()))
506+ : SQL .bindMarker (bindMarker .getPlaceholder ());
470507 }
471508
472509 /**
@@ -665,4 +702,89 @@ public String toString() {
665702 return toSql (IdentifierProcessing .ANSI );
666703 }
667704 }
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+ }
668790}
0 commit comments