25
25
import java .util .StringJoiner ;
26
26
27
27
import org .springframework .dao .InvalidDataAccessApiUsageException ;
28
+ import org .springframework .data .relational .core .dialect .condition .DialectCriteriaCondition ;
28
29
import org .springframework .data .relational .core .sql .IdentifierProcessing ;
29
30
import org .springframework .data .relational .core .sql .SqlIdentifier ;
30
31
import org .springframework .data .util .Pair ;
53
54
* @author Oliver Drotbohm
54
55
* @author Roman Chigvintsev
55
56
* @author Jens Schauder
57
+ * @author Mikhail Polivakha
56
58
* @since 2.0
57
59
*/
58
60
public class Criteria implements CriteriaDefinition {
59
61
60
- static final Criteria EMPTY = new Criteria (SqlIdentifier .EMPTY , Comparator .INITIAL , null );
62
+ static final Criteria EMPTY = new Criteria (SqlIdentifier .EMPTY , Comparator .INITIAL , null , null );
61
63
62
64
private final @ Nullable Criteria previous ;
63
65
private final Combinator combinator ;
@@ -68,17 +70,25 @@ public class Criteria implements CriteriaDefinition {
68
70
private final @ Nullable Object value ;
69
71
private final boolean ignoreCase ;
70
72
71
- private Criteria (SqlIdentifier column , Comparator comparator , @ Nullable Object value ) {
72
- this (null , Combinator .INITIAL , Collections .emptyList (), column , comparator , value , false );
73
+ private final DialectCriteriaCondition dialectCriteriaCondition ;
74
+
75
+ private Criteria (SqlIdentifier column , @ Nullable Comparator comparator , @ Nullable Object value , DialectCriteriaCondition dialectCriteriaCondition ) {
76
+ this (null , Combinator .INITIAL , Collections .emptyList (), column , comparator , value , false , dialectCriteriaCondition );
73
77
}
74
78
75
79
private Criteria (@ Nullable Criteria previous , Combinator combinator , List <CriteriaDefinition > group ,
76
- @ Nullable SqlIdentifier column , @ Nullable Comparator comparator , @ Nullable Object value ) {
77
- this (previous , combinator , group , column , comparator , value , false );
80
+ @ Nullable SqlIdentifier column , @ Nullable Comparator comparator , @ Nullable Object value , DialectCriteriaCondition dialectCriteriaCondition ) {
81
+ this (previous , combinator , group , column , comparator , value , false , dialectCriteriaCondition );
78
82
}
79
83
80
84
private Criteria (@ Nullable Criteria previous , Combinator combinator , List <CriteriaDefinition > group ,
81
- @ Nullable SqlIdentifier column , @ Nullable Comparator comparator , @ Nullable Object value , boolean ignoreCase ) {
85
+ @ Nullable SqlIdentifier column , @ Nullable Comparator comparator , @ Nullable Object value , boolean ignoreCase ,
86
+ @ Nullable DialectCriteriaCondition dialectCriteriaCondition ) {
87
+
88
+ Assert .state (
89
+ (dialectCriteriaCondition != null && comparator == null ) || (dialectCriteriaCondition == null && comparator != null ),
90
+ "Either DialectCriteriaCondition or Comparator should be specified for this criteria, but not both"
91
+ );
82
92
83
93
this .previous = previous ;
84
94
this .combinator = previous != null && previous .isEmpty () ? Combinator .INITIAL : combinator ;
@@ -87,6 +97,7 @@ private Criteria(@Nullable Criteria previous, Combinator combinator, List<Criter
87
97
this .comparator = comparator ;
88
98
this .value = value ;
89
99
this .ignoreCase = ignoreCase ;
100
+ this .dialectCriteriaCondition = dialectCriteriaCondition ;
90
101
}
91
102
92
103
private Criteria (@ Nullable Criteria previous , Combinator combinator , List <CriteriaDefinition > group ) {
@@ -98,6 +109,7 @@ private Criteria(@Nullable Criteria previous, Combinator combinator, List<Criter
98
109
this .comparator = null ;
99
110
this .value = null ;
100
111
this .ignoreCase = false ;
112
+ this .dialectCriteriaCondition = null ;
101
113
}
102
114
103
115
/**
@@ -169,8 +181,8 @@ public CriteriaStep and(String column) {
169
181
SqlIdentifier identifier = SqlIdentifier .unquoted (column );
170
182
return new DefaultCriteriaStep (identifier ) {
171
183
@ Override
172
- protected Criteria createCriteria (Comparator comparator , @ Nullable Object value ) {
173
- return new Criteria (Criteria .this , Combinator .AND , Collections .emptyList (), identifier , comparator , value );
184
+ protected Criteria createCriteria (Comparator comparator , @ Nullable Object value , DialectCriteriaCondition dialectCriteriaCondition ) {
185
+ return new Criteria (Criteria .this , Combinator .AND , Collections .emptyList (), identifier , comparator , value , dialectCriteriaCondition );
174
186
}
175
187
};
176
188
}
@@ -216,8 +228,8 @@ public CriteriaStep or(String column) {
216
228
SqlIdentifier identifier = SqlIdentifier .unquoted (column );
217
229
return new DefaultCriteriaStep (identifier ) {
218
230
@ Override
219
- protected Criteria createCriteria (Comparator comparator , @ Nullable Object value ) {
220
- return new Criteria (Criteria .this , Combinator .OR , Collections .emptyList (), identifier , comparator , value );
231
+ protected Criteria createCriteria (Comparator comparator , @ Nullable Object value , DialectCriteriaCondition dialectCriteriaCondition ) {
232
+ return new Criteria (Criteria .this , Combinator .OR , Collections .emptyList (), identifier , comparator , value , dialectCriteriaCondition );
221
233
}
222
234
};
223
235
}
@@ -259,7 +271,7 @@ public Criteria or(List<? extends CriteriaDefinition> criteria) {
259
271
*/
260
272
public Criteria ignoreCase (boolean ignoreCase ) {
261
273
if (this .ignoreCase != ignoreCase ) {
262
- return new Criteria (previous , combinator , group , column , comparator , value , ignoreCase );
274
+ return new Criteria (previous , combinator , group , column , comparator , value , ignoreCase , dialectCriteriaCondition );
263
275
}
264
276
return this ;
265
277
}
@@ -328,18 +340,25 @@ private boolean doIsEmpty() {
328
340
/**
329
341
* @return {@literal true} if this {@link Criteria} is empty.
330
342
*/
343
+ @ Override
331
344
public boolean isGroup () {
332
345
return !this .group .isEmpty ();
333
346
}
334
347
335
348
/**
336
349
* @return {@link Combinator} to combine this criteria with a previous one.
337
350
*/
351
+ @ Override
338
352
public Combinator getCombinator () {
339
353
return combinator ;
340
354
}
341
355
342
- @ Override
356
+ @ Override
357
+ public DialectCriteriaCondition getDialectCriteriaCondition () {
358
+ return dialectCriteriaCondition ;
359
+ }
360
+
361
+ @ Override
343
362
public List <CriteriaDefinition > getGroup () {
344
363
return group ;
345
364
}
@@ -476,8 +495,16 @@ private void render(CriteriaDefinition criteria, StringBuilder stringBuilder) {
476
495
return ;
477
496
}
478
497
479
- stringBuilder .append (criteria .getColumn ().toSql (IdentifierProcessing .NONE )).append (' ' )
480
- .append (criteria .getComparator ().getComparator ());
498
+ stringBuilder .append (criteria .getColumn ().toSql (IdentifierProcessing .NONE )).append (' ' );
499
+
500
+ DialectCriteriaCondition dialectCriteriaCondition = criteria .getDialectCriteriaCondition ();
501
+
502
+ if (dialectCriteriaCondition != null ) {
503
+ stringBuilder .append (dialectCriteriaCondition .render ());
504
+ return ;
505
+ }
506
+
507
+ stringBuilder .append (criteria .getComparator ().getComparator ());
481
508
482
509
switch (criteria .getComparator ()) {
483
510
case BETWEEN :
@@ -653,6 +680,39 @@ public interface CriteriaStep {
653
680
* @return a new {@link Criteria} object
654
681
*/
655
682
Criteria isFalse ();
683
+
684
+ /**
685
+ * Creates a {@link Criteria} using custom {@link DialectCriteriaCondition}. This API primarily exists
686
+ * to handle conditions in WHERE clause that are specific to particular RDBMS vendor.
687
+ * <p>
688
+ * There are some predefined vendor-specific conditions in the {@link org.springframework.data.relational.core.dialect.condition}
689
+ * package. For instance, an example of usage is:
690
+ * <p>
691
+ * <pre class="code">
692
+ * Criteria criteria = Criteria
693
+ * .where("tags")
694
+ * .satisfies(Postgres.arrayContains("computers", "electronics"))
695
+ * </pre>
696
+ *
697
+ * This will yield the following SQL:
698
+ * <p>
699
+ * <pre class="code">
700
+ * tags @> ARRAY['computers','electronics']::text[]
701
+ * </pre>
702
+ *
703
+ * In the sample above, the assumption is that the 'tags' column is of an 'ARRAY TEXT' or 'ARRAY VARCHAR' PostgreSQL type.
704
+ * <p>
705
+ * If there is no appropriate {@link DialectCriteriaCondition} built-in, please, consider to file an issue, and in the meantime,
706
+ * consider to write your own {@link DialectCriteriaCondition}, like this (case insensitive regexp-match in PostgreSQL):
707
+ * <p>
708
+ * <pre class="code">
709
+ *
710
+ * </pre>
711
+ *
712
+ * @see org.springframework.data.relational.core.dialect.condition.Postgres
713
+ * @return a new {@link Criteria} object
714
+ */
715
+ Criteria satisfies (DialectCriteriaCondition condition );
656
716
}
657
717
658
718
/**
@@ -671,15 +731,15 @@ public Criteria is(Object value) {
671
731
672
732
Assert .notNull (value , "Value must not be null" );
673
733
674
- return createCriteria (Comparator .EQ , value );
734
+ return createCriteria (Comparator .EQ , value , null );
675
735
}
676
736
677
737
@ Override
678
738
public Criteria not (Object value ) {
679
739
680
740
Assert .notNull (value , "Value must not be null" );
681
741
682
- return createCriteria (Comparator .NEQ , value );
742
+ return createCriteria (Comparator .NEQ , value , null );
683
743
}
684
744
685
745
@ Override
@@ -693,7 +753,7 @@ public Criteria in(Object... values) {
693
753
"You can only pass in one argument of type " + values [1 ].getClass ().getName ());
694
754
}
695
755
696
- return createCriteria (Comparator .IN , Arrays .asList (values ));
756
+ return createCriteria (Comparator .IN , Arrays .asList (values ), null );
697
757
}
698
758
699
759
@ Override
@@ -702,7 +762,7 @@ public Criteria in(Collection<?> values) {
702
762
Assert .notNull (values , "Values must not be null" );
703
763
Assert .noNullElements (values .toArray (), "Values must not contain a null value" );
704
764
705
- return createCriteria (Comparator .IN , values );
765
+ return createCriteria (Comparator .IN , values , null );
706
766
}
707
767
708
768
@ Override
@@ -716,7 +776,7 @@ public Criteria notIn(Object... values) {
716
776
"You can only pass in one argument of type " + values [1 ].getClass ().getName ());
717
777
}
718
778
719
- return createCriteria (Comparator .NOT_IN , Arrays .asList (values ));
779
+ return createCriteria (Comparator .NOT_IN , Arrays .asList (values ), null );
720
780
}
721
781
722
782
@ Override
@@ -725,7 +785,7 @@ public Criteria notIn(Collection<?> values) {
725
785
Assert .notNull (values , "Values must not be null" );
726
786
Assert .noNullElements (values .toArray (), "Values must not contain a null value" );
727
787
728
- return createCriteria (Comparator .NOT_IN , values );
788
+ return createCriteria (Comparator .NOT_IN , values , null );
729
789
}
730
790
731
791
@ Override
@@ -734,7 +794,7 @@ public Criteria between(Object begin, Object end) {
734
794
Assert .notNull (begin , "Begin value must not be null" );
735
795
Assert .notNull (end , "End value must not be null" );
736
796
737
- return createCriteria (Comparator .BETWEEN , Pair .of (begin , end ));
797
+ return createCriteria (Comparator .BETWEEN , Pair .of (begin , end ), null );
738
798
}
739
799
740
800
@ Override
@@ -743,77 +803,82 @@ public Criteria notBetween(Object begin, Object end) {
743
803
Assert .notNull (begin , "Begin value must not be null" );
744
804
Assert .notNull (end , "End value must not be null" );
745
805
746
- return createCriteria (Comparator .NOT_BETWEEN , Pair .of (begin , end ));
806
+ return createCriteria (Comparator .NOT_BETWEEN , Pair .of (begin , end ), null );
747
807
}
748
808
749
809
@ Override
750
810
public Criteria lessThan (Object value ) {
751
811
752
812
Assert .notNull (value , "Value must not be null" );
753
813
754
- return createCriteria (Comparator .LT , value );
814
+ return createCriteria (Comparator .LT , value , null );
755
815
}
756
816
757
817
@ Override
758
818
public Criteria lessThanOrEquals (Object value ) {
759
819
760
820
Assert .notNull (value , "Value must not be null" );
761
821
762
- return createCriteria (Comparator .LTE , value );
822
+ return createCriteria (Comparator .LTE , value , null );
763
823
}
764
824
765
825
@ Override
766
826
public Criteria greaterThan (Object value ) {
767
827
768
828
Assert .notNull (value , "Value must not be null" );
769
829
770
- return createCriteria (Comparator .GT , value );
830
+ return createCriteria (Comparator .GT , value , null );
771
831
}
772
832
773
833
@ Override
774
834
public Criteria greaterThanOrEquals (Object value ) {
775
835
776
836
Assert .notNull (value , "Value must not be null" );
777
837
778
- return createCriteria (Comparator .GTE , value );
838
+ return createCriteria (Comparator .GTE , value , null );
779
839
}
780
840
781
841
@ Override
782
842
public Criteria like (Object value ) {
783
843
784
844
Assert .notNull (value , "Value must not be null" );
785
845
786
- return createCriteria (Comparator .LIKE , value );
846
+ return createCriteria (Comparator .LIKE , value , null );
787
847
}
788
848
789
849
@ Override
790
850
public Criteria notLike (Object value ) {
791
851
Assert .notNull (value , "Value must not be null" );
792
- return createCriteria (Comparator .NOT_LIKE , value );
852
+ return createCriteria (Comparator .NOT_LIKE , value , null );
793
853
}
794
854
795
855
@ Override
796
856
public Criteria isNull () {
797
- return createCriteria (Comparator .IS_NULL , null );
857
+ return createCriteria (Comparator .IS_NULL , null , null );
798
858
}
799
859
800
860
@ Override
801
861
public Criteria isNotNull () {
802
- return createCriteria (Comparator .IS_NOT_NULL , null );
862
+ return createCriteria (Comparator .IS_NOT_NULL , null , null );
803
863
}
804
864
805
865
@ Override
806
866
public Criteria isTrue () {
807
- return createCriteria (Comparator .IS_TRUE , true );
867
+ return createCriteria (Comparator .IS_TRUE , true , null );
808
868
}
809
869
810
870
@ Override
811
871
public Criteria isFalse () {
812
- return createCriteria (Comparator .IS_FALSE , false );
872
+ return createCriteria (Comparator .IS_FALSE , false , null );
813
873
}
814
874
815
- protected Criteria createCriteria (Comparator comparator , @ Nullable Object value ) {
816
- return new Criteria (this .property , comparator , value );
875
+ @ Override
876
+ public Criteria satisfies (DialectCriteriaCondition condition ) {
877
+ return createCriteria (null , null , condition );
878
+ }
879
+
880
+ protected Criteria createCriteria (@ Nullable Comparator comparator , @ Nullable Object value , DialectCriteriaCondition dialectCriteriaCondition ) {
881
+ return new Criteria (this .property , comparator , value , dialectCriteriaCondition );
817
882
}
818
883
}
819
884
}
0 commit comments