[jOOQ/jOOQ#11070] Propagate type nullability through API - WIP

This commit is contained in:
Lukas Eder 2020-12-02 11:39:51 +01:00
parent 8cc490166c
commit b28b478d0f
11 changed files with 79 additions and 17 deletions

View File

@ -38,6 +38,7 @@
package org.jooq.impl;
import static org.jooq.impl.Names.N_COALESCE;
import static org.jooq.impl.Tools.anyNotNull;
import org.jooq.Context;
import org.jooq.DataType;
@ -54,9 +55,9 @@ final class Coalesce<T> extends AbstractField<T> {
private static final long serialVersionUID = -4546488210418866103L;
private final Field<T>[] fields;
@SuppressWarnings("unchecked")
Coalesce(DataType<T> dataType, Field<?>[] fields) {
super(N_COALESCE, dataType);
@SuppressWarnings({ "unchecked", "rawtypes" })
Coalesce(Field<?>[] fields) {
super(N_COALESCE, (DataType) anyNotNull(fields));
this.fields = (Field[]) fields;
}

View File

@ -107,8 +107,10 @@ import static org.jooq.impl.RankingFunction.RankingType.CUME_DIST;
import static org.jooq.impl.RankingFunction.RankingType.DENSE_RANK;
import static org.jooq.impl.RankingFunction.RankingType.PERCENT_RANK;
import static org.jooq.impl.RankingFunction.RankingType.RANK;
import static org.jooq.impl.SQLDataType.INTEGER;
import static org.jooq.impl.SQLDataType.JSON;
import static org.jooq.impl.SQLDataType.JSONB;
import static org.jooq.impl.SQLDataType.NUMERIC;
import static org.jooq.impl.SQLDataType.TIMESTAMP;
import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.combine;
@ -14529,7 +14531,7 @@ public class DSL {
// Java 8 is stricter than Java 7 with respect to generics and overload
// resolution (http://stackoverflow.com/q/5361513/521799)
static <T> Field<T> coalesce0(Field<T> field, Field<?>... fields) {
return new Coalesce<>(nullSafeDataType(field), nullSafe(combine(field, fields)));
return new Coalesce<>(nullSafe(combine(field, fields)));
}
/**
@ -22277,7 +22279,7 @@ public class DSL {
@NotNull
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
public static WindowOverStep<Integer> rank() {
return new RankingFunction<>(RANK, SQLDataType.INTEGER);
return new RankingFunction<>(RANK, INTEGER);
}
/**
@ -22286,7 +22288,7 @@ public class DSL {
@NotNull
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
public static WindowOverStep<Integer> denseRank() {
return new RankingFunction<>(DENSE_RANK, SQLDataType.INTEGER);
return new RankingFunction<>(DENSE_RANK, INTEGER);
}
/**
@ -22295,7 +22297,7 @@ public class DSL {
@NotNull
@Support({ CUBRID, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
public static WindowOverStep<BigDecimal> percentRank() {
return new RankingFunction<>(PERCENT_RANK, SQLDataType.NUMERIC);
return new RankingFunction<>(PERCENT_RANK, NUMERIC);
}
/**
@ -22304,7 +22306,7 @@ public class DSL {
@NotNull
@Support({ CUBRID, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
public static WindowOverStep<BigDecimal> cumeDist() {
return new RankingFunction<>(CUME_DIST, SQLDataType.NUMERIC);
return new RankingFunction<>(CUME_DIST, NUMERIC);
}
/**

View File

@ -55,7 +55,7 @@ final class Ntile extends AbstractWindowFunction<Integer> {
private final Field<Integer> tiles;
Ntile(Field<Integer> tiles) {
super(N_NTILE, INTEGER);
super(N_NTILE, INTEGER.notNull());
this.tiles = tiles;
}

View File

@ -58,7 +58,7 @@ final class NullIf<T> extends AbstractField<T> {
private final Field<T> arg2;
NullIf(Field<T> arg1, Field<T> arg2) {
super(N_NULLIF, arg1.getDataType());
super(N_NULLIF, arg1.getDataType().null_());
this.arg1 = arg1;
this.arg2 = arg2;

View File

@ -60,7 +60,7 @@ final class Nvl<T> extends AbstractField<T> {
private final Field<T> arg2;
Nvl(Field<T> arg1, Field<T> arg2) {
super(N_NVL, arg1.getDataType());
super(N_NVL, Tools.anyNotNull(arg1, arg2));
this.arg1 = arg1;
this.arg2 = arg2;

View File

@ -58,7 +58,7 @@ final class Nvl2<T> extends AbstractField<T> {
private final Field<T> arg3;
Nvl2(Field<?> arg1, Field<T> arg2, Field<T> arg3) {
super(N_NVL2, arg2.getDataType());
super(N_NVL2, !arg1.getDataType().nullable() ? arg2.getDataType() : Tools.allNotNull(arg2, arg3));
this.arg1 = arg1;
this.arg2 = arg2;

View File

@ -65,7 +65,7 @@ final class PositionalWindowFunction<T> extends AbstractWindowFunction<T> {
}
PositionalWindowFunction(PositionalFunctionType functionType, Field<T> arg, Field<Integer> offset, Field<T> defaultValue) {
super(functionType.name, arg.getDataType());
super(functionType.name, arg.getDataType().null_());
this.functionType = functionType;
this.arg = arg;

View File

@ -79,7 +79,7 @@ final class RankingFunction<T> extends AbstractWindowFunction<T> {
private final RankingType rankingType;
RankingFunction(RankingType rankingType, DataType<T> type) {
super(rankingType.name, type);
super(rankingType.name, type.notNull());
this.rankingType = rankingType;
}

View File

@ -55,7 +55,7 @@ final class RowNumber extends AbstractWindowFunction<Integer> {
private static final long serialVersionUID = -7318928420486422195L;
RowNumber() {
super(N_ROW_NUMBER, INTEGER);
super(N_ROW_NUMBER, INTEGER.notNull());
}
@Override

View File

@ -155,6 +155,7 @@ import static org.jooq.impl.SQLDataType.BLOB;
import static org.jooq.impl.SQLDataType.CLOB;
import static org.jooq.impl.SQLDataType.JSON;
import static org.jooq.impl.SQLDataType.JSONB;
import static org.jooq.impl.SQLDataType.OTHER;
import static org.jooq.impl.SQLDataType.VARCHAR;
import static org.jooq.impl.SQLDataType.XML;
import static org.jooq.impl.Tools.DataCacheKey.DATA_REFLECTION_CACHE_GET_ANNOTATED_GETTER;
@ -5898,4 +5899,58 @@ final class Tools {
return result;
}
static final <T> DataType<T> allNotNull(Field<T> f1, Field<T> f2) {
DataType<T> result = f1.getDataType();
if (result.nullable())
return result;
else if (f2.getDataType().nullable())
return result.null_();
else
return result;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
static final <T> DataType<T> allNotNull(Field<T>... fields) {
if (fields == null || fields.length == 0)
return (DataType) OTHER;
DataType<T> result = fields[0].getDataType();
if (result.nullable())
return result;
for (int i = 1; i < fields.length; i++)
if (fields[i].getDataType().nullable())
return result.null_();
return result;
}
static final <T> DataType<T> anyNotNull(Field<T> f1, Field<T> f2) {
DataType<T> result = f1.getDataType();
if (!result.nullable())
return result;
else if (!f2.getDataType().nullable())
return result.notNull();
else
return result;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
static final <T> DataType<T> anyNotNull(Field<T>... fields) {
if (fields == null || fields.length == 0)
return (DataType) OTHER;
DataType<T> result = fields[0].getDataType();
if (!result.nullable())
return result;
for (int i = 1; i < fields.length; i++)
if (!fields[i].getDataType().nullable())
return result.notNull();
return result;
}
}

View File

@ -67,11 +67,15 @@ final class Val<T> extends AbstractParam<T> {
private static final ConcurrentHashMap<Class<?>, Object> legacyWarnings = new ConcurrentHashMap<>();
Val(T value, DataType<T> type) {
super(value, type);
super(value, type(value, type));
}
Val(T value, DataType<T> type, String paramName) {
super(value, type, paramName);
super(value, type(value, type), paramName);
}
private static final <T> DataType<T> type(T value, DataType<T> type) {
return value == null ? type.null_() : type.notNull();
}
// ------------------------------------------------------------------------