[jOOQ/jOOQ#8553] Add support for foreign keys referencing unique key

columns in different order than in the unique key definition

- Added jOOQ-meta implementation
- Added H2Database implementation
This commit is contained in:
Lukas Eder 2020-06-30 17:05:43 +02:00
parent 8f9c389132
commit 4e140b7062
5 changed files with 87 additions and 18 deletions

View File

@ -99,6 +99,15 @@ implements TableDefinition {
return getDatabase().getRelations().getUniqueKeys(this);
}
@Override
public final UniqueKeyDefinition getUniqueKey(String name) {
for (UniqueKeyDefinition uk : getUniqueKeys())
if (uk.getInputName().equals(name))
return uk;
return null;
}
@Override
public final List<ForeignKeyDefinition> getForeignKeys() {
return getDatabase().getRelations().getForeignKeys(this);

View File

@ -44,18 +44,20 @@ import java.util.Set;
public class DefaultForeignKeyDefinition extends AbstractConstraintDefinition implements ForeignKeyDefinition {
private final List<ColumnDefinition> keyColumns;
private final UniqueKeyDefinition uniqueKey;
private final List<ColumnDefinition> fkColumns;
private final List<ColumnDefinition> ukColumns;
private final UniqueKeyDefinition uk;
public DefaultForeignKeyDefinition(SchemaDefinition schema, String name, TableDefinition table, UniqueKeyDefinition uniqueKey) {
this(schema, name, table, uniqueKey, true);
}
public DefaultForeignKeyDefinition(SchemaDefinition schema, String name, TableDefinition table, UniqueKeyDefinition uniqueKey, boolean enforced) {
public DefaultForeignKeyDefinition(SchemaDefinition schema, String name, TableDefinition table, UniqueKeyDefinition uk, boolean enforced) {
super(schema, table, name, enforced);
this.keyColumns = new ArrayList<>();
this.uniqueKey = uniqueKey;
this.fkColumns = new ArrayList<>();
this.ukColumns = new ArrayList<>();
this.uk = uk;
}
@Override
@ -65,22 +67,22 @@ public class DefaultForeignKeyDefinition extends AbstractConstraintDefinition im
@Override
public List<ColumnDefinition> getKeyColumns() {
return keyColumns;
return fkColumns;
}
@Override
public UniqueKeyDefinition getReferencedKey() {
return uniqueKey;
return uk;
}
@Override
public TableDefinition getReferencedTable() {
return uniqueKey.getTable();
return uk.getTable();
}
@Override
public List<ColumnDefinition> getReferencedColumns() {
return uniqueKey.getKeyColumns();
return ukColumns;
}
@Override

View File

@ -39,6 +39,7 @@ package org.jooq.meta;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
@ -189,14 +190,54 @@ public class DefaultRelations implements Relations {
ColumnDefinition foreignKeyColumn,
String uniqueKeyName,
TableDefinition uniqueKeyTable,
boolean enforced) {
boolean enforced
) {
UniqueKeyDefinition uk = uniqueKeys.get(key(uniqueKeyTable, uniqueKeyName));
Key key = key(foreignKeyTable, foreignKeyName);
if (uk == null) {
log.info("Ignoring foreign key", uniqueKeyName + " (unique key unavailable)");
// [#7826] Prevent incomplete keys from being generated
if (foreignKeyTable != null) {
incompleteKeys.add(key);
foreignKeys.remove(key);
}
return;
}
addForeignKey(foreignKeyName, foreignKeyTable, foreignKeyColumn, uniqueKeyName, uniqueKeyTable, getNextUkColumn(key, uk), enforced);
}
private Map<Key, Integer> nextUkColumnIndex = new HashMap<>();
private ColumnDefinition getNextUkColumn(Key key, UniqueKeyDefinition uk) {
Integer index = nextUkColumnIndex.get(key);
if (index == null)
nextUkColumnIndex.put(key, index = 0);
else
nextUkColumnIndex.put(key, index = index + 1);
return uk.getKeyColumns().get(index);
}
public void addForeignKey(
String foreignKeyName,
TableDefinition foreignKeyTable,
ColumnDefinition foreignKeyColumn,
String uniqueKeyName,
TableDefinition uniqueKeyTable,
ColumnDefinition uniqueKeyColumn,
boolean enforced
) {
// [#2718] Column exclusions may hit foreign key references. Ignore
// such foreign keys
Key key = key(foreignKeyTable, foreignKeyName);
if (foreignKeyColumn == null) {
log.info("Ignoring foreign key", foreignKeyColumn + " (column unavailable)");
if (foreignKeyColumn == null || uniqueKeyColumn == null) {
log.info("Ignoring foreign key", foreignKeyColumn + " referencing " + uniqueKeyColumn + " (column unavailable)");
// [#7826] Prevent incomplete keys from being generated
if (foreignKeyTable != null) {
@ -213,11 +254,11 @@ public class DefaultRelations implements Relations {
// [#1134] Prevent NPE's when a foreign key references a unique key
// from another schema
if (uniqueKeyTable == null) {
log.info("Ignoring foreign key", foreignKeyName + " (" + foreignKeyColumn + ") referencing " + uniqueKeyName + " references a schema out of scope for jooq-meta: " + uniqueKeyTable);
log.info("Ignoring foreign key", foreignKeyName + " (" + foreignKeyColumn + ") referencing " + uniqueKeyName + " (" + uniqueKeyColumn + ") references a schema out of scope for jooq-meta: " + uniqueKeyTable);
return;
}
log.info("Adding foreign key", foreignKeyName + " (" + foreignKeyColumn + ") referencing " + uniqueKeyName);
log.info("Adding foreign key", foreignKeyName + " (" + foreignKeyColumn + ") referencing " + uniqueKeyName + " (" + uniqueKeyColumn + ")");
ForeignKeyDefinition foreignKey = foreignKeys.get(key);
@ -226,15 +267,23 @@ public class DefaultRelations implements Relations {
// If the unique key is not loaded, ignore this foreign key
if (uniqueKey != null) {
foreignKey = new DefaultForeignKeyDefinition(foreignKeyColumn.getSchema(), foreignKeyName, foreignKeyColumn.getContainer(), uniqueKey, enforced);
foreignKeys.put(key, foreignKey);
foreignKey = new DefaultForeignKeyDefinition(
foreignKeyColumn.getSchema(),
foreignKeyName,
foreignKeyColumn.getContainer(),
uniqueKey,
enforced
);
foreignKeys.put(key, foreignKey);
uniqueKey.getForeignKeys().add(foreignKey);
}
}
if (foreignKey != null)
if (foreignKey != null) {
foreignKey.getKeyColumns().add(foreignKeyColumn);
foreignKey.getReferencedColumns().add(uniqueKeyColumn);
}
}
public void addCheckConstraint(TableDefinition table, CheckConstraintDefinition constraint) {

View File

@ -90,6 +90,11 @@ public interface TableDefinition extends Definition {
*/
List<UniqueKeyDefinition> getUniqueKeys();
/**
* Get the unique key for this table by name.
*/
UniqueKeyDefinition getUniqueKey(String name);
/**
* Get the foreign keys for this table.
*/

View File

@ -287,6 +287,7 @@ public class H2Database extends AbstractDatabase {
CrossReferences.FKTABLE_NAME,
CrossReferences.FKTABLE_SCHEMA,
CrossReferences.FKCOLUMN_NAME,
CrossReferences.PKCOLUMN_NAME,
Constraints.CONSTRAINT_NAME,
Constraints.TABLE_NAME,
Constraints.CONSTRAINT_SCHEMA)
@ -314,6 +315,7 @@ public class H2Database extends AbstractDatabase {
String foreignKeyColumn = record.get(CrossReferences.FKCOLUMN_NAME);
String uniqueKey = record.get(Constraints.CONSTRAINT_NAME);
String uniqueKeyTableName = record.get(Constraints.TABLE_NAME);
String uniqueKeyColumn = record.get(CrossReferences.PKCOLUMN_NAME);
TableDefinition foreignKeyTable = getTable(foreignKeySchema, foreignKeyTableName);
TableDefinition uniqueKeyTable = getTable(uniqueKeySchema, uniqueKeyTableName);
@ -324,7 +326,9 @@ public class H2Database extends AbstractDatabase {
foreignKeyTable,
foreignKeyTable.getColumn(foreignKeyColumn),
uniqueKey,
uniqueKeyTable
uniqueKeyTable,
uniqueKeyTable.getColumn(uniqueKeyColumn),
true
);
}
}