[jOOQ/jOOQ#12425] Move CONTAINS and related operators to API generator

This commit is contained in:
Lukas Eder 2021-09-22 14:27:59 +02:00
parent 8446afcaff
commit 6f0da04d3b
9 changed files with 937 additions and 410 deletions

View File

@ -1285,6 +1285,228 @@ extends
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Field<T> shr(Field<? extends Number> count);
// -------------------------------------------------------------------------
// String functions
// -------------------------------------------------------------------------
/**
* The <code>CONTAINS</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like ('%' || escape(value, '\') || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).contains(13)</code>
* <p>
* If you're using {@link SQLDialect#POSTGRES}, then you can use this method
* also to express the "ARRAY contains" operator. For example: <code><pre>
* // Use this expression
* val(new Integer[] { 1, 2, 3 }).contains(new Integer[] { 1, 2 })
*
* // ... to render this SQL
* ARRAY[1, 2, 3] @&gt; ARRAY[1, 2]
* </pre></code>
* <p>
* Note, this does not correspond to the Oracle Text <code>CONTAINS()</code>
* function. Refer to {@link OracleDSL#contains(Field, String)} instead.
*
* @param content is wrapped as {@link #val(Object)}.
*/
@NotNull
@Support
Condition contains(T content);
/**
* The <code>CONTAINS</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like ('%' || escape(value, '\') || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).contains(13)</code>
* <p>
* If you're using {@link SQLDialect#POSTGRES}, then you can use this method
* also to express the "ARRAY contains" operator. For example: <code><pre>
* // Use this expression
* val(new Integer[] { 1, 2, 3 }).contains(new Integer[] { 1, 2 })
*
* // ... to render this SQL
* ARRAY[1, 2, 3] @&gt; ARRAY[1, 2]
* </pre></code>
* <p>
* Note, this does not correspond to the Oracle Text <code>CONTAINS()</code>
* function. Refer to {@link OracleDSL#contains(Field, String)} instead.
*/
@NotNull
@Support
Condition contains(Field<T> content);
/**
* The <code>CONTAINS_IGNORE_CASE</code> operator.
* <p>
* Convenience method for {@link #likeIgnoreCase(String, char)} including
* proper adding of wildcards and escaping.
* <p>
* This translates to
* <code>this ilike ('%' || escape(value, '\') || '%') escape '\'</code> in
* {@link SQLDialect#POSTGRES}, or to
* <code>lower(this) not like lower(('%' || escape(value, '\') || '%') escape '\')</code>
* in all other dialects.
*
* @param content is wrapped as {@link #val(Object)}.
*/
@NotNull
@Support
Condition containsIgnoreCase(T content);
/**
* The <code>CONTAINS_IGNORE_CASE</code> operator.
* <p>
* Convenience method for {@link #likeIgnoreCase(String, char)} including
* proper adding of wildcards and escaping.
* <p>
* This translates to
* <code>this ilike ('%' || escape(value, '\') || '%') escape '\'</code> in
* {@link SQLDialect#POSTGRES}, or to
* <code>lower(this) not like lower(('%' || escape(value, '\') || '%') escape '\')</code>
* in all other dialects.
*/
@NotNull
@Support
Condition containsIgnoreCase(Field<T> content);
/**
* The <code>ENDS_WITH</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like ('%' || escape(value, '\')) escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).endsWith(33)</code>
*
* @param suffix is wrapped as {@link #val(Object)}.
*/
@NotNull
@Support
Condition endsWith(T suffix);
/**
* The <code>ENDS_WITH</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like ('%' || escape(value, '\')) escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).endsWith(33)</code>
*/
@NotNull
@Support
Condition endsWith(Field<T> suffix);
/**
* The <code>ENDS_WITH_IGNORE_CASE</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>lower(this) like ('%' || lower(escape(value, '\'))) escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).endsWithIgnoreCase(33)</code>
*
* @param suffix is wrapped as {@link #val(Object)}.
*/
@NotNull
@Support
Condition endsWithIgnoreCase(T suffix);
/**
* The <code>ENDS_WITH_IGNORE_CASE</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>lower(this) like ('%' || lower(escape(value, '\'))) escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).endsWithIgnoreCase(33)</code>
*/
@NotNull
@Support
Condition endsWithIgnoreCase(Field<T> suffix);
/**
* The <code>STARTS_WITH</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like (escape(value, '\') || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).startsWith(11)</code>
*
* @param prefix is wrapped as {@link #val(Object)}.
*/
@NotNull
@Support
Condition startsWith(T prefix);
/**
* The <code>STARTS_WITH</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like (escape(value, '\') || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).startsWith(11)</code>
*/
@NotNull
@Support
Condition startsWith(Field<T> prefix);
/**
* The <code>STARTS_WITH_IGNORE_CASE</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>lower(this) like (lower(escape(value, '\')) || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).startsWithIgnoreCase(11)</code>
*
* @param prefix is wrapped as {@link #val(Object)}.
*/
@NotNull
@Support
Condition startsWithIgnoreCase(T prefix);
/**
* The <code>STARTS_WITH_IGNORE_CASE</code> operator.
* <p>
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>lower(this) like (lower(escape(value, '\')) || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).startsWithIgnoreCase(11)</code>
*/
@NotNull
@Support
Condition startsWithIgnoreCase(Field<T> prefix);
@ -2081,62 +2303,6 @@ extends
@Support
Condition notLikeIgnoreCase(String value, char escape);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like ('%' || escape(value, '\') || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).contains(13)</code>
* <p>
* If you're using {@link SQLDialect#POSTGRES}, then you can use this method
* also to express the "ARRAY contains" operator. For example: <code><pre>
* // Use this expression
* val(new Integer[] { 1, 2, 3 }).contains(new Integer[] { 1, 2 })
*
* // ... to render this SQL
* ARRAY[1, 2, 3] @&gt; ARRAY[1, 2]
* </pre></code>
* <p>
* Note, this does not correspond to the Oracle Text <code>CONTAINS()</code>
* function. Refer to {@link OracleDSL#contains(Field, String)} instead.
*
* @see DSL#escape(String, char)
* @see #like(String, char)
*/
@NotNull
@Support
Condition contains(T value);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like ('%' || escape(value, '\') || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).contains(13)</code>
* <p>
* If you're using {@link SQLDialect#POSTGRES}, then you can use this method
* also to express the "ARRAY contains" operator. For example: <code><pre>
* // Use this expression
* val(new Integer[] { 1, 2, 3 }).contains(new Integer[] { 1, 2 })
*
* // ... to render this SQL
* ARRAY[1, 2, 3] @&gt; ARRAY[1, 2]
* </pre></code>
* <p>
* Note, this does not correspond to the Oracle Text <code>CONTAINS()</code>
* function. Refer to {@link OracleDSL#contains(Field, String)} instead.
*
* @see DSL#escape(Field, char)
* @see #like(Field, char)
*/
@NotNull
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Condition contains(Field<T> value);
/**
* Inverse of {@link #contains(Object)}.
*/
@ -2151,44 +2317,6 @@ extends
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Condition notContains(Field<T> value);
/**
* Convenience method for {@link #likeIgnoreCase(String, char)} including
* proper adding of wildcards and escaping.
* <p>
* This translates to
* <code>this ilike ('%' || escape(value, '\') || '%') escape '\'</code> in
* {@link SQLDialect#POSTGRES}, or to
* <code>lower(this) not like lower(('%' || escape(value, '\') || '%') escape '\')</code>
* in all other dialects.
* </p>
*
* @see DSL#escape(Field, char)
* @see #likeIgnoreCase(String, char)
* @see #contains(Object)
*/
@NotNull
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Condition containsIgnoreCase(T value);
/**
* Convenience method for {@link #likeIgnoreCase(String, char)} including
* proper adding of wildcards and escaping.
* <p>
* This translates to
* <code>this ilike ('%' || escape(value, '\') || '%') escape '\'</code>
* in {@link SQLDialect#POSTGRES}, or to
* <code>lower(this) like lower(('%' || escape(value, '\') || '%') escape '\')</code>
* in all other dialects.
* </p>
*
* @see DSL#escape(Field, char)
* @see #likeIgnoreCase(Field, char)
* @see #contains(Field)
*/
@NotNull
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Condition containsIgnoreCase(Field<T> value);
/**
* Inverse of {@link #containsIgnoreCase(Object)}
*/
@ -2203,134 +2331,6 @@ extends
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Condition notContainsIgnoreCase(Field<T> value);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like (escape(value, '\') || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).startsWith(11)</code>
*
* @see DSL#escape(String, char)
* @see #like(String, char)
*/
@NotNull
@Support
Condition startsWith(T value);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like (escape(value, '\') || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).startsWith(11)</code>
*
* @see DSL#escape(Field, char)
* @see #like(Field, char)
*/
@NotNull
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Condition startsWith(Field<T> value);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>lower(this) like (lower(escape(value, '\')) || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).startsWithIgnoreCase(11)</code>
*
* @see DSL#escape(String, char)
* @see #like(String, char)
*/
@NotNull
@Support
Condition startsWithIgnoreCase(T value);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>lower(this) like (lower(escape(value, '\')) || '%') escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).startsWithIgnoreCase(11)</code>
*
* @see DSL#escape(Field, char)
* @see #like(Field, char)
*/
@NotNull
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Condition startsWithIgnoreCase(Field<T> value);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like ('%' || escape(value, '\')) escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).endsWith(33)</code>
*
* @see DSL#escape(String, char)
* @see #like(String, char)
*/
@NotNull
@Support
Condition endsWith(T value);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like ('%' || escape(value, '\')) escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).endsWith(33)</code>
*
* @see DSL#escape(Field, char)
* @see #like(Field, char)
*/
@NotNull
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Condition endsWith(Field<T> value);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>lower(this) like ('%' || lower(escape(value, '\'))) escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).endsWithIgnoreCase(33)</code>
*
* @see DSL#escape(String, char)
* @see #like(String, char)
*/
@NotNull
@Support
Condition endsWithIgnoreCase(T value);
/**
* Convenience method for {@link #like(String, char)} including proper
* adding of wildcards and escaping.
* <p>
* SQL: <code>this like ('%' || lower(escape(value, '\'))) escape '\'</code>
* <p>
* Note: This also works with numbers, for instance
* <code>val(1133).endsWithIgnoreCase(33)</code>
*
* @see DSL#escape(Field, char)
* @see #like(Field, char)
*/
@NotNull
@Support({ CUBRID, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE, YUGABYTE })
Condition endsWithIgnoreCase(Field<T> value);
// ------------------------------------------------------------------------
// IN predicates
// ------------------------------------------------------------------------

View File

@ -2445,7 +2445,7 @@ public interface Table<R extends Record> extends TableLike<R>, RecordQualifier<R
* -- ... in other databases
* DELETE FROM x
* WHERE x.rowid IN (
* SELECT x.rowid FROM x ORDER BY x.a LIMIT 1
* SELECT x.rowid FROM x ORDER BY x.a LIMIT 1
* )
* </pre></code>
* <p>

View File

@ -770,6 +770,82 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
return DSL.shr((Field) this, count);
}
// -------------------------------------------------------------------------
// String functions
// -------------------------------------------------------------------------
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition contains(T content) {
return new Contains(this, Tools.field(content, this));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition contains(Field<T> content) {
return new Contains(this, nullSafe(content, getDataType()));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition containsIgnoreCase(T content) {
return new ContainsIgnoreCase(this, Tools.field(content, this));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition containsIgnoreCase(Field<T> content) {
return new ContainsIgnoreCase(this, nullSafe(content, getDataType()));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition endsWith(T suffix) {
return new EndsWith(this, Tools.field(suffix, this));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition endsWith(Field<T> suffix) {
return new EndsWith(this, nullSafe(suffix, getDataType()));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition endsWithIgnoreCase(T suffix) {
return new EndsWithIgnoreCase(this, Tools.field(suffix, this));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition endsWithIgnoreCase(Field<T> suffix) {
return new EndsWithIgnoreCase(this, nullSafe(suffix, getDataType()));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition startsWith(T prefix) {
return new StartsWith(this, Tools.field(prefix, this));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition startsWith(Field<T> prefix) {
return new StartsWith(this, nullSafe(prefix, getDataType()));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition startsWithIgnoreCase(T prefix) {
return new StartsWithIgnoreCase(this, Tools.field(prefix, this));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition startsWithIgnoreCase(Field<T> prefix) {
return new StartsWithIgnoreCase(this, nullSafe(prefix, getDataType()));
}
@ -1101,20 +1177,6 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
return likeRegex(pattern).not();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public final Condition contains(T value) {
if (value instanceof Field)
return contains((Field) value);
else
return new Contains<>(this, value, true, true);
}
@Override
public final Condition contains(Field<T> value) {
return new Contains<>(this, value, true, true);
}
@Override
public final Condition notContains(T value) {
return contains(value).not();
@ -1125,16 +1187,6 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
return contains(value).not();
}
@Override
public final Condition containsIgnoreCase(T value) {
return containsIgnoreCase(Tools.field(value, this));
}
@Override
public final Condition containsIgnoreCase(Field<T> value) {
return new ContainsIgnoreCase(this, value, true, true);
}
@Override
public final Condition notContainsIgnoreCase(T value) {
return containsIgnoreCase(value).not();
@ -1145,46 +1197,6 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
return containsIgnoreCase(value).not();
}
@Override
public final Condition startsWith(T value) {
return startsWith(Tools.field(value, this));
}
@Override
public final Condition startsWith(Field<T> value) {
return new Contains<>(this, value, false, true);
}
@Override
public final Condition startsWithIgnoreCase(T value) {
return startsWithIgnoreCase(Tools.field(value, this));
}
@Override
public final Condition startsWithIgnoreCase(Field<T> value) {
return new ContainsIgnoreCase(this, value, false, true);
}
@Override
public final Condition endsWith(T value) {
return endsWith(Tools.field(value, this));
}
@Override
public final Condition endsWith(Field<T> value) {
return new Contains<>(this, value, true, false);
}
@Override
public final Condition endsWithIgnoreCase(T value) {
return endsWithIgnoreCase(Tools.field(value, this));
}
@Override
public final Condition endsWithIgnoreCase(Field<T> value) {
return new ContainsIgnoreCase(this, value, true, false);
}
private final boolean isAccidentalSelect(T[] values) {
return (values != null && values.length == 1 && values[0] instanceof Select);
}

View File

@ -37,60 +37,56 @@
*/
package org.jooq.impl;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_COMPARISON;
// ...
import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.val;
import static org.jooq.impl.DSL.*;
import static org.jooq.impl.Internal.*;
import static org.jooq.impl.Keywords.*;
import static org.jooq.impl.Names.*;
import static org.jooq.impl.SQLDataType.*;
import static org.jooq.impl.Tools.*;
import static org.jooq.impl.Tools.BooleanDataKey.*;
import static org.jooq.impl.Tools.DataExtendedKey.*;
import static org.jooq.impl.Tools.DataKey.*;
import static org.jooq.SQLDialect.*;
import org.jooq.*;
import org.jooq.Record;
import org.jooq.conf.*;
import org.jooq.impl.*;
import org.jooq.tools.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Context;
import org.jooq.Field;
/**
* Abstraction for various "contains" operations
*
* @author Lukas Eder
* The <code>CONTAINS</code> statement.
*/
final class Contains<T> extends AbstractCondition {
private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON };
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
final class Contains<T>
extends
AbstractCondition
{
private final Field<T> lhs;
private final Field<T> rhs;
private final T value;
private final boolean leftWildcard;
private final boolean rightWildcard;
final Field<T> value;
final Field<T> content;
Contains(Field<T> field, T value, boolean leftWildcard, boolean rightWildcard) {
this.lhs = field;
this.rhs = null;
this.value = value;
this.leftWildcard = leftWildcard;
this.rightWildcard = rightWildcard;
Contains(
Field<T> value,
Field<T> content
) {
this.value = nullableIf(false, Tools.nullSafe(value, content.getDataType()));
this.content = nullableIf(false, Tools.nullSafe(content, value.getDataType()));
}
Contains(Field<T> field, Field<T> rhs, boolean leftWildcard, boolean rightWildcard) {
this.lhs = field;
this.rhs = rhs;
this.value = null;
this.leftWildcard = leftWildcard;
this.rightWildcard = rightWildcard;
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
@Override
public final void accept(Context<?> ctx) {
// [#1107] Some dialects support "contains" operations for ARRAYs
// [#5929] Check both sides of the operation for array types
if (lhs.getDataType().isArray()
|| (rhs != null && rhs.getDataType().isArray())
|| (rhs == null && value != null && value.getClass().isArray()))
ctx.visit(new PostgresArrayContains());
// "contains" operations on Strings
else {
switch (ctx.family()) {
switch (ctx.family()) {
@ -99,53 +95,49 @@ final class Contains<T> extends AbstractCondition {
default:
Field<?>[] array = new Field[1 + (leftWildcard ? 1 : 0) + (rightWildcard ? 1 : 0)];
int i = 0;
if (leftWildcard)
array[i++] = inline("%");
array[i++] = Tools.escapeForLike(rhs == null ? Tools.field(value, lhs) : rhs, ctx.configuration());
if (rightWildcard)
array[i++] = inline("%");
ctx.visit(lhs.like(DSL.concat(array), Tools.ESCAPE));
break;
case POSTGRES:
case YUGABYTE: {
// [#1107] Some dialects support "contains" operations for ARRAYs
// [#5929] Check both sides of the operation for array types
if (value.getDataType().isArray() || content.getDataType().isArray())
ctx.visit(value).sql(" @> ").visit(content);
else
acceptDefault(ctx);
break;
}
default:
acceptDefault(ctx);
break;
}
}
/**
* The Postgres array contains operator
*/
private class PostgresArrayContains extends AbstractCondition {
@Override
public final void accept(Context<?> ctx) {
ctx.visit(lhs).sql(" @> ").visit(rhs());
}
@Override
public final Clause[] clauses(Context<?> ctx) {
return CLAUSES;
}
private final Field<T> rhs() {
return (rhs == null) ? val(value, lhs) : rhs;
}
private final void acceptDefault(Context<?> ctx) {
ctx.visit(value.like(DSL.concat(inline("%"), Tools.escapeForLike(content, ctx.configuration()), inline("%")), Tools.ESCAPE));
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public final Clause[] clauses(Context<?> ctx) {
return CLAUSES;
public boolean equals(Object that) {
if (that instanceof Contains) {
return
StringUtils.equals(value, ((Contains) that).value) &&
StringUtils.equals(content, ((Contains) that).content)
;
}
else
return super.equals(that);
}
}

View File

@ -37,37 +37,53 @@
*/
package org.jooq.impl;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_COMPARISON;
import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.*;
import static org.jooq.impl.Internal.*;
import static org.jooq.impl.Keywords.*;
import static org.jooq.impl.Names.*;
import static org.jooq.impl.SQLDataType.*;
import static org.jooq.impl.Tools.*;
import static org.jooq.impl.Tools.BooleanDataKey.*;
import static org.jooq.impl.Tools.DataExtendedKey.*;
import static org.jooq.impl.Tools.DataKey.*;
import static org.jooq.SQLDialect.*;
import org.jooq.*;
import org.jooq.Record;
import org.jooq.conf.*;
import org.jooq.impl.*;
import org.jooq.tools.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Context;
import org.jooq.Field;
/**
* Abstraction for various "containsIgnoreCase" operations
*
* @author lmarchau
* The <code>CONTAINS IGNORE CASE</code> statement.
*/
final class ContainsIgnoreCase extends AbstractCondition {
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
final class ContainsIgnoreCase<T>
extends
AbstractCondition
{
private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON };
final Field<T> value;
final Field<T> content;
private final Field<?> lhs;
private final Field<?> rhs;
private final boolean leftWildcard;
private final boolean rightWildcard;
ContainsIgnoreCase(
Field<T> value,
Field<T> content
) {
ContainsIgnoreCase(Field<?> field, Field<?> rhs, boolean leftWildcard, boolean rightWildcard) {
this.lhs = field;
this.rhs = rhs;
this.leftWildcard = leftWildcard;
this.rightWildcard = rightWildcard;
this.value = nullableIf(false, Tools.nullSafe(value, content.getDataType()));
this.content = nullableIf(false, Tools.nullSafe(content, value.getDataType()));
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
@Override
public final void accept(Context<?> ctx) {
switch (ctx.family()) {
@ -77,31 +93,34 @@ final class ContainsIgnoreCase extends AbstractCondition {
default:
Field<?>[] array = new Field[1 + (leftWildcard ? 1 : 0) + (rightWildcard ? 1 : 0)];
int i = 0;
if (leftWildcard)
array[i++] = inline("%");
array[i++] = Tools.escapeForLike(rhs, ctx.configuration());
if (rightWildcard)
array[i++] = inline("%");
ctx.visit(lhs.likeIgnoreCase(DSL.concat(array), Tools.ESCAPE));
ctx.visit(value.likeIgnoreCase(DSL.concat(inline("%"), Tools.escapeForLike(content, ctx.configuration()), inline("%")), Tools.ESCAPE));
break;
}
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public final Clause[] clauses(Context<?> ctx) {
return CLAUSES;
public boolean equals(Object that) {
if (that instanceof ContainsIgnoreCase) {
return
StringUtils.equals(value, ((ContainsIgnoreCase) that).value) &&
StringUtils.equals(content, ((ContainsIgnoreCase) that).content)
;
}
else
return super.equals(that);
}
}

View File

@ -0,0 +1,126 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import static org.jooq.impl.DSL.*;
import static org.jooq.impl.Internal.*;
import static org.jooq.impl.Keywords.*;
import static org.jooq.impl.Names.*;
import static org.jooq.impl.SQLDataType.*;
import static org.jooq.impl.Tools.*;
import static org.jooq.impl.Tools.BooleanDataKey.*;
import static org.jooq.impl.Tools.DataExtendedKey.*;
import static org.jooq.impl.Tools.DataKey.*;
import static org.jooq.SQLDialect.*;
import org.jooq.*;
import org.jooq.Record;
import org.jooq.conf.*;
import org.jooq.impl.*;
import org.jooq.tools.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
/**
* The <code>ENDS WITH</code> statement.
*/
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
final class EndsWith<T>
extends
AbstractCondition
{
final Field<T> string;
final Field<T> suffix;
EndsWith(
Field<T> string,
Field<T> suffix
) {
this.string = nullableIf(false, Tools.nullSafe(string, suffix.getDataType()));
this.suffix = nullableIf(false, Tools.nullSafe(suffix, string.getDataType()));
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
@Override
public final void accept(Context<?> ctx) {
switch (ctx.family()) {
default:
ctx.visit(string.like(DSL.concat(inline("%"), Tools.escapeForLike(suffix, ctx.configuration())), Tools.ESCAPE));
break;
}
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof EndsWith) {
return
StringUtils.equals(string, ((EndsWith) that).string) &&
StringUtils.equals(suffix, ((EndsWith) that).suffix)
;
}
else
return super.equals(that);
}
}

View File

@ -0,0 +1,126 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import static org.jooq.impl.DSL.*;
import static org.jooq.impl.Internal.*;
import static org.jooq.impl.Keywords.*;
import static org.jooq.impl.Names.*;
import static org.jooq.impl.SQLDataType.*;
import static org.jooq.impl.Tools.*;
import static org.jooq.impl.Tools.BooleanDataKey.*;
import static org.jooq.impl.Tools.DataExtendedKey.*;
import static org.jooq.impl.Tools.DataKey.*;
import static org.jooq.SQLDialect.*;
import org.jooq.*;
import org.jooq.Record;
import org.jooq.conf.*;
import org.jooq.impl.*;
import org.jooq.tools.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
/**
* The <code>ENDS WITH IGNORE CASE</code> statement.
*/
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
final class EndsWithIgnoreCase<T>
extends
AbstractCondition
{
final Field<T> string;
final Field<T> suffix;
EndsWithIgnoreCase(
Field<T> string,
Field<T> suffix
) {
this.string = nullableIf(false, Tools.nullSafe(string, suffix.getDataType()));
this.suffix = nullableIf(false, Tools.nullSafe(suffix, string.getDataType()));
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
@Override
public final void accept(Context<?> ctx) {
switch (ctx.family()) {
default:
ctx.visit(string.likeIgnoreCase(DSL.concat(inline("%"), Tools.escapeForLike(suffix, ctx.configuration())), Tools.ESCAPE));
break;
}
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof EndsWithIgnoreCase) {
return
StringUtils.equals(string, ((EndsWithIgnoreCase) that).string) &&
StringUtils.equals(suffix, ((EndsWithIgnoreCase) that).suffix)
;
}
else
return super.equals(that);
}
}

View File

@ -0,0 +1,126 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import static org.jooq.impl.DSL.*;
import static org.jooq.impl.Internal.*;
import static org.jooq.impl.Keywords.*;
import static org.jooq.impl.Names.*;
import static org.jooq.impl.SQLDataType.*;
import static org.jooq.impl.Tools.*;
import static org.jooq.impl.Tools.BooleanDataKey.*;
import static org.jooq.impl.Tools.DataExtendedKey.*;
import static org.jooq.impl.Tools.DataKey.*;
import static org.jooq.SQLDialect.*;
import org.jooq.*;
import org.jooq.Record;
import org.jooq.conf.*;
import org.jooq.impl.*;
import org.jooq.tools.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
/**
* The <code>STARTS WITH</code> statement.
*/
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
final class StartsWith<T>
extends
AbstractCondition
{
final Field<T> string;
final Field<T> prefix;
StartsWith(
Field<T> string,
Field<T> prefix
) {
this.string = nullableIf(false, Tools.nullSafe(string, prefix.getDataType()));
this.prefix = nullableIf(false, Tools.nullSafe(prefix, string.getDataType()));
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
@Override
public final void accept(Context<?> ctx) {
switch (ctx.family()) {
default:
ctx.visit(string.like(DSL.concat(Tools.escapeForLike(prefix, ctx.configuration()), inline("%")), Tools.ESCAPE));
break;
}
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof StartsWith) {
return
StringUtils.equals(string, ((StartsWith) that).string) &&
StringUtils.equals(prefix, ((StartsWith) that).prefix)
;
}
else
return super.equals(that);
}
}

View File

@ -0,0 +1,126 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import static org.jooq.impl.DSL.*;
import static org.jooq.impl.Internal.*;
import static org.jooq.impl.Keywords.*;
import static org.jooq.impl.Names.*;
import static org.jooq.impl.SQLDataType.*;
import static org.jooq.impl.Tools.*;
import static org.jooq.impl.Tools.BooleanDataKey.*;
import static org.jooq.impl.Tools.DataExtendedKey.*;
import static org.jooq.impl.Tools.DataKey.*;
import static org.jooq.SQLDialect.*;
import org.jooq.*;
import org.jooq.Record;
import org.jooq.conf.*;
import org.jooq.impl.*;
import org.jooq.tools.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
/**
* The <code>STARTS WITH IGNORE CASE</code> statement.
*/
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
final class StartsWithIgnoreCase<T>
extends
AbstractCondition
{
final Field<T> string;
final Field<T> prefix;
StartsWithIgnoreCase(
Field<T> string,
Field<T> prefix
) {
this.string = nullableIf(false, Tools.nullSafe(string, prefix.getDataType()));
this.prefix = nullableIf(false, Tools.nullSafe(prefix, string.getDataType()));
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
@Override
public final void accept(Context<?> ctx) {
switch (ctx.family()) {
default:
ctx.visit(string.likeIgnoreCase(DSL.concat(Tools.escapeForLike(prefix, ctx.configuration()), inline("%")), Tools.ESCAPE));
break;
}
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof StartsWithIgnoreCase) {
return
StringUtils.equals(string, ((StartsWithIgnoreCase) that).string) &&
StringUtils.equals(prefix, ((StartsWithIgnoreCase) that).prefix)
;
}
else
return super.equals(that);
}
}