@@ -119,6 +119,13 @@ static <T, U extends Comparable<U>> Restriction<T> lessThanOrEqual(SingularAttri
119119 return restrict ( attribute , Range .lessThanOrEqualTo ( upperBound ) );
120120 }
121121
122+ static <T > Restriction <T > like (
123+ SingularAttribute <T , String > attribute ,
124+ String pattern , boolean caseSensitive ,
125+ char charWildcard , char stringWildcard ) {
126+ return like ( attribute , escape ( pattern , charWildcard , stringWildcard ), caseSensitive );
127+ }
128+
122129 static <T > Restriction <T > like (SingularAttribute <T , String > attribute , String pattern , boolean caseSensitive ) {
123130 return restrict ( attribute , Range .pattern ( pattern , caseSensitive ) );
124131 }
@@ -135,6 +142,22 @@ static <T> Restriction<T> notLike(SingularAttribute<T, String> attribute, String
135142 return like ( attribute , pattern , caseSensitive ).negated ();
136143 }
137144
145+ static <T > Restriction <T > startsWith (SingularAttribute <T , String > attribute , String prefix ) {
146+ return like ( attribute , escape ( prefix ) + '%' );
147+ }
148+
149+ static <T > Restriction <T > endWith (SingularAttribute <T , String > attribute , String suffix ) {
150+ return like ( attribute , '%' + escape ( suffix ) );
151+ }
152+
153+ static <T > Restriction <T > contains (SingularAttribute <T , String > attribute , String substring ) {
154+ return like ( attribute , '%' + escape ( substring ) + '%' );
155+ }
156+
157+ static <T > Restriction <T > notContains (SingularAttribute <T , String > attribute , String substring ) {
158+ return contains ( attribute , substring ).negated ();
159+ }
160+
138161 @ SafeVarargs
139162 static <T > Restriction <T > and (Restriction <T >... restrictions ) {
140163 return new Conjunction <>( java .util .List .of ( restrictions ) );
@@ -148,4 +171,36 @@ static <T> Restriction<T> or(Restriction<T>... restrictions) {
148171 static <T > Restriction <T > unrestricted () {
149172 return new Unrestricted <>();
150173 }
174+
175+ private static String escape (String literal , char charWildcard , char stringWildcard ) {
176+ final var result = new StringBuilder ();
177+ for ( int i = 0 ; i < literal .length (); i ++ ) {
178+ final char ch = literal .charAt ( i );
179+ if ( ch == charWildcard ) {
180+ result .append ( '_' );
181+ }
182+ else if ( ch == stringWildcard ) {
183+ result .append ( '%' );
184+ }
185+ else {
186+ if ( ch =='%' || ch =='_' || ch =='\\' ) {
187+ result .append ('\\' );
188+ }
189+ result .append ( ch );
190+ }
191+ }
192+ return result .toString ();
193+ }
194+
195+ private static String escape (String literal ) {
196+ final var result = new StringBuilder ();
197+ for ( int i = 0 ; i < literal .length (); i ++ ) {
198+ final char ch = literal .charAt ( i );
199+ if ( ch =='%' || ch =='_' || ch =='\\' ) {
200+ result .append ('\\' );
201+ }
202+ result .append ( ch );
203+ }
204+ return result .toString ();
205+ }
151206}
0 commit comments