diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 57008ce92..519246cb6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,5 +36,5 @@ jobs: # - name: Maven single test # run: mvn --batch-mode clean verify -Dtest="io.ebeaninternal.server.core.DefaultServer_getReferenceTest" -DfailIfNoTests=false - name: Build with Maven - run: mvn clean package + run: mvn -T 8 clean test diff --git a/.github/workflows/db2luw.yml b/.github/workflows/db2luw.yml index 2f3981ea2..bc33e42e4 100644 --- a/.github/workflows/db2luw.yml +++ b/.github/workflows/db2luw.yml @@ -35,4 +35,4 @@ jobs: ~/.m2 key: build-${{ env.cache-name }} - name: db2 - run: mvn clean test -Dprops.file=testconfig/ebean-db2.properties + run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-db2.properties diff --git a/.github/workflows/h2database.yml b/.github/workflows/h2database.yml index 19bf37db6..69327b590 100644 --- a/.github/workflows/h2database.yml +++ b/.github/workflows/h2database.yml @@ -37,5 +37,5 @@ jobs: - name: Maven version run: mvn --version - name: H2Database - run: mvn clean package + run: mvn -T 8 clean package diff --git a/.github/workflows/jdk-18-ea.yml b/.github/workflows/jdk-18-ea.yml index b814c77c9..22e4d9906 100644 --- a/.github/workflows/jdk-18-ea.yml +++ b/.github/workflows/jdk-18-ea.yml @@ -35,5 +35,5 @@ jobs: ~/.m2 key: build-${{ env.cache-name }} - name: Build with Maven - run: mvn package + run: mvn -T 8 test diff --git a/.github/workflows/jdk-ea.yml b/.github/workflows/jdk-ea.yml index 9bc66c0ef..04bc7026f 100644 --- a/.github/workflows/jdk-ea.yml +++ b/.github/workflows/jdk-ea.yml @@ -39,5 +39,5 @@ jobs: - name: Maven version run: mvn --version - name: Build with Maven - run: mvn package + run: mvn -T 8 test diff --git a/.github/workflows/mariadb.yml b/.github/workflows/mariadb.yml index b7db361cd..bcb65357a 100644 --- a/.github/workflows/mariadb.yml +++ b/.github/workflows/mariadb.yml @@ -35,4 +35,4 @@ jobs: ~/.m2 key: build-${{ env.cache-name }} - name: mariadb 10.6 - run: mvn clean test -Dprops.file=testconfig/ebean-mariadb.properties + run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-mariadb.properties diff --git a/.github/workflows/mysql.yml b/.github/workflows/mysql.yml index 3de91cb2d..2ab6722a2 100644 --- a/.github/workflows/mysql.yml +++ b/.github/workflows/mysql.yml @@ -35,4 +35,4 @@ jobs: ~/.m2 key: build-${{ env.cache-name }} - name: mysql - run: mvn clean test -Dprops.file=testconfig/ebean-mysql.properties + run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-mysql.properties diff --git a/.github/workflows/oracle18.yml b/.github/workflows/oracle.yml similarity index 87% rename from .github/workflows/oracle18.yml rename to .github/workflows/oracle.yml index 20a8d01e2..4be08e5e3 100644 --- a/.github/workflows/oracle18.yml +++ b/.github/workflows/oracle.yml @@ -1,5 +1,5 @@ -name: Oracle18 +name: Oracle on: workflow_dispatch: @@ -35,4 +35,4 @@ jobs: ~/.m2 key: build-${{ env.cache-name }} - name: oracle - run: mvn clean test -Dprops.file=testconfig/ebean-oracle.properties + run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-oracle.properties diff --git a/.github/workflows/postgres.yml b/.github/workflows/postgres.yml index b6359e698..a6efd5f0a 100644 --- a/.github/workflows/postgres.yml +++ b/.github/workflows/postgres.yml @@ -35,4 +35,4 @@ jobs: ~/.m2 key: build-${{ env.cache-name }} - name: postgres - run: mvn clean test -Dprops.file=testconfig/ebean-postgres.properties + run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-postgres.properties diff --git a/.github/workflows/sqlserver.yml b/.github/workflows/sqlserver.yml index 169dd0017..369d6c9a7 100644 --- a/.github/workflows/sqlserver.yml +++ b/.github/workflows/sqlserver.yml @@ -35,4 +35,4 @@ jobs: ~/.m2 key: build-${{ env.cache-name }} - name: sqlserver 2017 - run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver17.properties + run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-sqlserver17.properties diff --git a/README.md b/README.md index 83bcbae96..b43bd0b63 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ [![Postgres](https://github.com/ebean-orm/ebean/actions/workflows/postgres.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/postgres.yml) [![MySql](https://github.com/ebean-orm/ebean/actions/workflows/mysql.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mysql.yml) [![MariaDB](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml) +[![Oracle](https://github.com/ebean-orm/ebean/actions/workflows/oracle.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/oracle.yml) [![SqlServer](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml) [![Yugabyte](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 90c1a5bb0..20b7ccd00 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -802,20 +802,6 @@ public class DatabasePlatform { } } - /** - * Return true if partitions exist for the given table. - */ - public boolean tablePartitionsExist(Connection connection, String table) throws SQLException { - return true; - } - - /** - * Return the SQL to create an initial partition for the given table. - */ - public String tablePartitionInit(String tableName, PartitionMode mode) { - return null; - } - /** * Escapes the like string for this DB-Platform */ diff --git a/ebean-core-type/src/main/java/io/ebean/core/type/ScalarType.java b/ebean-core-type/src/main/java/io/ebean/core/type/ScalarType.java index 6c01811c5..af3e73493 100644 --- a/ebean-core-type/src/main/java/io/ebean/core/type/ScalarType.java +++ b/ebean-core-type/src/main/java/io/ebean/core/type/ScalarType.java @@ -16,25 +16,24 @@ import java.sql.SQLException; *

* Scalar in the sense that the types are not compound types. Scalar types only * map to a single database column. - *

*

* These types fall into two categories. Types that are mapped natively to JDBC * types and the rest. Types that map to native JDBC types do not require any * data type conversion to be persisted to the database. These are java types * that map via java.sql.Types. - *

*

* Types that are not native to JDBC require some conversion. These include some * common java types such as java.util.Date, java.util.Calendar, * java.math.BigInteger. - *

*

* Note that Booleans may be native for some databases and require conversion on * other databases. - *

