[jOOQ/jOOQ#8353] Fix known limitations of embeddable types

- Embeddables in scalar subqueries
- [jOOQ/jOOQ#10524] Better use of DataType::isEmbeddable
This commit is contained in:
Lukas Eder 2020-08-25 14:00:53 +02:00
parent fdc05e3349
commit 5c97467580
12 changed files with 31 additions and 29 deletions

View File

@ -44,7 +44,6 @@ import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.converterOrFail;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.indexOrFail;
import static org.jooq.impl.Tools.isEmbeddable;
import static org.jooq.impl.Tools.resetChangedOnNotNull;
import static org.jooq.impl.Tools.settings;
import static org.jooq.impl.Tools.ThreadGuard.Guard.RECORD_TOSTRING;
@ -330,7 +329,7 @@ abstract class AbstractRecord extends AbstractStore implements Record {
@Override
public final <T> void set(Field<T> field, T value) {
if (isEmbeddable(field)) {
if (field.getDataType().isEmbeddable()) {
Field<?>[] f = embeddedFields(field);
Object[] v = value instanceof EmbeddableRecord
? ((EmbeddableRecord) value).intoArray()

View File

@ -72,7 +72,6 @@ import static org.jooq.impl.Keywords.K_BETWEEN;
import static org.jooq.impl.Keywords.K_NOT;
import static org.jooq.impl.Keywords.K_SYMMETRIC;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.isEmbeddable;
import java.util.Set;
@ -138,7 +137,9 @@ final class BetweenCondition<T> extends AbstractCondition implements BetweenAndS
}
private final QueryPartInternal delegate(Configuration configuration) {
if (isEmbeddable(field) && isEmbeddable(minValue) && isEmbeddable(maxValue)) {
if (field.getDataType().isEmbeddable()
&& minValue.getDataType().isEmbeddable()
&& maxValue.getDataType().isEmbeddable()) {
RowN f = row(embeddedFields(field));
RowN min = row(embeddedFields(minValue));
RowN max = row(embeddedFields(maxValue));

View File

@ -80,7 +80,6 @@ import static org.jooq.impl.Keywords.K_ESCAPE;
import static org.jooq.impl.Keywords.K_VARCHAR;
import static org.jooq.impl.Tools.castIfNeeded;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.isEmbeddable;
import java.util.Set;
@ -122,9 +121,9 @@ final class CompareCondition extends AbstractCondition implements LikeEscapeStep
@Override
public final void accept(Context<?> ctx) {
boolean field1Embeddable = isEmbeddable(field1);
boolean field1Embeddable = field1.getDataType().isEmbeddable();
if (field1Embeddable && isEmbeddable(field2))
if (field1Embeddable && field2.getDataType().isEmbeddable())
ctx.visit(row(embeddedFields(field1)).compare(comparator, embeddedFields(field2)));
else if (field1Embeddable && field2 instanceof ScalarSubquery)
ctx.visit(row(embeddedFields(field1)).compare(comparator, ((ScalarSubquery<?>) field2).query));

View File

@ -39,6 +39,7 @@ package org.jooq.impl;
// ...
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.embeddedRecordType;
import static org.jooq.impl.Tools.recordFactory;
import java.io.InputStream;
@ -1698,9 +1699,9 @@ final class CursorImpl<R extends Record> extends AbstractCursor<R> implements Cu
// TODO: [#4695] Calculate the correct Record[B] type
recordType = RecordImplN.class;
}
else if (field instanceof EmbeddableTableField) {
else if (field.getDataType().isEmbeddable()) {
nested = embeddedFields(field);
recordType = (Class<AbstractRecord>) ((EmbeddableTableField<?, ?>) field).recordType;
recordType = embeddedRecordType(field);
}
if (nested != null) {

View File

@ -41,6 +41,7 @@ import static org.jooq.impl.QueryPartListView.wrap;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_LIST_ALREADY_INDENTED;
import org.jooq.Context;
import org.jooq.EmbeddableRecord;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.SQLDialect;
@ -50,18 +51,20 @@ import org.jooq.TableField;
/**
* @author Lukas Eder
*/
final class EmbeddableTableField<R extends Record, T extends Record> extends AbstractField<T> implements TableField<R, T> {
final class EmbeddableTableField<R extends Record, E extends EmbeddableRecord<E>>
extends AbstractField<E>
implements TableField<R, E> {
/**
* Generated UID
*/
private static final long serialVersionUID = -7105430856294526440L;
final Class<T> recordType;
final Class<E> recordType;
final boolean replacesFields;
final Table<R> table;
final TableField<R, ?>[] fields;
EmbeddableTableField(Name name, Class<T> recordType, boolean replacesFields, Table<R> table, TableField<R, ?>[] fields) {
EmbeddableTableField(Name name, Class<E> recordType, boolean replacesFields, Table<R> table, TableField<R, ?>[] fields) {
super(name, new DefaultDataType<>(SQLDialect.DEFAULT, recordType, name.last()));
this.recordType = recordType;

View File

@ -49,7 +49,6 @@ import static org.jooq.impl.Keywords.K_VALUES;
import static org.jooq.impl.Tools.collect;
import static org.jooq.impl.Tools.flatten;
import static org.jooq.impl.Tools.flattenCollection;
import static org.jooq.impl.Tools.isEmbeddable;
import static org.jooq.impl.Tools.lazy;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_EMULATE_BULK_INSERT_RETURNING;

View File

@ -79,7 +79,6 @@ import static org.jooq.impl.DSL.trueCondition;
import static org.jooq.impl.Keywords.K_AND;
import static org.jooq.impl.Keywords.K_OR;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.isEmbeddable;
import static org.jooq.tools.StringUtils.defaultIfNull;
import java.util.AbstractList;
@ -122,7 +121,7 @@ final class InCondition<T> extends AbstractCondition {
@Override
public final void accept(Context<?> ctx) {
if (isEmbeddable(field))
if (field.getDataType().isEmbeddable())
if (comparator == IN)
ctx.visit(row(embeddedFields(field)).in(rows()));
else

View File

@ -79,7 +79,7 @@ public final class Internal {
*/
@SafeVarargs
@NotNull
public static final <R extends Record, T extends Record> TableField<R, T> createEmbeddable(Name name, Class<T> recordType, Table<R> table, TableField<R, ?>... fields) {
public static final <R extends Record, E extends EmbeddableRecord<E>> TableField<R, E> createEmbeddable(Name name, Class<E> recordType, Table<R> table, TableField<R, ?>... fields) {
return createEmbeddable(name, recordType, false, table, fields);
}
@ -88,7 +88,7 @@ public final class Internal {
*/
@SafeVarargs
@NotNull
public static final <R extends Record, T extends Record> TableField<R, T> createEmbeddable(Name name, Class<T> recordType, boolean replacesFields, Table<R> table, TableField<R, ?>... fields) {
public static final <R extends Record, E extends EmbeddableRecord<E>> TableField<R, E> createEmbeddable(Name name, Class<E> recordType, boolean replacesFields, Table<R> table, TableField<R, ?>... fields) {
return new EmbeddableTableField<>(name, recordType, replacesFields, table, fields);
}

View File

@ -67,7 +67,6 @@ import static org.jooq.impl.DSL.notExists;
import static org.jooq.impl.DSL.row;
import static org.jooq.impl.DSL.select;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.isEmbeddable;
import java.util.Set;
@ -112,7 +111,7 @@ final class IsDistinctFrom<T> extends AbstractCondition {
@Override
public final void accept(Context<?> ctx) {
if (isEmbeddable(lhs) && isEmbeddable(rhs))
if (lhs.getDataType().isEmbeddable() && rhs.getDataType().isEmbeddable())
ctx.visit(row(embeddedFields(lhs)).compare(comparator, row(embeddedFields(rhs))));

View File

@ -45,7 +45,6 @@ import static org.jooq.impl.DSL.row;
import static org.jooq.impl.Keywords.K_IS_NOT_NULL;
import static org.jooq.impl.Keywords.K_IS_NULL;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.isEmbeddable;
import org.jooq.Clause;
import org.jooq.Context;
@ -75,7 +74,7 @@ final class IsNull extends AbstractCondition {
@Override
public final void accept(Context<?> ctx) {
if (isEmbeddable(field))
if (field.getDataType().isEmbeddable())
if (isNull)
ctx.visit(row(embeddedFields(field)).isNull());
else

View File

@ -72,7 +72,6 @@ import static org.jooq.impl.DSL.row;
import static org.jooq.impl.DSL.select;
import static org.jooq.impl.SQLDataType.VARCHAR;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.isEmbeddable;
import static org.jooq.tools.Convert.convert;
import java.util.ArrayList;
@ -123,7 +122,7 @@ final class QuantifiedComparisonCondition extends AbstractCondition implements L
@Override
public final void accept(Context<?> ctx) {
if (isEmbeddable(field))
if (field.getDataType().isEmbeddable())
ctx.visit(row(embeddedFields(field)).compare(comparator, query));
else
accept0(ctx);

View File

@ -5335,9 +5335,15 @@ final class Tools {
return array == null || array.length == 0;
}
static final boolean isEmbeddable(Field<?> field) {
@SuppressWarnings("unchecked")
static final Class<? extends AbstractRecord> embeddedRecordType(Field<?> field) {
return field instanceof EmbeddableTableField
|| field instanceof Val && EmbeddableRecord.class.isAssignableFrom(field.getType());
? (Class<AbstractRecord>) ((EmbeddableTableField<?, ?>) field).recordType
: field instanceof Val && ((Val<?>) field).value instanceof EmbeddableRecord
? ((AbstractRecord) ((Val<?>) field).value).getClass()
: EmbeddableRecord.class.isAssignableFrom(field.getType())
? ((Field<AbstractRecord>) field).getType()
: null;
}
@SuppressWarnings("unchecked")
@ -5346,12 +5352,10 @@ final class Tools {
? ((EmbeddableTableField<?, ?>) field).fields
: field instanceof Val && ((Val<?>) field).value instanceof EmbeddableRecord
? ((EmbeddableRecord<?>) ((Val<?>) field).value).valuesRow().fields()
// It's an embeddable type, but it is null
: field instanceof Val && EmbeddableRecord.class.isAssignableFrom(field.getType())
? newInstance((Class<? extends EmbeddableRecord<?>>) field.getType()).valuesRow().fields()
: field instanceof ScalarSubquery
? embeddedFields((ScalarSubquery<?>) field)
: EmbeddableRecord.class.isAssignableFrom(field.getType())
? newInstance(((Field<EmbeddableRecord<?>>) field).getType()).valuesRow().fields()
: null;
}