[jOOQ/jOOQ#12425] Move NOT predicate to API generator

Fixed a regression in the lazy type lookup and nullability propagation
This commit is contained in:
Lukas Eder 2021-09-16 11:01:31 +02:00
parent 04f00df329
commit 6b42ede21e
9 changed files with 169 additions and 128 deletions

View File

@ -380,14 +380,14 @@ public interface Condition extends QueryPart {
@Support
Condition orNotExists(Select<?> select);
/**
* Invert this condition
* <p>
* This is the same as calling {@link DSL#not(Condition)}
*
* @return This condition, inverted
* The <code>NOT</code> operator.
*/
@NotNull
@Support
Condition not();
}

View File

@ -178,19 +178,24 @@ abstract class AbstractCondition extends AbstractQueryPart implements Condition
return or(notExists(select));
}
@Override
public /* non-final */ Condition not() {
return new NotCondition(this);
}
static final Condition unwrapNot(Condition c, BiFunction<? super Condition, ? super Boolean, ? extends Condition> function) {
boolean not = false;
while (c instanceof NotCondition) {
c = ((NotCondition) c).condition;
while (c instanceof Not) {
c = ((Not) c).$arg1();
not = !not;
}
return function.apply(c, not);
}
@Override
public final Condition not() {
return DSL.not(this);
}
}

View File

@ -354,7 +354,7 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition isDistinctFrom(Field<T> arg2) {
return new IsDistinctFrom(this, arg2);
return new IsDistinctFrom(this, nullSafe(arg2, getDataType()));
}
@Override
@ -372,7 +372,7 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition isNotDistinctFrom(Field<T> arg2) {
return new IsNotDistinctFrom(this, arg2);
return new IsNotDistinctFrom(this, nullSafe(arg2, getDataType()));
}
@Override
@ -462,7 +462,7 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Field<T> mod(Field<? extends Number> arg2) {
return new Mod(this, arg2);
return new Mod(this, nullSafe(arg2, getDataType()));
}
@Override

View File

@ -14555,7 +14555,7 @@ public class DSL {
@NotNull
@Support
public static Condition unique(Select<?> query) {
return new UniqueCondition(query, true);
return new UniqueCondition(query);
}
/**
@ -14566,18 +14566,7 @@ public class DSL {
@NotNull
@Support
public static Condition notUnique(Select<?> query) {
return new UniqueCondition(query, false);
}
/**
* Invert a condition.
* <p>
* This is the same as calling {@link Condition#not()}
*/
@NotNull
@Support
public static Condition not(Condition condition) {
return condition.not();
return not(unique(query));
}
/**
@ -15689,6 +15678,15 @@ public class DSL {
/**
* The <code>NOT</code> function.
*/
@NotNull
@Support
public static Condition not(Condition arg1) {
return new Not(arg1);
}
// -------------------------------------------------------------------------
// Numeric functions
// -------------------------------------------------------------------------

View File

@ -74,8 +74,8 @@ extends
Field<T> arg2
) {
this.arg1 = nullSafeNotNull(arg1, (DataType) OTHER);
this.arg2 = nullSafeNotNull(arg2, (DataType) OTHER);
this.arg1 = nullableIf(true, Tools.nullSafe(arg1, arg2.getDataType()));
this.arg2 = nullableIf(true, Tools.nullSafe(arg2, arg1.getDataType()));
}
// -------------------------------------------------------------------------

View File

@ -74,8 +74,8 @@ extends
Field<T> arg2
) {
this.arg1 = nullSafeNotNull(arg1, (DataType) OTHER);
this.arg2 = nullSafeNotNull(arg2, (DataType) OTHER);
this.arg1 = nullableIf(true, Tools.nullSafe(arg1, arg2.getDataType()));
this.arg2 = nullableIf(true, Tools.nullSafe(arg2, arg1.getDataType()));
}
// -------------------------------------------------------------------------

View File

@ -0,0 +1,131 @@
/*
* 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>NOT</code> statement.
*/
@SuppressWarnings({ "unused" })
final class Not
extends
AbstractCondition
{
private final Condition arg1;
Not(
Condition arg1
) {
this.arg1 = arg1;
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
private static final Clause[] CLAUSES = { Clause.CONDITION, Clause.CONDITION_NOT };
@Override
boolean isNullable() {
return !(arg1 instanceof AbstractCondition) || ((AbstractCondition) arg1).isNullable();
}
@Override
public final void accept(Context<?> ctx) {
switch (ctx.family()) {
default:
ctx.visit(K_NOT).sql(" (").visit(arg1).sql(')');
break;
}
}
@Override
public final Clause[] clauses(Context<?> ctx) {
return CLAUSES;
}
final Condition $arg1() {
return arg1;
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof Not) {
return
StringUtils.equals(arg1, ((Not) that).arg1)
;
}
else
return super.equals(that);
}
}

View File

@ -1,82 +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_NOT;
import static org.jooq.impl.Keywords.K_NOT;
import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Context;
final class NotCondition extends AbstractCondition {
private static final Clause[] CLAUSES = { CONDITION, CONDITION_NOT };
final Condition condition;
NotCondition(Condition condition) {
this.condition = condition;
}
@Override
boolean isNullable() {
return !(condition instanceof AbstractCondition) || ((AbstractCondition) condition).isNullable();
}
@Override
public final void accept(Context<?> ctx) {
switch (ctx.family()) {
default:
ctx.visit(K_NOT).sql(" (").visit(condition).sql(')');
break;
}
}
@Override
public final Clause[] clauses(Context<?> ctx) {
return CLAUSES;
}
}

View File

@ -60,11 +60,9 @@ import org.jooq.Table;
final class UniqueCondition extends AbstractCondition {
private final Select<?> query;
private final boolean unique;
UniqueCondition(Select<?> query, boolean unique) {
UniqueCondition(Select<?> query) {
this.query = query;
this.unique = unique;
}
@Override
@ -76,9 +74,6 @@ final class UniqueCondition extends AbstractCondition {
public final void accept(Context<?> ctx) {
switch (ctx.family()) {
case H2:
if (!unique)
ctx.visit(K_NOT).sql(' ');
ctx.visit(K_UNIQUE).sql(' ');
visitSubquery(ctx, query);
break;
@ -92,15 +87,9 @@ final class UniqueCondition extends AbstractCondition {
.groupBy(queryFields)
.having(count().gt(one()));
ctx.visit(unique ? notExists(subquery) : exists(subquery));
// TODO: [#7362] [#10304] Find a better way to prevent double negation and unnecessary parentheses
ctx.visit(notExists(subquery));
break;
}
}
@Override
public final Condition not() {
// TODO: [#7362] [#10304] Find a better way to prevent double negation and unnecessary parentheses
return unique ? new UniqueCondition(query, false) : super.not();
}
}