*/ public interface ScalarType extends StringParser, StringFormatter, ScalarDataReader { + /** + * Return true for types that do mutation detection based on json content. + */ default boolean isJsonMapper() { return false; } @@ -43,38 +42,40 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData * Return true if this is a binary type and can not support parse() and format() from/to string. * This allows Ebean to optimise marshalling types to string. */ - boolean isBinaryType(); + default boolean isBinaryType() { + return false; + } /** * Return true if this is a mutable scalar type (like hstore). */ - boolean isMutable(); + default boolean isMutable() { + return false; + } /** * For mutable scalarType's return true if the value is dirty. * Non-dirty properties may be excluded from updates. */ - boolean isDirty(Object value); + default boolean isDirty(Object value) { + return false; + } /** * Return the default DB column length for this type. *

* If a BeanProperty has no explicit length defined then this length should * be assigned. - *

- *

- * This is primarily to support defining a length on Enum types (to - * supplement defining the length on the BeanProperty directly). - *

*/ - int getLength(); + default int getLength() { + return 0; + } /** * Return true if the type is native to JDBC. *

* If it is native to JDBC then its values/instances do not need to be * converted to and from an associated JDBC type. - *

*/ boolean isJdbcNative(); @@ -83,16 +84,13 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData *

* This type should be consistent with the toJdbcType() method in converting * the type to the appropriate type for binding to preparedStatements. - *

*/ int getJdbcType(); /** * Return the type that matches the bean property type. *

- * This represents the 'logical' type rather than the JDBC type this maps - * to. - *

+ * This represents the 'logical' type rather than the JDBC type this maps to. */ Class getType(); @@ -104,7 +102,7 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData T read(DataReader reader) throws SQLException; /** - * Ignore the reading of this value. Typically this means moving the index + * Ignore the reading of this value. Typically, this means moving the index * position in the ResultSet. */ void loadIgnore(DataReader reader); @@ -114,20 +112,16 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData *

* value may need to be converted from the logical bean property type to the * JDBC type. - *

*/ void bind(DataBinder binder, T value) throws SQLException; /** * Convert the value as necessary to the JDBC type. *

- * Note that this should also match the type as per the getJdbcType() - * method. - *

+ * Note that this should also match the type as per the getJdbcType() method. *

* This is typically used when the matching type is used in a where clause * and we use this to ensure it is an appropriate jdbc type. - *

*/ Object toJdbcType(Object value); @@ -135,19 +129,14 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData * Convert the value as necessary to the logical Bean type. *

* The type as per the bean property. - *

*

* This is used to automatically convert id values (typically from a string * to a int, long or UUID). - *

*/ T toBeanType(Object value); /** * Convert the type into a string representation. - *

- * Reciprocal of parse(). - *

*/ String formatValue(T value); @@ -155,10 +144,8 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData * Convert the type into a string representation. *

* This assumes the value is of the correct type. - *

*

* This is so that ScalarType also implements the StringFormatter interface. - *

*/ @Override String format(Object value); @@ -167,10 +154,6 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData * Convert the string value to the appropriate java object. *

* Mostly used to support CSV, JSON and XML parsing. - *

- *

- * Reciprocal of formatValue(). - *

*/ @Override T parse(String value); @@ -183,29 +166,32 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData /** * Return true if the type can accept long systemTimeMillis input. *

- * This is used to determine if is is sensible to use the + * This is used to determine if it is sensible to use the * {@link #convertFromMillis(long)} method. - *

*

* This includes the Date, Calendar, sql Date, Time, Timestamp, JODA types * as well as Long, BigDecimal and String (although it generally is not * expected to parse systemTimeMillis to a String or BigDecimal). - *

*/ - boolean isDateTimeCapable(); + default boolean isDateTimeCapable() { + return false; + } /** * Convert the value into a long version value. */ - long asVersion(T value); + default long asVersion(T value) { + throw new UnsupportedOperationException(); + } /** * Convert the systemTimeMillis into the appropriate java object. *

* For non dateTime types this will throw an exception. - *

*/ - T convertFromMillis(long dateTime); + default T convertFromMillis(long dateTime) { + throw new UnsupportedOperationException(); + } /** * Read the value from binary input. @@ -215,7 +201,7 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData /** * Write the value to binary output. */ - void writeData(DataOutput dataOutput, T v) throws IOException; + void writeData(DataOutput dataOutput, T value) throws IOException; /** * Read the value from JsonParser. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index f73fcb97d..2af16b25b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -77,8 +77,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP */ private List> updatedManys; /** - * Need to get and store the updated properties because the persist listener is notified - * later on a different thread and the bean has been reset at that point. + * Store the updated properties to notify persist listener. */ private Set updatedProperties; /** @@ -122,7 +121,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP */ private boolean complete; /** - * Many to many intersection table changes that are held for later batch processing. + * Many-to-many intersection table changes that are held for later batch processing. */ private List saveMany; @@ -148,9 +147,10 @@ public final class PersistRequestBean extends PersistRequest implements BeanP // 'stateless update' - set loaded properties as dirty intercept.setNewBeanForUpdate(); statelessUpdate = true; + } else if (!intercept.isDirty()) { + // check if any mutable scalar properties are dirty + beanDescriptor.checkAnyMutableProperties(intercept); } - // Mark Mutable scalar properties (like Hstore) as dirty where necessary - beanDescriptor.checkMutableProperties(intercept); } this.concurrencyMode = beanDescriptor.concurrencyMode(intercept); this.publish = Flags.isPublish(flags); @@ -726,10 +726,6 @@ public final class PersistRequestBean extends PersistRequest implements BeanP executeInsert(); return -1; case UPDATE: - if (beanPersistListener != null) { - // store the updated properties for sending later - updatedProperties = updatedProperties(); - } executeUpdate(); return -1; case DELETE_SOFT: @@ -1208,6 +1204,11 @@ public final class PersistRequestBean extends PersistRequest implements BeanP private void executeUpdate() { setTenantId(); if (controller == null || controller.preUpdate(this)) { + // check dirty state for all mutable scalar properties (like DbJson, Hstore) + beanDescriptor.checkAllMutableProperties(intercept); + if (beanPersistListener != null) { + updatedProperties = updatedProperties(); + } postControllerPrepareUpdate(); beanManager.getBeanPersister().update(this); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 6951438cf..e8d8f2d04 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -3140,9 +3140,9 @@ public class BeanDescriptor implements BeanType, STreeType, SpiBeanType { } /** - * Check for mutable scalar types and mark as dirty if necessary. + * Check all mutable scalar types and mark as dirty if necessary. */ - public void checkMutableProperties(EntityBeanIntercept ebi) { + public void checkAllMutableProperties(EntityBeanIntercept ebi) { for (BeanProperty beanProperty : propertiesMutable) { int propertyIndex = beanProperty.propertyIndex(); if (ebi.isLoadedProperty(propertyIndex)) { @@ -3156,6 +3156,23 @@ public class BeanDescriptor implements BeanType, STreeType, SpiBeanType { } } + /** + * Return true if any mutable properties are dirty. + */ + public boolean checkAnyMutableProperties(EntityBeanIntercept ebi) { + for (BeanProperty beanProperty : propertiesMutable) { + int propertyIndex = beanProperty.propertyIndex(); + if (ebi.isLoadedProperty(propertyIndex)) { + Object value = beanProperty.getValue(ebi.getOwner()); + if (beanProperty.checkMutable(value, ebi.isDirtyProperty(propertyIndex), ebi)) { + ebi.markPropertyAsChanged(propertyIndex); + return true; + } + } + } + return false; + } + public ConcurrencyMode concurrencyMode(EntityBeanIntercept ebi) { if (!hasVersionProperty(ebi)) { return ConcurrencyMode.NONE; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 9adcf5224..af652be12 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -359,6 +359,9 @@ public final class DefaultTypeManager implements TypeManager { Type genericType = prop.getGenericType(); boolean hasJacksonAnnotations = objectMapperPresent && checkJacksonAnnotations(prop); + if (type.equals(String.class)) { + return ScalarTypeJsonString.typeFor(postgres, dbType); + } if (type.equals(List.class)) { DocPropertyType docType = getDocType(genericType); if (!hasJacksonAnnotations && isValueTypeSimple(genericType)) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBase.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBase.java index 5d2bb45e9..93ab0a6a6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBase.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBase.java @@ -18,41 +18,6 @@ abstract class ScalarTypeBase implements ScalarType { this.jdbcType = jdbcType; } - @Override - public long asVersion(T value) { - throw new RuntimeException("not supported"); - } - - @Override - public boolean isBinaryType() { - // override for binary/byte based types - return false; - } - - /** - * Default implementation of mutable false. - */ - @Override - public boolean isMutable() { - return false; - } - - /** - * Default to true. - */ - @Override - public boolean isDirty(Object value) { - return true; - } - - /** - * Just return 0. - */ - @Override - public int getLength() { - return 0; - } - @Override public boolean isJdbcNative() { return jdbcNative; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBaseVarchar.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBaseVarchar.java index 7fd7d974e..75eaa17b5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBaseVarchar.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBaseVarchar.java @@ -88,16 +88,6 @@ abstract class ScalarTypeBaseVarchar extends ScalarTypeBase { return format(value); } - @Override - public T convertFromMillis(long systemTimeMillis) { - throw new TextException("Not Supported"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override @SuppressWarnings("unchecked") public String format(Object value) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBoolean.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBoolean.java index 56bc180a9..848b0fc2a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBoolean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBoolean.java @@ -234,7 +234,6 @@ public final class ScalarTypeBoolean { @Override public int getLength() { - // typically this will return 1 return Math.max(trueValue.length(), falseValue.length()); } @@ -329,16 +328,6 @@ public final class ScalarTypeBoolean { return Boolean.valueOf(value); } - @Override - public Boolean convertFromMillis(long systemTimeMillis) { - throw new TextException("Not Supported"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override public Boolean readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeByte.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeByte.java index 250bb1006..5437ecb77 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeByte.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeByte.java @@ -85,16 +85,6 @@ final class ScalarTypeByte extends ScalarTypeBase { throw new TextException("Not supported"); } - @Override - public Byte convertFromMillis(long systemTimeMillis) { - throw new TextException("Not Supported"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override public Byte readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBytesBase.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBytesBase.java index 437c626f8..51f811ede 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBytesBase.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBytesBase.java @@ -59,16 +59,6 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { throw new TextException("Not supported"); } - @Override - public byte[] convertFromMillis(long systemTimeMillis) { - throw new TextException("Not supported"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override public byte[] readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java index df8b32ba9..ec753b307 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java @@ -26,26 +26,11 @@ public final class ScalarTypeBytesEncrypted implements ScalarType { this.dataEncryptSupport = dataEncryptSupport; } - @Override - public long asVersion(byte[] value) { - throw new RuntimeException("not supported"); - } - @Override public boolean isBinaryType() { return true; } - @Override - public boolean isMutable() { - return false; - } - - @Override - public boolean isDirty(Object value) { - return false; - } - @Override public void bind(DataBinder binder, byte[] value) throws SQLException { value = dataEncryptSupport.encrypt(value); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeDuration.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeDuration.java index 8e34afe27..5daff6f4c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeDuration.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeDuration.java @@ -93,16 +93,6 @@ class ScalarTypeDuration extends ScalarTypeBase { return Duration.parse(value); } - @Override - public boolean isDateTimeCapable() { - return false; - } - - @Override - public Duration convertFromMillis(long systemTimeMillis) { - throw new TextException("Not Supported"); - } - @Override public Duration jsonRead(JsonParser parser) throws IOException { return Duration.parse(parser.getValueAsString()); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java index 1a552d11a..392fc1b86 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java @@ -30,11 +30,6 @@ public final class ScalarTypeEncryptedWrapper implements ScalarType, Local return dataEncryptSupport.encryptObject(formatValue); } - @Override - public long asVersion(T value) { - throw new RuntimeException("not supported"); - } - @Override public boolean isBinaryType() { return wrapped.isBinaryType(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java index 969bfd016..d33b06af4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java @@ -229,16 +229,6 @@ final class ScalarTypeEnumStandard { return Enum.valueOf(enumType, value); } - @Override - public Object convertFromMillis(long systemTimeMillis) { - throw new TextException("Not Supported"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override public Object jsonRead(JsonParser parser) throws IOException { if (parser.getCodec() != null) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java index cafee64f7..287c11f60 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java @@ -39,16 +39,6 @@ class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase implemen return enumType == null; } - @Override - public long asVersion(Object value) { - throw new RuntimeException("not supported"); - } - - @Override - public boolean isBinaryType() { - return false; - } - /** * Return the IN values for DB constraint construction. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeFile.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeFile.java index 6430e2d1c..b10b206de 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeFile.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeFile.java @@ -126,16 +126,6 @@ final class ScalarTypeFile extends ScalarTypeBase { throw new TextException("Not supported"); } - @Override - public File convertFromMillis(long systemTimeMillis) { - throw new TextException("Not supported"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override public File readData(DataInput dataInput) throws IOException { // skip reading large file diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonCollection.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonCollection.java index e40e1a9ae..e78f6b02d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonCollection.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonCollection.java @@ -80,16 +80,6 @@ abstract class ScalarTypeJsonCollection extends ScalarTypeBase implements return docPropertyType; } - @Override - public boolean isDateTimeCapable() { - return false; - } - - @Override - public T convertFromMillis(long dateTime) { - return null; - } - @Override public T readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMap.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMap.java index b5942289e..96030c23f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMap.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMap.java @@ -215,16 +215,6 @@ abstract class ScalarTypeJsonMap extends ScalarTypeBase { } } - @Override - public final Map convertFromMillis(long dateTime) { - throw new RuntimeException("Should never be called"); - } - - @Override - public final boolean isDateTimeCapable() { - return false; - } - @Override public final Map readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java index 8d2501f04..5efcb2c7b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java @@ -167,16 +167,6 @@ abstract class ScalarTypeJsonNode extends ScalarTypeBase { } } - @Override - public JsonNode convertFromMillis(long dateTime) { - throw new RuntimeException("Should never be called"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override public JsonNode readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java index 3a863df1e..94bfd4c88 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java @@ -55,16 +55,6 @@ final class ScalarTypeJsonObjectMapper { NoMutationDetection(TypeJsonManager jsonManager, AnnotatedField field, int dbType, DocPropertyType docType) { super(Object.class, jsonManager, field, dbType, docType); } - - @Override - public boolean isMutable() { - return false; - } - - @Override - public boolean isDirty(Object value) { - return false; - } } /** @@ -79,6 +69,11 @@ final class ScalarTypeJsonObjectMapper { this.jsonb = "jsonb".equals(pgType); } + @Override + public boolean isMutable() { + return true; + } + @Override public boolean isJsonMapper() { return true; @@ -144,11 +139,6 @@ final class ScalarTypeJsonObjectMapper { this.objectWriter = helper.objectWriter(); } - @Override - public boolean isMutable() { - return true; - } - @Override public T read(DataReader reader) throws SQLException { String json = reader.getString(); @@ -212,16 +202,6 @@ final class ScalarTypeJsonObjectMapper { return docType; } - @Override - public final boolean isDateTimeCapable() { - return false; - } - - @Override - public final T convertFromMillis(long dateTime) { - throw new IllegalStateException("Not supported"); - } - @Override public final T jsonRead(JsonParser parser) throws IOException { return objectReader.readValue(parser, deserType); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonString.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonString.java new file mode 100644 index 000000000..51fb54d4b --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonString.java @@ -0,0 +1,41 @@ +package io.ebeaninternal.server.type; + +import io.ebean.config.dbplatform.DbPlatformType; +import io.ebean.config.dbplatform.ExtraDbTypes; +import io.ebean.core.type.DataBinder; +import io.ebean.core.type.ScalarType; + +import java.sql.SQLException; + +final class ScalarTypeJsonString { + + static final Postgres JSONB = new Postgres(ExtraDbTypes.JSONB, PostgresHelper.JSONB_TYPE); + static final Postgres JSON = new Postgres(ExtraDbTypes.JSON, PostgresHelper.JSON_TYPE); + + static ScalarType typeFor(boolean postgres, int dbType) { + if (postgres) { + switch (dbType) { + case DbPlatformType.JSONB: + return JSONB; + case DbPlatformType.JSON: + return JSON; + } + } + return ScalarTypeString.INSTANCE; + } + + private static class Postgres extends ScalarTypeStringBase { + final String postgresType; + + Postgres(int jdbcType, String postgresType) { + super(true, jdbcType); + this.postgresType = postgresType; + } + + @Override + public void bind(DataBinder binder, String rawJson) throws SQLException { + binder.setObject(PostgresHelper.asObject(postgresType, rawJson)); + } + } + +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonthDay.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonthDay.java index eb26a84b9..f655894ee 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonthDay.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonthDay.java @@ -78,16 +78,6 @@ final class ScalarTypeMonthDay extends ScalarTypeBase { return MonthDay.parse(value); } - @Override - public boolean isDateTimeCapable() { - return false; - } - - @Override - public MonthDay convertFromMillis(long dateTime) { - throw new RuntimeException("Not supported on this type"); - } - @Override public MonthDay readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeNotFound.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeNotFound.java index 7fbb5b5e9..ef0495296 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeNotFound.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeNotFound.java @@ -22,25 +22,6 @@ class ScalarTypeNotFound implements ScalarType { public static final ScalarTypeNotFound INSTANCE = new ScalarTypeNotFound(); private ScalarTypeNotFound() { } - @Override - public boolean isBinaryType() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isMutable() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isDirty(Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public int getLength() { - throw new UnsupportedOperationException(); - } @Override public boolean isJdbcNative() { @@ -102,21 +83,6 @@ class ScalarTypeNotFound implements ScalarType { throw new UnsupportedOperationException(); } - @Override - public boolean isDateTimeCapable() { - throw new UnsupportedOperationException(); - } - - @Override - public long asVersion(Void value) { - throw new UnsupportedOperationException(); - } - - @Override - public Void convertFromMillis(long dateTime) { - throw new UnsupportedOperationException(); - } - @Override public Void readData(DataInput dataInput) throws IOException { throw new UnsupportedOperationException(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypePostgresHstore.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypePostgresHstore.java index 69b3d8a5b..2f33dc929 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypePostgresHstore.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypePostgresHstore.java @@ -82,16 +82,6 @@ final class ScalarTypePostgresHstore extends ScalarTypeBase { } } - @Override - public Map convertFromMillis(long dateTime) { - throw new RuntimeException("Should never be called"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override public Map readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeShort.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeShort.java index b3205b747..11bfa7b22 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeShort.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeShort.java @@ -57,16 +57,6 @@ final class ScalarTypeShort extends ScalarTypeBase { return Short.valueOf(value); } - @Override - public Short convertFromMillis(long systemTimeMillis) { - throw new TextException("Not Supported"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override public Short readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeUUIDBase.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeUUIDBase.java index 7da989b82..db003d526 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeUUIDBase.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeUUIDBase.java @@ -25,16 +25,6 @@ abstract class ScalarTypeUUIDBase extends ScalarTypeBase implements Scalar return DbPlatformType.UUID; } - @Override - public boolean isMutable() { - return false; - } - - @Override - public boolean isDirty(Object value) { - return true; - } - @Override public String format(Object value) { return String.valueOf(value); @@ -50,16 +40,6 @@ abstract class ScalarTypeUUIDBase extends ScalarTypeBase implements Scalar return UUID.fromString(value); } - @Override - public UUID convertFromMillis(long dateTime) { - throw new RuntimeException("Should never be called"); - } - - @Override - public boolean isDateTimeCapable() { - return false; - } - @Override public UUID toBeanType(Object value) { return BasicTypeConverter.toUUID(value, false); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeWrapper.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeWrapper.java index 1ce79bec0..f0e83bed3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeWrapper.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeWrapper.java @@ -44,8 +44,7 @@ public class ScalarTypeWrapper implements ScalarType { @Override public long asVersion(B value) { - S unwrapValue = converter.unwrapValue(value); - return scalarType.asVersion(unwrapValue); + return scalarType.asVersion(converter.unwrapValue(value)); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeYear.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeYear.java index c515de0e3..7d19c248c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeYear.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeYear.java @@ -81,16 +81,6 @@ final class ScalarTypeYear extends ScalarTypeBase { return Year.parse(value); } - @Override - public boolean isDateTimeCapable() { - return false; - } - - @Override - public Year convertFromMillis(long systemTimeMillis) { - throw new TextException("Not Supported"); - } - @Override public Year jsonRead(JsonParser parser) throws IOException { return Year.of(parser.getIntValue()); diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/profile/BasicProfileLocationTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/profile/BasicProfileLocationTest.java index d08afe225..ea33744b8 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/profile/BasicProfileLocationTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/profile/BasicProfileLocationTest.java @@ -17,11 +17,11 @@ class BasicProfileLocationTest { assertThat(loc.fullLocation()).endsWith("invoke0(Native Method:12)"); assertThat(loc.location()).isEqualTo("sun.reflect.NativeMethodAccessorImpl.invoke0"); assertThat(loc.label()).isEqualTo("NativeMethodAccessorImpl.invoke0"); - } else if (javaVersion.startsWith("18") || javaVersion.startsWith("19")){ + } else if (javaVersion.startsWith("18") || javaVersion.startsWith("19") || javaVersion.startsWith("20")){ assertThat(loc.fullLocation()).endsWith("jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)"); assertThat(loc.location()).isEqualTo("java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke"); assertThat(loc.label()).isEqualTo("DirectMethodHandleAccessor.invoke"); - } else { + } else if (javaVersion.startsWith("11") || javaVersion.startsWith("17")) { assertThat(loc.fullLocation()).endsWith("jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method:12)"); assertThat(loc.location()).isEqualTo("java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0"); assertThat(loc.label()).isEqualTo("NativeMethodAccessorImpl.invoke0"); diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeDurationTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeDurationTest.java index 1a57f6080..1a8fb3218 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeDurationTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeDurationTest.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.type; -import io.ebean.text.TextException; import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; @@ -11,13 +10,12 @@ import java.time.Duration; import static org.junit.jupiter.api.Assertions.*; -public class ScalarTypeDurationTest { +class ScalarTypeDurationTest { ScalarTypeDuration type = new ScalarTypeDuration(); @Test - public void testReadData() throws Exception { - + void testReadData() throws Exception { Duration duration = Duration.ofSeconds(1234); ByteArrayOutputStream os = new ByteArrayOutputStream(); @@ -39,8 +37,7 @@ public class ScalarTypeDurationTest { } @Test - public void testToJdbcType() throws Exception { - + void testToJdbcType() throws Exception { Duration duration = Duration.ofSeconds(1234); long seconds = duration.getSeconds(); @@ -52,8 +49,7 @@ public class ScalarTypeDurationTest { } @Test - public void testToBeanType() throws Exception { - + void testToBeanType() throws Exception { Duration duration = Duration.ofSeconds(1234); long seconds = duration.getSeconds(); @@ -67,37 +63,34 @@ public class ScalarTypeDurationTest { } @Test - public void testFormatValue() throws Exception { - + void testFormatValue() { Duration duration = Duration.ofSeconds(1234); String formatValue = type.formatValue(duration); assertEquals("PT20M34S", formatValue); } @Test - public void testParse() { + void testParse() { Duration duration = type.parse("PT20M34S"); assertEquals(Duration.ofSeconds(1234), duration); } @Test - public void testIsDateTimeCapable() { + void testIsDateTimeCapable() { assertFalse(type.isDateTimeCapable()); } @Test - public void testConvertFromMillis() { - assertThrows(TextException.class, () -> type.convertFromMillis(1000)); + void testConvertFromMillis() { + assertThrows(UnsupportedOperationException.class, () -> type.convertFromMillis(1000)); } @Test - public void testJsonRead() throws Exception { - + void testJsonRead() throws Exception { Duration duration = Duration.ofSeconds(1234); JsonTester jsonTester = new JsonTester<>(type); jsonTester.test(duration); - } } diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeDurationWithNanosTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeDurationWithNanosTest.java index 60e4ffe29..aca406df5 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeDurationWithNanosTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeDurationWithNanosTest.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.type; -import io.ebean.text.TextException; import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; @@ -12,13 +11,12 @@ import java.time.Duration; import static org.junit.jupiter.api.Assertions.*; -public class ScalarTypeDurationWithNanosTest { +class ScalarTypeDurationWithNanosTest { ScalarTypeDurationWithNanos type = new ScalarTypeDurationWithNanos(); @Test - public void testReadData() throws Exception { - + void testReadData() throws Exception { Duration duration = Duration.ofSeconds(323, 1500000); ByteArrayOutputStream os = new ByteArrayOutputStream(); @@ -40,8 +38,7 @@ public class ScalarTypeDurationWithNanosTest { } @Test - public void testToJdbcType() throws Exception { - + void testToJdbcType() throws Exception { Duration duration = Duration.ofSeconds(323, 1500000); BigDecimal bigDecimal = DecimalUtils.toDecimal(duration); @@ -53,8 +50,7 @@ public class ScalarTypeDurationWithNanosTest { } @Test - public void testToBeanType() throws Exception { - + void testToBeanType() throws Exception { Duration duration = Duration.ofSeconds(323, 1500000); BigDecimal bigDecimal = DecimalUtils.toDecimal(duration); @@ -66,32 +62,31 @@ public class ScalarTypeDurationWithNanosTest { } @Test - public void testFormatValue() throws Exception { - + void testFormatValue() { Duration duration = Duration.ofSeconds(323, 1500000); String formatValue = type.formatValue(duration); assertEquals("PT5M23.0015S", formatValue); } @Test - public void testParse() { + void testParse() { Duration duration = Duration.ofSeconds(323, 1500000); Duration val1 = type.parse("PT5M23.0015S"); assertEquals(duration, val1); } @Test - public void testIsDateTimeCapable() { + void testIsDateTimeCapable() { assertFalse(type.isDateTimeCapable()); } @Test - public void testConvertFromMillis() { - assertThrows(TextException.class, () -> type.convertFromMillis(1000)); + void testConvertFromMillis() { + assertThrows(UnsupportedOperationException.class, () -> type.convertFromMillis(1000)); } @Test - public void testJsonRead() throws Exception { + void testJsonRead() throws Exception { Duration duration = Duration.ofSeconds(323, 1500000); JsonTester jsonTester = new JsonTester<>(type); diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeYearTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeYearTest.java index c37282744..9a0440b67 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeYearTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/type/ScalarTypeYearTest.java @@ -11,13 +11,12 @@ import java.time.Year; import static org.junit.jupiter.api.Assertions.*; -public class ScalarTypeYearTest { +class ScalarTypeYearTest { ScalarTypeYear type = new ScalarTypeYear(); @Test - public void testReadData() throws Exception { - + void testReadData() throws Exception { ByteArrayOutputStream os = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(os); @@ -37,8 +36,7 @@ public class ScalarTypeYearTest { } @Test - public void testToJdbcType() throws Exception { - + void testToJdbcType() throws Exception { Integer year = 2013; Object val1 = type.toJdbcType(Year.of(2013)); Object val2 = type.toJdbcType(2013); @@ -50,8 +48,7 @@ public class ScalarTypeYearTest { } @Test - public void testToBeanType() throws Exception { - + void testToBeanType() throws Exception { Year year = Year.of(2013); Year val1 = type.toBeanType(year); Year val2 = type.toBeanType(2013); @@ -63,29 +60,29 @@ public class ScalarTypeYearTest { } @Test - public void testFormatValue() throws Exception { + void testFormatValue() { String formatted = type.formatValue(Year.of(2013)); assertEquals("2013", formatted); } @Test - public void testParse() { + void testParse() { Year year = type.parse("2013"); assertEquals(Year.of(2013), year); } @Test - public void testIsDateTimeCapable() { + void testIsDateTimeCapable() { assertFalse(type.isDateTimeCapable()); } @Test - public void testConvertFromMillis() { - assertThrows(TextException.class, () -> type.convertFromMillis(1000)); + void testConvertFromMillis() { + assertThrows(UnsupportedOperationException.class, () -> type.convertFromMillis(1000)); } @Test - public void testJson() throws Exception { + void testJson() throws Exception { JsonTester jsonTester = new JsonTester<>(type); jsonTester.test(Year.of(2013)); } diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlPlugin.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlPlugin.java index 25966df06..1811ffa1f 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlPlugin.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlPlugin.java @@ -11,19 +11,12 @@ import io.ebean.util.IOUtils; import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.dbmigration.model.CurrentModel; -import io.ebeaninternal.dbmigration.model.MTable; import io.ebeaninternal.extraddl.model.ExtraDdlXmlReader; -import io.ebeaninternal.server.deploy.PartitionMeta; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.persistence.PersistenceException; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.LineNumberReader; -import java.io.Reader; -import java.io.Writer; +import java.io.*; import java.sql.Connection; import java.sql.SQLException; @@ -201,7 +194,6 @@ public class DdlPlugin implements Plugin { createAllContent = readFile(getCreateFileName()); } runScript(connection, false, createAllContent, getCreateFileName()); - if (extraDdl && jaxbPresent) { if (currentModel().isTablePartitioning()) { String extraPartitioning = ExtraDdlXmlReader.buildPartitioning(platform); @@ -209,43 +201,10 @@ public class DdlPlugin implements Plugin { runScript(connection, false, extraPartitioning, "builtin-partitioning-ddl"); } } - String extraApply = ExtraDdlXmlReader.buildExtra(platform, false); if (extraApply != null) { runScript(connection, false, extraApply, "extra-ddl"); } - - if (currentModel().isTablePartitioning()) { - checkInitialTablePartitions(connection); - } - } - } - - /** - * Check if table partitions exist and if not create some. The expectation is that - * extra-ddl.xml should have some partition initialisation but this helps people get going. - */ - private void checkInitialTablePartitions(Connection connection) { - DatabasePlatform databasePlatform = server.databasePlatform(); - try { - StringBuilder sb = new StringBuilder(); - for (MTable table : currentModel.getPartitionedTables()) { - String tableName = table.getName(); - if (!databasePlatform.tablePartitionsExist(connection, tableName)) { - log.info("No table partitions for table {}", tableName); - PartitionMeta meta = table.getPartitionMeta(); - String initPart = databasePlatform.tablePartitionInit(tableName, meta.getMode()); - sb.append(initPart).append("\n"); - } - } - - String initialPartitionSql = sb.toString(); - if (!initialPartitionSql.isEmpty()) { - runScript(connection, false, initialPartitionSql, "initial table partitions"); - } - - } catch (SQLException e) { - log.error("Error checking initial table partitions", e); } } diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java index 438bd5907..17e6a3b26 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -214,6 +214,8 @@ public class BaseTableDdl implements TableDdl { String partitionMode = createTable.getPartitionMode(); if (partitionMode != null) { platformDdl.addTablePartition(apply, partitionMode, createTable.getPartitionColumn()); + apply.endOfStatement().newLine(); + platformDdl.addDefaultTablePartition(apply, createTable.getName()); } apply.endOfStatement(); diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NuoDbDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NuoDbDdl.java index 0f0c15871..9966878c9 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NuoDbDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NuoDbDdl.java @@ -13,6 +13,22 @@ public class NuoDbDdl extends PlatformDdl { this.dropConstraintIfExists = "drop constraint"; } + @Override + public String createSequence(String sequenceName, DdlIdentity identity) { + StringBuilder sb = new StringBuilder("create sequence "); + sb.append(quote(sequenceName)); + int start = identity.getStart(); + if (start > 0) { + sb.append(" ").append(sequenceStartWith).append(" ").append(start); + } + int cache = identity.getCache(); + if (cache > 0) { + sb.append(" quantum size ").append(cache); + } + sb.append(";"); + return sb.toString(); + } + @Override public void addTableComment(DdlBuffer apply, String tableName, String tableComment) { // do nothing diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java index d9c7de750..f18b3c79e 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -733,7 +733,11 @@ public class PlatformDdl { } public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) { - // only supported by postgres initially + // only supported by postgres and yugabyte + } + + public void addDefaultTablePartition(DdlBuffer apply, String tableName) { + // only supported by postgres and yugabyte } /** diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java index b5b21ab15..3054a73d9 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java @@ -45,6 +45,11 @@ public class PostgresDdl extends PlatformDdl { apply.append(" partition by range (").append(partitionColumn).append(")"); } + @Override + public void addDefaultTablePartition(DdlBuffer apply, String tableName) { + apply.append("create table ").append(tableName).append("_default partition of ").append(tableName).append(" default"); + } + @Override public String dropIndex(String indexName, String tableName, boolean concurrent) { return (concurrent ? dropIndexConcurrentlyIfExists : dropIndexIfExists) + maxConstraintName(indexName); diff --git a/ebean-ddl-generator/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml b/ebean-ddl-generator/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml index 0e3608090..b0a6accf3 100644 --- a/ebean-ddl-generator/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml +++ b/ebean-ddl-generator/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml @@ -1,7 +1,7 @@ - + -- partitioning helper functions (UTC based) ------------------------------------------------------------------------------------ diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/PostgresPlatformTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/PostgresPlatformTest.java index 814580225..81546816a 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/PostgresPlatformTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/PostgresPlatformTest.java @@ -7,11 +7,10 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; -public class PostgresPlatformTest { +class PostgresPlatformTest { @Test - public void testTypeConversion() { - + void testTypeConversion() { PostgresPlatform platform = new PostgresPlatform(); PlatformDdl ddl = PlatformDdlBuilder.create(platform); diff --git a/ebean-postgis/src/main/java/io/ebean/postgis/ScalarTypePgisBase.java b/ebean-postgis/src/main/java/io/ebean/postgis/ScalarTypePgisBase.java index adc3bbd98..d96f45476 100644 --- a/ebean-postgis/src/main/java/io/ebean/postgis/ScalarTypePgisBase.java +++ b/ebean-postgis/src/main/java/io/ebean/postgis/ScalarTypePgisBase.java @@ -86,26 +86,6 @@ abstract class ScalarTypePgisBase implements ScalarType { } - @Override - public boolean isBinaryType() { - return false; - } - - @Override - public boolean isMutable() { - return false; - } - - @Override - public boolean isDirty(Object value) { - return false; - } - - @Override - public int getLength() { - return 0; - } - @Override public void loadIgnore(DataReader reader) { reader.incrementPos(1); @@ -141,22 +121,6 @@ abstract class ScalarTypePgisBase implements ScalarType { return null; } - @Override - public boolean isDateTimeCapable() { - return false; - } - - @Override - public long asVersion(T value) { - return 0; - } - - @Override - public T convertFromMillis(long dateTime) { - return null; - } - - @Override public T jsonRead(JsonParser parser) { return null; diff --git a/ebean-postgis/src/main/java/io/ebean/postgis/latte/ScalarTypeGeoLatteBase.java b/ebean-postgis/src/main/java/io/ebean/postgis/latte/ScalarTypeGeoLatteBase.java index 2dd779c38..c90b887f5 100644 --- a/ebean-postgis/src/main/java/io/ebean/postgis/latte/ScalarTypeGeoLatteBase.java +++ b/ebean-postgis/src/main/java/io/ebean/postgis/latte/ScalarTypeGeoLatteBase.java @@ -77,26 +77,6 @@ abstract class ScalarTypeGeoLatteBase implements ScalarType< } - @Override - public boolean isBinaryType() { - return false; - } - - @Override - public boolean isMutable() { - return false; - } - - @Override - public boolean isDirty(Object value) { - return false; - } - - @Override - public int getLength() { - return 0; - } - @Override public void loadIgnore(DataReader reader) { reader.incrementPos(1); @@ -132,21 +112,6 @@ abstract class ScalarTypeGeoLatteBase implements ScalarType< return null; } - @Override - public boolean isDateTimeCapable() { - return false; - } - - @Override - public long asVersion(T value) { - return 0; - } - - @Override - public T convertFromMillis(long dateTime) { - return null; - } - @Override public T jsonRead(JsonParser parser) { return null; diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index f727591df..94ca95d80 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -228,7 +228,7 @@ com.nuodb.jdbc nuodb-jdbc - 22.0.0 + 23.0.0 test diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java index 3da2f3eee..4dd36034a 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java @@ -17,7 +17,7 @@ class Config { /** * Common optional docker parameters that we just transfer to docker properties. */ - private static final String[] DOCKER_TEST_PARAMS = {"fastStartMode", "inMemory", "initSqlFile", "seedSqlFile", "adminUser", "adminPassword", "extraDb", "extraDb.dbName", "extraDb.username", "extraDb.password", "extraDb.initSqlFile", "extraDb.seedSqlFile"}; + private static final String[] DOCKER_TEST_PARAMS = {"fastStartMode", "inMemory", "initSqlFile", "seedSqlFile", "adminUser", "adminPassword", "extraDb", "extraDb.dbName", "extraDb.username", "extraDb.password", "extraDb.extensions", "extraDb.initSqlFile", "extraDb.seedSqlFile"}; private static final String[] DOCKER_PLATFORM_PARAMS = {"containerName", "image", "internalPort", "startMode", "shutdownMode", "maxReadyAttempts", "tmpfs", "collation", "characterSet"}; private static final String DDL_MODE_OPTIONS = "dropCreate, create, none, migration, createOnly or migrationDropCreate"; @@ -224,14 +224,22 @@ class Config { properties.setProperty(dsKey, val); } - void setUrl(String urlPattern) { - String val = getKey("url", urlPattern); + private void setUrl(String key, String urlPattern) { + String val = getKey(key, urlPattern); val = val.replace("${host}", host()); val = val.replace("${port}", String.valueOf(port)); val = val.replace("${databaseName}", databaseName); this.url = val; } + void setUrl(String urlPattern) { + setUrl("url", urlPattern); + } + + void setExtraUrl(String urlPattern) { + setUrl("extraDb.url", urlPattern); + } + String host() { String explicitDockerHost = getKey("dockerHost", null); return getKey("host", dockerHost.dockerHost(explicitDockerHost)); @@ -343,9 +351,17 @@ class Config { void setExtensions(String defaultValue) { // ebean.test.postgres.extensions=hstore,pgcrypto - String val = getKey("extensions", defaultValue); + setExtensionsInternal("extensions", defaultValue); + } + + void setExtraExtensions(String defaultValue) { + setExtensionsInternal("extraDb.extensions", defaultValue); + } + + void setExtensionsInternal(String key, String defaultValue) { + String val = getKey(key, defaultValue); if (val != null) { - dockerProperties.setProperty(dockerKey("extensions"), trimExtensions(val)); + dockerProperties.setProperty(dockerKey(key), trimExtensions(val)); } } diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/OracleSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/OracleSetup.java index b93660615..db50d60be 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/OracleSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/OracleSetup.java @@ -6,25 +6,21 @@ class OracleSetup implements PlatformSetup { @Override public Properties setup(Config config) { - config.ddlMode("dropCreate"); config.setDefaultPort(1521); config.setUsernameDefault(); config.setPasswordDefault(); config.setDatabaseName("XE"); config.setUrl("jdbc:oracle:thin:@localhost:${port}:${databaseName}"); - config.setDriver("oracle.jdbc.driver.OracleDriver"); config.datasourceDefaults(); return dockerProperties(config); } private Properties dockerProperties(Config dbConfig) { - if (!dbConfig.isUseDocker()) { return new Properties(); } - - dbConfig.setDockerVersion("latest"); + dbConfig.setDockerVersion("21.3.0-slim"); return dbConfig.getDockerProperties(); } diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java index 3a9cc34e3..b254aad60 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java @@ -12,8 +12,7 @@ class PostgisSetup implements PlatformSetup { @Override public Properties setup(Config config) { int defaultPort = config.isUseDocker() ? 7432 : 5432; - - config.setDockerPlatform("postgres"); + config.setDockerPlatform("postgis"); config.ddlMode("dropCreate"); config.setDefaultPort(defaultPort); config.setUsernameDefault(); @@ -35,14 +34,18 @@ class PostgisSetup implements PlatformSetup { } config.setExtensions("hstore,pgcrypto,postgis"); config.setDockerContainerName("ut_postgis"); - config.setDockerImage("postgis/postgis"); - config.setDockerVersion("14"); + config.setDockerVersion("14-3.2"); return config.getDockerProperties(); } @Override public void setupExtraDbDataSource(Config config) { - // not supported yet + int defaultPort = config.isUseDocker() ? 7432 : 5432; + config.setDefaultPort(defaultPort); + config.setExtraUsernameDefault(); + config.setExtraDbPasswordDefault(); + config.setExtraUrl("jdbc:postgresql_lwgis://${host}:${port}/${databaseName}"); + config.extraDatasourceDefaults(); } @Override diff --git a/ebean-test/src/test/java/io/ebean/test/config/platform/ConfigTest.java b/ebean-test/src/test/java/io/ebean/test/config/platform/ConfigTest.java index 7971c2bb7..3537954ed 100644 --- a/ebean-test/src/test/java/io/ebean/test/config/platform/ConfigTest.java +++ b/ebean-test/src/test/java/io/ebean/test/config/platform/ConfigTest.java @@ -35,6 +35,43 @@ class ConfigTest { assertThat(config.trimExtensions(" a , , b ")).isEqualTo("a,b"); } + @Test + void extensions_whenNoSetValues() { + DatabaseConfig databaseConfig = new DatabaseConfig(); + databaseConfig.loadFromProperties(new Properties()); + + Config config = new Config("db", "postgis", "db", databaseConfig); + + config.setUsernameDefault(); + config.setPasswordDefault(); + config.setDefaultPort(42); + config.setExtensions("a,b"); + config.setExtraExtensions("c,d"); + + Properties dockerProperties = config.getDockerProperties(); + assertThat(dockerProperties.getProperty("postgis.extensions")).isEqualTo("a,b"); + assertThat(dockerProperties.getProperty("postgis.extraDb.extensions")).isEqualTo("c,d"); + } + + @Test + void extensions_whenSetValues() { + DatabaseConfig databaseConfig = new DatabaseConfig(); + Properties properties = new Properties(); + properties.setProperty("ebean.test.extensions", "x,y"); + properties.setProperty("ebean.test.extraDb.extensions", "z"); + databaseConfig.loadFromProperties(properties); + + Config config = new Config("db", "postgis", "db", databaseConfig); + + config.setExtensions("a,b"); + config.setExtraExtensions("c,d"); + + Properties dockerProperties = config.getDockerProperties(); + assertThat(dockerProperties.getProperty("postgis.extensions")).isEqualTo("x,y"); + assertThat(dockerProperties.getProperty("postgis.extraDb.extensions")).isEqualTo("z"); + } + + @Test void extraDbProperties_basic() { Properties p = new Properties(); diff --git a/ebean-test/src/test/java/io/ebean/xtest/event/BeanPersistControllerTest.java b/ebean-test/src/test/java/io/ebean/xtest/event/BeanPersistControllerTest.java index e584bc40b..b991e07be 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/event/BeanPersistControllerTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/event/BeanPersistControllerTest.java @@ -4,6 +4,7 @@ package io.ebean.xtest.event; import io.ebean.Database; import io.ebean.DatabaseFactory; import io.ebean.Transaction; +import io.ebean.ValuePair; import io.ebean.config.DatabaseConfig; import io.ebean.event.BeanDeleteIdRequest; import io.ebean.event.BeanPersistAdapter; @@ -13,9 +14,7 @@ import org.tests.model.basic.EBasicVer; import org.tests.model.basic.UTDetail; import org.tests.model.basic.UTMaster; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; import static org.assertj.core.api.Assertions.assertThat; @@ -26,8 +25,30 @@ public class BeanPersistControllerTest { private final PersistAdapter stopPersistingAdapter = new PersistAdapter(false); @Test - public void issue_1341() { + public void issued1() { + Database db = getDatabase(continuePersistingAdapter); + UTMaster bean0 = new UTMaster("m0"); + bean0.setJournal(new UTMaster.Journal()); + db.save(bean0); + + UTMaster change0 = db.find(UTMaster.class, bean0.getId()); + change0.setName("change0"); + db.save(change0); + + UTMaster change1 = db.find(UTMaster.class, bean0.getId()); + change1.setName("change1"); + db.save(change1); + + UTMaster again = db.find(UTMaster.class, bean0.getId()); + UTMaster.Journal journal = again.getJournal(); + assertThat(journal.getEntries()).hasSize(2); + + db.shutdown(); + } + + @Test + public void issue_1341() { Database db = getDatabase(continuePersistingAdapter); UTMaster bean0 = new UTMaster("one0"); @@ -118,7 +139,6 @@ public class BeanPersistControllerTest { } private Database getDatabase(PersistAdapter persistAdapter) { - DatabaseConfig config = new DatabaseConfig(); config.setName("h2ebasicver"); config.loadFromProperties(); @@ -133,7 +153,6 @@ public class BeanPersistControllerTest { config.getClasses().add(UTDetail.class); config.add(persistAdapter); - return DatabaseFactory.create(config); } @@ -177,6 +196,16 @@ public class BeanPersistControllerTest { // invoke lazy loading ... which invoke the flush of the jdbc batch detail.setQty(42); } + if (bean instanceof UTMaster) { + UTMaster master = (UTMaster)bean; + UTMaster.Journal journal = master.getJournal(); + if (journal == null) { + journal = new UTMaster.Journal(); + master.setJournal(journal); + } + // modify a "mutable scalar type" in preUpdate, should be included in update + journal.addEntry(); + } return continueDefaultPersisting; } diff --git a/ebean-test/src/test/java/io/ebean/xtest/internal/server/transaction/DefaultPersistenceContextTest.java b/ebean-test/src/test/java/io/ebean/xtest/internal/server/transaction/DefaultPersistenceContextTest.java index 6879eb0ba..a8c14920e 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/internal/server/transaction/DefaultPersistenceContextTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/internal/server/transaction/DefaultPersistenceContextTest.java @@ -178,16 +178,16 @@ class DefaultPersistenceContextTest { assertThat(pc.size(Customer.class)).isEqualTo(100); assertThat(pc.size(Contact.class)).isEqualTo(1010); - addCustomers(pc, 200, 100); - addContacts(pc, 2000, 1010); - - assertThat(pc.size(Customer.class)).isEqualTo(200); - assertThat(pc.size(Contact.class)).isEqualTo(2020); + addCustomers(pc, 200, 103); + assertThat(pc.size(Customer.class)).isEqualTo(203); + addContacts(pc, 2000, 1013); + assertThat(pc.size(Contact.class)).isEqualTo(2023); pc.endIterate(); System.gc(); - Thread.sleep(50); // give the GC some time + Thread.sleep(100); // give the GC some time + // back to pre beginIterate() now assertThat(pc.size(Customer.class)).isEqualTo(100); assertThat(pc.size(Contact.class)).isEqualTo(1010); } diff --git a/ebean-test/src/test/java/main/StartPostgres.java b/ebean-test/src/test/java/main/StartPostgres.java index b65aea1f2..0356ff25c 100644 --- a/ebean-test/src/test/java/main/StartPostgres.java +++ b/ebean-test/src/test/java/main/StartPostgres.java @@ -5,12 +5,12 @@ import io.ebean.test.containers.PostgresContainer; public class StartPostgres { public static void main(String[] args) { - PostgresContainer.builder("13") - .port(5432) + PostgresContainer.builder("14") .dbName("unit") - .user("unit") - .password("unit") - .containerName("pg13x") + //.port(6432) + //.user("unit") + //.password("test") + //.containerName("ut_postgres") .extensions("hstore,pgcrypto") .build() .startWithDropCreate(); diff --git a/ebean-test/src/test/java/org/tests/idkeys/TestSimpleIdInsert.java b/ebean-test/src/test/java/org/tests/idkeys/TestSimpleIdInsert.java index b869f9cf9..b977974a3 100644 --- a/ebean-test/src/test/java/org/tests/idkeys/TestSimpleIdInsert.java +++ b/ebean-test/src/test/java/org/tests/idkeys/TestSimpleIdInsert.java @@ -7,45 +7,15 @@ import org.tests.model.basic.ESimple; import static org.junit.jupiter.api.Assertions.assertNotNull; -public class TestSimpleIdInsert extends BaseTestCase { +class TestSimpleIdInsert extends BaseTestCase { @Test - public void test() { + void test() { ESimple e = new ESimple(); e.setName("name"); - DB.save(e); assertNotNull(e.getId()); - } -// // This test fails with jdbc drivers that don't -// // support batch insert with getGeneratedKeys -// public void testJdbcBatch() { -// -// GlobalProperties.put("datasource.default", "hsqldb"); -// GlobalProperties.put("ebean.classes", ESimple.class.getName()); -// -// Transaction transaction = DB.beginTransaction(); -// try { -// transaction.setBatchMode(true); -// transaction.setLogLevel(LogLevel.SQL); -// ESimple e = new ESimple(); -// e.setName("name"); -// DB.save(e); -// -// ESimple e2 = new ESimple(); -// e2.setName("name2"); -// DB.save(e2); -// transaction.commit(); -// -// Assert.assertNotNull(e.getId()); -// Assert.assertNotNull(e2.getId()); -// -// } finally { -// DB.endTransaction(); -// } -// } - } diff --git a/ebean-test/src/test/java/org/tests/json/TestDbJsonBStringType.java b/ebean-test/src/test/java/org/tests/json/TestDbJsonBStringType.java new file mode 100644 index 000000000..f26235d68 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/json/TestDbJsonBStringType.java @@ -0,0 +1,47 @@ +package org.tests.json; + +import io.ebean.DB; +import io.ebean.test.LoggedSql; +import org.junit.jupiter.api.Test; +import org.tests.model.json.EBasicJsonBString; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class TestDbJsonBStringType { + + @Test + void test() { + var bean = new EBasicJsonBString("hi").content("{\"mykey\": 42}"); // JsonB format with space + DB.save(bean); + + var found = DB.find(EBasicJsonBString.class, bean.id()); + // Note that Postgres JsonB will format the result + assertThat(found.content()).isEqualTo("{\"mykey\": 42}"); + + LoggedSql.start(); + + // change title only, expect content not in update + found.title("changeTitleOnly"); + DB.save(found); + List sql = LoggedSql.collect(); + // update does NOT contain our json content + assertThat(sql.get(0)).contains("update ebasic_json_bstring set title=?, version=? where id=? and version=?"); + + // change title and content + found.title("changeAgain"); + found.content("{\"mykey\": 92}"); + DB.save(found); + sql = LoggedSql.collect(); + assertThat(sql.get(0)).contains("update ebasic_json_bstring set title=?, content=?, version=? where id=? and version=?"); + + + // change content only + found.content("{\"mykey\": 95}"); + DB.save(found); + sql = LoggedSql.stop(); + assertThat(sql.get(0)).contains("update ebasic_json_bstring set content=?, version=? where id=? and version=?"); + + } +} diff --git a/ebean-test/src/test/java/org/tests/json/TestDbJsonStringType.java b/ebean-test/src/test/java/org/tests/json/TestDbJsonStringType.java new file mode 100644 index 000000000..307b0e561 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/json/TestDbJsonStringType.java @@ -0,0 +1,47 @@ +package org.tests.json; + +import io.ebean.DB; +import io.ebean.test.LoggedSql; +import org.junit.jupiter.api.Test; +import org.tests.model.json.EBasicJsonString; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class TestDbJsonStringType { + + @Test + void test() { + var bean = new EBasicJsonString("hi").content("{\"mykey\": 52}"); // JsonB format with space + DB.save(bean); + + var found = DB.find(EBasicJsonString.class, bean.id()); + // Note that Postgres JsonB will format the result + assertThat(found.content()).isEqualTo("{\"mykey\": 52}"); + + LoggedSql.start(); + + // change title only, expect content not in update + found.title("changeTitleOnly"); + DB.save(found); + List sql = LoggedSql.collect(); + // update does NOT contain our json content + assertThat(sql.get(0)).contains("update ebasic_json_string set title=?, version=? where id=? and version=?"); + + // change title and content + found.title("changeAgain"); + found.content("{\"mykey\": 92}"); + DB.save(found); + sql = LoggedSql.collect(); + assertThat(sql.get(0)).contains("update ebasic_json_string set title=?, content=?, version=? where id=? and version=?"); + + + // change content only + found.content("{\"mykey\": 95}"); + DB.save(found); + sql = LoggedSql.stop(); + assertThat(sql.get(0)).contains("update ebasic_json_string set content=?, version=? where id=? and version=?"); + + } +} diff --git a/ebean-test/src/test/java/org/tests/model/basic/UTMaster.java b/ebean-test/src/test/java/org/tests/model/basic/UTMaster.java index 07c5fec39..4c1b2998c 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/UTMaster.java +++ b/ebean-test/src/test/java/org/tests/model/basic/UTMaster.java @@ -1,9 +1,11 @@ package org.tests.model.basic; import io.ebean.Model; +import io.ebean.annotation.DbJsonB; import javax.persistence.*; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -20,12 +22,31 @@ public class UTMaster extends Model { LocalDate eventDate; + @DbJsonB + Journal journal; + @Version Integer version; @OneToMany(cascade = CascadeType.ALL) List details; + /** + * Mutating content persisted as JSON. + */ + public static class Journal { + private List entries = new ArrayList<>(); + public List getEntries() { + return entries; + } + public void setEntries(List entries) { + this.entries = entries; + } + public void addEntry() { + entries.add(LocalDateTime.now().toString()); + } + } + public UTMaster() { } @@ -74,6 +95,14 @@ public class UTMaster extends Model { this.version = version; } + public Journal getJournal() { + return journal; + } + + public void setJournal(Journal journal) { + this.journal = journal; + } + public List getDetails() { return details; } diff --git a/ebean-test/src/test/java/org/tests/model/json/EBasicJsonBString.java b/ebean-test/src/test/java/org/tests/model/json/EBasicJsonBString.java new file mode 100644 index 000000000..ee4617c0e --- /dev/null +++ b/ebean-test/src/test/java/org/tests/model/json/EBasicJsonBString.java @@ -0,0 +1,62 @@ +package org.tests.model.json; + +import io.ebean.annotation.DbJsonB; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +@Entity +public class EBasicJsonBString { + + @Id + long id; + + String title; + + @DbJsonB + String content; + + @Version + long version; + + public EBasicJsonBString(String title) { + this.title = title; + } + + public long id() { + return id; + } + + public EBasicJsonBString id(long id) { + this.id = id; + return this; + } + + public String title() { + return title; + } + + public EBasicJsonBString title(String title) { + this.title = title; + return this; + } + + public String content() { + return content; + } + + public EBasicJsonBString content(String content) { + this.content = content; + return this; + } + + public long version() { + return version; + } + + public EBasicJsonBString version(long version) { + this.version = version; + return this; + } +} diff --git a/ebean-test/src/test/java/org/tests/model/json/EBasicJsonString.java b/ebean-test/src/test/java/org/tests/model/json/EBasicJsonString.java new file mode 100644 index 000000000..45af516dc --- /dev/null +++ b/ebean-test/src/test/java/org/tests/model/json/EBasicJsonString.java @@ -0,0 +1,62 @@ +package org.tests.model.json; + +import io.ebean.annotation.DbJson; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +@Entity +public class EBasicJsonString { + + @Id + long id; + + String title; + + @DbJson + String content; + + @Version + long version; + + public EBasicJsonString(String title) { + this.title = title; + } + + public long id() { + return id; + } + + public EBasicJsonString id(long id) { + this.id = id; + return this; + } + + public String title() { + return title; + } + + public EBasicJsonString title(String title) { + this.title = title; + return this; + } + + public String content() { + return content; + } + + public EBasicJsonString content(String content) { + this.content = content; + return this; + } + + public long version() { + return version; + } + + public EBasicJsonString version(long version) { + this.version = version; + return this; + } +} diff --git a/ebean-test/testconfig/ebean-nuodb.properties b/ebean-test/testconfig/ebean-nuodb.properties index 9bc26267b..54adde9e1 100644 --- a/ebean-test/testconfig/ebean-nuodb.properties +++ b/ebean-test/testconfig/ebean-nuodb.properties @@ -1,3 +1,3 @@ ebean.test.platform=nuodb ebean.test.dbName=testdb -ebean.test.nuodb.version=latest \ No newline at end of file +ebean.test.nuodb.version=4.3.2 diff --git a/platforms/postgres/src/main/java/io/ebean/platform/postgres/PostgresPlatform.java b/platforms/postgres/src/main/java/io/ebean/platform/postgres/PostgresPlatform.java index 0c1b33053..6257153dc 100644 --- a/platforms/postgres/src/main/java/io/ebean/platform/postgres/PostgresPlatform.java +++ b/platforms/postgres/src/main/java/io/ebean/platform/postgres/PostgresPlatform.java @@ -147,40 +147,4 @@ public class PostgresPlatform extends DatabasePlatform { } return FOR_UPDATE; } - - @Override - public boolean tablePartitionsExist(Connection connection, String table) throws SQLException { - try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) { - statement.setString(1, table); - try (ResultSet resultSet = statement.executeQuery()) { - return resultSet.next() && resultSet.getInt(1) > 0; - } - } - } - - /** - * Return SQL using built in partition helper functions to create some initial partitions. - *

- * Only use this if extra-ddl doesn't have some initial partitions defined (which it should). - */ - @Override - public String tablePartitionInit(String tableName, PartitionMode mode) { - // default partition required pg11 but this is only used for testing but bumped test docker container to pg14 by default - String[] schemaTable = SplitName.split(tableName); - - String baseTable; - String plusSchema; - if (schemaTable[0] == null) { - plusSchema = ""; - baseTable = tableName; - } else { - // table in an explicit schema - plusSchema = ",'" + schemaTable[0] + "'"; - baseTable = schemaTable[1]; - } - return - "create table " + tableName + "_default" + " partition of " + tableName + " default;\n" + - "select partition('" + mode.name().toLowerCase() + "','" + baseTable + "',1" + plusSchema + ");"; - } - } diff --git a/platforms/postgres/src/test/java/io/ebean/platform/postgres/PostgresPlatformTest.java b/platforms/postgres/src/test/java/io/ebean/platform/postgres/PostgresPlatformTest.java index 747fbbcff..b52e3d216 100644 --- a/platforms/postgres/src/test/java/io/ebean/platform/postgres/PostgresPlatformTest.java +++ b/platforms/postgres/src/test/java/io/ebean/platform/postgres/PostgresPlatformTest.java @@ -1,6 +1,5 @@ package io.ebean.platform.postgres; -import io.ebean.annotation.PartitionMode; import io.ebean.annotation.Platform; import io.ebean.config.PlatformConfig; import io.ebean.config.dbplatform.DatabasePlatform; @@ -16,7 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; class PostgresPlatformTest { @Test - void testUuidType() { + void testUuidType() { PostgresPlatform platform = new PostgresPlatform(); platform.configure(new PlatformConfig()); @@ -26,20 +25,6 @@ class PostgresPlatformTest { assertThat(columnDefn).isEqualTo("uuid"); } - @Test - void tablePartitionInit() { - String sql = new PostgresPlatform().tablePartitionInit("foo", PartitionMode.WEEK); - assertThat(sql).isEqualTo("create table foo_default partition of foo default;\n" + - "select partition('week','foo',1);"); - } - - @Test - void tablePartitionInit_withSchema() { - String sql = new PostgresPlatform().tablePartitionInit("bar.foo", PartitionMode.WEEK); - assertThat(sql).isEqualTo("create table bar.foo_default partition of bar.foo default;\n" + - "select partition('week','foo',1,'bar');"); - } - @Test void default_forUpdate_expect_noKeyUsed() { PostgresPlatform platform = new PostgresPlatform(); diff --git a/pom.xml b/pom.xml index 30ca8ac8b..66b0f59e5 100644 --- a/pom.xml +++ b/pom.xml @@ -44,10 +44,10 @@ 2.0 1.2 13.6.0 - 6.0 + 6.1 8.0 - 13.6.3 - 13.6.3 + 13.6.4 + 13.6.4 false diff --git a/tests/test-java16/pom.xml b/tests/test-java16/pom.xml index c64065ff4..e8e40883b 100644 --- a/tests/test-java16/pom.xml +++ b/tests/test-java16/pom.xml @@ -52,7 +52,7 @@ io.ebean querybean-generator - 13.6.4-SNAPSHOT + 13.6.5-SNAPSHOT