[jOOQ/jOOQ#15251] Add support for synthetic DEFAULT expressions

This commit is contained in:
Lukas Eder 2024-05-17 11:33:52 +02:00
parent 58a152db44
commit cb18d58ba7
10 changed files with 441 additions and 1 deletions

View File

@ -765,6 +765,12 @@ public class MetaExtensions {
setIdentities(l);
}
public void defaults(Action<SyntheticDefaultTypeListExtension> action) {
SyntheticDefaultTypeListExtension l = objects.newInstance(SyntheticDefaultTypeListExtension.class, objects);
action.execute(l);
setDefaults(l);
}
public void enums(Action<SyntheticEnumTypeListExtension> action) {
SyntheticEnumTypeListExtension l = objects.newInstance(SyntheticEnumTypeListExtension.class, objects);
action.execute(l);
@ -842,6 +848,16 @@ public class MetaExtensions {
}
}
public static class SyntheticDefaultTypeExtension extends SyntheticDefaultType {
final ObjectFactory objects;
@Inject
public SyntheticDefaultTypeExtension(ObjectFactory objects) {
this.objects = objects;
}
}
public static class SyntheticEnumTypeExtension extends SyntheticEnumType {
final ObjectFactory objects;
@ -1468,6 +1484,22 @@ public class MetaExtensions {
}
}
public static class SyntheticDefaultTypeListExtension extends ArrayList<SyntheticDefaultType> {
final ObjectFactory objects;
@Inject
public SyntheticDefaultTypeListExtension(ObjectFactory objects) {
this.objects = objects;
}
public void default_(Action<SyntheticDefaultTypeExtension> action) {
SyntheticDefaultTypeExtension o = objects.newInstance(SyntheticDefaultTypeExtension.class, objects);
action.execute(o);
add(o);
}
}
public static class SyntheticEnumTypeListExtension extends ArrayList<SyntheticEnumType> {
final ObjectFactory objects;

View File

@ -567,6 +567,17 @@ fun MutableList<SyntheticIdentityType>.identity(block: SyntheticIdentityType.()
add(e)
}
fun SyntheticObjectsType.defaults(block: MutableList<SyntheticDefaultType>.() -> Unit) {
block(defaults)
}
@JvmName("mutableListSyntheticDefaultType")
fun MutableList<SyntheticDefaultType>.default_(block: SyntheticDefaultType.() -> Unit) {
val e = SyntheticDefaultType()
block(e)
add(e)
}
fun SyntheticObjectsType.enums(block: MutableList<SyntheticEnumType>.() -> Unit) {
block(enums)
}

View File

@ -143,6 +143,7 @@ import org.jooq.meta.jaxb.RegexFlag;
import org.jooq.meta.jaxb.SchemaMappingType;
import org.jooq.meta.jaxb.SyntheticColumnType;
import org.jooq.meta.jaxb.SyntheticDaoType;
import org.jooq.meta.jaxb.SyntheticDefaultType;
import org.jooq.meta.jaxb.SyntheticEnumType;
import org.jooq.meta.jaxb.SyntheticForeignKeyType;
import org.jooq.meta.jaxb.SyntheticIdentityType;
@ -253,6 +254,8 @@ public abstract class AbstractDatabase implements Database {
private Set<SyntheticReadonlyRowidType> unusedSyntheticReadonlyRowids = new HashSet<>();
private List<SyntheticIdentityType> configuredSyntheticIdentities = new ArrayList<>();
private Set<SyntheticIdentityType> unusedSyntheticIdentities = new HashSet<>();
private List<SyntheticDefaultType> configuredSyntheticDefaults = new ArrayList<>();
private Set<SyntheticDefaultType> unusedSyntheticDefaults = new HashSet<>();
private List<SyntheticEnumType> configuredSyntheticEnums = new ArrayList<>();
private Set<SyntheticEnumType> unusedSyntheticEnums = new HashSet<>();
private List<SyntheticPrimaryKeyType> configuredSyntheticPrimaryKeys = new ArrayList<>();
@ -3573,6 +3576,7 @@ public abstract class AbstractDatabase implements Database {
getConfiguredSyntheticReadonlyColumns().addAll(configuredSyntheticObjects.getReadonlyColumns());
getConfiguredSyntheticReadonlyRowids().addAll(configuredSyntheticObjects.getReadonlyRowids());
getConfiguredSyntheticIdentities().addAll(configuredSyntheticObjects.getIdentities());
getConfiguredSyntheticDefaults().addAll(configuredSyntheticObjects.getDefaults());
getConfiguredSyntheticEnums().addAll(configuredSyntheticObjects.getEnums());
getConfiguredSyntheticPrimaryKeys().addAll(configuredSyntheticObjects.getPrimaryKeys());
getConfiguredSyntheticUniqueKeys().addAll(configuredSyntheticObjects.getUniqueKeys());
@ -3584,6 +3588,7 @@ public abstract class AbstractDatabase implements Database {
unusedSyntheticReadonlyColumns.addAll(configuredSyntheticObjects.getReadonlyColumns());
unusedSyntheticReadonlyRowids.addAll(configuredSyntheticObjects.getReadonlyRowids());
unusedSyntheticIdentities.addAll(configuredSyntheticObjects.getIdentities());
unusedSyntheticDefaults.addAll(configuredSyntheticObjects.getDefaults());
unusedSyntheticEnums.addAll(configuredSyntheticObjects.getEnums());
unusedSyntheticPrimaryKeys.addAll(configuredSyntheticObjects.getPrimaryKeys());
unusedSyntheticUniqueKeys.addAll(configuredSyntheticObjects.getUniqueKeys());
@ -3597,6 +3602,8 @@ public abstract class AbstractDatabase implements Database {
if (!configuredSyntheticObjects.getColumns().isEmpty())
log.info("Commercial feature", "Synthetic columns are a commercial only feature. Please upgrade to the jOOQ Professional Edition");
if (!configuredSyntheticObjects.getDefaults().isEmpty())
log.info("Commercial feature", "Synthetic defaults are a commercial only feature. Please upgrade to the jOOQ Professional Edition");
if (!configuredSyntheticObjects.getEnums().isEmpty())
log.info("Commercial feature", "Synthetic enums are a commercial only feature. Please upgrade to the jOOQ Professional Edition");
if (!configuredSyntheticObjects.getReadonlyColumns().isEmpty())
@ -3642,6 +3649,14 @@ public abstract class AbstractDatabase implements Database {
return configuredSyntheticIdentities;
}
@Override
public List<SyntheticDefaultType> getConfiguredSyntheticDefaults() {
if (configuredSyntheticDefaults == null)
configuredSyntheticDefaults = new ArrayList<>();
return configuredSyntheticDefaults;
}
@Override
public List<SyntheticEnumType> getConfiguredSyntheticEnums() {
if (configuredSyntheticEnums == null)
@ -3710,6 +3725,11 @@ public abstract class AbstractDatabase implements Database {
unusedSyntheticIdentities.remove(identity);
}
@Override
public void markUsed(SyntheticDefaultType default_) {
unusedSyntheticDefaults.remove(default_);
}
@Override
public void markUsed(SyntheticEnumType e) {
unusedSyntheticEnums.remove(e);
@ -3755,6 +3775,11 @@ public abstract class AbstractDatabase implements Database {
return new ArrayList<>(unusedSyntheticIdentities);
}
@Override
public List<SyntheticDefaultType> getUnusedSyntheticDefaults() {
return new ArrayList<>(unusedSyntheticDefaults);
}
@Override
public List<SyntheticEnumType> getUnusedSyntheticEnums() {
return new ArrayList<>(unusedSyntheticEnums);

View File

@ -62,6 +62,7 @@ import org.jooq.meta.jaxb.RegexFlag;
import org.jooq.meta.jaxb.SchemaMappingType;
import org.jooq.meta.jaxb.SyntheticColumnType;
import org.jooq.meta.jaxb.SyntheticDaoType;
import org.jooq.meta.jaxb.SyntheticDefaultType;
import org.jooq.meta.jaxb.SyntheticEnumType;
import org.jooq.meta.jaxb.SyntheticForeignKeyType;
import org.jooq.meta.jaxb.SyntheticIdentityType;
@ -1371,6 +1372,11 @@ public interface Database extends AutoCloseable {
*/
List<SyntheticIdentityType> getConfiguredSyntheticIdentities();
/**
* Get the configured synthetic defaults.
*/
List<SyntheticDefaultType> getConfiguredSyntheticDefaults();
/**
* Get the configured synthetic enums.
*/
@ -1447,6 +1453,16 @@ public interface Database extends AutoCloseable {
*/
List<SyntheticIdentityType> getUnusedSyntheticIdentities();
/**
* Mark a synthetic default as used.
*/
void markUsed(SyntheticDefaultType default_);
/**
* Retrieve the not-yet used synthetic defaults.
*/
List<SyntheticDefaultType> getUnusedSyntheticDefaults();
/**
* Mark a synthetic enum as used.
*/

View File

@ -43,6 +43,7 @@ import static java.util.Collections.singletonList;
import java.util.ArrayList;
import java.util.List;
import org.jooq.meta.jaxb.SyntheticDefaultType;
import org.jooq.meta.jaxb.SyntheticEnumType;
import org.jooq.meta.jaxb.SyntheticIdentityType;
import org.jooq.meta.jaxb.SyntheticReadonlyColumnType;
@ -60,6 +61,7 @@ public class DefaultColumnDefinition
private static final JooqLogger log = JooqLogger.getLogger(DefaultColumnDefinition.class);
private final int position;
private final boolean identity;
private final String defaultValue;
private final boolean hidden;
private final boolean readonly;
private transient List<EmbeddableDefinition> replacedByEmbeddables;
@ -102,6 +104,7 @@ public class DefaultColumnDefinition
this.position = position;
this.identity = identity || isSyntheticIdentity(this);
this.defaultValue = getSyntheticDefault(this);
this.hidden = hidden;
this.readonly = readonly || isSyntheticReadonlyColumn(this, this.identity);
@ -110,6 +113,7 @@ public class DefaultColumnDefinition
dd.identity(this.identity);
dd.hidden(this.hidden);
dd.readonly(this.readonly);
dd.defaultValue(this.defaultValue);
@ -136,6 +140,25 @@ public class DefaultColumnDefinition
return false;
}
@SuppressWarnings("unused")
private static String getSyntheticDefault(DefaultColumnDefinition column) {
return column.getDefinedType().getDefaultValue();
}
private static boolean isSyntheticReadonlyColumn(DefaultColumnDefinition column, boolean identity) {

View File

@ -82,7 +82,7 @@ public class DefaultDataTypeDefinition implements DataTypeDefinition {
private GenerationOption generationOption;
private XMLTypeDefinition xmlTypeDefinition;
private boolean identity;
private final String defaultValue;
private String defaultValue;
private final int length;
private final int precision;
private final int scale;
@ -262,6 +262,11 @@ public class DefaultDataTypeDefinition implements DataTypeDefinition {
return this;
}
public final DefaultDataTypeDefinition defaultValue(String d) {
this.defaultValue = d;
return this;
}
@Override
public final boolean isIdentity() {
return identity;

View File

@ -253,6 +253,14 @@ public class ObjectFactory {
return new SyntheticIdentityType();
}
/**
* Create an instance of {@link SyntheticDefaultType }
*
*/
public SyntheticDefaultType createSyntheticDefaultType() {
return new SyntheticDefaultType();
}
/**
* Create an instance of {@link SyntheticEnumType }
*

View File

@ -0,0 +1,243 @@
package org.jooq.meta.jaxb;
import java.io.Serializable;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.jooq.util.jaxb.tools.StringAdapter;
import org.jooq.util.jaxb.tools.XMLAppendable;
import org.jooq.util.jaxb.tools.XMLBuilder;
/**
* <p>Java class for SyntheticDefaultType complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType name="SyntheticDefaultType"&gt;
* &lt;complexContent&gt;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
* &lt;all&gt;
* &lt;element name="tables" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
* &lt;element name="fields" type="{http://www.w3.org/2001/XMLSchema}string"/&gt;
* &lt;element name="expression" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
* &lt;element name="ignoreUnused" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/&gt;
* &lt;/all&gt;
* &lt;/restriction&gt;
* &lt;/complexContent&gt;
* &lt;/complexType&gt;
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "SyntheticDefaultType", propOrder = {
})
@SuppressWarnings({
"all"
})
public class SyntheticDefaultType implements Serializable, XMLAppendable
{
private final static long serialVersionUID = 32000L;
@XmlJavaTypeAdapter(StringAdapter.class)
protected String tables;
@XmlElement(required = true)
@XmlJavaTypeAdapter(StringAdapter.class)
protected String fields;
@XmlJavaTypeAdapter(StringAdapter.class)
protected String expression;
@XmlElement(defaultValue = "false")
protected Boolean ignoreUnused = false;
/**
* A regular expression matching all tables on which to apply this synthetic default.
*
*/
public String getTables() {
return tables;
}
/**
* A regular expression matching all tables on which to apply this synthetic default.
*
*/
public void setTables(String value) {
this.tables = value;
}
/**
* A regular expression matching all fields on which to apply this synthetic default.
*
*/
public String getFields() {
return fields;
}
/**
* A regular expression matching all fields on which to apply this synthetic default.
*
*/
public void setFields(String value) {
this.fields = value;
}
/**
* The default expression to apply to the field. This is expected to be a valid SQL expression, e.g. <code>'some string'</code>, not <code>some string</code>
*
*/
public String getExpression() {
return expression;
}
/**
* The default expression to apply to the field. This is expected to be a valid SQL expression, e.g. <code>'some string'</code>, not <code>some string</code>
*
*/
public void setExpression(String value) {
this.expression = value;
}
/**
* Set this flag to true if no warning should be logged if this object was not used by a code generation run.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isIgnoreUnused() {
return ignoreUnused;
}
/**
* Set this flag to true if no warning should be logged if this object was not used by a code generation run.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setIgnoreUnused(Boolean value) {
this.ignoreUnused = value;
}
/**
* A regular expression matching all tables on which to apply this synthetic default.
*
*/
public SyntheticDefaultType withTables(String value) {
setTables(value);
return this;
}
/**
* A regular expression matching all fields on which to apply this synthetic default.
*
*/
public SyntheticDefaultType withFields(String value) {
setFields(value);
return this;
}
/**
* The default expression to apply to the field. This is expected to be a valid SQL expression, e.g. <code>'some string'</code>, not <code>some string</code>
*
*/
public SyntheticDefaultType withExpression(String value) {
setExpression(value);
return this;
}
/**
* Set this flag to true if no warning should be logged if this object was not used by a code generation run.
*
*/
public SyntheticDefaultType withIgnoreUnused(Boolean value) {
setIgnoreUnused(value);
return this;
}
@Override
public final void appendTo(XMLBuilder builder) {
builder.append("tables", tables);
builder.append("fields", fields);
builder.append("expression", expression);
builder.append("ignoreUnused", ignoreUnused);
}
@Override
public String toString() {
XMLBuilder builder = XMLBuilder.nonFormatting();
appendTo(builder);
return builder.toString();
}
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass()!= that.getClass()) {
return false;
}
SyntheticDefaultType other = ((SyntheticDefaultType) that);
if (tables == null) {
if (other.tables!= null) {
return false;
}
} else {
if (!tables.equals(other.tables)) {
return false;
}
}
if (fields == null) {
if (other.fields!= null) {
return false;
}
} else {
if (!fields.equals(other.fields)) {
return false;
}
}
if (expression == null) {
if (other.expression!= null) {
return false;
}
} else {
if (!expression.equals(other.expression)) {
return false;
}
}
if (ignoreUnused == null) {
if (other.ignoreUnused!= null) {
return false;
}
} else {
if (!ignoreUnused.equals(other.ignoreUnused)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = ((prime*result)+((tables == null)? 0 :tables.hashCode()));
result = ((prime*result)+((fields == null)? 0 :fields.hashCode()));
result = ((prime*result)+((expression == null)? 0 :expression.hashCode()));
result = ((prime*result)+((ignoreUnused == null)? 0 :ignoreUnused.hashCode()));
return result;
}
}

View File

@ -43,6 +43,9 @@ public class SyntheticObjectsType implements Serializable, XMLAppendable
@XmlElementWrapper(name = "identities")
@XmlElement(name = "identity")
protected List<SyntheticIdentityType> identities;
@XmlElementWrapper(name = "defaults")
@XmlElement(name = "default")
protected List<SyntheticDefaultType> defaults;
@XmlElementWrapper(name = "enums")
@XmlElement(name = "enum")
protected List<SyntheticEnumType> enums;
@ -106,6 +109,17 @@ public class SyntheticObjectsType implements Serializable, XMLAppendable
this.identities = identities;
}
public List<SyntheticDefaultType> getDefaults() {
if (defaults == null) {
defaults = new ArrayList<SyntheticDefaultType>();
}
return defaults;
}
public void setDefaults(List<SyntheticDefaultType> defaults) {
this.defaults = defaults;
}
public List<SyntheticEnumType> getEnums() {
if (enums == null) {
enums = new ArrayList<SyntheticEnumType>();
@ -256,6 +270,27 @@ public class SyntheticObjectsType implements Serializable, XMLAppendable
return this;
}
public SyntheticObjectsType withDefaults(SyntheticDefaultType... values) {
if (values!= null) {
for (SyntheticDefaultType value: values) {
getDefaults().add(value);
}
}
return this;
}
public SyntheticObjectsType withDefaults(Collection<SyntheticDefaultType> values) {
if (values!= null) {
getDefaults().addAll(values);
}
return this;
}
public SyntheticObjectsType withDefaults(List<SyntheticDefaultType> defaults) {
setDefaults(defaults);
return this;
}
public SyntheticObjectsType withEnums(SyntheticEnumType... values) {
if (values!= null) {
for (SyntheticEnumType value: values) {
@ -388,6 +423,7 @@ public class SyntheticObjectsType implements Serializable, XMLAppendable
builder.append("readonlyRowids", "readonlyRowid", readonlyRowids);
builder.append("columns", "column", columns);
builder.append("identities", "identity", identities);
builder.append("defaults", "default", defaults);
builder.append("enums", "enum", enums);
builder.append("primaryKeys", "primaryKey", primaryKeys);
builder.append("uniqueKeys", "uniqueKey", uniqueKeys);
@ -451,6 +487,15 @@ public class SyntheticObjectsType implements Serializable, XMLAppendable
return false;
}
}
if (defaults == null) {
if (other.defaults!= null) {
return false;
}
} else {
if (!defaults.equals(other.defaults)) {
return false;
}
}
if (enums == null) {
if (other.enums!= null) {
return false;
@ -516,6 +561,7 @@ public class SyntheticObjectsType implements Serializable, XMLAppendable
result = ((prime*result)+((readonlyRowids == null)? 0 :readonlyRowids.hashCode()));
result = ((prime*result)+((columns == null)? 0 :columns.hashCode()));
result = ((prime*result)+((identities == null)? 0 :identities.hashCode()));
result = ((prime*result)+((defaults == null)? 0 :defaults.hashCode()));
result = ((prime*result)+((enums == null)? 0 :enums.hashCode()));
result = ((prime*result)+((primaryKeys == null)? 0 :primaryKeys.hashCode()));
result = ((prime*result)+((uniqueKeys == null)? 0 :uniqueKeys.hashCode()));

View File

@ -1475,6 +1475,10 @@ This feature is available in the commercial distribution only.]]></jxb:javadoc><
<element name="identities" type="tns:SyntheticIdentitiesType" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Synthetic identity configuration]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="defaults" type="tns:SyntheticDefaultsType" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Synthetic default configuration]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="enums" type="tns:SyntheticEnumsType" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Synthetic enum configuration]]></jxb:javadoc></jxb:property></appinfo></annotation>
@ -1608,6 +1612,33 @@ Use this along with the synthetic primary key feature to replace existing primar
</all>
</complexType>
<complexType name="SyntheticDefaultsType">
<sequence>
<element name="default" type="tns:SyntheticDefaultType" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType name="SyntheticDefaultType">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Synthetic default configuration]]></jxb:javadoc></jxb:property></appinfo></annotation>
<all>
<element name="tables" type="string" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A regular expression matching all tables on which to apply this synthetic default.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="fields" type="string" minOccurs="1" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A regular expression matching all fields on which to apply this synthetic default.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="expression" type="string" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The default expression to apply to the field. This is expected to be a valid SQL expression, e.g. <code>'some string'</code>, not <code>some string</code>]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="ignoreUnused" type="boolean" default="false" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Set this flag to true if no warning should be logged if this object was not used by a code generation run.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
</all>
</complexType>
<complexType name="SyntheticEnumsType">
<sequence>
<element name="enum" type="tns:SyntheticEnumType" minOccurs="0" maxOccurs="unbounded"/>