#615 - ENH: Change DDL generation with @SoftDelete to add 'default false' to column definition

This commit is contained in:
Robin Bygrave
2016-03-23 11:10:35 +13:00
parent 90ee903c52
commit 7d89b97e2b
28 changed files with 212 additions and 60 deletions
@@ -18,7 +18,7 @@ public class DB2Platform extends DatabasePlatform {
this.maxTableNameLength = 18;
this.maxConstraintNameLength = 18;
this.sqlLimiter = new Db2SqlLimiter();
this.platformDdl = new DB2Ddl(dbTypeMap, dbIdentity);
this.platformDdl = new DB2Ddl(this);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
@@ -18,7 +18,6 @@ public class DatabasePlatform {
private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class);
/**
* Behavior used when ending a query only transaction (at read committed isolation level).
*/
@@ -72,6 +71,11 @@ public class DatabasePlatform {
*/
protected DbTypeMap dbTypeMap = new DbTypeMap();
/**
* Default values for DB columns.
*/
protected DbDefaultValue dbDefaultValue = new DbDefaultValue();
/**
* Set to true if the DB has native UUID type support.
*/
@@ -291,6 +295,13 @@ public class DatabasePlatform {
return dbTypeMap;
}
/**
* Return the mapping for DB column default values.
*/
public DbDefaultValue getDbDefaultValue() {
return dbDefaultValue;
}
/**
* Return the column alias prefix.
*/
@@ -425,6 +436,20 @@ public class DatabasePlatform {
return sqlLimiter;
}
/**
* Set the DB TRUE literal (from the registered boolean ScalarType)
*/
public void setDbTrueLiteral(String dbTrueLiteral) {
this.dbDefaultValue.setTrue(dbTrueLiteral);
}
/**
* Set the DB FALSE literal (from the registered boolean ScalarType)
*/
public void setDbFalseLiteral(String dbFalseLiteral) {
this.dbDefaultValue.setFalse(dbFalseLiteral);
}
/**
* Convert backticks to the platform specific open quote and close quote
* <p>
@@ -0,0 +1,70 @@
package com.avaje.ebean.config.dbplatform;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* DB Column default values mapping to database platform specific literals.
*/
public class DbDefaultValue {
/**
* The key for FALSE.
*/
public static final String FALSE = "false";
/**
* The key for TRUE.
*/
public static final String TRUE = "true";
/**
* The key for the NOW / current timestamp.
*/
public static final String NOW = "now";
protected Map<String,String> map = new LinkedHashMap<String,String>();
/**
* Set the DB now function.
*/
public void setNow(String dbFunction) {
put(NOW, dbFunction);
}
/**
* Set the DB false literal.
*/
public void setFalse(String dbFalseLiteral) {
put(FALSE, dbFalseLiteral);
}
/**
* Set the DB true literal.
*/
public void setTrue(String dbTrueLiteral) {
put(TRUE, dbTrueLiteral);
}
/**
* Add an translation entry.
*/
public void put(String dbLiteral, String dbTranslated) {
map.put(dbLiteral, dbTranslated);
}
/**
* Convert the DB default literal to platform specific type or function.
* <p>
* This is intended for the DB column default clause in DDL.
* </p>
*/
public String convert(String dbDefaultLiteral) {
if (dbDefaultLiteral == null) {
return null;
}
String val = map.get(dbDefaultLiteral);
return val != null ? val : dbDefaultLiteral;
}
}
@@ -14,9 +14,10 @@ public class H2Platform extends DatabasePlatform {
super();
this.name = "h2";
this.dbEncrypt = new H2DbEncrypt();
this.platformDdl = new H2Ddl(this.dbTypeMap, dbIdentity);
this.platformDdl = new H2Ddl(this);
this.historySupport = new H2HistorySupport();
this.nativeUuidType = true;
this.dbDefaultValue.setNow("now()");
// only support getGeneratedKeys with non-batch JDBC
// so generally use SEQUENCE instead of IDENTITY for H2
@@ -15,7 +15,7 @@ public class HsqldbPlatform extends DatabasePlatform {
super();
this.name = "hsqldb";
this.dbEncrypt = new H2DbEncrypt();
this.platformDdl = new HsqldbDdl(dbTypeMap, dbIdentity);
this.platformDdl = new HsqldbDdl(this);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
@@ -25,7 +25,7 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
this.idInExpandedForm = true;
this.selectCountWithAlias = true;
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
this.platformDdl = new MsSqlServerDdl(dbTypeMap, dbIdentity);
this.platformDdl = new MsSqlServerDdl(this);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsIdentity(true);
@@ -25,7 +25,7 @@ public class MySqlPlatform extends DatabasePlatform {
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.dbEncrypt = new MySqlDbEncrypt();
this.platformDdl = new MySqlDdl(this.dbTypeMap, this.dbIdentity);
this.platformDdl = new MySqlDdl(this);
this.historySupport = new MySqlHistorySupport();
this.dbIdentity.setIdType(IdType.IDENTITY);
@@ -18,7 +18,7 @@ public class OraclePlatform extends DatabasePlatform {
this.maxConstraintNameLength = 30;
this.dbEncrypt = new OracleDbEncrypt();
this.sqlLimiter = new RownumSqlLimiter();
this.platformDdl = new Oracle10Ddl(this.dbTypeMap, this.dbIdentity);
this.platformDdl = new Oracle10Ddl(this);
this.historySupport = new OracleDbHistorySupport();
// Not using getGeneratedKeys as instead we will
@@ -27,7 +27,7 @@ public class PostgresPlatform extends DatabasePlatform {
this.dbEncrypt = new PostgresDbEncrypt();
this.historySupport = new PostgresHistorySupport();
this.platformDdl = new PostgresDdl(this.dbTypeMap, this.dbIdentity);
this.platformDdl = new PostgresDdl(this);
// Use Identity and getGeneratedKeys
this.dbIdentity.setIdType(IdType.IDENTITY);
@@ -9,7 +9,7 @@ public class SQLitePlatform extends DatabasePlatform {
public SQLitePlatform() {
super();
this.name = "sqlite";
this.platformDdl = new SQLiteDdl(dbTypeMap, dbIdentity);
this.platformDdl = new SQLiteDdl(this);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(false);
@@ -1,15 +1,14 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
/**
* DB2 platform specific DDL.
*/
public class DB2Ddl extends PlatformDdl {
public DB2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
super(platformTypes, dbIdentity);
public DB2Ddl(DatabasePlatform platform) {
super(platform);
this.identitySuffix = " generated by default as identity";
}
@@ -1,15 +1,14 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
/**
* H2 platform specific DDL.
*/
public class H2Ddl extends PlatformDdl {
public H2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
super(platformTypes, dbIdentity);
public H2Ddl(DatabasePlatform platform) {
super(platform);
this.historyDdl = new H2HistoryDdl();
}
@@ -1,15 +1,14 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
/**
* Hsqldb platform specific DDL.
*/
public class HsqldbDdl extends PlatformDdl {
public HsqldbDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
super(platformTypes, dbIdentity);
public HsqldbDdl(DatabasePlatform platform) {
super(platform);
this.identitySuffix = " generated by default as identity (start with 1) ";
}
@@ -1,7 +1,6 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import com.avaje.ebean.dbmigration.migration.AlterColumn;
@@ -12,8 +11,8 @@ import java.io.IOException;
*/
public class MsSqlServerDdl extends PlatformDdl {
public MsSqlServerDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
super(platformTypes, dbIdentity);
public MsSqlServerDdl(DatabasePlatform platform) {
super(platform);
this.identitySuffix = " identity(1,1)";
this.foreignKeyRestrict = "";
this.inlineUniqueOneToOne = false;
@@ -1,7 +1,6 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.Column;
@@ -14,8 +13,8 @@ import java.io.IOException;
*/
public class MySqlDdl extends PlatformDdl {
public MySqlDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
super(platformTypes, dbIdentity);
public MySqlDdl(DatabasePlatform platform) {
super(platform);
this.alterColumn = "modify";
this.dropUniqueConstraint = "drop index";
this.historyDdl = new MySqlHistoryDdl();
@@ -1,15 +1,14 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
/**
* Oracle platform specific DDL.
*/
public class Oracle10Ddl extends PlatformDdl {
public Oracle10Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
super(platformTypes, dbIdentity);
public Oracle10Ddl(DatabasePlatform platform) {
super(platform);
this.dropTableIfExists = "drop table ";
this.dropSequenceIfExists = "drop sequence ";
this.dropTableCascade = " cascade constraints purge";
@@ -2,8 +2,9 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbDefaultValue;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.dbmigration.ddlgeneration.BaseDdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
@@ -90,9 +91,12 @@ public class PlatformDdl {
*/
protected boolean inlineForeignKeys;
public PlatformDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
this.dbIdentity = dbIdentity;
this.typeConverter = new PlatformTypeConverter(platformTypes);
protected final DbDefaultValue dbDefaultValue;
public PlatformDdl(DatabasePlatform platform) {
this.dbIdentity = platform.getDbIdentity();
this.dbDefaultValue = platform.getDbDefaultValue();
this.typeConverter = new PlatformTypeConverter(platform.getDbTypeMap());
}
/**
@@ -165,6 +169,12 @@ public class PlatformDdl {
buffer.append(" ");
buffer.append(lowerColumnName(column.getName()), 29);
buffer.append(platformType);
if (!typeContainsDefault(platformType)) {
String defaultValue = convertDefaultValue(column.getDefaultValue());
if (defaultValue != null) {
buffer.append(" default ").append(defaultValue);
}
}
if (isTrue(column.isNotnull()) || isTrue(column.isPrimaryKey())) {
buffer.append(" not null");
}
@@ -173,6 +183,20 @@ public class PlatformDdl {
// so that the database can potentially provide a nice SQL error
}
/**
* Return true if the type definition already contains a default value.
*/
private boolean typeContainsDefault(String platformType) {
return platformType.toLowerCase().contains(" default");
}
/**
* Convert the DB column default literal to platform specific.
*/
private String convertDefaultValue(String dbDefault) {
return dbDefaultValue.convert(dbDefault);
}
/**
* Return the drop foreign key clause.
*/
@@ -1,15 +1,14 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
/**
* Postgres specific DDL.
*/
public class PostgresDdl extends PlatformDdl {
public PostgresDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
super(platformTypes, dbIdentity);
public PostgresDdl(DatabasePlatform platform) {
super(platform);
this.historyDdl = new PostgresHistoryDdl();
this.dropTableCascade = " cascade";
this.columnSetType = "type ";
@@ -1,7 +1,6 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import java.io.IOException;
@@ -11,8 +10,8 @@ import java.io.IOException;
*/
public class SQLiteDdl extends PlatformDdl {
public SQLiteDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
super(platformTypes, dbIdentity);
public SQLiteDdl(DatabasePlatform platform) {
super(platform);
this.identitySuffix = "";
this.inlineForeignKeys = true;
}
@@ -230,6 +230,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
}
MColumn col = new MColumn(p.getDbColumn(), ctx.getColumnDefn(p));
col.setDefaultValue(p.getDbColumnDefault());
col.setComment(p.getDbComment());
col.setDraftOnly(p.isDraftOnly());
@@ -219,6 +219,11 @@ public class BeanProperty implements ElPropertyValue, Property {
*/
final String dbColumnDefn;
/**
* DB Column default value for DDL definition (FALSE, NOW etc).
*/
final String dbColumnDefault;
/**
* Database DDL column comment.
*/
@@ -298,6 +303,7 @@ public class BeanProperty implements ElPropertyValue, Property {
this.dbScale = deploy.getDbScale();
this.dbColumnDefn = InternString.intern(deploy.getDbColumnDefn());
this.dbConstraintExpression = InternString.intern(deploy.getDbConstraintExpression());
this.dbColumnDefault = deploy.getDbColumnDefault();
this.inherited = false;// deploy.isInherited();
this.owningType = deploy.getOwningType();
@@ -407,6 +413,7 @@ public class BeanProperty implements ElPropertyValue, Property {
this.dbScale = source.getDbScale();
this.dbColumnDefn = InternString.intern(source.getDbColumnDefn());
this.dbConstraintExpression = InternString.intern(source.getDbConstraintExpression());
this.dbColumnDefault = source.dbColumnDefault;
this.inherited = source.isInherited();
this.owningType = source.owningType;
@@ -945,6 +952,13 @@ public class BeanProperty implements ElPropertyValue, Property {
return dbType.renderType(dbLength, dbScale);
}
/**
* Return the DB column default to use for DDL.
*/
public String getDbColumnDefault() {
return dbColumnDefn != null ? null : dbColumnDefault;
}
/**
* Return the bean Field associated with this property.
*/
@@ -11,6 +11,7 @@ import com.avaje.ebean.annotation.WhenModified;
import com.avaje.ebean.annotation.WhoCreated;
import com.avaje.ebean.annotation.WhoModified;
import com.avaje.ebean.config.ScalarTypeConverter;
import com.avaje.ebean.config.dbplatform.DbDefaultValue;
import com.avaje.ebean.config.dbplatform.DbEncrypt;
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
import com.avaje.ebeaninternal.server.core.InternString;
@@ -202,6 +203,8 @@ public class DeployBeanProperty {
private String dbComment;
private String dbColumnDefault;
public DeployBeanProperty(DeployBeanDescriptor<?> desc, Class<?> propertyType, ScalarType<?> scalarType, ScalarTypeConverter<?, ?> typeConverter) {
this.desc = desc;
this.propertyType = propertyType;
@@ -902,6 +905,7 @@ public class DeployBeanProperty {
public void setSoftDelete() {
this.softDelete = true;
this.nullable = false;
this.dbColumnDefault = DbDefaultValue.FALSE;
}
public boolean isSoftDelete() {
@@ -932,4 +936,7 @@ public class DeployBeanProperty {
return docMapping.create();
}
public String getDbColumnDefault() {
return dbColumnDefault;
}
}
@@ -20,7 +20,7 @@ public class DefaultTypeFactory {
this.serverConfig = serverConfig;
}
protected ScalarType<Boolean> createBoolean(String trueValue, String falseValue) {
protected ScalarTypeBool createBoolean(String trueValue, String falseValue) {
try {
// first try Integer based boolean
@@ -40,7 +40,7 @@ public class DefaultTypeFactory {
* native data type and for others Booleans will be converted to Y/N or 0/1
* etc.
*/
public ScalarType<Boolean> createBoolean() {
public ScalarTypeBool createBoolean() {
if (serverConfig == null) {
return new ScalarTypeBoolean.Native();
@@ -848,10 +848,14 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
ScalarType<?> mathBigIntType = extraTypeFactory.createMathBigInteger();
typeMap.put(BigInteger.class, mathBigIntType);
ScalarType<?> booleanType = extraTypeFactory.createBoolean();
ScalarTypeBool booleanType = extraTypeFactory.createBoolean();
typeMap.put(Boolean.class, booleanType);
typeMap.put(boolean.class, booleanType);
// register the boolean literals to the platform for DDL default values
databasePlatform.setDbTrueLiteral(booleanType.getDbTrueLiteral());
databasePlatform.setDbFalseLiteral(booleanType.getDbFalseLiteral());
// always register Types.BOOLEAN to our boolean type
nativeMap.put(Types.BOOLEAN, booleanType);
if (booleanType.getJdbcType() == Types.BIT) {
@@ -0,0 +1,17 @@
package com.avaje.ebeaninternal.server.type;
/**
* Boolean ScalarType's must implement to support DDL default values etc.
*/
public interface ScalarTypeBool extends ScalarType<Boolean> {
/**
* Return the DB literal value for FALSE.
*/
String getDbFalseLiteral();
/**
* Return the DB literal value for TRUE.
*/
String getDbTrueLiteral();
}
@@ -70,12 +70,12 @@ public class ScalarTypeBoolean {
* type.boolean.dbtype="bit" in the ebean configuration
* </p>
*/
public static class BitBoolean extends BooleanBase {
static class BitBoolean extends BooleanBase {
/**
* Native Boolean database type.
*/
public BitBoolean() {
BitBoolean() {
super(true, Types.BIT);
}
@@ -116,12 +116,12 @@ public class ScalarTypeBoolean {
/**
* Converted to/from an Integer in the Database.
*/
public static class IntBoolean extends BooleanBase {
static class IntBoolean extends BooleanBase {
private final Integer trueValue;
private final Integer falseValue;
public IntBoolean(Integer trueValue, Integer falseValue) {
IntBoolean(Integer trueValue, Integer falseValue) {
super(false, Types.INTEGER);
this.trueValue = trueValue;
this.falseValue = falseValue;
@@ -169,7 +169,7 @@ public class ScalarTypeBoolean {
/**
* Convert the Boolean value to the db value.
*/
public Integer toInteger(Object value) {
Integer toInteger(Object value) {
if (value == null) {
return null;
}
@@ -199,12 +199,12 @@ public class ScalarTypeBoolean {
/**
* Converted to/from an Integer in the Database.
*/
public static class StringBoolean extends BooleanBase {
static class StringBoolean extends BooleanBase {
private final String trueValue;
private final String falseValue;
public StringBoolean(String trueValue, String falseValue) {
StringBoolean(String trueValue, String falseValue) {
super(false, Types.VARCHAR);
this.trueValue = trueValue;
this.falseValue = falseValue;
@@ -280,9 +280,9 @@ public class ScalarTypeBoolean {
}
}
public static abstract class BooleanBase extends ScalarTypeBase<Boolean> {
public static abstract class BooleanBase extends ScalarTypeBase<Boolean> implements ScalarTypeBool {
public BooleanBase(boolean jdbcNative, int jdbcType) {
BooleanBase(boolean jdbcNative, int jdbcType) {
super(Boolean.class, jdbcNative, jdbcType);
}