[jOOQ/jOOQ#2530] [jOOQ/jOOQ#6124] [jOOQ/jOOQ#10481] Improved embeddable support and added code generation support for embeddable keys

This commit is contained in:
Lukas Eder 2020-08-12 17:11:36 +02:00
parent ee3bdcc6fd
commit 29bce7c908
24 changed files with 923 additions and 230 deletions

View File

@ -142,7 +142,6 @@ abstract class AbstractGenerator implements Generator {
boolean generateTableValuedFunctions = false;
boolean generateEmptyCatalogs = false;
boolean generateEmptySchemas = false;
boolean generatePrimaryKeyTypes = false;
String generateNewline = "\n";
String generateIndentation;
@ -1077,16 +1076,6 @@ abstract class AbstractGenerator implements Generator {
this.generateEmptySchemas = generateEmptySchemas;
}
@Override
public boolean generatePrimaryKeyTypes() {
return generatePrimaryKeyTypes;
}
@Override
public void setGeneratePrimaryKeyTypes(boolean generatePrimaryKeyTypes) {
this.generatePrimaryKeyTypes = generatePrimaryKeyTypes;
}
@Override
public String generateNewline() {
return generateNewline;

View File

@ -156,6 +156,10 @@ public class DefaultGeneratorStrategy extends AbstractGeneratorStrategy {
else if (definition instanceof ForeignKeyDefinition && asList(POSTGRES).contains(definition.getDatabase().getDialect().family()))
return ((ForeignKeyDefinition) definition).getTable().getOutputName().toUpperCase() + "__" + definition.getOutputName().toUpperCase();
// [#10481] Embeddables have a defining name (class name) and a referencing name (identifier name).
else if (definition instanceof EmbeddableDefinition)
return ((EmbeddableDefinition) definition).getReferencingOutputName().toUpperCase();
else
return definition.getOutputName().toUpperCase();
}

View File

@ -546,6 +546,8 @@ public class GenerationTool {
database.setConfiguredEnumTypes(d.getEnumTypes());
database.setConfiguredForcedTypes(d.getForcedTypes());
database.setConfiguredEmbeddables(d.getEmbeddables());
database.setEmbeddablePrimaryKeys(TRUE.equals(g.getDatabase().isEmbeddablePrimaryKeys()));
database.setEmbeddableUniqueKeys(TRUE.equals(g.getDatabase().isEmbeddableUniqueKeys()));
database.setLogSlowQueriesAfterSeconds(defaultIfNull(g.getDatabase().getLogSlowQueriesAfterSeconds(), 5));
database.setLogSlowResultsAfterSeconds(defaultIfNull(g.getDatabase().getLogSlowResultsAfterSeconds(), 5));
@ -806,8 +808,6 @@ public class GenerationTool {
generator.setGenerateEmptyCatalogs(g.getGenerate().isEmptyCatalogs());
if (g.getGenerate().isEmptySchemas() != null)
generator.setGenerateEmptySchemas(g.getGenerate().isEmptySchemas());
if (g.getGenerate().isPrimaryKeyTypes() != null)
generator.setGeneratePrimaryKeyTypes(g.getGenerate().isPrimaryKeyTypes());
if (g.getGenerate().getNewline() != null)
generator.setGenerateNewline(g.getGenerate().getNewline());
if (g.getGenerate().getIndentation() != null)

View File

@ -959,16 +959,6 @@ public interface Generator {
*/
void setGenerateEmptySchemas(boolean generateEmptySchemas);
/**
* Whether wrapper types for primary keys should be generated.
*/
boolean generatePrimaryKeyTypes();
/**
* Whether wrapper types for primary keys should be generated.
*/
void setGeneratePrimaryKeyTypes(boolean generatePrimaryKeyTypes);
/**
* The newline character(s) to be used in generated code.
*/

View File

@ -96,6 +96,7 @@ import org.jooq.Index;
import org.jooq.Name;
import org.jooq.OrderField;
import org.jooq.Parameter;
// ...
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.Row;
@ -1036,7 +1037,44 @@ public class JavaGenerator extends AbstractGenerator {
out.println(";");
}
private void printCreateUniqueKey(JavaWriter out, UniqueKeyDefinition uniqueKey) {
printCreateNonEmbeddableUniqueKey(out, uniqueKey);
}
private void printCreateNonEmbeddableUniqueKey(JavaWriter out, UniqueKeyDefinition uniqueKey) {
if (scala)
out.print("%s.createUniqueKey(%s, %s.name(\"%s\"), Array([[%s]]).asInstanceOf[Array[%s[%s, _] ] ], %s)",
Internal.class,
@ -1066,6 +1104,21 @@ public class JavaGenerator extends AbstractGenerator {
uniqueKey.enforced());
}
protected void printForeignKey(JavaWriter out, int foreignKeyCounter, ForeignKeyDefinition foreignKey) {
final int block = foreignKeyCounter / INITIALISER_SIZE;
@ -1083,11 +1136,47 @@ public class JavaGenerator extends AbstractGenerator {
}
if (scala)
out.println("val %s: %s[%s, %s] = %s.createForeignKey(%s, %s.name(\"%s\"), Array([[%s]]).asInstanceOf[Array[%s[%s, _] ] ], %s, Array([[%s]]).asInstanceOf[Array[%s[%s, _] ] ], %s)",
out.print("val %s: %s[%s, %s] = ",
getStrategy().getJavaIdentifier(foreignKey),
ForeignKey.class,
out.ref(getStrategy().getFullJavaClassName(foreignKey.getKeyTable(), Mode.RECORD)),
out.ref(getStrategy().getFullJavaClassName(foreignKey.getReferencedTable(), Mode.RECORD)));
else if (kotlin)
out.print("val %s: %s<%s, %s> = ",
getStrategy().getJavaIdentifier(foreignKey),
ForeignKey.class,
out.ref(getStrategy().getFullJavaClassName(foreignKey.getKeyTable(), Mode.RECORD)),
out.ref(getStrategy().getFullJavaClassName(foreignKey.getReferencedTable(), Mode.RECORD)));
else
out.print("static final %s<%s, %s> %s = ",
ForeignKey.class,
out.ref(getStrategy().getFullJavaClassName(foreignKey.getKeyTable(), Mode.RECORD)),
out.ref(getStrategy().getFullJavaClassName(foreignKey.getReferencedTable(), Mode.RECORD)),
getStrategy().getJavaIdentifier(foreignKey));
printCreateNonEmbeddableForeignKey(out, foreignKey);
if (scala || kotlin)
out.println();
else
out.println(";");
}
private void printCreateNonEmbeddableForeignKey(JavaWriter out, ForeignKeyDefinition foreignKey) {
if (scala)
out.print("%s.createForeignKey(%s, %s.name(\"%s\"), Array([[%s]]).asInstanceOf[Array[%s[%s, _] ] ], %s, Array([[%s]]).asInstanceOf[Array[%s[%s, _] ] ], %s)",
Internal.class,
out.ref(getStrategy().getFullJavaIdentifier(foreignKey.getKeyTable()), 2),
DSL.class,
@ -1102,11 +1191,7 @@ public class JavaGenerator extends AbstractGenerator {
foreignKey.enforced()
);
else if (kotlin)
out.println("val %s: %s<%s, %s> = %s.createForeignKey(%s, %s.name(\"%s\"), arrayOf([[%s]]), %s, arrayOf([[%s]]), %s)",
getStrategy().getJavaIdentifier(foreignKey),
ForeignKey.class,
out.ref(getStrategy().getFullJavaClassName(foreignKey.getKeyTable(), Mode.RECORD)),
out.ref(getStrategy().getFullJavaClassName(foreignKey.getReferencedTable(), Mode.RECORD)),
out.print("%s.createForeignKey(%s, %s.name(\"%s\"), arrayOf([[%s]]), %s, arrayOf([[%s]]), %s)",
Internal.class,
out.ref(getStrategy().getFullJavaIdentifier(foreignKey.getKeyTable()), 2),
DSL.class,
@ -1117,11 +1202,7 @@ public class JavaGenerator extends AbstractGenerator {
foreignKey.enforced()
);
else
out.println("static final %s<%s, %s> %s = %s.createForeignKey(%s, %s.name(\"%s\"), new %s[] { [[%s]] }, %s, new %s[] { [[%s]] }, %s);",
ForeignKey.class,
out.ref(getStrategy().getFullJavaClassName(foreignKey.getKeyTable(), Mode.RECORD)),
out.ref(getStrategy().getFullJavaClassName(foreignKey.getReferencedTable(), Mode.RECORD)),
getStrategy().getJavaIdentifier(foreignKey),
out.print("%s.createForeignKey(%s, %s.name(\"%s\"), new %s[] { [[%s]] }, %s, new %s[] { [[%s]] }, %s)",
Internal.class,
out.ref(getStrategy().getFullJavaIdentifier(foreignKey.getKeyTable()), 2),
DSL.class,
@ -1135,6 +1216,31 @@ public class JavaGenerator extends AbstractGenerator {
);
}
protected void generateRecords(SchemaDefinition schema) {
log.info("Generating table records");
@ -1226,35 +1332,44 @@ public class JavaGenerator extends AbstractGenerator {
if (generateInterfaces())
interfaces.add(out.ref(getStrategy().getFullJavaClassName(tableUdtOrEmbeddable, Mode.INTERFACE)));
if (scala) {
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition) {
out.println("private object %s {", className);
out.println("val FIELDS: Array[%s [_] ] = Array(", Field.class);
String separator = " ";
for (EmbeddableColumnDefinition column : ((EmbeddableDefinition) tableUdtOrEmbeddable).getColumns()) {
final String colIdentifier = out.ref(getStrategy().getFullJavaIdentifier(column.getColumn()), colRefSegments(column));
out.println("%s%s.field(%s.name(\"%s\"), %s.getDataType)", separator, DSL.class, DSL.class, column.getOutputName(), colIdentifier);
separator = ", ";
}
out.println(")");
out.println("}");
out.println();
}
}
if (scala)
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.println("class %s extends %s[%s](%s.FIELDS:_*)[[before= with ][separator= with ][%s]] {", className, baseClass, className, className, interfaces);
out.println("class %s extends %s[%s](%s.fields(%s.%s):_*)[[before= with ][separator= with ][%s]] {",
className,
baseClass,
className,
Internal.class,
out.ref(getStrategy().getFullJavaIdentifier(((EmbeddableDefinition) tableUdtOrEmbeddable).getTable()), 2),
getStrategy().getJavaIdentifier(tableUdtOrEmbeddable),
interfaces
);
else
out.println("class %s extends %s[%s](%s)[[before= with ][separator= with ][%s]] {", className, baseClass, className, tableIdentifier, interfaces);
out.println("class %s extends %s[%s](%s)[[before= with ][separator= with ][%s]] {",
className,
baseClass,
className,
tableIdentifier,
interfaces
);
else if (kotlin)
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.println("class %s() : %s<%s>(*FIELDS)[[before=, ][%s]] {", className, baseClass, className, interfaces);
out.println("class %s() : %s<%s>(*%s.fields(%s.%s))[[before=, ][%s]] {",
className,
baseClass,
className,
Internal.class,
out.ref(getStrategy().getFullJavaIdentifier(((EmbeddableDefinition) tableUdtOrEmbeddable).getTable()), 2),
getStrategy().getJavaIdentifier(tableUdtOrEmbeddable),
interfaces
);
else
out.println("class %s() : %s<%s>(%s)[[before=, ][%s]] {", className, baseClass, className, tableIdentifier, interfaces);
out.println("class %s() : %s<%s>(%s)[[before=, ][%s]] {",
className,
baseClass,
className,
tableIdentifier,
interfaces
);
else
out.println("public class %s extends %s<%s>[[before= implements ][%s]] {", className, baseClass, className, interfaces);
@ -1293,7 +1408,7 @@ public class JavaGenerator extends AbstractGenerator {
}
if (tableUdtOrEmbeddable instanceof TableDefinition) {
List<EmbeddableDefinition> embeddables = ((TableDefinition) tableUdtOrEmbeddable).getEmbeddables();
List<EmbeddableDefinition> embeddables = ((TableDefinition) tableUdtOrEmbeddable).getReferencedEmbeddables();
for (int i = 0; i < embeddables.size(); i++) {
EmbeddableDefinition embeddable = embeddables.get(i);
@ -1407,7 +1522,16 @@ public class JavaGenerator extends AbstractGenerator {
printDeprecationIfUnknownType(out, colTypeFull);
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.println("override def field%s: %s[%s] = %s.FIELDS(%s).asInstanceOf[%s [%s] ]", i, Field.class, colType, i - 1, className, Field.class, colType);
out.println("override def field%s: %s[%s] = %s.fields(%s.%s):_*.asInstanceOf[%s [%s] ]",
i,
Field.class,
colType,
Internal.class,
out.ref(getStrategy().getFullJavaIdentifier(((EmbeddableDefinition) tableUdtOrEmbeddable).getTable()), 2),
getStrategy().getJavaIdentifier(tableUdtOrEmbeddable),
Field.class,
colType
);
else
out.println("override def field%s: %s[%s] = %s", i, Field.class, colType, colIdentifier);
}
@ -1415,7 +1539,16 @@ public class JavaGenerator extends AbstractGenerator {
printDeprecationIfUnknownType(out, colTypeFull);
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.println("override fun field%s(): %s<%s?> = FIELDS[%s] as %s<%s>", i, Field.class, colType, i - 1, Field.class, colType);
out.println("override fun field%s(): %s<%s?> = %s.fields(%s.%s) as %s<%s>",
i,
Field.class,
colType,
Internal.class,
out.ref(getStrategy().getFullJavaIdentifier(((EmbeddableDefinition) tableUdtOrEmbeddable).getTable()), 2),
getStrategy().getJavaIdentifier(tableUdtOrEmbeddable),
Field.class,
colType
);
else
out.println("override fun field%s(): %s<%s?> = %s", i, Field.class, colType, colIdentifier);
}
@ -1597,47 +1730,19 @@ public class JavaGenerator extends AbstractGenerator {
printFromAndInto(out, tableUdtOrEmbeddable, Mode.RECORD);
// [#2530] TODO Implement this for Scala & Kotlin
if (scala) {}
else if (kotlin) {
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition) {
out.println();
out.println("private companion object {");
out.println("val FIELDS: Array<%s<*>> = arrayOf(", Field.class);
String separator = " ";
for (EmbeddableColumnDefinition column : ((EmbeddableDefinition) tableUdtOrEmbeddable).getColumns()) {
final String colIdentifier = out.ref(getStrategy().getFullJavaIdentifier(column.getColumn()), colRefSegments(column));
out.println("%s%s.field(%s.name(\"%s\"), %s.dataType)", separator, DSL.class, DSL.class, column.getOutputName(), colIdentifier);
separator = ", ";
}
out.println(")");
out.println("}");
}
}
else if (kotlin) {}
else {
out.header("Constructors");
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition) {
out.println();
out.println("private static final %s<?>[] FIELDS = {", Field.class);
for (EmbeddableColumnDefinition column : ((EmbeddableDefinition) tableUdtOrEmbeddable).getColumns()) {
final String colIdentifier = out.ref(getStrategy().getFullJavaIdentifier(column.getColumn()), colRefSegments(column));
out.println("%s.field(%s.name(\"%s\"), %s.getDataType()),", DSL.class, DSL.class, column.getOutputName(), colIdentifier);
}
out.println("};");
out.println();
}
out.javadoc("Create a detached %s", className);
out.println("public %s() {", className);
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.println("super(FIELDS);");
out.println("super(%s.fields(%s.%s));",
Internal.class,
out.ref(getStrategy().getFullJavaIdentifier(((EmbeddableDefinition) tableUdtOrEmbeddable).getTable()), 2),
getStrategy().getJavaIdentifier(tableUdtOrEmbeddable));
else
out.println("super(%s);", tableIdentifier);
out.println("}");
@ -4299,29 +4404,37 @@ public class JavaGenerator extends AbstractGenerator {
final String columnName = column.getName();
final List<String> converter = out.ref(list(column.getType(resolver()).getConverter()));
final List<String> binding = out.ref(list(column.getType(resolver()).getBinding()));
final String columnVisibility =
scala || kotlin ?
"" :
"public ";
if (!printDeprecationIfUnknownType(out, columnTypeFull))
out.javadoc("The column <code>%s</code>.[[before= ][%s]]", column.getQualifiedOutputName(), list(escapeEntities(comment(column))));
if (scala) {
out.println("val %s: %s[%s, %s] = createField(%s.name(\"%s\"), %s, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + ")",
columnId, TableField.class, recordType, columnType, DSL.class, columnName, columnTypeRef, escapeString(comment(column)), converter, binding);
out.println("%sval %s: %s[%s, %s] = createField(%s.name(\"%s\"), %s, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + ")",
columnVisibility, columnId, TableField.class, recordType, columnType, DSL.class, columnName, columnTypeRef, escapeString(comment(column)), converter, binding);
}
else if (kotlin) {
out.println("val %s: %s<%s, %s?> = createField(%s.name(\"%s\"), %s, this, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + ")",
columnId, TableField.class, recordType, columnType, DSL.class, columnName, columnTypeRef, escapeString(comment(column)), converter, binding);
out.println("%sval %s: %s<%s, %s?> = createField(%s.name(\"%s\"), %s, this, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + ")",
columnVisibility, columnId, TableField.class, recordType, columnType, DSL.class, columnName, columnTypeRef, escapeString(comment(column)), converter, binding);
}
else {
String isStatic = generateInstanceFields() ? "" : "static ";
String tableRef = generateInstanceFields() ? "this" : out.ref(getStrategy().getJavaIdentifier(table), 2);
out.println("public %sfinal %s<%s, %s> %s = createField(%s.name(\"%s\"), %s, %s, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + ");",
isStatic, TableField.class, recordType, columnType, columnId, DSL.class, columnName, columnTypeRef, tableRef, escapeString(comment(column)), converter, binding);
out.println("%s%sfinal %s<%s, %s> %s = createField(%s.name(\"%s\"), %s, %s, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + ");",
columnVisibility, isStatic, TableField.class, recordType, columnType, columnId, DSL.class, columnName, columnTypeRef, tableRef, escapeString(comment(column)), converter, binding);
}
}
// [#2530] Embeddable types
for (EmbeddableDefinition embeddable : table.getEmbeddables()) {
for (EmbeddableDefinition embeddable : table.getReferencedEmbeddables()) {
final String columnId = out.ref(getStrategy().getJavaIdentifier(embeddable), colRefSegments(null));
final String columnType = out.ref(getStrategy().getFullJavaClassName(embeddable, Mode.RECORD));
@ -4332,14 +4445,14 @@ public class JavaGenerator extends AbstractGenerator {
out.javadoc("The embeddable type <code>%s</code>.", embeddable.getOutputName());
if (scala)
out.println("val %s: %s[%s, %s] = %s.createEmbeddable(%s.name(\"%s\"), classOf[%s], this, [[%s]])",
columnId, TableField.class, recordType, columnType, Internal.class, DSL.class, embeddable.getName(), columnType, columnIds);
out.println("val %s: %s[%s, %s] = %s.createEmbeddable(%s.name(\"%s\"), classOf[%s], %s, this, [[%s]])",
columnId, TableField.class, recordType, columnType, Internal.class, DSL.class, escapeString(embeddable.getName()), columnType, embeddable.replacesFields(), columnIds);
else if (kotlin)
out.println("val %s: %s<%s, %s> = %s.createEmbeddable(%s.name(\"%s\"), %s::class.java, this, [[%s]])",
columnId, TableField.class, recordType, columnType, Internal.class, DSL.class, embeddable.getName(), columnType, columnIds);
out.println("val %s: %s<%s, %s> = %s.createEmbeddable(%s.name(\"%s\"), %s::class.java, %s, this, [[%s]])",
columnId, TableField.class, recordType, columnType, Internal.class, DSL.class, escapeString(embeddable.getName()), columnType, embeddable.replacesFields(), columnIds);
else
out.println("public final %s<%s, %s> %s = %s.createEmbeddable(%s.name(\"%s\"), %s.class, this, [[%s]]);",
TableField.class, recordType, columnType, columnId, Internal.class, DSL.class, embeddable.getName(), columnType, columnIds);
out.println("public final %s<%s, %s> %s = %s.createEmbeddable(%s.name(\"%s\"), %s.class, %s, this, [[%s]]);",
TableField.class, recordType, columnType, columnId, Internal.class, DSL.class, escapeString(embeddable.getName()), columnType, embeddable.replacesFields(), columnIds);
}
out.println();
@ -5073,7 +5186,10 @@ public class JavaGenerator extends AbstractGenerator {
for (EmbeddableDefinition embeddable : database.getEmbeddables(schema)) {
try {
generateEmbeddable(schema, embeddable);
// [#6124] [#10481] Don't generate embeddable types for FKs
if (embeddable.getTable().equals(embeddable.getReferencingTable()))
generateEmbeddable(schema, embeddable);
}
catch (Exception e) {
log.error("Error while generating embeddable " + embeddable, e);

View File

@ -38,12 +38,14 @@
package org.jooq.meta;
import static java.lang.Boolean.TRUE;
import static org.jooq.Log.Level.ERROR;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.FIREBIRD;
import static org.jooq.SQLDialect.SQLITE;
import static org.jooq.impl.DSL.falseCondition;
import static org.jooq.meta.AbstractTypedElementDefinition.customType;
import static org.jooq.tools.StringUtils.defaultIfBlank;
import static org.jooq.tools.StringUtils.defaultIfEmpty;
import java.io.File;
@ -155,6 +157,8 @@ public abstract class AbstractDatabase implements Database {
private String[] syntheticPrimaryKeys;
private String[] overridePrimaryKeys;
private String[] syntheticIdentities;
private boolean embeddablePrimaryKeys = false;
private boolean embeddableUniqueKeys = false;
private boolean supportsUnsignedTypes;
private boolean integerDisplayWidths;
private boolean ignoreProcedureReturnValues;
@ -208,8 +212,9 @@ public abstract class AbstractDatabase implements Database {
private transient Map<SchemaDefinition, List<ForeignKeyDefinition>> foreignKeysBySchema;
private transient Map<SchemaDefinition, List<CheckConstraintDefinition>> checkConstraintsBySchema;
private transient Map<SchemaDefinition, List<TableDefinition>> tablesBySchema;
private transient Map<SchemaDefinition, List<EmbeddableDefinition>> embeddablesBySchema;
private transient Map<TableDefinition, List<EmbeddableDefinition>> embeddablesByTable;
private transient Map<SchemaDefinition, List<EmbeddableDefinition>> embeddablesByDefiningSchema;
private transient Map<TableDefinition, List<EmbeddableDefinition>> embeddablesByDefiningTable;
private transient Map<TableDefinition, List<EmbeddableDefinition>> embeddablesByReferencingTable;
private transient Map<SchemaDefinition, List<EnumDefinition>> enumsBySchema;
private transient Map<SchemaDefinition, List<DomainDefinition>> domainsBySchema;
private transient Map<SchemaDefinition, List<UDTDefinition>> udtsBySchema;
@ -1533,10 +1538,8 @@ public abstract class AbstractDatabase implements Database {
return filterSchema(identities, schema, identitiesBySchema);
}
@Override
public final List<UniqueKeyDefinition> getUniqueKeys(SchemaDefinition schema) {
public final List<UniqueKeyDefinition> getUniqueKeys() {
if (uniqueKeys == null) {
uniqueKeys = new ArrayList<>();
@ -1549,14 +1552,19 @@ public abstract class AbstractDatabase implements Database {
sort(uniqueKeys);
}
if (uniqueKeysBySchema == null)
uniqueKeysBySchema = new LinkedHashMap<>();
return filterSchema(uniqueKeys, schema, uniqueKeysBySchema);
return uniqueKeys;
}
@Override
public final List<ForeignKeyDefinition> getForeignKeys(SchemaDefinition schema) {
public final List<UniqueKeyDefinition> getUniqueKeys(SchemaDefinition schema) {
if (uniqueKeysBySchema == null)
uniqueKeysBySchema = new LinkedHashMap<>();
return filterSchema(getUniqueKeys(), schema, uniqueKeysBySchema);
}
@Override
public final List<ForeignKeyDefinition> getForeignKeys() {
if (foreignKeys == null) {
foreignKeys = new ArrayList<>();
@ -1569,10 +1577,15 @@ public abstract class AbstractDatabase implements Database {
sort(foreignKeys);
}
return foreignKeys;
}
@Override
public final List<ForeignKeyDefinition> getForeignKeys(SchemaDefinition schema) {
if (foreignKeysBySchema == null)
foreignKeysBySchema = new LinkedHashMap<>();
return filterSchema(foreignKeys, schema, foreignKeysBySchema);
return filterSchema(getForeignKeys(), schema, foreignKeysBySchema);
}
@Override
@ -1596,7 +1609,7 @@ public abstract class AbstractDatabase implements Database {
}
@Override
public final List<TableDefinition> getTables(SchemaDefinition schema) {
public final List<TableDefinition> getTables() {
if (tables == null) {
tables = new ArrayList<>();
@ -1615,10 +1628,15 @@ public abstract class AbstractDatabase implements Database {
log.info("Tables excluded");
}
return tables;
}
@Override
public final List<TableDefinition> getTables(SchemaDefinition schema) {
if (tablesBySchema == null)
tablesBySchema = new LinkedHashMap<>();
return filterSchema(tables, schema, tablesBySchema);
return filterSchema(getTables(), schema, tablesBySchema);
}
@Override
@ -1776,37 +1794,41 @@ public abstract class AbstractDatabase implements Database {
}
@Override
public final List<EmbeddableDefinition> getEmbeddables() {
List<EmbeddableDefinition> result = new ArrayList<>();
public boolean embeddablePrimaryKeys() {
return embeddablePrimaryKeys;
}
for (SchemaDefinition schema : getSchemata()) {
for (TableDefinition table : getTables(schema)) {
for (Embeddable embeddable : getConfiguredEmbeddables()) {
List<ColumnDefinition> columns = new ArrayList<>();
List<String> names = new ArrayList<>();
@SuppressWarnings("unused")
@Override
public void setEmbeddablePrimaryKeys(boolean embeddablePrimaryKeys) {
for (EmbeddableField embeddableField : embeddable.getFields()) {
boolean matched = false;
for (ColumnDefinition column : table.getColumns())
if (matches(patterns.pattern(embeddableField.getExpression()), column))
if (matched)
log.warn("EmbeddableField configuration matched several columns in table " + table + ": " + embeddableField);
else
matched = columns.add(column) && names.add(defaultIfEmpty(embeddableField.getName(), column.getName()));
}
if (columns.size() == embeddable.getFields().size())
result.add(new DefaultEmbeddableDefinition(embeddable.getName(), names, table, columns));
}
}
}
if (embeddablePrimaryKeys)
log.info("Commercial feature", "Embeddable primary and unique keys are a commercial only feature. Please consider upgrading to the jOOQ Professional Edition");
return result;
this.embeddablePrimaryKeys = embeddablePrimaryKeys;
}
@Override
public final List<EmbeddableDefinition> getEmbeddables(SchemaDefinition schema) {
public boolean embeddableUniqueKeys() {
return embeddableUniqueKeys;
}
@SuppressWarnings("unused")
@Override
public void setEmbeddableUniqueKeys(boolean embeddableUniqueKeys) {
if (embeddableUniqueKeys)
log.info("Commercial feature", "Embeddable primary and unique keys are a commercial only feature. Please consider upgrading to the jOOQ Professional Edition");
this.embeddableUniqueKeys = embeddableUniqueKeys;
}
@Override
public final List<EmbeddableDefinition> getEmbeddables() {
if (embeddables == null) {
embeddables = new ArrayList<>();
@ -1814,7 +1836,7 @@ public abstract class AbstractDatabase implements Database {
onError(ERROR, "Error while fetching embeddables", new ExceptionRunnable() {
@Override
public void run() throws Exception {
List<EmbeddableDefinition> r = getEmbeddables();
List<EmbeddableDefinition> r = getEmbeddables0();
embeddables = sort(r);
// indexes = sort(filterExcludeInclude(r)); TODO Support include / exclude for indexes (and constraints!)
@ -1826,18 +1848,145 @@ public abstract class AbstractDatabase implements Database {
log.info("Embeddables excluded");
}
if (embeddablesBySchema == null)
embeddablesBySchema = new LinkedHashMap<>();
return embeddables;
}
return filterSchema(embeddables, schema, embeddablesBySchema);
@Override
public final List<EmbeddableDefinition> getEmbeddables(SchemaDefinition schema) {
if (embeddablesByDefiningSchema == null)
embeddablesByDefiningSchema = new LinkedHashMap<>();
return filterSchema(getEmbeddables(), schema, embeddablesByDefiningSchema);
}
@Override
public final List<EmbeddableDefinition> getEmbeddables(TableDefinition table) {
if (embeddablesByTable == null)
embeddablesByTable = new LinkedHashMap<>();
if (embeddablesByDefiningTable == null)
embeddablesByDefiningTable = new LinkedHashMap<>();
return filterTable(getEmbeddables(table.getSchema()), table, embeddablesByTable);
return filterTable(getEmbeddables(table.getSchema()), table, embeddablesByDefiningTable);
}
@Override
public final List<EmbeddableDefinition> getEmbeddablesByReferencingTable(TableDefinition table) {
if (embeddablesByReferencingTable == null)
embeddablesByReferencingTable = new LinkedHashMap<>();
return filterReferencingTable(getEmbeddables(), table, embeddablesByReferencingTable);
}
private final List<EmbeddableDefinition> getEmbeddables0() {
Map<Name, EmbeddableDefinition> result = new LinkedHashMap<>();
for (TableDefinition table : getTables()) {
for (Embeddable embeddable : getConfiguredEmbeddables()) {
List<ColumnDefinition> columns = new ArrayList<>();
List<String> names = new ArrayList<>();
for (EmbeddableField embeddableField : embeddable.getFields()) {
boolean matched = false;
for (ColumnDefinition column : table.getColumns())
if (matches(patterns.pattern(embeddableField.getExpression()), column))
if (matched)
log.warn("EmbeddableField configuration matched several columns in table " + table + ": " + embeddableField);
else
matched = columns.add(column) && names.add(defaultIfEmpty(embeddableField.getName(), column.getName()));
}
if (columns.size() == embeddable.getFields().size()) {
Name name = table.getQualifiedNamePart().append(embeddable.getName());
if (result.containsKey(name))
log.warn("Embeddable configuration", "Table " + table + " already has embeddable " + embeddable);
else
result.put(
name,
new DefaultEmbeddableDefinition(
embeddable.getName(),
table,
names,
defaultIfBlank(embeddable.getReferencingName(), embeddable.getName()),
table,
columns,
TRUE.equals(embeddable.isReplacesFields())
)
);
}
}
}
return new ArrayList<>(result.values());
}
@Override
@ -2219,6 +2368,30 @@ public abstract class AbstractDatabase implements Database {
return result;
}
private final <T extends EmbeddableDefinition> List<T> filterReferencingTable(List<T> definitions, TableDefinition table, Map<TableDefinition, List<T>> cache) {
List<T> result = cache.get(table);
if (result == null) {
result = filterReferencingTable(definitions, table);
cache.put(table, result);
}
return result;
}
private final <T extends EmbeddableDefinition> List<T> filterReferencingTable(List<T> definitions, TableDefinition table) {
if (table == null)
return definitions;
List<T> result = new ArrayList<>();
for (T definition : definitions)
if (definition.getReferencingTable().equals(table))
result.add(definition);
return result;
}
@Override
public final <T extends Definition> List<T> filterExcludeInclude(List<T> definitions) {
List<T> result = filterExcludeInclude(definitions, excludes, includes, filters);
@ -2319,7 +2492,7 @@ public abstract class AbstractDatabase implements Database {
onError(ERROR, "Error while fetching unique keys", new ExceptionRunnable() {
@Override
public void run() throws Exception {
loadUniqueKeys(result);
loadUniqueKeys(result);
}
});
}
@ -2328,7 +2501,7 @@ public abstract class AbstractDatabase implements Database {
onError(ERROR, "Error while fetching foreign keys", new ExceptionRunnable() {
@Override
public void run() throws Exception {
loadForeignKeys(result);
loadForeignKeys(result);
}
});
}

View File

@ -80,6 +80,11 @@ implements TableDefinition {
return getDatabase().getEmbeddables(this);
}
@Override
public final List<EmbeddableDefinition> getReferencedEmbeddables() {
return getDatabase().getEmbeddablesByReferencingTable(this);
}
@Override
public final UniqueKeyDefinition getPrimaryKey() {
for (ColumnDefinition column : getColumns())

View File

@ -40,6 +40,8 @@ package org.jooq.meta;
import java.util.List;
// ...
/**
* An interface defining a column of a table.
*
@ -76,4 +78,22 @@ public interface ColumnDefinition extends TypedElementDefinition<TableDefinition
*/
@Deprecated
boolean isNullable();
}

View File

@ -114,11 +114,21 @@ public interface Database extends AutoCloseable {
*/
List<IndexDefinition> getIndexes(TableDefinition schema);
/**
* The unique keys contained in this database.
*/
List<UniqueKeyDefinition> getUniqueKeys();
/**
* The unique keys contained in this database.
*/
List<UniqueKeyDefinition> getUniqueKeys(SchemaDefinition schema);
/**
* The foreign keys contained in this database.
*/
List<ForeignKeyDefinition> getForeignKeys();
/**
* The foreign keys contained in this database.
*/
@ -129,6 +139,11 @@ public interface Database extends AutoCloseable {
*/
List<CheckConstraintDefinition> getCheckConstraints(SchemaDefinition schema);
/**
* The tables contained in this database.
*/
List<TableDefinition> getTables();
/**
* The tables contained in this database.
*/
@ -160,15 +175,20 @@ public interface Database extends AutoCloseable {
List<EmbeddableDefinition> getEmbeddables();
/**
* Get all embeddables for a given schema.
* Get all embeddables for a given defining schema.
*/
List<EmbeddableDefinition> getEmbeddables(SchemaDefinition schema);
/**
* Get all embeddables for a given table.
* Get all embeddables for a given defining table.
*/
List<EmbeddableDefinition> getEmbeddables(TableDefinition table);
/**
* Get all embeddables for a given referencing table.
*/
List<EmbeddableDefinition> getEmbeddablesByReferencingTable(TableDefinition table);
/**
* The enum UDTs defined in this database.
*/
@ -868,6 +888,26 @@ public interface Database extends AutoCloseable {
*/
List<Embeddable> getConfiguredEmbeddables();
/**
* Whether embeddable types for primary keys should be generated.
*/
boolean embeddablePrimaryKeys();
/**
* Whether embeddable types for primary keys should be generated.
*/
void setEmbeddablePrimaryKeys(boolean embeddablePrimaryKeys);
/**
* Whether embeddable types for unique keys should be generated.
*/
boolean embeddableUniqueKeys();
/**
* Whether embeddable types for unique keys should be generated.
*/
void setEmbeddableUniqueKeys(boolean embeddableUniqueKeys);
/**
* Get the dialect for this database.
*/

View File

@ -40,6 +40,8 @@ package org.jooq.meta;
import static java.util.Collections.singletonList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jooq.tools.JooqLogger;
@ -53,9 +55,11 @@ public class DefaultColumnDefinition
extends AbstractTypedElementDefinition<TableDefinition>
implements ColumnDefinition {
private static final JooqLogger log = JooqLogger.getLogger(DefaultColumnDefinition.class);
private final int position;
private final boolean isIdentity;
private static final JooqLogger log = JooqLogger.getLogger(DefaultColumnDefinition.class);
private final int position;
private final boolean isIdentity;
private transient List<EmbeddableDefinition> containedInEmbeddables;
private transient EmbeddableDefinition replacedByEmbeddable;
public DefaultColumnDefinition(TableDefinition table, String name, int position, DataTypeDefinition type,
boolean isIdentity, String comment) {
@ -110,4 +114,35 @@ public class DefaultColumnDefinition
public final boolean isNullable() {
return getType().isNullable();
}
}

View File

@ -41,6 +41,8 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.jooq.tools.JooqLogger;
/**
* @author Lukas Eder
*/
@ -48,28 +50,74 @@ public class DefaultEmbeddableDefinition
extends AbstractElementContainerDefinition<EmbeddableColumnDefinition>
implements EmbeddableDefinition {
private final List<String> columnNames;
private final TableDefinition table;
private static final JooqLogger log = JooqLogger.getLogger(DefaultEmbeddableDefinition.class);
private final TableDefinition definingTable;
private final List<String> definingColumnNames;
private final String referencingName;
private final TableDefinition referencingTable;
private final List<EmbeddableColumnDefinition> embeddableColumns;
private final boolean replacesFields;
public DefaultEmbeddableDefinition(String name, List<String> columnNames, TableDefinition table, List<ColumnDefinition> columns) {
super(table.getSchema(), name, "");
@SuppressWarnings("unused")
public DefaultEmbeddableDefinition(
String definingName,
TableDefinition definingTable,
List<String> definingColumnNames,
String referencingName,
TableDefinition referencingTable,
List<ColumnDefinition> referencingColumns,
boolean replacesFields
) {
super(definingTable.getSchema(), definingName, "");
this.columnNames = columnNames;
this.table = table;
this.definingColumnNames = definingColumnNames;
this.definingTable = definingTable;
this.referencingName = referencingName;
this.referencingTable = referencingTable;
this.embeddableColumns = new ArrayList<>();
this.replacesFields = replacesFields;
for (int i = 0; i < columns.size(); i++)
embeddableColumns.add(new DefaultEmbeddableColumnDefinition(this, columnNames.get(i), columns.get(i), i));
log.info("Commercial feature", "Embeddables replacing fields is a commercial only feature. Please upgrade to the jOOQ Professional Edition");
for (int i = 0; i < referencingColumns.size(); i++)
embeddableColumns.add(new DefaultEmbeddableColumnDefinition(this, definingColumnNames.get(i), referencingColumns.get(i), i));
}
@Override
public final TableDefinition getTable() {
return table;
return getDefiningTable();
}
@Override
protected List<EmbeddableColumnDefinition> getElements0() throws SQLException {
public final TableDefinition getDefiningTable() {
return definingTable;
}
@Override
public final String getReferencingName() {
return getReferencingInputName();
}
@Override
public final String getReferencingInputName() {
return referencingName;
}
@Override
public final String getReferencingOutputName() {
return referencingName;
}
@Override
public final TableDefinition getReferencingTable() {
return referencingTable;
}
@Override
protected final List<EmbeddableColumnDefinition> getElements0() throws SQLException {
return embeddableColumns;
}
@ -92,4 +140,9 @@ public class DefaultEmbeddableDefinition
public final EmbeddableColumnDefinition getColumn(int columnIndex) {
return getElement(columnIndex);
}
@Override
public final boolean replacesFields() {
return replacesFields;
}
}

View File

@ -44,9 +44,9 @@ import java.util.Set;
public class DefaultForeignKeyDefinition extends AbstractConstraintDefinition implements ForeignKeyDefinition {
private final List<ColumnDefinition> fkColumns;
private final List<ColumnDefinition> ukColumns;
private final UniqueKeyDefinition uk;
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);
@ -75,6 +75,11 @@ public class DefaultForeignKeyDefinition extends AbstractConstraintDefinition im
return uk;
}
@Override
public UniqueKeyDefinition resolveReferencedKey() {
return uk.resolveReferencedKey();
}
@Override
public TableDefinition getReferencedTable() {
return uk.getTable();

View File

@ -40,11 +40,16 @@ package org.jooq.meta;
import java.util.ArrayList;
import java.util.List;
import org.jooq.tools.JooqLogger;
public class DefaultUniqueKeyDefinition extends AbstractConstraintDefinition implements UniqueKeyDefinition {
private static final JooqLogger log = JooqLogger.getLogger(DefaultUniqueKeyDefinition.class);
private final List<ForeignKeyDefinition> foreignKeys;
private final List<ColumnDefinition> keyColumns;
private final boolean isPrimaryKey;
private transient boolean resolvedUKCalculated;
private transient UniqueKeyDefinition resolvedUK;
public DefaultUniqueKeyDefinition(SchemaDefinition schema, String name, TableDefinition table, boolean isPrimaryKey) {
this(schema, name, table, isPrimaryKey, true);
@ -72,4 +77,28 @@ public class DefaultUniqueKeyDefinition extends AbstractConstraintDefinition imp
public List<ForeignKeyDefinition> getForeignKeys() {
return foreignKeys;
}
@Override
public final UniqueKeyDefinition resolveReferencedKey() {
if (!resolvedUKCalculated) {
resolvedUKCalculated = true;
ForeignKeyDefinition candidate = null;
for (ForeignKeyDefinition fk : getTable().getForeignKeys()) {
if (keyColumns.equals(fk.getKeyColumns())) {
if (candidate == null) {
candidate = fk;
}
else {
log.info("Cannot resolve key", (isPrimaryKey ? "Primary" : "Unique") + " key coincides with at least two foreign keys: " + candidate + " and " + fk);
return null;
}
}
}
resolvedUK = candidate == null ? this : candidate.resolveReferencedKey();
}
return resolvedUK;
}
}

View File

@ -48,23 +48,56 @@ import java.util.List;
public interface EmbeddableDefinition extends TableElementDefinition {
/**
* All columns in the type, table or view.
* The table defining the embeddable (same as {@link #getTable()}).
*/
TableDefinition getDefiningTable();
/**
* The referencing name of this embeddable, if it differs from the defining
* name ({@link #getName()}).
*/
String getReferencingName();
/**
* The referencing input name of this embeddable, if it differs from the defining
* name ({@link #getInputName()}).
*/
String getReferencingInputName();
/**
* The referencing output name of this embeddable, if it differs from the defining
* name ({@link #getOutputName()}).
*/
String getReferencingOutputName();
/**
* The table referencing the embeddable.
*/
TableDefinition getReferencingTable();
/**
* All referencing columns in the type, table or view.
*/
List<EmbeddableColumnDefinition> getColumns();
/**
* Get a column in this type by its name.
* Get a referencing column in this type by its name.
*/
EmbeddableColumnDefinition getColumn(String columnName);
/**
* Get a column in this type by its name.
* Get a referencing column in this type by its name.
*/
EmbeddableColumnDefinition getColumn(String columnName, boolean ignoreCase);
/**
* Get a column in this type by its index (starting at 0).
* Get a referencing column in this type by its index (starting at 0).
*/
EmbeddableColumnDefinition getColumn(int columnIndex);
/**
* Whether this embeddable replaces the fields it represents.
*/
boolean replacesFields();
}

View File

@ -64,6 +64,16 @@ public interface ForeignKeyDefinition extends ConstraintDefinition {
*/
UniqueKeyDefinition getReferencedKey();
/**
* Resolve a referenced key.
* <p>
* If {@link #getReferencedKey()} coincides itself with a foreign key,
* resolve that foreign key recursively. In case of ambiguity (two foreign
* keys coinciding with a single unique key), this returns
* <code>null</code>.
*/
UniqueKeyDefinition resolveReferencedKey();
/**
* The definition of the referenced table.
*/

View File

@ -71,10 +71,15 @@ public interface TableDefinition extends Definition {
ColumnDefinition getColumn(int columnIndex);
/**
* All embeddable types in the table.
* All embeddable types in this defining table.
*/
List<EmbeddableDefinition> getEmbeddables();
/**
* All embeddable types in this referencing table.
*/
List<EmbeddableDefinition> getReferencedEmbeddables();
/**
* Get the indexes for this table.
*/

View File

@ -63,4 +63,14 @@ public interface UniqueKeyDefinition extends ConstraintDefinition {
* The foreign keys referencing this primary key
*/
List<ForeignKeyDefinition> getForeignKeys();
/**
* Resolve a referenced key.
* <p>
* If this key coincides with a foreign key, resolve that foreign key
* recursively. In case of ambiguity (two foreign keys coinciding with a
* single unique key), this returns <code>null</code>.
*/
UniqueKeyDefinition resolveReferencedKey();
}

View File

@ -133,6 +133,10 @@ public class Database implements Serializable, XMLAppendable
@XmlElement(defaultValue = "")
@XmlJavaTypeAdapter(StringAdapter.class)
protected String orderProvider = "";
@XmlElement(defaultValue = "false")
protected Boolean embeddablePrimaryKeys = false;
@XmlElement(defaultValue = "false")
protected Boolean embeddableUniqueKeys = false;
@XmlElement(defaultValue = "true")
protected Boolean forceIntegerTypesOnZeroScaleDecimals = true;
protected Boolean tableValuedFunctions;
@ -1355,6 +1359,54 @@ public class Database implements Serializable, XMLAppendable
this.orderProvider = value;
}
/**
* Whether wrapper types should be generated for primary key columns, and for their referencing foreign keys.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isEmbeddablePrimaryKeys() {
return embeddablePrimaryKeys;
}
/**
* Sets the value of the embeddablePrimaryKeys property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setEmbeddablePrimaryKeys(Boolean value) {
this.embeddablePrimaryKeys = value;
}
/**
* Whether wrapper types should be generated for unique key columns, and for their referencing foreign keys.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isEmbeddableUniqueKeys() {
return embeddableUniqueKeys;
}
/**
* Sets the value of the embeddableUniqueKeys property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setEmbeddableUniqueKeys(Boolean value) {
this.embeddableUniqueKeys = value;
}
/**
* Historically, zero-scale decimal types are generated as their most appropriate, corresponding integer type (e.g. NUMBER(2, 0) and less: Byte). This allows for turning off this feature. In case of conflict between this rule and actual {@link #getForcedTypes()}, the latter will win.
*
@ -1989,6 +2041,16 @@ public class Database implements Serializable, XMLAppendable
return this;
}
public Database withEmbeddablePrimaryKeys(Boolean value) {
setEmbeddablePrimaryKeys(value);
return this;
}
public Database withEmbeddableUniqueKeys(Boolean value) {
setEmbeddableUniqueKeys(value);
return this;
}
public Database withForceIntegerTypesOnZeroScaleDecimals(Boolean value) {
setForceIntegerTypesOnZeroScaleDecimals(value);
return this;
@ -2215,6 +2277,8 @@ public class Database implements Serializable, XMLAppendable
builder.append("schemaVersionProvider", schemaVersionProvider);
builder.append("catalogVersionProvider", catalogVersionProvider);
builder.append("orderProvider", orderProvider);
builder.append("embeddablePrimaryKeys", embeddablePrimaryKeys);
builder.append("embeddableUniqueKeys", embeddableUniqueKeys);
builder.append("forceIntegerTypesOnZeroScaleDecimals", forceIntegerTypesOnZeroScaleDecimals);
builder.append("tableValuedFunctions", tableValuedFunctions);
builder.append("logSlowQueriesAfterSeconds", logSlowQueriesAfterSeconds);
@ -2634,6 +2698,24 @@ public class Database implements Serializable, XMLAppendable
return false;
}
}
if (embeddablePrimaryKeys == null) {
if (other.embeddablePrimaryKeys!= null) {
return false;
}
} else {
if (!embeddablePrimaryKeys.equals(other.embeddablePrimaryKeys)) {
return false;
}
}
if (embeddableUniqueKeys == null) {
if (other.embeddableUniqueKeys!= null) {
return false;
}
} else {
if (!embeddableUniqueKeys.equals(other.embeddableUniqueKeys)) {
return false;
}
}
if (forceIntegerTypesOnZeroScaleDecimals == null) {
if (other.forceIntegerTypesOnZeroScaleDecimals!= null) {
return false;
@ -2783,6 +2865,8 @@ public class Database implements Serializable, XMLAppendable
result = ((prime*result)+((schemaVersionProvider == null)? 0 :schemaVersionProvider.hashCode()));
result = ((prime*result)+((catalogVersionProvider == null)? 0 :catalogVersionProvider.hashCode()));
result = ((prime*result)+((orderProvider == null)? 0 :orderProvider.hashCode()));
result = ((prime*result)+((embeddablePrimaryKeys == null)? 0 :embeddablePrimaryKeys.hashCode()));
result = ((prime*result)+((embeddableUniqueKeys == null)? 0 :embeddableUniqueKeys.hashCode()));
result = ((prime*result)+((forceIntegerTypesOnZeroScaleDecimals == null)? 0 :forceIntegerTypesOnZeroScaleDecimals.hashCode()));
result = ((prime*result)+((tableValuedFunctions == null)? 0 :tableValuedFunctions.hashCode()));
result = ((prime*result)+((logSlowQueriesAfterSeconds == null)? 0 :logSlowQueriesAfterSeconds.hashCode()));

View File

@ -35,12 +35,16 @@ public class Embeddable implements Serializable, XMLAppendable
private final static long serialVersionUID = 31400L;
@XmlJavaTypeAdapter(StringAdapter.class)
protected String name;
@XmlJavaTypeAdapter(StringAdapter.class)
protected String referencingName;
@XmlElement(defaultValue = "false")
protected Boolean replacesFields = false;
@XmlElementWrapper(name = "fields")
@XmlElement(name = "field")
protected List<EmbeddableField> fields;
/**
* The name of the embeddable type
* The defining name of the embeddable type.
*
*/
public String getName() {
@ -48,13 +52,53 @@ public class Embeddable implements Serializable, XMLAppendable
}
/**
* The name of the embeddable type
* The defining name of the embeddable type.
*
*/
public void setName(String value) {
this.name = value;
}
/**
* The referencing name of the embeddable type, defaulting to the defining name.
*
*/
public String getReferencingName() {
return referencingName;
}
/**
* The referencing name of the embeddable type, defaulting to the defining name.
*
*/
public void setReferencingName(String value) {
this.referencingName = value;
}
/**
* Specify that the embeddable field replaces its underlying fields in code generation output, and when working with asterisks.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isReplacesFields() {
return replacesFields;
}
/**
* Sets the value of the replacesFields property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setReplacesFields(Boolean value) {
this.replacesFields = value;
}
public List<EmbeddableField> getFields() {
if (fields == null) {
fields = new ArrayList<EmbeddableField>();
@ -67,7 +111,7 @@ public class Embeddable implements Serializable, XMLAppendable
}
/**
* The name of the embeddable type
* The defining name of the embeddable type.
*
*/
public Embeddable withName(String value) {
@ -75,6 +119,20 @@ public class Embeddable implements Serializable, XMLAppendable
return this;
}
/**
* The referencing name of the embeddable type, defaulting to the defining name.
*
*/
public Embeddable withReferencingName(String value) {
setReferencingName(value);
return this;
}
public Embeddable withReplacesFields(Boolean value) {
setReplacesFields(value);
return this;
}
public Embeddable withFields(EmbeddableField... values) {
if (values!= null) {
for (EmbeddableField value: values) {
@ -99,6 +157,8 @@ public class Embeddable implements Serializable, XMLAppendable
@Override
public final void appendTo(XMLBuilder builder) {
builder.append("name", name);
builder.append("referencingName", referencingName);
builder.append("replacesFields", replacesFields);
builder.append("fields", "field", fields);
}
@ -130,6 +190,24 @@ public class Embeddable implements Serializable, XMLAppendable
return false;
}
}
if (referencingName == null) {
if (other.referencingName!= null) {
return false;
}
} else {
if (!referencingName.equals(other.referencingName)) {
return false;
}
}
if (replacesFields == null) {
if (other.replacesFields!= null) {
return false;
}
} else {
if (!replacesFields.equals(other.replacesFields)) {
return false;
}
}
if (fields == null) {
if (other.fields!= null) {
return false;
@ -147,6 +225,8 @@ public class Embeddable implements Serializable, XMLAppendable
final int prime = 31;
int result = 1;
result = ((prime*result)+((name == null)? 0 :name.hashCode()));
result = ((prime*result)+((referencingName == null)? 0 :referencingName.hashCode()));
result = ((prime*result)+((replacesFields == null)? 0 :replacesFields.hashCode()));
result = ((prime*result)+((fields == null)? 0 :fields.hashCode()));
return result;
}

View File

@ -190,8 +190,6 @@ public class Generate implements Serializable, XMLAppendable
protected Boolean emptySchemas = false;
@XmlElement(defaultValue = "true")
protected Boolean javaTimeTypes = true;
@XmlElement(defaultValue = "false")
protected Boolean primaryKeyTypes = false;
@XmlElement(defaultValue = "\\n")
@XmlJavaTypeAdapter(StringAdapter.class)
protected String newline = "\\n";
@ -2092,30 +2090,6 @@ public class Generate implements Serializable, XMLAppendable
this.javaTimeTypes = value;
}
/**
* Whether wrapper types should be generated for primary key columns, and for their referencing foreign keys.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isPrimaryKeyTypes() {
return primaryKeyTypes;
}
/**
* Sets the value of the primaryKeyTypes property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setPrimaryKeyTypes(Boolean value) {
this.primaryKeyTypes = value;
}
/**
* The newline characters to be used in generated code. Whitespace characters can be used, e.g. \n, \r\n
*
@ -2568,11 +2542,6 @@ public class Generate implements Serializable, XMLAppendable
return this;
}
public Generate withPrimaryKeyTypes(Boolean value) {
setPrimaryKeyTypes(value);
return this;
}
/**
* The newline characters to be used in generated code. Whitespace characters can be used, e.g. \n, \r\n
*
@ -2672,7 +2641,6 @@ public class Generate implements Serializable, XMLAppendable
builder.append("emptyCatalogs", emptyCatalogs);
builder.append("emptySchemas", emptySchemas);
builder.append("javaTimeTypes", javaTimeTypes);
builder.append("primaryKeyTypes", primaryKeyTypes);
builder.append("newline", newline);
builder.append("indentation", indentation);
}
@ -3407,15 +3375,6 @@ public class Generate implements Serializable, XMLAppendable
return false;
}
}
if (primaryKeyTypes == null) {
if (other.primaryKeyTypes!= null) {
return false;
}
} else {
if (!primaryKeyTypes.equals(other.primaryKeyTypes)) {
return false;
}
}
if (newline == null) {
if (other.newline!= null) {
return false;
@ -3520,7 +3479,6 @@ public class Generate implements Serializable, XMLAppendable
result = ((prime*result)+((emptyCatalogs == null)? 0 :emptyCatalogs.hashCode()));
result = ((prime*result)+((emptySchemas == null)? 0 :emptySchemas.hashCode()));
result = ((prime*result)+((javaTimeTypes == null)? 0 :javaTimeTypes.hashCode()));
result = ((prime*result)+((primaryKeyTypes == null)? 0 :primaryKeyTypes.hashCode()));
result = ((prime*result)+((newline == null)? 0 :newline.hashCode()));
result = ((prime*result)+((indentation == null)? 0 :indentation.hashCode()));
return result;

View File

@ -793,6 +793,14 @@ This comparator can be used to influence the order of any object that is produce
<element name="embeddables" type="tns:Embeddables" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Configure embeddable types.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="embeddablePrimaryKeys" type="boolean" default="false" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether wrapper types should be generated for primary key columns, and for their referencing foreign keys.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="embeddableUniqueKeys" type="boolean" default="false" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether wrapper types should be generated for unique key columns, and for their referencing foreign keys.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="customTypes" type="tns:CustomTypes" minOccurs="0" maxOccurs="1">
<annotation>
@ -1005,12 +1013,20 @@ for Oracle.]]></jxb:javadoc></jxb:property></appinfo></annotation>
<annotation><appinfo><jxb:class><jxb:javadoc><![CDATA[An embeddable type declaration]]></jxb:javadoc></jxb:class></appinfo></annotation>
<all>
<element name="name" type="string" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The name of the embeddable type]]></jxb:javadoc></jxb:property></appinfo></annotation>
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The defining name of the embeddable type.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="referencingName" type="string" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The referencing name of the embeddable type, defaulting to the defining name.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="fields" type="tns:EmbeddableFields" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A set of field specifications for the embeddable type.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="replacesFields" type="boolean" minOccurs="0" maxOccurs="1" default="false">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Specify that the embeddable field replaces its underlying fields in code generation output, and when working with asterisks.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
</all>
</complexType>
@ -1497,10 +1513,6 @@ source code generator, rather than JDBC's java.sql types.
<p>
This flag is ignored in the commercial Java 6 distribution of jOOQ 3.9+ ]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="primaryKeyTypes" type="boolean" default="false" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether wrapper types should be generated for primary key columns, and for their referencing foreign keys.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="newline" type="string" default="\n" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The newline characters to be used in generated code. Whitespace characters can be used, e.g. \n, \r\n]]></jxb:javadoc></jxb:property></appinfo></annotation>

View File

@ -41,6 +41,7 @@ import org.jooq.Converter;
import org.jooq.EmbeddableRecord;
import org.jooq.Field;
import org.jooq.Row;
import org.jooq.TableField;
/**
* A record implementation for a record originating from a single table
@ -61,6 +62,10 @@ public class EmbeddableRecordImpl<R extends EmbeddableRecord<R>> extends Abstrac
super(fields);
}
public EmbeddableRecordImpl(TableField<?, ?>... fields) {
super(fields);
}
@SuppressWarnings("unchecked")
@Override
public final <T> R with(Field<T> field, T value) {

View File

@ -56,15 +56,17 @@ final class EmbeddableTableField<R extends Record, T extends Record> extends Abs
* Generated UID
*/
private static final long serialVersionUID = -7105430856294526440L;
final Class<T> recordType;
final boolean replacesFields;
final Table<R> table;
final TableField<R, ?>[] fields;
final Class<T> recordType;
EmbeddableTableField(Name name, Class<T> recordType, Table<R> table, TableField<R, ?>[] fields) {
EmbeddableTableField(Name name, Class<T> recordType, boolean replacesFields, Table<R> table, TableField<R, ?>[] fields) {
super(name, new DefaultDataType<>(SQLDialect.DEFAULT, recordType, name.last()));
this.table = table;
this.recordType = recordType;
this.replacesFields = replacesFields;
this.table = table;
this.fields = fields;
}

View File

@ -42,6 +42,7 @@ import org.jooq.Check;
import org.jooq.Converter;
import org.jooq.DataType;
import org.jooq.Domain;
import org.jooq.EmbeddableRecord;
import org.jooq.ForeignKey;
import org.jooq.Identity;
import org.jooq.Index;
@ -76,9 +77,19 @@ public final class Internal {
/**
* Factory method for embeddable types.
*/
@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) {
return new EmbeddableTableField<>(name, recordType, table, fields);
return createEmbeddable(name, recordType, false, table, fields);
}
/**
* Factory method for embeddable types.
*/
@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) {
return new EmbeddableTableField<>(name, recordType, replacesFields, table, fields);
}
/**
@ -123,6 +134,14 @@ public final class Internal {
return new UniqueKeyImpl<>(table, name, fields, enforced);
}
/**
* Factory method for unique keys.
*/
@NotNull
public static final <R extends Record, ER extends EmbeddableRecord<ER>> UniqueKey<R> createUniqueKey(Table<R> table, Name name, TableField<R, ER> embeddableField, boolean enforced) {
return createUniqueKey(table, name, fields(embeddableField), enforced);
}
/**
* Factory method for foreign keys.
*
@ -148,6 +167,14 @@ public final class Internal {
return result;
}
/**
* Factory method for foreign keys.
*/
@NotNull
public static final <R extends Record, U extends Record, ER extends EmbeddableRecord<ER>> ForeignKey<R, U> createForeignKey(Table<R> table, Name name, TableField<R, ER> fkEmbeddableField, UniqueKey<U> uk, TableField<U, ER> ukEmbeddableField, boolean enforced) {
return createForeignKey(table, name, fields(fkEmbeddableField), uk, fields(ukEmbeddableField), enforced);
}
/**
* Factory method for sequences.
*/
@ -322,4 +349,12 @@ public final class Internal {
public static final <R extends Record, U extends Record> ForeignKey<R, U> createForeignKey(UniqueKey<U> key, Table<R> table, String name, TableField<R, ?>[] fields, boolean enforced) {
return createForeignKey(table, DSL.name(name), fields, key, key.getFieldsArray(), enforced);
}
/**
* Get the fields of an embeddable type.
*/
@NotNull
public static final <R extends Record, ER extends EmbeddableRecord<ER>> TableField<R, ?>[] fields(TableField<R, ER> embeddableField) {
return ((EmbeddableTableField<R, ER>) embeddableField).fields;
}
}