[#578] Add KEY JOIN syntax to simulate joining using generated foreign keys
This commit is contained in:
parent
1119c72bf6
commit
10720d1fe6
@ -5952,11 +5952,51 @@ public abstract class jOOQAbstractTest<
|
||||
.orderBy(TBook_ID())
|
||||
.fetch();
|
||||
|
||||
// Test the Select API
|
||||
// -------------------
|
||||
assertEquals(2, result2.size());
|
||||
assertEquals(BOOK_AUTHOR_IDS.subList(0, 2), result2.getValues(0));
|
||||
assertEquals(BOOK_TITLES.subList(0, 2), result2.getValues(1));
|
||||
|
||||
// Test the Select API
|
||||
// -------------------
|
||||
Result<Record> result3 =
|
||||
create().select(TAuthor_ID(), TBook_TITLE())
|
||||
.from(TAuthor())
|
||||
.join(TBook()).onKey(TBook_AUTHOR_ID())
|
||||
.orderBy(TBook_ID())
|
||||
.fetch();
|
||||
|
||||
assertEquals(4, result3.size());
|
||||
assertEquals(BOOK_AUTHOR_IDS, result3.getValues(0));
|
||||
assertEquals(BOOK_TITLES, result3.getValues(1));
|
||||
|
||||
// Test using unambiguous keys
|
||||
// ---------------------------
|
||||
Result<Record> result4 =
|
||||
create().select(TBook_ID(), TBookStore_NAME())
|
||||
.from(TBook())
|
||||
.join(TBookToBookStore()).onKey()
|
||||
.join(TBookStore()).onKey()
|
||||
.orderBy(TBook_ID(), TBookStore_NAME())
|
||||
.fetch();
|
||||
|
||||
assertEquals(6, result4.size());
|
||||
assertEquals(asList(1, 1, 2, 3, 3, 3), result4.getValues(0));
|
||||
assertEquals(asList(
|
||||
"Ex Libris", "Orell Füssli", "Orell Füssli",
|
||||
"Buchhandlung im Volkshaus", "Ex Libris", "Orell Füssli"), result4.getValues(1));
|
||||
|
||||
// Test inverse join relationship [#671] TODO
|
||||
// ------------------------------
|
||||
// Result<Record> result5 =
|
||||
// create().select(TBook_TITLE(), TBookStore_NAME())
|
||||
// .from(TBook())
|
||||
// .join(TBookToBookStore()
|
||||
// .join(TBookStore()).onKey())
|
||||
// .onKey()
|
||||
// .orderBy(TBook_ID(), TBookStore_NAME())
|
||||
// .fetch();
|
||||
//
|
||||
// assertEquals(result4, result5);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -45,6 +45,7 @@ import static org.jooq.SQLDialect.SQLITE;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.impl.Factory;
|
||||
|
||||
/**
|
||||
@ -123,42 +124,42 @@ public interface SelectOnStep {
|
||||
@Support
|
||||
SelectOnConditionStep on(String sql, Object... bindings);
|
||||
|
||||
// /**
|
||||
// * Join the previous table on a non-ambiguous foreign key relationship
|
||||
// * between the two joined tables.
|
||||
// * <p>
|
||||
// * See {@link Table#onKey(Key)} for examples.
|
||||
// *
|
||||
// * @see Table#onKey(Key)
|
||||
// * @throws DataAccessException If there is no non-ambiguous key definition
|
||||
// * known to jOOQ
|
||||
// */
|
||||
// @Support
|
||||
// SelectOnConditionStep onKey() throws DataAccessException;
|
||||
//
|
||||
// /**
|
||||
// * Join the previous table on a non-ambiguous foreign key relationship
|
||||
// * between the two joined tables.
|
||||
// * <p>
|
||||
// * See {@link Table#onKey(Key)} for examples.
|
||||
// *
|
||||
// * @see Table#onKey(Key)
|
||||
// * @throws DataAccessException If there is no non-ambiguous key definition
|
||||
// * known to jOOQ
|
||||
// */
|
||||
// @Support
|
||||
// SelectOnConditionStep onKey(TableField<?, ?>... keyFields) throws DataAccessException;
|
||||
//
|
||||
// /**
|
||||
// * Join the table on a non-ambiguous foreign key relationship between the
|
||||
// * two joined tables.
|
||||
// * <p>
|
||||
// * See {@link Table#onKey(Key)} for examples.
|
||||
// *
|
||||
// * @see Table#onKey(Key)
|
||||
// */
|
||||
// @Support
|
||||
// SelectOnConditionStep onKey(ForeignKey<?, ?> key);
|
||||
/**
|
||||
* Join the previous table on a non-ambiguous foreign key relationship
|
||||
* between the two joined tables.
|
||||
* <p>
|
||||
* See {@link Table#onKey(Key)} for examples.
|
||||
*
|
||||
* @see Table#onKey(Key)
|
||||
* @throws DataAccessException If there is no non-ambiguous key definition
|
||||
* known to jOOQ
|
||||
*/
|
||||
@Support
|
||||
SelectJoinStep onKey() throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Join the previous table on a non-ambiguous foreign key relationship
|
||||
* between the two joined tables.
|
||||
* <p>
|
||||
* See {@link Table#onKey(Key)} for examples.
|
||||
*
|
||||
* @see Table#onKey(Key)
|
||||
* @throws DataAccessException If there is no non-ambiguous key definition
|
||||
* known to jOOQ
|
||||
*/
|
||||
@Support
|
||||
SelectJoinStep onKey(TableField<?, ?>... keyFields) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Join the table on a non-ambiguous foreign key relationship between the
|
||||
* two joined tables.
|
||||
* <p>
|
||||
* See {@link Table#onKey(Key)} for examples.
|
||||
*
|
||||
* @see Table#onKey(Key)
|
||||
*/
|
||||
@Support
|
||||
SelectJoinStep onKey(ForeignKey<?, ?> key);
|
||||
|
||||
/**
|
||||
* Join the previous table with the <code>USING(column [, column...])</code>
|
||||
|
||||
@ -46,6 +46,8 @@ import static org.jooq.SQLDialect.SQLITE;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.exception.DataAccessException;
|
||||
|
||||
/**
|
||||
* A query for data selection
|
||||
*
|
||||
@ -129,41 +131,41 @@ public interface SelectQuery extends Select<Record>, ConditionProvider, OrderPro
|
||||
@Support({ DERBY, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLITE })
|
||||
void addJoinUsing(TableLike<?> table, JoinType type, Collection<? extends Field<?>> fields);
|
||||
|
||||
// /**
|
||||
// * Joins the existing table product to a new table using a foreign key
|
||||
// *
|
||||
// * @param table The joined table
|
||||
// * @param type The type of join
|
||||
// * @see Table#onKey(Key)
|
||||
// * @throws DataAccessException If there is no non-ambiguous key definition
|
||||
// * known to jOOQ
|
||||
// */
|
||||
// @Support
|
||||
// void addJoinOnKey(TableLike<?> table, JoinType type) throws DataAccessException;
|
||||
//
|
||||
// /**
|
||||
// * Joins the existing table product to a new table using a foreign key
|
||||
// *
|
||||
// * @param table The joined table
|
||||
// * @param type The type of join
|
||||
// * @param keyFields The foreign key fields
|
||||
// * @see Table#onKey(Key)
|
||||
// * @throws DataAccessException If there is no non-ambiguous key definition
|
||||
// * known to jOOQ
|
||||
// */
|
||||
// @Support
|
||||
// void addJoinOnKey(TableLike<?> table, JoinType type, TableField<?, ?>... keyFields) throws DataAccessException;
|
||||
//
|
||||
// /**
|
||||
// * Joins the existing table product to a new table using a foreign key
|
||||
// *
|
||||
// * @param table The joined table
|
||||
// * @param type The type of join
|
||||
// * @param key The foreign key
|
||||
// * @see Table#onKey(Key)
|
||||
// */
|
||||
// @Support
|
||||
// void addJoinOnKey(TableLike<?> table, JoinType type, ForeignKey<?, ?> key);
|
||||
/**
|
||||
* Joins the existing table product to a new table using a foreign key
|
||||
*
|
||||
* @param table The joined table
|
||||
* @param type The type of join
|
||||
* @see Table#onKey(Key)
|
||||
* @throws DataAccessException If there is no non-ambiguous key definition
|
||||
* known to jOOQ
|
||||
*/
|
||||
@Support
|
||||
void addJoinOnKey(TableLike<?> table, JoinType type) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Joins the existing table product to a new table using a foreign key
|
||||
*
|
||||
* @param table The joined table
|
||||
* @param type The type of join
|
||||
* @param keyFields The foreign key fields
|
||||
* @see Table#onKey(Key)
|
||||
* @throws DataAccessException If there is no non-ambiguous key definition
|
||||
* known to jOOQ
|
||||
*/
|
||||
@Support
|
||||
void addJoinOnKey(TableLike<?> table, JoinType type, TableField<?, ?>... keyFields) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Joins the existing table product to a new table using a foreign key
|
||||
*
|
||||
* @param table The joined table
|
||||
* @param type The type of join
|
||||
* @param key The foreign key
|
||||
* @see Table#onKey(Key)
|
||||
*/
|
||||
@Support
|
||||
void addJoinOnKey(TableLike<?> table, JoinType type, ForeignKey<?, ?> key);
|
||||
|
||||
/**
|
||||
* Adds grouping fields
|
||||
|
||||
@ -40,6 +40,7 @@ import static org.jooq.impl.Factory.condition;
|
||||
import static org.jooq.impl.Factory.exists;
|
||||
import static org.jooq.impl.Factory.notExists;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@ -96,6 +97,17 @@ class JoinTable extends AbstractTable<Record> implements TableOnStep, TableOnCon
|
||||
// Table API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public final List<ForeignKey<Record, ?>> getReferences() {
|
||||
List<ForeignKey<?, ?>> result = new ArrayList<ForeignKey<?, ?>>();
|
||||
|
||||
result.addAll(lhs.getReferences());
|
||||
result.addAll(rhs.getReferences());
|
||||
|
||||
return (List) result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void toSQL(RenderContext context) {
|
||||
context.sql(lhs)
|
||||
|
||||
@ -46,6 +46,7 @@ import java.util.Collection;
|
||||
import org.jooq.Condition;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.ForeignKey;
|
||||
import org.jooq.JoinType;
|
||||
import org.jooq.Operator;
|
||||
import org.jooq.Record;
|
||||
@ -62,7 +63,9 @@ import org.jooq.SelectQuery;
|
||||
import org.jooq.SelectSelectStep;
|
||||
import org.jooq.SortField;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
import org.jooq.TableLike;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
|
||||
/**
|
||||
* A wrapper for a {@link SelectQuery}
|
||||
@ -511,6 +514,34 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
|
||||
return on(condition(sql, bindings));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SelectImpl onKey() throws DataAccessException {
|
||||
conditionStep = ConditionStep.ON;
|
||||
getQuery().addJoinOnKey(joinTable, joinType);
|
||||
joinTable = null;
|
||||
joinType = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SelectImpl onKey(TableField<?, ?>... keyFields) throws DataAccessException {
|
||||
conditionStep = ConditionStep.ON;
|
||||
getQuery().addJoinOnKey(joinTable, joinType, keyFields);
|
||||
joinTable = null;
|
||||
joinType = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SelectImpl onKey(ForeignKey<?, ?> key) {
|
||||
conditionStep = ConditionStep.ON;
|
||||
getQuery().addJoinOnKey(joinTable, joinType, key);
|
||||
joinTable = null;
|
||||
joinType = null;
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SelectImpl using(Field<?>... fields) {
|
||||
return using(Arrays.asList(fields));
|
||||
|
||||
@ -42,12 +42,15 @@ import java.util.Collection;
|
||||
import org.jooq.Condition;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.ForeignKey;
|
||||
import org.jooq.JoinType;
|
||||
import org.jooq.Operator;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.SelectQuery;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
import org.jooq.TableLike;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
@ -137,6 +140,8 @@ class SelectQueryImpl extends AbstractSubSelect<Record> implements SelectQuery {
|
||||
|
||||
@Override
|
||||
public final void addJoin(TableLike<?> table, JoinType type, Condition... conditions) {
|
||||
// TODO: This and similar methods should be refactored, patterns extracted...
|
||||
|
||||
int index = getFrom().size() - 1;
|
||||
Table<?> joined = null;
|
||||
|
||||
@ -172,6 +177,123 @@ class SelectQueryImpl extends AbstractSubSelect<Record> implements SelectQuery {
|
||||
getFrom().set(index, joined);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void addJoinOnKey(TableLike<?> table, JoinType type) throws DataAccessException {
|
||||
// TODO: This and similar methods should be refactored, patterns extracted...
|
||||
|
||||
int index = getFrom().size() - 1;
|
||||
Table<?> joined = null;
|
||||
|
||||
switch (type) {
|
||||
case JOIN:
|
||||
joined = getFrom().get(index).join(table).onKey();
|
||||
break;
|
||||
case LEFT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).leftOuterJoin(table).onKey();
|
||||
break;
|
||||
case RIGHT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).rightOuterJoin(table).onKey();
|
||||
break;
|
||||
case FULL_OUTER_JOIN:
|
||||
joined = getFrom().get(index).fullOuterJoin(table).onKey();
|
||||
break;
|
||||
|
||||
// These join types don't take any ON clause. Ignore conditions.
|
||||
case CROSS_JOIN:
|
||||
joined = getFrom().get(index).crossJoin(table);
|
||||
break;
|
||||
case NATURAL_JOIN:
|
||||
joined = getFrom().get(index).naturalJoin(table);
|
||||
break;
|
||||
case NATURAL_LEFT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).naturalLeftOuterJoin(table);
|
||||
break;
|
||||
case NATURAL_RIGHT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).naturalRightOuterJoin(table);
|
||||
break;
|
||||
}
|
||||
|
||||
getFrom().set(index, joined);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void addJoinOnKey(TableLike<?> table, JoinType type, TableField<?, ?>... keyFields) throws DataAccessException {
|
||||
// TODO: This and similar methods should be refactored, patterns extracted...
|
||||
|
||||
int index = getFrom().size() - 1;
|
||||
Table<?> joined = null;
|
||||
|
||||
switch (type) {
|
||||
case JOIN:
|
||||
joined = getFrom().get(index).join(table).onKey(keyFields);
|
||||
break;
|
||||
case LEFT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).leftOuterJoin(table).onKey(keyFields);
|
||||
break;
|
||||
case RIGHT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).rightOuterJoin(table).onKey(keyFields);
|
||||
break;
|
||||
case FULL_OUTER_JOIN:
|
||||
joined = getFrom().get(index).fullOuterJoin(table).onKey(keyFields);
|
||||
break;
|
||||
|
||||
// These join types don't take any ON clause. Ignore conditions.
|
||||
case CROSS_JOIN:
|
||||
joined = getFrom().get(index).crossJoin(table);
|
||||
break;
|
||||
case NATURAL_JOIN:
|
||||
joined = getFrom().get(index).naturalJoin(table);
|
||||
break;
|
||||
case NATURAL_LEFT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).naturalLeftOuterJoin(table);
|
||||
break;
|
||||
case NATURAL_RIGHT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).naturalRightOuterJoin(table);
|
||||
break;
|
||||
}
|
||||
|
||||
getFrom().set(index, joined);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void addJoinOnKey(TableLike<?> table, JoinType type, ForeignKey<?, ?> key) {
|
||||
// TODO: This and similar methods should be refactored, patterns extracted...
|
||||
|
||||
int index = getFrom().size() - 1;
|
||||
Table<?> joined = null;
|
||||
|
||||
switch (type) {
|
||||
case JOIN:
|
||||
joined = getFrom().get(index).join(table).onKey(key);
|
||||
break;
|
||||
case LEFT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).leftOuterJoin(table).onKey(key);
|
||||
break;
|
||||
case RIGHT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).rightOuterJoin(table).onKey(key);
|
||||
break;
|
||||
case FULL_OUTER_JOIN:
|
||||
joined = getFrom().get(index).fullOuterJoin(table).onKey(key);
|
||||
break;
|
||||
|
||||
// These join types don't take any ON clause. Ignore conditions.
|
||||
case CROSS_JOIN:
|
||||
joined = getFrom().get(index).crossJoin(table);
|
||||
break;
|
||||
case NATURAL_JOIN:
|
||||
joined = getFrom().get(index).naturalJoin(table);
|
||||
break;
|
||||
case NATURAL_LEFT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).naturalLeftOuterJoin(table);
|
||||
break;
|
||||
case NATURAL_RIGHT_OUTER_JOIN:
|
||||
joined = getFrom().get(index).naturalRightOuterJoin(table);
|
||||
break;
|
||||
}
|
||||
|
||||
getFrom().set(index, joined);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void addJoinUsing(TableLike<?> table, Collection<? extends Field<?>> fields) {
|
||||
addJoinUsing(table, JoinType.JOIN, fields);
|
||||
@ -179,6 +301,8 @@ class SelectQueryImpl extends AbstractSubSelect<Record> implements SelectQuery {
|
||||
|
||||
@Override
|
||||
public final void addJoinUsing(TableLike<?> table, JoinType type, Collection<? extends Field<?>> fields) {
|
||||
// TODO: This and similar methods should be refactored, patterns extracted...
|
||||
|
||||
int index = getFrom().size() - 1;
|
||||
Table<?> joined = null;
|
||||
|
||||
|
||||
@ -41,6 +41,7 @@ import java.util.List;
|
||||
import org.jooq.Attachable;
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.ForeignKey;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.Table;
|
||||
@ -65,6 +66,11 @@ class TableAlias<R extends Record> extends AbstractTable<R> {
|
||||
this.aliasProvider = new AliasProviderImpl<Table<R>>(table, alias, wrapInParentheses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<ForeignKey<R, ?>> getReferences() {
|
||||
return aliasProvider.getAliasProvider().getReferences();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<Attachable> getAttachables0() {
|
||||
return getAttachables(aliasProvider, aliasedFields);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user