From c5002cda9a50f2ed1433fa655209053b573c5828 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Mon, 20 Sep 2021 13:53:43 +0200 Subject: [PATCH] [jOOQ/jOOQ#12425] [jOOQ/jOOQ#12432] Move AND and OR to API generator --- jOOQ/src/main/java/org/jooq/Condition.java | 36 ++-- jOOQ/src/main/java/org/jooq/Operator.java | 17 +- .../java/org/jooq/impl/AbstractCondition.java | 22 ++- .../java/org/jooq/impl/AbstractField.java | 8 - jOOQ/src/main/java/org/jooq/impl/And.java | 175 ++++++++++++++++++ .../java/org/jooq/impl/CombinedCondition.java | 166 ----------------- jOOQ/src/main/java/org/jooq/impl/DSL.java | 33 +++- jOOQ/src/main/java/org/jooq/impl/Or.java | 175 ++++++++++++++++++ .../impl/QuantifiedComparisonCondition.java | 2 +- .../java/org/jooq/impl/SelectQueryImpl.java | 10 - jOOQ/src/main/java/org/jooq/impl/Tools.java | 8 + .../main/java/org/jooq/impl/Transform.java | 6 +- 12 files changed, 427 insertions(+), 231 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/impl/And.java delete mode 100644 jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/Or.java diff --git a/jOOQ/src/main/java/org/jooq/Condition.java b/jOOQ/src/main/java/org/jooq/Condition.java index 53cae8bdd4..edda3fabcb 100644 --- a/jOOQ/src/main/java/org/jooq/Condition.java +++ b/jOOQ/src/main/java/org/jooq/Condition.java @@ -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 AND operator. + */ + @NotNull + @Support + Condition and(Condition arg2); + /** * The NOT operator. */ @@ -393,5 +378,12 @@ public interface Condition extends QueryPart { @Support Condition not(); + /** + * The OR operator. + */ + @NotNull + @Support + Condition or(Condition arg2); + } diff --git a/jOOQ/src/main/java/org/jooq/Operator.java b/jOOQ/src/main/java/org/jooq/Operator.java index d313df9747..de63eb6738 100644 --- a/jOOQ/src/main/java/org/jooq/Operator.java +++ b/jOOQ/src/main/java/org/jooq/Operator.java @@ -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(); + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractCondition.java b/jOOQ/src/main/java/org/jooq/impl/AbstractCondition.java index 8df5a991b7..60daefc518 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractCondition.java @@ -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 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); + } + } diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java index 4851718482..fed1da121a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java @@ -358,7 +358,6 @@ abstract class AbstractField extends AbstractTypedNamed implements Field extends AbstractTypedNamed implements Field extends AbstractTypedNamed implements Field extends AbstractTypedNamed implements Field extends AbstractTypedNamed implements Field bitNot() { return DSL.bitNot((Field) this); } @@ -595,7 +588,6 @@ abstract class AbstractField extends AbstractTypedNamed implements FieldAND 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.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 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); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java b/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java deleted file mode 100644 index 305ad1a402..0000000000 --- a/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java +++ /dev/null @@ -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 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 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.acceptAssociative( - ctx, - this, - q -> new Expr<>(q.op1, q.operator.toKeyword(), q.op2), - Context::formatSeparator - ); - ctx.sqlIndentEnd(')'); - } - } -} diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 93439012a2..a781a73cdb 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -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 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(); } // ------------------------------------------------------------------------- diff --git a/jOOQ/src/main/java/org/jooq/impl/Or.java b/jOOQ/src/main/java/org/jooq/impl/Or.java new file mode 100644 index 0000000000..19fa2c93ca --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/Or.java @@ -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 OR 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.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 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); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java b/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java index 54f73753d0..339c06b85f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java @@ -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) v)) diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index aadd0d39ff..937f1f5932 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -1221,11 +1221,6 @@ final class SelectQueryImpl extends AbstractResultQuery imp - - - - - @@ -2944,11 +2939,6 @@ final class SelectQueryImpl extends AbstractResultQuery imp - - - - - diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 2e6ca1975e..bc9a9288ae 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -6438,6 +6438,14 @@ final class Tools { + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/Transform.java b/jOOQ/src/main/java/org/jooq/impl/Transform.java index f96b058744..834bd8b5f6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Transform.java +++ b/jOOQ/src/main/java/org/jooq/impl/Transform.java @@ -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