[jOOQ/jOOQ#12425] [jOOQ/jOOQ#12432] Move AND and OR to API generator

This commit is contained in:
Lukas Eder 2021-09-20 13:53:43 +02:00
parent 94898a738a
commit c5002cda9a
12 changed files with 427 additions and 231 deletions

View File

@ -84,17 +84,6 @@ import org.jooq.impl.DSL;
*/
public interface Condition extends QueryPart {
/**
* Combine this condition with another one using the {@link Operator#AND}
* operator.
*
* @param other The other condition
* @return The combined condition
*/
@NotNull
@Support
Condition and(Condition other);
/**
* Combine this condition with another one using the {@link Operator#AND}
* operator.
@ -232,17 +221,6 @@ public interface Condition extends QueryPart {
@Support
Condition andNotExists(Select<?> select);
/**
* Combine this condition with another one using the {@link Operator#OR}
* operator.
*
* @param other The other condition
* @return The combined condition
*/
@NotNull
@Support
Condition or(Condition other);
/**
* Combine this condition with another one using the {@link Operator#OR}
* operator.
@ -386,6 +364,13 @@ public interface Condition extends QueryPart {
// Generic predicates
// -------------------------------------------------------------------------
/**
* The <code>AND</code> operator.
*/
@NotNull
@Support
Condition and(Condition arg2);
/**
* The <code>NOT</code> operator.
*/
@ -393,5 +378,12 @@ public interface Condition extends QueryPart {
@Support
Condition not();
/**
* The <code>OR</code> operator.
*/
@NotNull
@Support
Condition or(Condition arg2);
}

View File

@ -38,15 +38,15 @@
package org.jooq;
import static org.jooq.impl.DSL.falseCondition;
import static org.jooq.impl.DSL.keyword;
import org.jooq.impl.DSL;
import static org.jooq.impl.DSL.trueCondition;
import org.jetbrains.annotations.*;
/**
* An operator used for combining conditions
* An operator used for combining conditions.
*
* @author Lukas Eder
*/
@ -66,8 +66,8 @@ public enum Operator {
@Support
OR("or");
private final String sql;
private final Keyword keyword;
private final String sql;
private final Keyword keyword;
private Operator(String sql) {
this.sql = sql;
@ -87,4 +87,11 @@ public enum Operator {
public final Keyword toKeyword() {
return keyword;
}
/**
* The identity condition for this operator.
*/
public final Condition identity() {
return this == AND ? trueCondition() : falseCondition();
}
}

View File

@ -38,6 +38,8 @@
package org.jooq.impl;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Operator.AND;
import static org.jooq.Operator.OR;
import static org.jooq.impl.DSL.condition;
import static org.jooq.impl.DSL.exists;
import static org.jooq.impl.DSL.notExists;
@ -75,11 +77,6 @@ abstract class AbstractCondition extends AbstractQueryPart implements Condition
return CLAUSES;
}
@Override
public final Condition and(Condition other) {
return DSL.and(this, other);
}
/*
* Subclasses may override this implementation when implementing
* A BETWEEN B AND C
@ -89,11 +86,6 @@ abstract class AbstractCondition extends AbstractQueryPart implements Condition
return and(condition(other));
}
@Override
public final Condition or(Condition other) {
return DSL.or(this, other);
}
@Override
public final Condition or(Field<Boolean> other) {
return or(condition(other));
@ -196,11 +188,21 @@ abstract class AbstractCondition extends AbstractQueryPart implements Condition
// Generic predicates
// -------------------------------------------------------------------------
@Override
public final Condition and(Condition arg2) {
return DSL.condition(AND, this, arg2);
}
@Override
public final Condition not() {
return DSL.not(this);
}
@Override
public final Condition or(Condition arg2) {
return DSL.condition(OR, this, arg2);
}
}

View File

@ -358,7 +358,6 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition isNull() {
return new IsNull(this);
}
@ -382,7 +381,6 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition isNotNull() {
return new IsNotNull(this);
}
@ -392,13 +390,11 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
// -------------------------------------------------------------------------
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition isDocument() {
return new IsDocument(this);
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition isNotDocument() {
return new IsNotDocument(this);
}
@ -408,13 +404,11 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
// -------------------------------------------------------------------------
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition isJson() {
return new IsJson(this);
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition isNotJson() {
return new IsNotJson(this);
}
@ -460,7 +454,6 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Field<T> bitNot() {
return DSL.bitNot((Field) this);
}
@ -595,7 +588,6 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
// ------------------------------------------------------------------------
// XXX: Arithmetic operations
// ------------------------------------------------------------------------

View File

@ -0,0 +1,175 @@
/*
* 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.*;
/**
* The <code>AND</code> statement.
*/
@SuppressWarnings({ "unused" })
final class And
extends
AbstractCondition
{
final Condition arg1;
final Condition arg2;
And(
Condition arg1,
Condition arg2
) {
this.arg1 = arg1;
this.arg2 = arg2;
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
private static final Clause[] CLAUSES = { Clause.CONDITION, Clause.CONDITION_AND };
@Override
public final void accept(Context<?> ctx) {
{
ctx.sqlIndentStart('(');
Expression.<Condition, And>acceptAssociative(
ctx,
this,
q -> new Expression.Expr<>(q.arg1, Operator.AND.toKeyword(), q.arg2),
Context::formatSeparator
);
ctx.sqlIndentEnd(')');
}
}
/**
* @deprecated - This will be implemented using QOM.replace, instead.
*/
@Deprecated
final Condition transform(java.util.function.Function<? super Condition, ? extends Condition> function) {
Condition t1 = arg1 instanceof And
? ((And) arg1).transform(function)
: arg1 instanceof Or
? ((And) arg1).transform(function)
: function.apply(arg1);
Condition t2 = arg2 instanceof And
? ((And) arg2).transform(function)
: arg2 instanceof Or
? ((Or) arg2).transform(function)
: function.apply(arg2);
if (t1 == arg1 && t2 == arg2)
return this;
else
return DSL.and(t1, t2);
}
@Override
final boolean isNullable() {
return ((AbstractCondition) arg1).isNullable() || ((AbstractCondition) arg2).isNullable();
}
@Override
public final Clause[] clauses(Context<?> ctx) {
return CLAUSES;
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof And) {
return
StringUtils.equals(arg1, ((And) that).arg1) &&
StringUtils.equals(arg2, ((And) that).arg2)
;
}
else
return super.equals(that);
}
}

View File

@ -1,166 +0,0 @@
/*
* 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.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_AND;
import static org.jooq.Clause.CONDITION_OR;
import static org.jooq.Operator.AND;
// ...
import static org.jooq.impl.DSL.falseCondition;
import static org.jooq.impl.DSL.noCondition;
import static org.jooq.impl.DSL.trueCondition;
import java.util.Collection;
import java.util.function.Function;
import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Context;
import org.jooq.Operator;
import org.jooq.impl.Expression.Expr;
/**
* @author Lukas Eder
*/
final class CombinedCondition extends AbstractCondition {
private static final Clause[] CLAUSES_AND = { CONDITION, CONDITION_AND };
private static final Clause[] CLAUSES_OR = { CONDITION, CONDITION_OR };
final Operator operator;
final Condition op1;
final Condition op2;
static Condition of(Operator operator, Condition left, Condition right) {
if (left == null || left instanceof NoCondition)
return right;
else if (right == null || right instanceof NoCondition)
return left;
else
return new CombinedCondition(operator, left, right);
}
static Condition of(Operator operator, Collection<? extends Condition> conditions) {
Condition result = null;
for (Condition condition : conditions)
if (!(condition instanceof NoCondition))
if (result == null)
result = condition;
else
result = new CombinedCondition(operator, result, condition);
if (result != null)
return result;
// [#9998] All conditions were NoCondition
else if (!conditions.isEmpty())
return noCondition();
// [#9998] Otherwise, return the identity for the operator
else
return identity(operator);
}
@Override
final boolean isNullable() {
return ((AbstractCondition) op1).isNullable() || ((AbstractCondition) op2).isNullable();
}
static final Condition identity(Operator operator) {
return operator == AND ? trueCondition() : falseCondition();
}
final Condition transform(Function<? super Condition, ? extends Condition> function) {
Condition t1 = op1 instanceof CombinedCondition
? ((CombinedCondition) op1).transform(function)
: function.apply(op1);
Condition t2 = op2 instanceof CombinedCondition
? ((CombinedCondition) op2).transform(function)
: function.apply(op2);
if (t1 == op1 && t2 == op2)
return this;
else
return of(operator, t1, t2);
}
private CombinedCondition(Operator operator, Condition op1, Condition op2) {
if (operator == null)
throw new IllegalArgumentException("The argument 'operator' must not be null");
this.operator = operator;
this.op1 = op1;
this.op2 = op2;
}
@Override
public final Clause[] clauses(Context<?> ctx) {
return operator == AND ? CLAUSES_AND : CLAUSES_OR;
}
@Override
public final void accept(Context<?> ctx) {
{
ctx.sqlIndentStart('(');
Expression.<Condition, CombinedCondition>acceptAssociative(
ctx,
this,
q -> new Expr<>(q.op1, q.operator.toKeyword(), q.op2),
Context::formatSeparator
);
ctx.sqlIndentEnd(')');
}
}
}

View File

@ -98,7 +98,6 @@ import static org.jooq.SQLDialect.SQLITE;
import static org.jooq.SQLDialect.YUGABYTE;
import static org.jooq.conf.ParamType.INLINED;
import static org.jooq.impl.Keywords.K_CUBE;
import static org.jooq.impl.Keywords.K_DEFAULT;
import static org.jooq.impl.Keywords.K_GROUPING_SETS;
import static org.jooq.impl.Names.N_AVG;
import static org.jooq.impl.Names.N_COUNT;
@ -152,7 +151,6 @@ import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.temporal.Temporal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@ -212,7 +210,6 @@ import org.jooq.ConstraintTypeStep;
import org.jooq.CreateTableColumnStep;
import org.jooq.CreateTypeStep;
import org.jooq.CreateViewAsStep;
import org.jooq.DMLQuery;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.DatePart;
@ -339,7 +336,6 @@ import org.jooq.Record6;
import org.jooq.Record7;
import org.jooq.Record8;
import org.jooq.Record9;
import org.jooq.RecordHandler;
import org.jooq.RecordType;
// ...
import org.jooq.Result;
@ -387,7 +383,6 @@ import org.jooq.Support;
import org.jooq.Table;
import org.jooq.TableLike;
import org.jooq.True;
import org.jooq.UDTRecord;
import org.jooq.Update;
import org.jooq.UpdateSetFirstStep;
import org.jooq.User;
@ -14502,7 +14497,14 @@ public class DSL {
@NotNull
@Support
public static Condition condition(Operator operator, Condition left, Condition right) {
return CombinedCondition.of(operator, left, right);
if (left == null || left instanceof NoCondition)
return right == null ? noCondition() : right;
else if (right == null || right instanceof NoCondition)
return left;
else if (operator == AND)
return new And(left, right);
else
return new Or(left, right);
}
/**
@ -14522,7 +14524,24 @@ public class DSL {
@NotNull
@Support
public static Condition condition(Operator operator, Collection<? extends Condition> conditions) {
return CombinedCondition.of(operator, conditions);
Condition result = null;
for (Condition condition : conditions)
if (result == null)
result = condition;
else
result = condition(operator, result, condition);
if (result != null)
return result;
// [#9998] All conditions were NoCondition
else if (!conditions.isEmpty())
return noCondition();
// [#9998] Otherwise, return the identity for the operator
else
return operator.identity();
}
// -------------------------------------------------------------------------

View File

@ -0,0 +1,175 @@
/*
* 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.*;
/**
* The <code>OR</code> statement.
*/
@SuppressWarnings({ "unused" })
final class Or
extends
AbstractCondition
{
final Condition arg1;
final Condition arg2;
Or(
Condition arg1,
Condition arg2
) {
this.arg1 = arg1;
this.arg2 = arg2;
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
private static final Clause[] CLAUSES = { Clause.CONDITION, Clause.CONDITION_OR };
@Override
public final void accept(Context<?> ctx) {
{
ctx.sqlIndentStart('(');
Expression.<Condition, Or>acceptAssociative(
ctx,
this,
q -> new Expression.Expr<>(q.arg1, Operator.OR.toKeyword(), q.arg2),
Context::formatSeparator
);
ctx.sqlIndentEnd(')');
}
}
/**
* @deprecated - This will be implemented using QOM.replace, instead.
*/
@Deprecated
final Condition transform(java.util.function.Function<? super Condition, ? extends Condition> function) {
Condition t1 = arg1 instanceof And
? ((And) arg1).transform(function)
: arg1 instanceof Or
? ((And) arg1).transform(function)
: function.apply(arg1);
Condition t2 = arg2 instanceof And
? ((And) arg2).transform(function)
: arg2 instanceof Or
? ((Or) arg2).transform(function)
: function.apply(arg2);
if (t1 == arg1 && t2 == arg2)
return this;
else
return DSL.or(t1, t2);
}
@Override
final boolean isNullable() {
return ((AbstractCondition) arg1).isNullable() || ((AbstractCondition) arg2).isNullable();
}
@Override
public final Clause[] clauses(Context<?> ctx) {
return CLAUSES;
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof Or) {
return
StringUtils.equals(arg1, ((Or) that).arg1) &&
StringUtils.equals(arg2, ((Or) that).arg2)
;
}
else
return super.equals(that);
}
}

View File

@ -183,7 +183,7 @@ final class QuantifiedComparisonCondition extends AbstractCondition implements L
accept1(ctx);
}
else if (query.values != null || quantifiedArray) {
ctx.visit(CombinedCondition.of(
ctx.visit(DSL.condition(
query.quantifier == Quantifier.ALL ? Operator.AND : Operator.OR,
query.values != null
? map(query.values, v -> comparisonCondition(comparator, (Field<String>) v))

View File

@ -1221,11 +1221,6 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
@ -2944,11 +2939,6 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp

View File

@ -6438,6 +6438,14 @@ final class Tools {

View File

@ -72,8 +72,10 @@ final class Transform {
Condition transform(Condition condition) {
if (condition instanceof ConditionProviderImpl)
return transform(((ConditionProviderImpl) condition).getWhere());
else if (condition instanceof CombinedCondition)
return CombinedCondition.of(((CombinedCondition) condition).operator, transform(((CombinedCondition) condition).op1), transform(((CombinedCondition) condition).op2));
else if (condition instanceof And)
return transform(((And) condition).arg1).and(transform(((And) condition).arg2));
else if (condition instanceof Or)
return transform(((Or) condition).arg1).or(transform(((Or) condition).arg2));
else if (condition instanceof CompareCondition)
return new CompareCondition(fieldTransformer.apply(((CompareCondition) condition).field1), fieldTransformer.apply(((CompareCondition) condition).field2), ((CompareCondition) condition).comparator);
else