[jOOQ/jOOQ#5216] Add UpdatableRecord.children(ForeignKey)
This includes: - UpdatableRecord.children() - TableRecord.parent() - ForeignKey.children() - ForeignKey.parents() - Result.children() - Result.parents() - Re-implementation of existing fetch methods - [jOOQ/jOOQ#10353] Add a new internal InlineDerivedTable implementation
This commit is contained in:
parent
e2d0d1455c
commit
61b16c5740
@ -90,8 +90,8 @@ public interface ForeignKey<R extends Record, O extends Record> extends Key<R> {
|
||||
* Fetch a parent record of a given record through this foreign key
|
||||
* <p>
|
||||
* This returns a parent record referenced by a given record through this
|
||||
* foreign key. If no parent record was found, this returns
|
||||
* <code>null</code>
|
||||
* foreign key, as if fetching from {@link #parent(Record)}. If no parent
|
||||
* record was found, this returns <code>null</code>
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @see TableRecord#fetchParent(ForeignKey)
|
||||
@ -103,7 +103,8 @@ public interface ForeignKey<R extends Record, O extends Record> extends Key<R> {
|
||||
* Fetch parent records of a given set of record through this foreign key
|
||||
* <p>
|
||||
* This returns parent records referenced by any record in a given set of
|
||||
* records through this foreign key.
|
||||
* records through this foreign key, as if fetching from
|
||||
* {@link #parents(Record...)}.
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @see TableRecord#fetchParent(ForeignKey)
|
||||
@ -115,7 +116,8 @@ public interface ForeignKey<R extends Record, O extends Record> extends Key<R> {
|
||||
* Fetch parent records of a given set of record through this foreign key
|
||||
* <p>
|
||||
* This returns parent records referenced by any record in a given set of
|
||||
* records through this foreign key.
|
||||
* records through this foreign key, as if fetching from
|
||||
* {@link #parents(Collection)}.
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @see TableRecord#fetchParent(ForeignKey)
|
||||
@ -127,7 +129,7 @@ public interface ForeignKey<R extends Record, O extends Record> extends Key<R> {
|
||||
* Fetch child records of a given record through this foreign key
|
||||
* <p>
|
||||
* This returns childs record referencing a given record through this
|
||||
* foreign key
|
||||
* foreign key, as if fetching from {@link #children(Record)}.
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @see UpdatableRecord#fetchChild(ForeignKey)
|
||||
@ -140,7 +142,8 @@ public interface ForeignKey<R extends Record, O extends Record> extends Key<R> {
|
||||
* Fetch child records of a given set of records through this foreign key
|
||||
* <p>
|
||||
* This returns childs record referencing any record in a given set of
|
||||
* records through this foreign key
|
||||
* records through this foreign key, as if fetching from
|
||||
* {@link #children(Record...)}.
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @see UpdatableRecord#fetchChild(ForeignKey)
|
||||
@ -153,7 +156,8 @@ public interface ForeignKey<R extends Record, O extends Record> extends Key<R> {
|
||||
* Fetch child records of a given set of records through this foreign key
|
||||
* <p>
|
||||
* This returns childs record referencing any record in a given set of
|
||||
* records through this foreign key
|
||||
* records through this foreign key, as if fetching from
|
||||
* {@link #children(Collection)}.
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @see UpdatableRecord#fetchChild(ForeignKey)
|
||||
@ -161,4 +165,46 @@ public interface ForeignKey<R extends Record, O extends Record> extends Key<R> {
|
||||
*/
|
||||
@NotNull
|
||||
Result<R> fetchChildren(Collection<? extends O> records) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Get a table expression representing the parent of a record, given this
|
||||
* foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
Table<O> parent(R record);
|
||||
|
||||
/**
|
||||
* Get a table expression representing the parents of a record, given this
|
||||
* foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
Table<O> parents(R... records);
|
||||
|
||||
/**
|
||||
* Get a table expression representing the parents of a record, given this
|
||||
* foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
Table<O> parents(Collection<? extends R> records);
|
||||
|
||||
/**
|
||||
* Get a table expression representing the children of a record, given this
|
||||
* foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
Table<R> children(O record);
|
||||
|
||||
/**
|
||||
* Get a table expression representing the children of a record, given this
|
||||
* foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
Table<R> children(O... records);
|
||||
|
||||
/**
|
||||
* Get a table expression representing the children of a record, given this
|
||||
* foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
Table<R> children(Collection<? extends O> records);
|
||||
}
|
||||
|
||||
@ -3196,7 +3196,8 @@ public interface Result<R extends Record> extends List<R>, Attachable, Formattab
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fetch parent records of this record, given a foreign key.
|
||||
* Fetch parent records of this record, given a foreign key, as if fetching
|
||||
* from {@link #parents(ForeignKey)}.
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query.
|
||||
* @see ForeignKey#fetchParent(Record)
|
||||
@ -3207,7 +3208,8 @@ public interface Result<R extends Record> extends List<R>, Attachable, Formattab
|
||||
<O extends UpdatableRecord<O>> Result<O> fetchParents(ForeignKey<R, O> key) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Fetch child records of this record, given a foreign key.
|
||||
* Fetch child records of this record, given a foreign key, as if fetching
|
||||
* from {@link #children(ForeignKey)}.
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query.
|
||||
* @see ForeignKey#fetchChildren(java.util.Collection)
|
||||
@ -3217,6 +3219,20 @@ public interface Result<R extends Record> extends List<R>, Attachable, Formattab
|
||||
@NotNull
|
||||
<O extends TableRecord<O>> Result<O> fetchChildren(ForeignKey<O, R> key) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Get a table expression representing the parents of all of this result's
|
||||
* records, given a foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
<O extends UpdatableRecord<O>> Table<O> parents(ForeignKey<R, O> key);
|
||||
|
||||
/**
|
||||
* Get a table expression representing the children of all of this result's
|
||||
* records, given a foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
<O extends TableRecord<O>> Table<O> children(ForeignKey<O, R> key);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Specialisations of Attachable methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@ -106,8 +106,8 @@ public interface TableRecord<R extends TableRecord<R>> extends Record {
|
||||
* Fetch a parent record of this record, given a foreign key.
|
||||
* <p>
|
||||
* This returns a parent record referenced by this record through a given
|
||||
* foreign key. If no parent record was found, this returns
|
||||
* <code>null</code>
|
||||
* foreign key, as if fetching from {@link #parent(ForeignKey)}. If no
|
||||
* parent record was found, this returns <code>null</code>
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @see ForeignKey#fetchParent(Record)
|
||||
@ -118,6 +118,14 @@ public interface TableRecord<R extends TableRecord<R>> extends Record {
|
||||
@Support
|
||||
<O extends UpdatableRecord<O>> O fetchParent(ForeignKey<R, O> key) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Get a table expression representing the parent of this record, given a
|
||||
* foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
@Support
|
||||
<O extends UpdatableRecord<O>> Table<O> parent(ForeignKey<R, O> key);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
<T> R with(Field<T> field, T value);
|
||||
|
||||
@ -582,7 +582,8 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
|
||||
* Fetch a child record of this record, given a foreign key.
|
||||
* <p>
|
||||
* This returns a child record referencing this record through a given
|
||||
* foreign key. If no child record was found, this returns <code>null</code>
|
||||
* foreign key, as if fetching from {@link #children(ForeignKey)}.. If no
|
||||
* child record was found, this returns <code>null</code>.
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @throws TooManyRowsException if the query returned more than one record
|
||||
@ -597,8 +598,8 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
|
||||
/**
|
||||
* Fetch child records of this record, given a foreign key.
|
||||
* <p>
|
||||
* This returns childs record referencing this record through a given
|
||||
* foreign key.
|
||||
* This returns child records referencing this record through a given
|
||||
* foreign key, as if fetching from {@link #children(ForeignKey)}.
|
||||
*
|
||||
* @throws DataAccessException if something went wrong executing the query
|
||||
* @see ForeignKey#fetchChildren(java.util.Collection)
|
||||
@ -608,4 +609,12 @@ public interface UpdatableRecord<R extends UpdatableRecord<R>> extends TableReco
|
||||
@NotNull
|
||||
@Support
|
||||
<O extends TableRecord<O>> Result<O> fetchChildren(ForeignKey<O, R> key) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Get a table expression representing the children of this record, given a
|
||||
* foreign key.
|
||||
*/
|
||||
@NotNull
|
||||
@Support
|
||||
<O extends TableRecord<O>> Table<O> children(ForeignKey<O, R> key);
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ import org.jooq.TableOptions;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class DerivedTable<R extends Record> extends AbstractTable<R> {
|
||||
class DerivedTable<R extends Record> extends AbstractTable<R> {
|
||||
|
||||
private static final long serialVersionUID = 6272398035926615668L;
|
||||
|
||||
|
||||
71
jOOQ/src/main/java/org/jooq/impl/InlineDerivedTable.java
Normal file
71
jOOQ/src/main/java/org/jooq/impl/InlineDerivedTable.java
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.selectFrom;
|
||||
|
||||
import org.jooq.Condition;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Table;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class InlineDerivedTable<R extends Record> extends DerivedTable<R> {
|
||||
|
||||
private static final long serialVersionUID = 6272398035926615668L;
|
||||
|
||||
private final Table<R> table;
|
||||
private final Condition where;
|
||||
|
||||
InlineDerivedTable(Table<R> table, Condition where) {
|
||||
super(selectFrom(table).where(where));
|
||||
|
||||
this.table = table;
|
||||
this.where = where;
|
||||
}
|
||||
|
||||
final Table<R> table() {
|
||||
return table;
|
||||
}
|
||||
|
||||
final Condition condition() {
|
||||
return where;
|
||||
}
|
||||
}
|
||||
@ -106,6 +106,14 @@ final class ReferenceImpl<R extends Record, O extends Record> extends AbstractKe
|
||||
return fetchParents(list(records));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Result<O> fetchParents(Collection<? extends R> records) {
|
||||
if (records == null || records.size() == 0)
|
||||
return new ResultImpl<>(new DefaultConfiguration(), uk.getFields());
|
||||
else
|
||||
return extractDSLContext(records).selectFrom(parents(records)).fetch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Result<R> fetchChildren(O record) {
|
||||
return fetchChildren(list(record));
|
||||
@ -117,48 +125,59 @@ final class ReferenceImpl<R extends Record, O extends Record> extends AbstractKe
|
||||
return fetchChildren(list(records));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Result<O> fetchParents(Collection<? extends R> records) {
|
||||
if (records == null || records.size() == 0)
|
||||
return new ResultImpl<>(new DefaultConfiguration(), uk.getFields());
|
||||
else
|
||||
return fetch(records, uk.getTable(), uk.getFieldsArray(), getFieldsArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Result<R> fetchChildren(Collection<? extends O> records) {
|
||||
if (records == null || records.size() == 0)
|
||||
return new ResultImpl<>(new DefaultConfiguration(), getFields());
|
||||
else
|
||||
return fetch(records, getTable(), getFieldsArray(), uk.getFieldsArray());
|
||||
return extractDSLContext(records).selectFrom(children(records)).fetch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<O> parent(R record) {
|
||||
return parents(list(record));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@Override
|
||||
public final Table<O> parents(R... records) {
|
||||
return parents(list(records));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<O> parents(Collection<? extends R> records) {
|
||||
return table(records, uk.getTable(), uk.getFieldsArray(), getFieldsArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<R> children(O record) {
|
||||
return children(list(record));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@Override
|
||||
public final Table<R> children(O... records) {
|
||||
return children(list(records));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<R> children(Collection<? extends O> records) {
|
||||
return table(records, getTable(), getFieldsArray(), uk.getFieldsArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actual fetching
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <R1 extends Record, R2 extends Record> Result<R1> fetch(
|
||||
private static <R1 extends Record, R2 extends Record> Table<R1> table(
|
||||
Collection<? extends R2> records,
|
||||
Table<R1> table,
|
||||
TableField<R1, ?>[] fields1,
|
||||
TableField<R2, ?>[] fields2) {
|
||||
|
||||
// Use regular predicates
|
||||
if (fields1.length == 1) {
|
||||
return extractDSLContext(records)
|
||||
.selectFrom(table)
|
||||
.where(((Field<Object>) fields1[0]).in(extractValues(records, fields2[0])))
|
||||
.fetch();
|
||||
}
|
||||
|
||||
// Use row value expressions
|
||||
else {
|
||||
return extractDSLContext(records)
|
||||
.selectFrom(table)
|
||||
.where(row(fields1).in(extractRows(records, fields2)))
|
||||
.fetch();
|
||||
}
|
||||
|
||||
TableField<R2, ?>[] fields2
|
||||
) {
|
||||
return new InlineDerivedTable<>(
|
||||
table,
|
||||
fields1.length == 1
|
||||
? ((Field<Object>) fields1[0]).in(extractValues(records, fields2[0]))
|
||||
: row(fields1).in(extractRows(records, fields2))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1496,6 +1496,16 @@ final class ResultImpl<R extends Record> extends AbstractCursor<R> implements Re
|
||||
return key.fetchChildren(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <O extends UpdatableRecord<O>> Table<O> parents(ForeignKey<R, O> key) {
|
||||
return key.parents(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <O extends TableRecord<O>> Table<O> children(ForeignKey<O, R> key) {
|
||||
return key.children(this);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Object API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -1654,6 +1654,8 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
|
||||
|
||||
tablelist = transformInlineDerivedTables(tablelist, where);
|
||||
|
||||
context.formatSeparator()
|
||||
.visit(K_FROM)
|
||||
.separatorRequired(true)
|
||||
@ -1903,6 +1905,97 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
}
|
||||
}
|
||||
|
||||
private final boolean hasOuterJoins(TableList tablelist) {
|
||||
for (Table<?> table : tablelist)
|
||||
if (table instanceof JoinTable && hasOuterJoins((JoinTable) table))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private final boolean hasOuterJoins(JoinTable join) {
|
||||
switch (join.type) {
|
||||
case CROSS_JOIN:
|
||||
case JOIN:
|
||||
case NATURAL_JOIN:
|
||||
case STRAIGHT_JOIN:
|
||||
return join.lhs instanceof JoinTable && hasOuterJoins((JoinTable) join.lhs)
|
||||
|| join.rhs instanceof JoinTable && hasOuterJoins((JoinTable) join.rhs);
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final boolean hasInlineDerivedTables(TableList tablelist) {
|
||||
for (Table<?> table : tablelist)
|
||||
if (table instanceof InlineDerivedTable)
|
||||
return true;
|
||||
else if (table instanceof JoinTable && hasInlineDerivedTables((JoinTable) table))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private final boolean hasInlineDerivedTables(JoinTable join) {
|
||||
return join.lhs instanceof InlineDerivedTable
|
||||
|| join.rhs instanceof InlineDerivedTable
|
||||
|| join.lhs instanceof JoinTable && hasInlineDerivedTables((JoinTable) join.lhs)
|
||||
|| join.rhs instanceof JoinTable && hasInlineDerivedTables((JoinTable) join.rhs);
|
||||
}
|
||||
|
||||
private final TableList transformInlineDerivedTables(TableList tablelist, ConditionProviderImpl where) {
|
||||
|
||||
// [#10353] A first implementation supports this feature only when there are no outer joins
|
||||
if (hasOuterJoins(tablelist) || !hasInlineDerivedTables(tablelist))
|
||||
return tablelist;
|
||||
|
||||
TableList result = new TableList();
|
||||
|
||||
for (Table<?> table : tablelist)
|
||||
transformInlineDerivedTable0(table, result, where);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private final void transformInlineDerivedTable0(Table<?> table, TableList result, ConditionProviderImpl where) {
|
||||
if (table instanceof InlineDerivedTable) {
|
||||
InlineDerivedTable<?> t = (InlineDerivedTable<?>) table;
|
||||
|
||||
result.add(t.table());
|
||||
where.addConditions(t.condition());
|
||||
}
|
||||
else if (table instanceof JoinTable) {
|
||||
result.add(transformInlineDerivedTables0(table, where));
|
||||
}
|
||||
else
|
||||
result.add(table);
|
||||
}
|
||||
|
||||
private final Table<?> transformInlineDerivedTables0(Table<?> table, ConditionProviderImpl where) {
|
||||
if (table instanceof InlineDerivedTable) {
|
||||
InlineDerivedTable<?> t = (InlineDerivedTable<?>) table;
|
||||
|
||||
where.addConditions(t.condition());
|
||||
return t.table();
|
||||
}
|
||||
else if (table instanceof JoinTable) {
|
||||
JoinTable join = (JoinTable) table;
|
||||
JoinTable result = new JoinTable(
|
||||
transformInlineDerivedTables0(join.lhs, where),
|
||||
transformInlineDerivedTables0(join.rhs, where),
|
||||
join.type
|
||||
);
|
||||
|
||||
if (!join.using.isEmpty())
|
||||
return result.using(join.using);
|
||||
else
|
||||
return result.on(join.condition);
|
||||
}
|
||||
else
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -151,6 +151,12 @@ public class TableRecordImpl<R extends TableRecord<R>> extends AbstractRecord im
|
||||
return key.fetchParent((R) this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final <O extends UpdatableRecord<O>> Table<O> parent(ForeignKey<R, O> key) {
|
||||
return key.parent((R) this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int insert() {
|
||||
return insert(fields.fields.fields);
|
||||
|
||||
@ -115,6 +115,12 @@ public class UpdatableRecordImpl<R extends UpdatableRecord<R>> extends TableReco
|
||||
return key.fetchChildren((R) this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final <O extends TableRecord<O>> Table<O> children(ForeignKey<O, R> key) {
|
||||
return key.children((R) this);
|
||||
}
|
||||
|
||||
@Override
|
||||
final UniqueKey<R> getPrimaryKey() {
|
||||
return getTable().getPrimaryKey();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user