From a14f7a17669bdc65a431c6c0e7adb5f3e6c58c52 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 22 Sep 2021 16:23:10 +1200 Subject: [PATCH 1/2] #2039 Map LocalDateTime when generating DB migrations for Postgres to timestamp DB type --- .../dbplatform/DbPlatformTypeMapping.java | 8 +- .../io/ebean/config/dbplatform/DbType.java | 1 + .../ebean/config/dbplatform/ExtraDbTypes.java | 11 +- .../clickhouse/ClickHousePlatform.java | 5 +- .../dbplatform/mysql/BaseMySqlPlatform.java | 1 + .../dbplatform/mysql/MySql55Platform.java | 1 + .../dbplatform/postgres/PostgresPlatform.java | 5 +- .../sqlserver/SqlServer16Platform.java | 2 + .../sqlserver/SqlServerBasePlatform.java | 5 +- .../ebeaninternal/server/persist/Binder.java | 1 + .../platform/AbstractMultiValueBind.java | 1 + .../server/type/ScalarTypeLocalDateTime.java | 4 +- .../config/dbplatform/DbTypeMapTest.java | 125 ++++++++++++++++-- 13 files changed, 135 insertions(+), 35 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java index 1860888e6..3dfbdf748 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java @@ -70,7 +70,6 @@ public class DbPlatformTypeMapping { * Load the standard types. These can be overridden by DB specific platform. */ private void loadDefaults(boolean logicalTypes) { - put(DbType.BOOLEAN, BOOLEAN_LOGICAL); put(DbType.BIT); put(DbType.INTEGER); @@ -88,7 +87,6 @@ public class DbPlatformTypeMapping { put(DbType.LONGVARCHAR); // most commonly real maps to db float put(DbType.REAL, new DbPlatformType("float")); - put(DbType.POINT, POINT); put(DbType.POLYGON, POLYGON); put(DbType.LINESTRING, LINESTRING); @@ -103,7 +101,7 @@ public class DbPlatformTypeMapping { put(DbType.VARBINARY, new DbPlatformType("varbinary")); put(DbType.BINARY, new DbPlatformType("binary")); put(DbType.CHAR, new DbPlatformType("char")); - + put(DbType.LOCALDATETIME, new DbPlatformType("localdatetime", false)); put(DbType.HSTORE, new DbPlatformType("hstore", false)); put(DbType.JSON, new DbPlatformType("json", false)); put(DbType.JSONB, new DbPlatformType("jsonb", false)); @@ -120,7 +118,7 @@ public class DbPlatformTypeMapping { put(DbType.VARBINARY, new DbPlatformType("varbinary", 255)); put(DbType.BINARY, new DbPlatformType("binary", 255)); put(DbType.CHAR, new DbPlatformType("char", 1)); - + put(DbType.LOCALDATETIME, DbType.TIMESTAMP.createPlatformType()); put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB put(DbType.JSONCLOB, JSON_CLOB_PLACEHOLDER); @@ -137,7 +135,6 @@ public class DbPlatformTypeMapping { * Lookup the platform specific DbType given the standard sql type name. */ public DbPlatformType lookup(String name, boolean withScale) { - DbType type = lookup.byName(name); if (type == null) { throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type"); @@ -160,7 +157,6 @@ public class DbPlatformTypeMapping { } private DbPlatformType getJsonType(DbType type, boolean withScale) { - DbPlatformType dbType = get(type); if (dbType == JSON_CLOB_PLACEHOLDER) { // if we have scale that implies this maps to varchar diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/DbType.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/DbType.java index 5a9fa51bb..eee8aa44b 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/DbType.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/DbType.java @@ -34,6 +34,7 @@ public enum DbType { ARRAY(Types.ARRAY), + LOCALDATETIME(ExtraDbTypes.LOCALDATETIME), UUID(ExtraDbTypes.UUID), INET(ExtraDbTypes.INET), CIDR(ExtraDbTypes.CIDR), diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/ExtraDbTypes.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/ExtraDbTypes.java index e56fe2b89..91f77fdbe 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/ExtraDbTypes.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/ExtraDbTypes.java @@ -5,11 +5,6 @@ package io.ebean.config.dbplatform; */ public interface ExtraDbTypes { - /** - * DB native UUID type (H2 and Postgres). - */ - int UUID = 5010; - /** * Type to map Map content to Postgres HSTORE. */ @@ -40,6 +35,12 @@ public interface ExtraDbTypes { */ int JSONBlob = 5005; + int LOCALDATETIME = 5009; + + /** + * DB native UUID type (H2 and Postgres). + */ + int UUID = 5010; int INET = 5020; int CIDR = 5021; diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/clickhouse/ClickHousePlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/clickhouse/ClickHousePlatform.java index 549fa3959..f1e8eca21 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/clickhouse/ClickHousePlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/clickhouse/ClickHousePlatform.java @@ -26,7 +26,6 @@ public class ClickHousePlatform extends DatabasePlatform { this.booleanDbType = Types.INTEGER; dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("UInt8")); - // using unsigned as default types ... dbTypeMap.put(DbType.TINYINT, new DbPlatformType("UInt8", false)); dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("UInt16", false)); @@ -34,15 +33,13 @@ public class ClickHousePlatform extends DatabasePlatform { dbTypeMap.put(DbType.BIGINT, new DbPlatformType("UInt64", false)); dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("Decimal", 16, 3)); dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("Float64", false)); - dbTypeMap.put(DbType.DATE, new DbPlatformType("Date", false)); dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("DateTime", false)); - + dbTypeMap.put(DbType.LOCALDATETIME, new DbPlatformType("DateTime", false)); dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("String", false)); dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("String", false)); dbTypeMap.put(DbType.CLOB, new DbPlatformType("String", false)); dbTypeMap.put(DbType.JSONVARCHAR, new DbPlatformType("String", false)); - dbTypeMap.put(DbType.UUID, new DbPlatformType("UUID", false)); dbTypeMap.put(DbType.INET, new DbPlatformType("String", false)); dbTypeMap.put(DbType.CIDR, new DbPlatformType("String", false)); diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/mysql/BaseMySqlPlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/mysql/BaseMySqlPlatform.java index b5d009a44..438b53697 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/mysql/BaseMySqlPlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/mysql/BaseMySqlPlatform.java @@ -51,6 +51,7 @@ public abstract class BaseMySqlPlatform extends DatabasePlatform { dbTypeMap.put(DbType.BIT, new DbPlatformType("tinyint(1)")); dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("tinyint(1)")); dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime(6)")); + dbTypeMap.put(DbType.LOCALDATETIME, new DbPlatformType("datetime(6)")); dbTypeMap.put(DbType.CLOB, new MySqlClob()); dbTypeMap.put(DbType.BLOB, new MySqlBlob()); dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255)); diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/mysql/MySql55Platform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/mysql/MySql55Platform.java index 780668f02..dd8093683 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/mysql/MySql55Platform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/mysql/MySql55Platform.java @@ -10,5 +10,6 @@ public class MySql55Platform extends BaseMySqlPlatform { super(); this.platform = Platform.MYSQL55; dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime")); + dbTypeMap.put(DbType.LOCALDATETIME, new DbPlatformType("datetime")); } } diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java index 19d8a9683..d6397c615 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java @@ -69,22 +69,19 @@ public class PostgresPlatform extends DatabasePlatform { DbPlatformType dbTypeText = new DbPlatformType("text", false); DbPlatformType dbBytea = new DbPlatformType("bytea", false); - dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false)); dbTypeMap.put(DbType.INET, new DbPlatformType("inet", false)); dbTypeMap.put(DbType.CIDR, new DbPlatformType("cidr", false)); dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false)); dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false)); dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false)); - dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false)); dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float")); dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint")); dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("timestamptz")); - + dbTypeMap.put(DbType.LOCALDATETIME, new DbPlatformType("timestamp")); dbTypeMap.put(DbType.BINARY, dbBytea); dbTypeMap.put(DbType.VARBINARY, dbBytea); - dbTypeMap.put(DbType.BLOB, dbBytea); dbTypeMap.put(DbType.CLOB, dbTypeText); dbTypeMap.put(DbType.LONGVARBINARY, dbBytea); diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java index af0d7582a..5b15620d7 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java @@ -21,6 +21,8 @@ public class SqlServer16Platform extends SqlServerBasePlatform { dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("varchar", 255)); dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text")); dbTypeMap.put(DbType.CLOB, new DbPlatformType("text")); + dbTypeMap.put(DbType.JSON, new DbPlatformType("text")); + dbTypeMap.put(DbType.JSONB, new DbPlatformType("text")); } } diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java index 4490c148d..bc14ab0c6 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java @@ -57,7 +57,6 @@ abstract class SqlServerBasePlatform extends DatabasePlatform { this.dbDefaultValue.setTrue("1"); this.dbDefaultValue.setNow("SYSUTCDATETIME()"); dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit")); - dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false)); dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19)); dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)")); @@ -67,16 +66,14 @@ abstract class SqlServerBasePlatform extends DatabasePlatform { dbTypeMap.put(DbType.DATE, new DbPlatformType("date")); dbTypeMap.put(DbType.TIME, new DbPlatformType("time")); dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime2")); - + dbTypeMap.put(DbType.LOCALDATETIME, new DbPlatformType("datetime2")); // UTF8 aware types - overwritten in SqlServer16 platform dbTypeMap.put(DbType.CHAR, new DbPlatformType("nchar", 1)); dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("nvarchar", 255)); dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); dbTypeMap.put(DbType.CLOB, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); - dbTypeMap.put(DbType.JSON, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); dbTypeMap.put(DbType.JSONB, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); - dbTypeMap.put(DbType.BLOB, new DbPlatformType("image")); dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image")); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/Binder.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/Binder.java index bec0223d0..6b64c305f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/Binder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/Binder.java @@ -303,6 +303,7 @@ public final class Binder { break; case java.sql.Types.TIMESTAMP: + case DbPlatformType.LOCALDATETIME: b.setTimestamp((java.sql.Timestamp) data); break; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/platform/AbstractMultiValueBind.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/platform/AbstractMultiValueBind.java index c4c4a24d7..2c2ed1645 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/platform/AbstractMultiValueBind.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/platform/AbstractMultiValueBind.java @@ -73,6 +73,7 @@ abstract class AbstractMultiValueBind extends MultiValueBind { case TIMESTAMP: case TIME_WITH_TIMEZONE: case TIMESTAMP_WITH_TIMEZONE: + case ExtraDbTypes.LOCALDATETIME: return "timestamp"; //case LONGVARCHAR: //case CLOB: diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalDateTime.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalDateTime.java index 5e43af855..5e697029d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalDateTime.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalDateTime.java @@ -3,10 +3,10 @@ package io.ebeaninternal.server.type; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import io.ebean.config.JsonConfig; +import io.ebean.config.dbplatform.ExtraDbTypes; import java.io.IOException; import java.sql.Timestamp; -import java.sql.Types; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -17,7 +17,7 @@ import java.time.ZoneId; final class ScalarTypeLocalDateTime extends ScalarTypeBaseDateTime { ScalarTypeLocalDateTime(JsonConfig.DateTime mode) { - super(mode, LocalDateTime.class, false, Types.TIMESTAMP); + super(mode, LocalDateTime.class, false, ExtraDbTypes.LOCALDATETIME); } @Override diff --git a/ebean-test/src/test/java/io/ebean/config/dbplatform/DbTypeMapTest.java b/ebean-test/src/test/java/io/ebean/config/dbplatform/DbTypeMapTest.java index e85f6ea15..2053e98f6 100644 --- a/ebean-test/src/test/java/io/ebean/config/dbplatform/DbTypeMapTest.java +++ b/ebean-test/src/test/java/io/ebean/config/dbplatform/DbTypeMapTest.java @@ -1,39 +1,144 @@ package io.ebean.config.dbplatform; +import io.ebean.config.dbplatform.clickhouse.ClickHousePlatform; +import io.ebean.config.dbplatform.h2.H2Platform; +import io.ebean.config.dbplatform.mysql.MySqlPlatform; +import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer16Platform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +class DbTypeMapTest { -public class DbTypeMapTest { + final DbPlatformTypeMapping logicalTypeMap = DbPlatformTypeMapping.logicalTypes(); @Test - public void testLookupRender_given_postgresPlatformType() throws Exception { - + void testLookupRender_given_postgresPlatformType() { PostgresPlatform pg = new PostgresPlatform(); DbPlatformTypeMapping dbTypeMap = pg.getDbTypeMap(); assertThat(dbTypeMap.lookup("clob", false).renderType(0, 0)).isEqualTo("text"); assertThat(dbTypeMap.lookup("CLOB", false).renderType(0, 0)).isEqualTo("text"); - assertThat(dbTypeMap.lookup("varchar", true).renderType(20, 0)).isEqualTo("varchar(20)"); - + assertThat(dbTypeMap.lookup("timestamp", false).renderType(0, 0)).isEqualTo("timestamptz"); + assertThat(dbTypeMap.lookup("localdatetime", false).renderType(0, 0)).isEqualTo("timestamp"); assertThat(dbTypeMap.lookup("json", false).renderType(0, 0)).isEqualTo("json"); assertThat(dbTypeMap.lookup("jsonb", false).renderType(0, 0)).isEqualTo("jsonb"); assertThat(dbTypeMap.lookup("jsonclob", false).renderType(0, 0)).isEqualTo("text"); assertThat(dbTypeMap.lookup("jsonblob", false).renderType(0, 0)).isEqualTo("bytea"); assertThat(dbTypeMap.lookup("jsonvarchar", false).renderType(200, 0)).isEqualTo("varchar(200)"); - } @Test - public void testPlatformTypes() { + void testLookupRender_given_mysql() { + DbPlatformTypeMapping dbTypeMap = new MySqlPlatform().getDbTypeMap(); - DbPlatformTypeMapping dbTypeMap = DbPlatformTypeMapping.logicalTypes(); - DbPlatformType dbType = dbTypeMap.get(DbPlatformType.JSON); - DbPlatformType json = dbTypeMap.lookup("json", false); + assertThat(dbTypeMap.lookup("clob", false).renderType(0, 0)).isEqualTo("longtext"); + assertThat(dbTypeMap.lookup("CLOB", false).renderType(0, 0)).isEqualTo("longtext"); + assertThat(dbTypeMap.lookup("varchar", true).renderType(20, 0)).isEqualTo("varchar(20)"); + assertThat(dbTypeMap.lookup("timestamp", false).renderType(0, 0)).isEqualTo("datetime(6)"); + assertThat(dbTypeMap.lookup("localdatetime", false).renderType(0, 0)).isEqualTo("datetime(6)"); + assertThat(dbTypeMap.lookup("json", false).renderType(0, 0)).isEqualTo("json"); + assertThat(dbTypeMap.lookup("jsonb", false).renderType(0, 0)).isEqualTo("json"); + assertThat(dbTypeMap.lookup("jsonclob", false).renderType(0, 0)).isEqualTo("longtext"); + assertThat(dbTypeMap.lookup("jsonblob", false).renderType(0, 0)).isEqualTo("longblob"); + assertThat(dbTypeMap.lookup("jsonvarchar", false).renderType(200, 0)).isEqualTo("varchar(200)"); + } + @Test + void testLookupRender_given_sqlserver17() { + DbPlatformTypeMapping dbTypeMap = new SqlServer17Platform().getDbTypeMap(); + + assertThat(dbTypeMap.lookup("clob", false).renderType(0, 0)).isEqualTo("nvarchar(max)"); + assertThat(dbTypeMap.lookup("CLOB", false).renderType(0, 0)).isEqualTo("nvarchar(max)"); + assertThat(dbTypeMap.lookup("varchar", true).renderType(20, 0)).isEqualTo("nvarchar(20)"); + assertThat(dbTypeMap.lookup("timestamp", false).renderType(0, 0)).isEqualTo("datetime2"); + assertThat(dbTypeMap.lookup("localdatetime", false).renderType(0, 0)).isEqualTo("datetime2"); + assertThat(dbTypeMap.lookup("json", false).renderType(0, 0)).isEqualTo("nvarchar(max)"); + assertThat(dbTypeMap.lookup("jsonb", false).renderType(0, 0)).isEqualTo("nvarchar(max)"); + assertThat(dbTypeMap.lookup("jsonclob", false).renderType(0, 0)).isEqualTo("nvarchar(max)"); + assertThat(dbTypeMap.lookup("jsonblob", false).renderType(0, 0)).isEqualTo("image"); + assertThat(dbTypeMap.lookup("jsonvarchar", false).renderType(200, 0)).isEqualTo("nvarchar(200)"); + } + + @Test + void testLookupRender_given_sqlserver16() { + DbPlatformTypeMapping dbTypeMap = new SqlServer16Platform().getDbTypeMap(); + + assertThat(dbTypeMap.lookup("clob", false).renderType(0, 0)).isEqualTo("text"); + assertThat(dbTypeMap.lookup("CLOB", false).renderType(0, 0)).isEqualTo("text"); + assertThat(dbTypeMap.lookup("varchar", true).renderType(20, 0)).isEqualTo("varchar(20)"); + assertThat(dbTypeMap.lookup("timestamp", false).renderType(0, 0)).isEqualTo("datetime2"); + assertThat(dbTypeMap.lookup("localdatetime", false).renderType(0, 0)).isEqualTo("datetime2"); + assertThat(dbTypeMap.lookup("json", false).renderType(0, 0)).isEqualTo("text"); + assertThat(dbTypeMap.lookup("jsonb", false).renderType(0, 0)).isEqualTo("text"); + assertThat(dbTypeMap.lookup("jsonclob", false).renderType(0, 0)).isEqualTo("text"); + assertThat(dbTypeMap.lookup("jsonblob", false).renderType(0, 0)).isEqualTo("image"); + assertThat(dbTypeMap.lookup("jsonvarchar", false).renderType(200, 0)).isEqualTo("varchar(200)"); + } + + @Test + void testLookupRender_given_oracle() { + DbPlatformTypeMapping dbTypeMap = new OraclePlatform().getDbTypeMap(); + + assertThat(dbTypeMap.lookup("clob", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("CLOB", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("varchar", true).renderType(20, 0)).isEqualTo("varchar2(20)"); + assertThat(dbTypeMap.lookup("timestamp", false).renderType(0, 0)).isEqualTo("timestamp"); + assertThat(dbTypeMap.lookup("localdatetime", false).renderType(0, 0)).isEqualTo("timestamp"); + assertThat(dbTypeMap.lookup("json", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("jsonb", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("jsonclob", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("jsonblob", false).renderType(0, 0)).isEqualTo("blob"); + assertThat(dbTypeMap.lookup("jsonvarchar", false).renderType(200, 0)).isEqualTo("varchar2(200)"); + } + + @Test + void testLookupRender_given_h2() { + DbPlatformTypeMapping dbTypeMap = new H2Platform().getDbTypeMap(); + + assertThat(dbTypeMap.lookup("clob", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("CLOB", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("varchar", true).renderType(20, 0)).isEqualTo("varchar(20)"); + assertThat(dbTypeMap.lookup("timestamp", false).renderType(0, 0)).isEqualTo("timestamp"); + assertThat(dbTypeMap.lookup("localdatetime", false).renderType(0, 0)).isEqualTo("timestamp"); + assertThat(dbTypeMap.lookup("json", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("jsonb", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("jsonclob", false).renderType(0, 0)).isEqualTo("clob"); + assertThat(dbTypeMap.lookup("jsonblob", false).renderType(0, 0)).isEqualTo("blob"); + assertThat(dbTypeMap.lookup("jsonvarchar", false).renderType(200, 0)).isEqualTo("varchar(200)"); + } + + @Test + void testLookupRender_given_clickhouse() { + DbPlatformTypeMapping dbTypeMap = new ClickHousePlatform().getDbTypeMap(); + + assertThat(dbTypeMap.lookup("clob", false).renderType(0, 0)).isEqualTo("String"); + assertThat(dbTypeMap.lookup("CLOB", false).renderType(0, 0)).isEqualTo("String"); + assertThat(dbTypeMap.lookup("varchar", true).renderType(20, 0)).isEqualTo("String"); + assertThat(dbTypeMap.lookup("timestamp", false).renderType(0, 0)).isEqualTo("DateTime"); + assertThat(dbTypeMap.lookup("localdatetime", false).renderType(0, 0)).isEqualTo("DateTime"); + assertThat(dbTypeMap.lookup("json", false).renderType(0, 0)).isEqualTo("String"); + assertThat(dbTypeMap.lookup("jsonb", false).renderType(0, 0)).isEqualTo("String"); + assertThat(dbTypeMap.lookup("jsonclob", false).renderType(0, 0)).isEqualTo("String"); + assertThat(dbTypeMap.lookup("jsonblob", false).renderType(0, 0)).isEqualTo("blob"); + assertThat(dbTypeMap.lookup("jsonvarchar", false).renderType(200, 0)).isEqualTo("String"); + } + + @Test + void testPlatformTypes_logical_json() { + DbPlatformType dbType = logicalTypeMap.get(DbPlatformType.JSON); + DbPlatformType json = logicalTypeMap.lookup("json", false); assertThat(dbType).isSameAs(json); } + + @Test + void testPlatformTypes_logical_localDateTime() { + DbPlatformType dbType = logicalTypeMap.get(DbPlatformType.LOCALDATETIME); + DbPlatformType localDateTime = logicalTypeMap.lookup("localdatetime", false); + assertThat(dbType).isSameAs(localDateTime); + } } From 23cd45b5d1306760e76b33063949411a87ecf961 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 22 Sep 2021 16:51:47 +1200 Subject: [PATCH 2/2] #2039 LocalDateTime ignore timestamp->localdatetime as a type change Historically LocalDateTime mapped to logical timestamp and we need to treat that to be not a change in type. Migrations then will not generate a AlterColumn migration when we start using the new logical type localdatetime. --- .../dbmigration/model/MColumn.java | 11 ++- .../dbmigration/model/MColumnTest.java | 83 +++++++++---------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java index de71d794d..712690e0b 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java @@ -15,6 +15,8 @@ import java.util.Objects; */ public class MColumn { + private static final String LOCALDATETIME = "localdatetime"; + private static final String TIMESTAMP = "timestamp"; private String name; private String type; private String checkConstraint; @@ -377,7 +379,7 @@ public class MColumn { getAlterColumn(tableName, tableWithHistory).setHistoryExclude(newColumn.historyExclude); } - if (different(type, newColumn.type)) { + if (different(type, newColumn.type) && !localDateTime(type, newColumn.type)) { changeBaseAttribute = true; getAlterColumn(tableName, tableWithHistory).setType(newColumn.type); } @@ -465,6 +467,13 @@ public class MColumn { } } + /** + * Ignore the case of new type LocalDateTime which was historically mapped to Timestamp. + */ + boolean localDateTime(String type, String newType) { + return LOCALDATETIME.equalsIgnoreCase(newType) && TIMESTAMP.equalsIgnoreCase(type); + } + public void setDbMigrationInfos(List dbMigrationInfos) { this.dbMigrationInfos = dbMigrationInfos; } diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/model/MColumnTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/model/MColumnTest.java index 29d01efdc..501fd8b0b 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/model/MColumnTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/model/MColumnTest.java @@ -4,23 +4,36 @@ import io.ebeaninternal.dbmigration.migration.AlterColumn; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +class MColumnTest { -public class MColumnTest { + private final MTable table = new MTable("tab"); - MTable table = new MTable("tab"); - - MColumn basic() { + private MColumn basic() { return new MColumn("col", "integer"); } - ModelDiff diff() { + private ModelDiff diff() { return new ModelDiff(); } @Test - public void noDiff() throws Exception { + void localDateTime() { + assertTrue(basic().localDateTime("timestamp", "localdatetime")); + } + @Test + void localDateTime_when_not() { + assertFalse(basic().localDateTime("other", "localdatetime")); + assertFalse(basic().localDateTime("timestamp", "other")); + assertFalse(basic().localDateTime("localdatetime", "timestamp")); + assertFalse(basic().localDateTime("timestamp2", "localdatetime")); + } + + @Test + void noDiff(){ ModelDiff diff = diff(); basic().compare(diff, table, basic()); @@ -29,8 +42,7 @@ public class MColumnTest { } @Test - public void diffType() throws Exception { - + void diffType() { ModelDiff diff = diff(); basic().compare(diff, table, new MColumn("col", "integer(8)")); @@ -40,8 +52,7 @@ public class MColumnTest { } @Test - public void diffNotNull() throws Exception { - + void diffNotNull() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setNotnull(true); @@ -58,8 +69,7 @@ public class MColumnTest { } @Test - public void diffNull() throws Exception { - + void diffNull() { ModelDiff diff = diff(); MColumn newCol = basic(); @@ -76,8 +86,7 @@ public class MColumnTest { } @Test - public void applyNotNull_expect_notNull() throws Exception { - + void applyNotNull_expect_notNull() { MColumn newCol = basic(); newCol.setNotnull(true); @@ -89,8 +98,7 @@ public class MColumnTest { } @Test - public void diffCheckAdd() throws Exception { - + void diffCheckAdd() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setCheckConstraint("abc"); @@ -102,8 +110,7 @@ public class MColumnTest { } @Test - public void diffCheckRemove() throws Exception { - + void diffCheckRemove() { ModelDiff diff = diff(); MColumn newCol = basic(); MColumn oldCol = basic(); @@ -117,8 +124,7 @@ public class MColumnTest { } @Test - public void diffCheckChange() throws Exception { - + void diffCheckChange() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setCheckConstraint("abc"); @@ -133,8 +139,7 @@ public class MColumnTest { } @Test - public void diffDefaultValueAdd() throws Exception { - + void diffDefaultValueAdd() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setDefaultValue("abc"); @@ -145,8 +150,7 @@ public class MColumnTest { } @Test - public void diffDefaultValueRemove() throws Exception { - + void diffDefaultValueRemove() { ModelDiff diff = diff(); MColumn newCol = basic(); MColumn oldCol = basic(); @@ -158,8 +162,7 @@ public class MColumnTest { } @Test - public void diffDefaultValueChange() throws Exception { - + void diffDefaultValueChange() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setDefaultValue("abc"); @@ -172,8 +175,7 @@ public class MColumnTest { } @Test - public void diffReferencesAdd() throws Exception { - + void diffReferencesAdd() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setReferences("abc"); @@ -184,10 +186,8 @@ public class MColumnTest { assertThat(getAlterColumn(diff).getDropForeignKey()).isNull(); } - @Test - public void diffReferencesRemove() throws Exception { - + void diffReferencesRemove() { ModelDiff diff = diff(); MColumn newCol = basic(); MColumn oldCol = basic(); @@ -206,8 +206,7 @@ public class MColumnTest { } @Test - public void diffReferencesChange() throws Exception { - + void diffReferencesChange() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setReferences("ab"); @@ -231,8 +230,7 @@ public class MColumnTest { } @Test - public void diffUniqueAdd() throws Exception { - + void diffUniqueAdd() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setUnique("uq_one"); @@ -243,8 +241,7 @@ public class MColumnTest { } @Test - public void diffUniqueRemove() throws Exception { - + void diffUniqueRemove() { ModelDiff diff = diff(); MColumn newCol = basic(); MColumn oldCol = basic(); @@ -256,8 +253,7 @@ public class MColumnTest { } @Test - public void diffUniqueOneToOneAdd() throws Exception { - + void diffUniqueOneToOneAdd() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setUniqueOneToOne("uq_new"); @@ -271,8 +267,7 @@ public class MColumnTest { } @Test - public void diffUniqueOneToOneRemove() throws Exception { - + void diffUniqueOneToOneRemove() { ModelDiff diff = diff(); MColumn newCol = basic(); MColumn oldCol = basic(); @@ -284,8 +279,7 @@ public class MColumnTest { } @Test - public void diffHistoryExcludeAdd() throws Exception { - + void diffHistoryExcludeAdd() { ModelDiff diff = diff(); MColumn newCol = basic(); newCol.setHistoryExclude(true); @@ -296,8 +290,7 @@ public class MColumnTest { } @Test - public void diffHistoryExcludeRemove() throws Exception { - + void diffHistoryExcludeRemove() { ModelDiff diff = diff(); MColumn newCol = basic(); MColumn oldCol = basic();