[#1089] Add Field.contains(), .startsWith(), .endsWith() as a convenience for Field.like() (including escaping)

This commit is contained in:
Lukas Eder 2012-02-03 15:50:04 +00:00
parent 0a3d532c99
commit bbd02c1813
4 changed files with 164 additions and 7 deletions

View File

@ -8282,13 +8282,36 @@ public abstract class jOOQAbstractTest<
assertEquals(1, books.size());
assertEquals(5, (int) books.get(0).getValue(TBook_ID()));
// DERBY doesn't know any REPLACE function, hence only test those
// conditions that do not use REPLACE internally
boolean derby = getDialect() == DERBY;
// [#1106] Add checks for Factory.escape() function
books =
create().selectFrom(TBook())
.where(TBook_TITLE().like(concat(val("%"), escape("(%)", '!'), val("%")), '!'))
.and(TBook_TITLE().like(concat(val("%"), escape(val("(_)"), '#'), val("%")), '#'))
.and(TBook_TITLE().notLike(concat(val("%"), escape("(!%)", '#'), val("%")), '#'))
.and(TBook_TITLE().notLike(concat(val("%"), escape(val("(#_)"), '!'), val("%")), '!'))
.where(TBook_TITLE().like(concat("%", escape("(%)", '!'), "%"), '!'))
.and(derby ? trueCondition() :
TBook_TITLE().like(concat(val("%"), escape(val("(_)"), '#'), val("%")), '#'))
.and(TBook_TITLE().notLike(concat("%", escape("(!%)", '#'), "%"), '#'))
.and(derby ? trueCondition() :
TBook_TITLE().notLike(concat(val("%"), escape(val("(#_)"), '!'), val("%")), '!'))
.fetch();
assertEquals(1, books.size());
assertEquals(5, (int) books.get(0).getValue(TBook_ID()));
// [#1089] Add checks for convenience methods
books =
create().selectFrom(TBook())
.where(TBook_TITLE().contains("%"))
.and(derby ? trueCondition() :
TBook_TITLE().contains(val("(_")))
.and(TBook_TITLE().startsWith("About"))
.and(derby ? trueCondition() :
TBook_TITLE().startsWith(val("Abo")))
.and(TBook_TITLE().endsWith("review"))
.and(derby ? trueCondition() :
TBook_TITLE().endsWith(val("review")))
.fetch();
assertEquals(1, books.size());

View File

@ -475,6 +475,78 @@ public interface Field<T> extends NamedTypeProviderQueryPart<T>, AliasProvider<F
@Support
Condition notLike(T value, char escape);
/**
* Convenience method for {@link #like(Object, char)} including proper
* adding of wildcards and escaping
* <p>
* SQL: <code>this like ('%' || escape(value, '\') || '%') escape '\'</code>
*
* @see Factory#escape(String, char)
* @see #like(Object, char)
*/
@Support
Condition contains(T value);
/**
* Convenience method for {@link #like(Object, char)} including proper
* adding of wildcards and escaping
* <p>
* SQL: <code>this like ('%' || escape(value, '\') || '%') escape '\'</code>
*
* @see Factory#escape(Field, char)
* @see #like(Field, char)
*/
@Support({ ASE, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE, SQLITE })
Condition contains(Field<T> value);
/**
* Convenience method for {@link #like(Object, char)} including proper
* adding of wildcards and escaping
* <p>
* SQL: <code>this like (escape(value, '\') || '%') escape '\'</code>
*
* @see Factory#escape(String, char)
* @see #like(Object, char)
*/
@Support
Condition startsWith(T value);
/**
* Convenience method for {@link #like(Object, char)} including proper
* adding of wildcards and escaping
* <p>
* SQL: <code>this like (escape(value, '\') || '%') escape '\'</code>
*
* @see Factory#escape(Field, char)
* @see #like(Field, char)
*/
@Support({ ASE, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE, SQLITE })
Condition startsWith(Field<T> value);
/**
* Convenience method for {@link #like(Object, char)} including proper
* adding of wildcards and escaping
* <p>
* SQL: <code>this like ('%' || escape(value, '\')) escape '\'</code>
*
* @see Factory#escape(String, char)
* @see #like(Object, char)
*/
@Support
Condition endsWith(T value);
/**
* Convenience method for {@link #like(Object, char)} including proper
* adding of wildcards and escaping
* <p>
* SQL: <code>this like ('%' || escape(value, '\')) escape '\'</code>
*
* @see Factory#escape(Field, char)
* @see #like(Field, char)
*/
@Support({ ASE, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE, SQLITE })
Condition endsWith(Field<T> value);
/**
* Create a condition to check this field against several values
* <p>

View File

@ -39,6 +39,7 @@ import static org.jooq.impl.ExpressionOperator.ADD;
import static org.jooq.impl.ExpressionOperator.DIVIDE;
import static org.jooq.impl.ExpressionOperator.MULTIPLY;
import static org.jooq.impl.ExpressionOperator.SUBTRACT;
import static org.jooq.impl.Factory.escape;
import static org.jooq.impl.Factory.falseCondition;
import static org.jooq.impl.Factory.nullSafe;
import static org.jooq.impl.Factory.trueCondition;
@ -378,6 +379,62 @@ abstract class AbstractField<T> extends AbstractNamedTypeProviderQueryPart<T> im
return new CompareCondition<T>(this, nullSafe(value), Comparator.NOT_LIKE, escape);
}
@Override
public final Condition contains(T value) {
Field<String> concat = Factory.concat(
Factory.literal("'%'"),
Factory.val(escape("" + value, '!')),
Factory.literal("'%'"));
return like(concat.cast(this), '!');
}
@Override
public final Condition contains(Field<T> value) {
Field<String> concat = Factory.concat(
Factory.literal("'%'"),
escape(value.cast(String.class), '!'),
Factory.literal("'%'"));
return like(concat.cast(this), '!');
}
@Override
public final Condition startsWith(T value) {
Field<String> concat = Factory.concat(
Factory.val(escape("" + value, '!')),
Factory.literal("'%'"));
return like(concat.cast(this), '!');
}
@Override
public final Condition startsWith(Field<T> value) {
Field<String> concat = Factory.concat(
escape(value.cast(String.class), '!'),
Factory.literal("'%'"));
return like(concat.cast(this), '!');
}
@Override
public final Condition endsWith(T value) {
Field<String> concat = Factory.concat(
Factory.literal("'%'"),
Factory.val(escape("" + value, '!')));
return like(concat.cast(this), '!');
}
@Override
public final Condition endsWith(Field<T> value) {
Field<String> concat = Factory.concat(
Factory.literal("'%'"),
escape(value.cast(String.class), '!'));
return like(concat.cast(this), '!');
}
@Override
public final Condition in(T... values) {
return in(vals(values).toArray(new Field<?>[0]));

View File

@ -1920,8 +1920,8 @@ public class Factory implements FactoryOperations {
* @see Field#like(Field, char)
*/
@Support
public static Field<String> escape(String value, char escape) {
return val(value.replace("%", escape + "%").replace("_", escape + "_"));
public static String escape(String value, char escape) {
return value.replace("%", escape + "%").replace("_", escape + "_");
}
/**
@ -1935,7 +1935,12 @@ public class Factory implements FactoryOperations {
*/
@Support({ ASE, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE, SQLITE })
public static Field<String> escape(Field<String> field, char escape) {
return replace(replace(field, "%", escape + "%"), "_", escape + "_");
Field<String> replace = field;
replace = replace(replace, literal("'%'"), literal("'" + escape + "%'"));
replace = replace(replace, literal("'_'"), literal("'" + escape + "_'"));
return replace;
}
/**