Compare commits

..
Author SHA1 Message Date
Rob BygraveandGitHub d92abbbe9c Merge branch 'master' into feature/sequencedSet 2024-02-10 14:13:21 +13:00
Rob Bygrave 39500567c3 Build needs to use Java 21 to support the multi-release jar 2024-02-10 13:29:40 +13:00
Rob Bygrave ded6fd71b2 Refactor rename method getBeanCollectionAdd() -> collectionAdd() 2024-01-12 16:42:58 +13:00
Rob Bygrave cbc4883672 Refactor BeanSet, BeanList, BeanMap replacing setActualSet|List|Map
Replace with collectionAdd() and refresh() methods.
2024-01-12 16:41:32 +13:00
Rob Bygrave 64e227117b Add support for Java 21 SequencedSet and SequencedMap
Such that these can be used in place of Set and Map if desired.
2024-01-12 16:14:08 +13:00
289 changed files with 5950 additions and 5720 deletions
+2 -5
View File
@@ -1,10 +1,7 @@
name: Build
on:
pull_request:
push:
branches: master
on: [push, pull_request]
jobs:
build:
@@ -16,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
java_version: [11]
java_version: [21]
os: [ubuntu-latest]
steps:
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+7 -7
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -14,7 +14,7 @@
<properties>
<postgis.jdbc.version>2.5.1</postgis.jdbc.version>
<postgres.jdbc.version>42.7.2</postgres.jdbc.version>
<postgres.jdbc.version>42.6.0</postgres.jdbc.version>
</properties>
<dependencies>
@@ -22,13 +22,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -47,19 +47,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+8 -8
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,31 +17,31 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>14.0.0</version>
<version>13.24.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>14.0.0</version>
<version>13.24.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -60,13 +60,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</parent>
<artifactId>composites</artifactId>
+49 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</parent>
<name>ebean api</name>
@@ -39,7 +39,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>3.12</version>
<version>3.10</version>
</dependency>
<dependency>
@@ -126,6 +126,53 @@
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>11</release>
</configuration>
</execution>
<execution>
<id>compile-21</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>21</release>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/java21</compileSourceRoot>
</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</archive>
</configuration>
<!-- <manifest>-->
<!-- <addDefaultImplementationEntries>true</addDefaultImplementationEntries>-->
<!-- </manifest>-->
</plugin>
</plugins>
</build>
</project>
+49
View File
@@ -266,6 +266,55 @@ public final class DB {
getDefault().register(transactionCallback);
}
/**
* Deprecated for removal migrate using try-with-resources and commit on the transaction itself.
* <p>
* Commit the current transaction.
*/
@Deprecated(forRemoval = true)
public static void commitTransaction() {
getDefault().commitTransaction();
}
/**
* Deprecated for removal migrate to using try-with-resources and rollback on the transaction itself.
* <p>
* Rollback the current transaction.
*/
@Deprecated(forRemoval = true)
public static void rollbackTransaction() {
getDefault().rollbackTransaction();
}
/**
* If the current transaction has already been committed do nothing otherwise
* rollback the transaction.
* <p>
* It is preferable to use <em>try with resources</em> rather than this.
* <p>
* Useful to put in a finally block to ensure the transaction is ended, rather
* than a rollbackTransaction() in each catch block.
* <p>
* Code example:
*
* <pre>{@code
* DB.beginTransaction();
* try {
* // do some fetching and or persisting
*
* // commit at the end
* DB.commitTransaction();
*
* } finally {
* // if commit didn't occur then rollback the transaction
* DB.endTransaction();
* }
* }</pre>
*/
public static void endTransaction() {
getDefault().endTransaction();
}
/**
* Mark the current transaction as rollback only.
*/
@@ -3,7 +3,7 @@ package io.ebean;
import jakarta.persistence.PersistenceException;
/**
* Thrown when a foreign key constraint is enforced or a field is too large.
* Thrown when a foreign key constraint is enforced.
*/
public class DataIntegrityException extends PersistenceException {
private static final long serialVersionUID = -6740171949170180970L;
@@ -14,11 +14,4 @@ public class DataIntegrityException extends PersistenceException {
public DataIntegrityException(String message, Throwable cause) {
super(message, cause);
}
/**
* Create with message only.
*/
public DataIntegrityException(String message) {
super(message);
}
}
+53 -10
View File
@@ -88,16 +88,16 @@ public interface Database {
/**
* Return a new database builder.
* <pre>{@code
*
* // build the 'default' database using configuration
* // from application.properties / application.yaml
*
* Database db = Database.builder()
* .loadFromProperties()
* .build();
*
* }</pre>
* <pre>{@code
*
* // build the 'default' database using configuration
* // from application.properties / application.yaml
*
* Database db = Database.builder()
* .loadFromProperties()
* .build();
*
* }</pre>
*/
static DatabaseBuilder builder() {
return new DatabaseConfig();
@@ -666,6 +666,49 @@ public interface Database {
*/
void flush();
/**
* Deprecated for removal migrate using try-with-resources and commit on the transaction itself.
* <p>
* Commit the current transaction.
*/
@Deprecated(forRemoval = true)
void commitTransaction();
/**
* Deprecated for removal migrate to using try-with-resources and rollback on the transaction itself.
* <p>
* Rollback the current transaction.
*/
@Deprecated(forRemoval = true)
void rollbackTransaction();
/**
* If the current transaction has already been committed do nothing otherwise
* rollback the transaction.
* <p>
* Useful to put in a finally block to ensure the transaction is ended, rather
* than a rollbackTransaction() in each catch block.
* <p>
* Code example:
* <p>
* <pre>{@code
*
* database.beginTransaction();
* try {
* // do some fetching and or persisting ...
*
* // commit at the end
* database.commitTransaction();
*
* } finally {
* // if commit didn't occur then rollback the transaction
* database.endTransaction();
* }
*
* }</pre>
*/
void endTransaction();
/**
* Refresh the values of a bean.
* <p>
@@ -87,7 +87,6 @@ public interface DatabaseBuilder {
}
return this;
}
/**
* Set the name of the Database.
*/
@@ -2209,15 +2208,6 @@ public interface DatabaseBuilder {
@Deprecated
DatabaseBuilder setLoadModuleInfo(boolean loadModuleInfo);
/**
* Set if generated SQL SELECT should include the query label as an
* inline SQL comment (to help reference back from the SQL to the code
* that executed the query.
*
* @param includeLabelInSql When true include a SQL inline comment in generated SELECT queries.
*/
DatabaseConfig includeLabelInSql(boolean includeLabelInSql);
/**
* Set the naming convention to apply to metrics names.
*/
@@ -2231,11 +2221,6 @@ public interface DatabaseBuilder {
@Deprecated
DatabaseBuilder setMetricNaming(Function<String, String> metricNaming);
/**
* Sets the length check mode.
*/
DatabaseConfig lengthCheck(LengthCheck lengthCheck);
/**
* Provides read access (getters) for the DatabaseBuilder configuration
* that has been set.
@@ -3113,20 +3098,10 @@ public interface DatabaseBuilder {
*/
boolean isLoadModuleInfo();
/**
* Return true if generated sql select query should include an inline sql comment with the
* query label or profile location label.
*/
boolean isIncludeLabelInSql();
/**
* Return the naming convention to apply to metrics names.
*/
Function<String, String> getMetricNaming();
/**
* Returns the length check mode.
*/
LengthCheck getLengthCheck();
}
}
@@ -222,8 +222,6 @@ public interface ExpressionList<T> {
int delete();
/**
* @deprecated migrate to {@link #usingTransaction(Transaction)} then delete().
* <p>
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
@@ -233,7 +231,6 @@ public interface ExpressionList<T> {
*
* @return the number of rows that were deleted.
*/
@Deprecated(forRemoval = true, since = "13.1.0")
int delete(Transaction transaction);
/**
@@ -245,14 +242,11 @@ public interface ExpressionList<T> {
int update();
/**
* @deprecated migrate to {@link #usingTransaction(Transaction)} then update().
* <p>
* Execute as a update query with the given transaction.
*
* @return the number of rows that were updated.
* @see UpdateQuery
*/
@Deprecated(forRemoval = true, since = "13.1.0")
int update(Transaction transaction);
/**
File diff suppressed because it is too large Load Diff
@@ -1,975 +0,0 @@
package io.ebean;
import io.avaje.lang.Nullable;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* Build and execute an ORM query.
*
* @param <SELF> The type of the builder
* @param <T> The entity bean type
*/
public interface QueryBuilder<SELF, T> extends QueryBuilderProjection<SELF, T> {
/**
* Set root table alias.
*/
SELF alias(String alias);
/**
* Apply changes to the query conditional on the supplied predicate.
* <p>
* Typically, the changes are extra predicates etc.
*
* @param predicate The predicate which when true the changes are applied
* @param apply The changes to apply to the query
*/
SELF alsoIf(BooleanSupplier predicate, Consumer<SELF> apply);
/**
* Perform an 'As of' query using history tables to return the object graph
* as of a time in the past.
* <p>
* To perform this query the DB must have underlying history tables.
*
* @param asOf the date time in the past at which you want to view the data
*/
SELF asOf(Timestamp asOf);
/**
* Execute the query against the draft set of tables.
*/
SELF asDraft();
/**
* Convert the query to a DTO bean query.
* <p>
* We effectively use the underlying ORM query to build the SQL and then execute
* and map it into DTO beans.
*/
<D> DtoQuery<D> asDto(Class<D> dtoClass);
/**
* Convert the query to a UpdateQuery.
* <p>
* Typically this is used with query beans to covert a query bean
* query into an UpdateQuery like the examples below.
* </p>
*
* <pre>{@code
*
* int rowsUpdated = new QCustomer()
* .name.startsWith("Rob")
* .asUpdate()
* .set("active", false)
* .update();;
*
* }</pre>
*
* <pre>{@code
*
* int rowsUpdated = new QContact()
* .notes.note.startsWith("Make Inactive")
* .email.endsWith("@foo.com")
* .customer.id.equalTo(42)
* .asUpdate()
* .set("inactive", true)
* .setRaw("email = lower(email)")
* .update();
*
* }</pre>
*/
UpdateQuery<T> asUpdate();
/**
* Return a copy of the query.
* <p>
* This is so that you can use a Query as a "prototype" for creating other
* query instances. You could create a Query with various where expressions
* and use that as a "prototype" - using this copy() method to create a new
* instance that you can then add other expressions then execute.
* </p>
*/
SELF copy();
/**
* Execute the query using the given transaction.
*/
SELF usingTransaction(Transaction transaction);
/**
* Execute the query using the given connection.
*/
SELF usingConnection(Connection connection);
/**
* Execute the query using the given database.
*/
SELF usingDatabase(Database database);
/**
* Ensure that the master DataSource is used if there is a read only data source
* being used (that is using a read replica database potentially with replication lag).
* <p>
* When the database is configured with a read-only DataSource via
* say {@link io.ebean.config.DatabaseConfig#setReadOnlyDataSource(DataSource)} then
* by default when a query is run without an active transaction, it uses the read-only data
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
SELF usingMaster();
/**
* Set the base table to use for this query.
* <p>
* Typically this is used when a table has partitioning and we wish to specify a specific
* partition/table to query against.
* </p>
* <pre>{@code
*
* QOrder()
* .setBaseTable("order_2019_05")
* .status.equalTo(Status.NEW)
* .findList();
*
* }</pre>
*/
SELF setBaseTable(String baseTable);
/**
* Specify the PersistenceContextScope to use for this query.
* <p>
* When this is not set the 'default' configured on {@link io.ebean.config.DatabaseConfig#setPersistenceContextScope(PersistenceContextScope)}
* is used - this value defaults to {@link PersistenceContextScope#TRANSACTION}.
* <p>
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
* <p>
* Note that #findEach uses a 'per object graph' PersistenceContext so this scope is ignored for
* queries executed as #findIterate, #findEach, #findEachWhile.
*
* @param scope The scope to use for this query and subsequent lazy loading.
*/
SELF setPersistenceContextScope(PersistenceContextScope scope);
/**
* Explicitly specify whether to use AutoTune for this query.
* <p>
* If you do not call this method on a query the "Implicit AutoTune mode" is
* used to determine if AutoTune should be used for a given query.
* <p>
* AutoTune can add additional fetch paths to the query and specify which
* properties are included for each path. If you have explicitly defined some
* fetch paths AutoTune will not remove them.
*/
SELF setAutoTune(boolean autoTune);
/**
* Execute the query allowing properties with invalid JSON to be collected and not fail the query.
* <pre>{@code
*
* // fetch a bean with JSON content
* EBasicJsonList bean= DB.find(EBasicJsonList.class)
* .setId(42)
* .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON
* .findOne();
*
*
* // get the invalid JSON errors from the bean state
* Map<String, Exception> errors = server().getBeanState(bean).getLoadErrors();
*
* // If this map is not empty tell we have invalid JSON
* // and should try and fix the JSON content or inform the user
*
* }</pre>
*/
SELF setAllowLoadErrors();
/**
* Set the default lazy loading batch size to use.
* <p>
* When lazy loading is invoked on beans loaded by this query then this sets the
* batch size used to load those beans.
*
* @param lazyLoadBatchSize the number of beans to lazy load in a single batch
*/
SELF setLazyLoadBatchSize(int lazyLoadBatchSize);
/**
* Set a label on the query.
* <p>
* This label can be used to help identify query performance metrics but we can also use
* profile location enhancement on Finders so for some that would be a better option.
*/
SELF setLabel(String label);
/**
* Set a SQL query hint.
* <p>
* This results in an inline comment that immediately follows
* after the select keyword in the form: {@code /*+ hint *\/ }
*/
SELF setHint(String hint);
/**
* Set the index(es) to search for a document store which uses partitions.
* <p>
* For example, when executing a query against ElasticSearch with daily indexes we can
* explicitly specify the indexes to search against.
* </p>
* <pre>{@code
*
* // explicitly specify the indexes to search
* query.setDocIndexName("logstash-2016.11.5,logstash-2016.11.6")
*
* // search today's index
* query.setDocIndexName("$today")
*
* // search the last 3 days
* query.setDocIndexName("$last-3")
*
* }</pre>
* <p>
* If the indexName is specified with ${daily} e.g. "logstash-${daily}" ... then we can use
* $today and $last-x as the search docIndexName like the examples below.
* </p>
* <pre>{@code
*
* // search today's index
* query.setDocIndexName("$today")
*
* // search the last 3 days
* query.setDocIndexName("$last-3")
*
* }</pre>
*
* @param indexName The index or indexes to search against
* @return This query
*/
SELF setDocIndexName(String indexName);
/**
* Execute the query including soft deleted rows.
* <p>
* This means that Ebean will not add any predicates to the query for filtering out
* soft deleted rows. You can still add your own predicates for the deleted properties
* and effectively you have full control over the query to include or exclude soft deleted
* rows as needed for a given use case.
*/
SELF setIncludeSoftDeletes();
/**
* Disable read auditing for this query.
* <p>
* This is intended to be used when the query is not a user initiated query and instead
* part of the internal processing in an application to load a cache or document store etc.
* In these cases we don't want the query to be part of read auditing.
*/
SELF setDisableReadAuditing();
/**
* Set true if you want to disable lazy loading.
* <p>
* That is, once the object graph is returned further lazy loading is disabled.
*/
SELF setDisableLazyLoading(boolean disableLazyLoading);
/**
* Set whether this query uses DISTINCT.
*/
SELF setDistinct(boolean distinct);
/**
* Restrict the query to only return subtypes of the given inherit type.
* <pre>{@code
*
* List<Animal> animals =
* new QAnimal()
* .name.startsWith("Fluffy")
* .setInheritType(Cat.class)
* .findList();
*
* }</pre>
*/
SELF setInheritType(Class<? extends T> type);
/**
* Set the first row to return for this query.
*
* @param firstRow the first row to include in the query result.
*/
SELF setFirstRow(int firstRow);
/**
* Set the maximum number of rows to return in the query.
*
* @param maxRows the maximum number of rows to return in the query.
*/
SELF setMaxRows(int maxRows);
/**
* Set RawSql to use for this query.
*/
SELF setRawSql(RawSql rawSql);
/**
* Extended version for setDistinct in conjunction with "findSingleAttributeList";
*
* <pre>{@code
*
* List<CountedValue<Order.Status>> orderStatusCount =
*
* DB.find(Order.class)
* .select("status")
* .where()
* .gt("orderDate", LocalDate.now().minusMonths(3))
*
* // fetch as single attribute with a COUNT
* .setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
* .findSingleAttributeList();
*
* for (CountedValue<Order.Status> entry : orderStatusCount) {
* System.out.println(" count:" + entry.getCount()+" orderStatus:" + entry.getValue() );
* }
*
* // produces
*
* count:3 orderStatus:NEW
* count:1 orderStatus:SHIPPED
* count:1 orderStatus:COMPLETE
*
* }</pre>
*/
SELF setCountDistinct(CountDistinctOrder orderBy);
/**
* Set the property to use as keys for a map.
* <p>
* If no property is set then the id property is used.
* </p>
* <pre>{@code
*
* // Assuming sku is unique for products...
*
* Map<String,Product> productMap = DB.find(Product.class)
* .setMapKey("sku") // sku map keys...
* .findMap();
*
* }</pre>
*
* @param mapKey the property to use as keys for a map.
*/
SELF setMapKey(String mapKey);
/**
* Set to true if this query should execute against the doc store.
* <p>
* When setting this you may also consider disabling lazy loading.
*/
SELF setUseDocStore(boolean useDocStore);
/**
* When set to true when you want the returned beans to be read only.
*/
SELF setReadOnly(boolean readOnly);
/**
* Set a timeout on this query.
* <p>
* This will typically result in a call to setQueryTimeout() on a
* preparedStatement. If the timeout occurs an exception will be thrown - this
* will be a SQLException wrapped up in a PersistenceException.
* </p>
*
* @param secs the query timeout limit in seconds. Zero means there is no limit.
*/
SELF setTimeout(int secs);
/**
* A hint which for JDBC translates to the Statement.fetchSize().
* <p>
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for ResultSet.
* </p>
* <p>
* Note that internally findEach and findEachWhile will set the fetch size
* if it has not already as these queries expect to process a lot of rows.
* If we didn't then Postgres and MySql for example would eagerly pull back
* all the row data and potentially consume a lot of memory in the process.
* </p>
* <p>
* As findEach and findEachWhile automatically set the fetch size we don't have
* to do so generally but we might still wish to for tuning a specific use case.
* </p>
*/
SELF setBufferFetchSizeHint(int fetchSize);
/**
* Set the mode to use the bean cache when executing this query.
* <p>
* By default, "find by id" and "find by natural key" will use the bean cache
* when bean caching is enabled. Setting this to false means that the query
* will not use the bean cache and instead hit the database.
* <p>
* By default, findList() with natural keys will not use the bean cache. In that
* case we need to explicitly use the bean cache.
*/
SELF setBeanCacheMode(CacheMode beanCacheMode);
/**
* Set the {@link CacheMode} to use the query for executing this query.
*/
SELF setUseQueryCache(CacheMode cacheMode);
/**
* Set this to false to not use the bean cache.
* <p>
* This method is now superseded by {@link #setBeanCacheMode(CacheMode)}
* which provides more explicit options controlled bean cache use.
* <p>
* This method is likely to be deprecated in the future with migration
* over to setUseBeanCache().
*/
default SELF setUseCache(boolean useCache) {
return setBeanCacheMode(useCache ? CacheMode.ON : CacheMode.OFF);
}
/**
* Calls {@link #setUseQueryCache(CacheMode)} with <code>ON</code> or <code>OFF</code>.
*/
default SELF setUseQueryCache(boolean enabled) {
return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF);
}
/**
* Set the order by clause replacing the existing order by clause if there is
* one.
* <p>
* This follows SQL syntax using commas between each property with the
* optional asc and desc keywords representing ascending and descending order
* respectively.
*/
SELF orderBy(String orderByClause);
/**
* Set an OrderBy object to replace any existing OrderBy clause.
*/
SELF setOrderBy(OrderBy<T> orderBy);
/**
* Controls, if paginated queries should always append an 'order by id' statement at the end to
* guarantee a deterministic sort result. This may affect performance.
* If this is not enabled, and an orderBy is set on the query, it's up to the programmer that
* this query provides a deterministic result.
*/
SELF orderById(boolean orderById);
/**
* Execute the query with the given lock type and WAIT.
* <p>
* Note that <code>forUpdate()</code> is the same as
* <code>withLock(LockType.UPDATE)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
SELF withLock(Query.LockType lockType);
/**
* Execute the query with the given lock type and lock wait.
* <p>
* Note that <code>forUpdateNoWait()</code> is the same as
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
SELF withLock(Query.LockType lockType, Query.LockWait lockWait);
/**
* Execute using "for update" clause which results in the DB locking the record.
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.WAIT)</code>.
*/
SELF forUpdate();
/**
* Execute using "for update" clause with "no wait" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
*/
SELF forUpdateNoWait();
/**
* Execute using "for update" clause with "skip locked" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.SKIPLOCKED)</code>.
*/
SELF forUpdateSkipLocked();
/**
* Returns the set of properties or paths that are unknown (do not map to known properties or paths).
* <p>
* Validate the query checking the where and orderBy expression paths to confirm if
* they represent valid properties or paths for the given bean type.
*/
Set<String> validate();
/**
* Return the sql that was generated for executing this query.
* <p>
* This is only available after the query has been executed and provided only
* for informational purposes.
*/
String getGeneratedSql();
/**
* Return the type of beans being queried.
*/
Class<T> getBeanType();
/**
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
*
* @return the number of beans/rows that were deleted.
*/
int delete();
/**
* Execute the query returning true if a row is found.
* <p>
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
*
* <h2>Example using a query bean:</h2>
* <pre>{@code
*
* boolean userExists =
* new QContact()
* .email.equalTo("rob@foo.com")
* .exists();
*
* }</pre>
*
* <h2>Example:</h2>
* <pre>{@code
*
* boolean userExists = query()
* .where().eq("email", "rob@foo.com")
* .exists();
*
* }</pre>
*
* @return True if the query finds a matching row in the database
*/
boolean exists();
/**
* Execute the query returning either a single bean or null (if no matching
* bean is found).
* <p>
* If more than 1 row is found for this query then a PersistenceException is
* thrown.
* <p>
* This is useful when your predicates dictate that your query should only
* return 0 or 1 results.
* <p>
* <pre>{@code
*
* // assuming the sku of products is unique...
* Product product =
* new QProduct()
* .sku.equalTo("aa113")
* .findOne();
* ...
* }</pre>
* <p>
* It is also useful with finding objects by their id when you want to specify
* further join information to optimise the query.
* <p>
* <pre>{@code
*
* // Fetch order 42 and additionally fetch join its order details...
* Order order =
* new QOrder()
* .fetch("details") // eagerly load the order details
* .id.equalTo(42)
* .findOne();
*
* // the order details were eagerly loaded
* List<OrderDetail> details = order.getDetails();
* ...
* }</pre>
*/
@Nullable
T findOne();
/**
* Execute the query returning an optional bean.
*/
Optional<T> findOneOrEmpty();
/**
* Execute the query returning the list of objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* <p>
* <pre>{@code
*
* List<Customer> customers =
* new QCustomer()
* .name.ilike("rob%")
* .findList();
*
* }</pre>
*
* @see Query#findList()
*/
List<T> findList();
/**
* Execute the query returning the result as a Stream.
* <p>
* Note that this can support very large queries iterating
* any number of results. To do so internally it can use
* multiple persistence contexts.
* </p>
* <pre>{@code
*
* // use try with resources to ensure Stream is closed
*
* try (Stream<Customer> stream = query.findStream()) {
* stream
* .map(...)
* .collect(...);
* }
*
* }</pre>
*/
Stream<T> findStream();
/**
* Execute the query returning the set of objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* <p>
* <pre>{@code
*
* Set<Customer> customers =
* new QCustomer()
* .name.ilike("rob%")
* .findSet();
*
* }</pre>
*
* @see Query#findSet()
*/
Set<T> findSet();
/**
* Execute the query returning the list of Id's.
* <p>
* This query will execute against the EbeanServer that was used to create it.
*
* @see Query#findIds()
*/
<A> List<A> findIds();
/**
* Execute the query returning a map of the objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* <p>
* You can use setMapKey() or asMapKey() to specify the property to be used as keys
* on the map. If one is not specified then the id property is used.
* <p>
* <pre>{@code
*
* Map<String, Product> map =
* new QProduct()
* .sku.asMapKey()
* .findMap();
*
* }</pre>
*
* @see Query#findMap()
*/
<K> Map<K, T> findMap();
/**
* Execute the query iterating over the results.
* <p>
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
* <p>
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results (typically in a finally block).
* <p>
* findEach() and findEachWhile() are preferred to findIterate() as they ensure
* the jdbc statement and resultSet are closed at the end of the iteration.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* </p>
* <pre>{@code
*
* Query<Customer> query =
* new QCustomer()
* .status.equalTo(Customer.Status.NEW)
* .orderBy()
* id.asc()
* .query();
*
* try (QueryIterator<Customer> it = query.findIterate()) {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* }
*
* }</pre>
*/
QueryIterator<T> findIterate();
/**
* Execute the query returning a list of values for a single property.
* <p>
* <h3>Example</h3>
* <pre>{@code
*
* List<String> names =
* new QCustomer()
* .setDistinct(true)
* .select(name)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*/
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning a single value or null for a single property.
* <p>
* <h3>Example</h3>
* <pre>{@code
*
* LocalDate maxDate =
* new QCustomer()
* .select("max(startDate)")
* .findSingleAttribute();
*
* }</pre>
*
* @return a single value or null for the selected property
*/
@Nullable
<A> A findSingleAttribute();
/**
* Execute the query returning a single optional attribute value.
* <p>
* <h3>Example</h3>
* <pre>{@code
*
* Optional<String> maybeName =
* new QCustomer()
* .select(name)
* .id.eq(42)
* .status.eq(NEW)
* .findSingleAttributeOrEmpty();
*
* }</pre>
*
* @return an optional value for the selected property
*/
<A> Optional<A> findSingleAttributeOrEmpty();
/**
* Execute the query returning a hashset of values for a single property.
*/
<A> Set<A> findSingleAttributeSet();
/**
* Execute the query processing the beans one at a time.
* <p>
* This method is appropriate to process very large query results as the
* beans are consumed one at a time and do not need to be held in memory
* (unlike #findList #findSet etc)
* <p>
* Note that internally Ebean can inform the JDBC driver that it is expecting larger
* resultSet and specifically for MySQL this hint is required to stop it's JDBC driver
* from buffering the entire resultSet. As such, for smaller resultSets findList() is
* generally preferable.
* <p>
* Compared with #findEachWhile this will always process all the beans where as
* #findEachWhile provides a way to stop processing the query result early before
* all the beans have been read.
* <p>
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the Consumer interface which is better suited to use with closures.
*
* <pre>{@code
*
* new QCustomer()
* .status.equalTo(Status.NEW)
* .orderBy().id.asc()
* .findEach((Customer customer) -> {
*
* // do something with customer
* System.out.println("-- visit " + customer);
* });
*
* }</pre>
*
* @param consumer the consumer used to process the queried beans.
*/
void findEach(Consumer<T> consumer);
/**
* Execute findEach streaming query batching the results for consuming.
* <p>
* This query execution will stream the results and is suited to consuming
* large numbers of results from the database.
* <p>
* Typically, we use this batch consumer when we want to do further processing on
* the beans and want to do that processing in batch form, for example - 100 at
* a time.
*
* @param batch The number of beans processed in the batch
* @param consumer Process the batch of beans
*/
void findEach(int batch, Consumer<List<T>> consumer);
/**
* Execute the query using callbacks to a visitor to process the resulting
* beans one at a time.
* <p>
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the Predicate interface which is better suited to use with closures.
*
* <pre>{@code
*
* new QCustomer()
* .status.equalTo(Status.NEW)
* .orderBy().id.asc()
* .findEachWhile((Customer customer) -> {
*
* // do something with customer
* System.out.println("-- visit " + customer);
*
* // return true to continue processing or false to stop
* return (customer.getId() < 40);
* });
*
* }</pre>
*
* @param consumer the consumer used to process the queried beans.
*/
void findEachWhile(Predicate<T> consumer);
/**
* Return versions of a @History entity bean.
* <p>
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
*/
List<Version<T>> findVersions();
/**
* Return versions of a @History entity bean between a start and end timestamp.
* <p>
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
*/
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
* Return the count of entities this query should return.
* <p>
* This is the number of 'top level' or 'root level' entities.
*/
int findCount();
/**
* Execute find row count query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
*
* @return a Future object for the row count query
*/
FutureRowCount<T> findFutureCount();
/**
* Execute find Id's query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
*
* @return a Future object for the list of Id's
*/
FutureIds<T> findFutureIds();
/**
* Execute find list query in a background thread.
* <p>
* This query will execute in it's own PersistenceContext and using its own transaction.
* What that means is that it will not share any bean instances with other queries.
*
* @return a Future object for the list result of the query
*/
FutureList<T> findFutureList();
/**
* Return a PagedList for this query using firstRow and maxRows.
* <p>
* The benefit of using this over findList() is that it provides functionality to get the
* total row count etc.
* <p>
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* <p>
* <pre>{@code
*
* PagedList<Order> pagedList =
* new QOrder()
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
*
* // fetch the total row count in the background
* pagedList.loadRowCount();
*
* List<Order> orders = pagedList.getList();
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* @return The PagedList
*/
PagedList<T> findPagedList();
}
@@ -1,242 +0,0 @@
package io.ebean;
/**
* Builder for ORM Query projection (the select and fetch part).
*
* @param <SELF> The builder type
* @param <T> The entity bean type
*/
public interface QueryBuilderProjection<SELF, T> {
/**
* Apply the path properties replacing the select and fetch clauses.
* <p>
* This is typically used when the FetchPath is applied to both the query and the JSON output.
*/
SELF apply(FetchPath fetchPath);
/**
* Specify the properties to fetch on the root level entity bean in comma delimited format.
* <p>
* The Id property is automatically included in the properties to fetch unless setDistinct(true)
* is set on the query.
* </p>
* <p>
* Use {@link #fetch(String, String)} to specify specific properties to fetch
* on other non-root level paths of the object graph.
* </p>
* <pre>{@code
*
* List<Customer> customers = DB.find(Customer.class)
* // Only fetch the customer id, name and status.
* // This is described as a "Partial Object"
* .select("name, status")
* .where.ilike("name", "rob%")
* .findList();
*
* }</pre>
*
* @param fetchProperties the properties to fetch for this bean (* = all properties).
*/
SELF select(String fetchProperties);
/**
* Apply the fetchGroup which defines what part of the object graph to load.
*/
SELF select(FetchGroup<T> fetchGroup);
/**
* Specify a path to fetch eagerly including specific properties.
* <p>
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
* </p>
* <pre>{@code
*
* // query orders...
* List<Order> orders = DB.find(Order.class)
* // fetch the customer...
* // ... getting the customers name and phone number
* .fetch("customer", "name, phoneNumber")
*
* // ... also fetch the customers billing address (* = all properties)
* .fetch("customer.billingAddress", "*")
* .findList();
* }</pre>
* <p>
* If columns is null or "*" then all columns/properties for that path are fetched.
* </p>
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers = DB.find(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName,lastName,email")
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
SELF fetch(String path, String fetchProperties);
/**
* Fetch the path and properties using a "query join" (separate SQL query).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, fetchProperties, FetchConfig.ofQuery())
*
* }</pre>
* <p>
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
* part of the object graph rather than a SQL join.
* <p>
* We might typically get a performance benefit when the path to fetch is a OneToMany
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
* is high.
*
* @param path the property path we wish to fetch eagerly.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
SELF fetchQuery(String path, String fetchProperties);
/**
* Fetch the path and properties using L2 bean cache.
*
* @param path The path of the beans we are fetching from L2 cache.
* @param fetchProperties The properties that should be loaded.
*/
SELF fetchCache(String path, String fetchProperties);
/**
* Fetch the path and properties lazily (via batch lazy loading).
* <p>
* This is the same as:
*
* <pre>{@code
*
* fetch(path, fetchProperties, FetchConfig.ofLazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @param path the property path we wish to fetch lazily.
* @param fetchProperties properties of the associated bean that you want to include in the
* fetch (* means all properties, null also means all properties).
*/
SELF fetchLazy(String path, String fetchProperties);
/**
* Additionally specify a FetchConfig to use a separate query or lazy loading
* to load this path.
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers = DB.find(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName,lastName,email", FetchConfig.ofLazy(10))
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
*/
SELF fetch(String path, String fetchProperties, FetchConfig fetchConfig);
/**
* Specify a path to fetch eagerly including all its properties.
* <p>
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
* </p>
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers = DB.find(Customer.class)
* // eager fetch the contacts
* .fetch("contacts")
* .findList();
*
* }</pre>
*
* @param path the property path we wish to fetch eagerly.
*/
SELF fetch(String path);
/**
* Fetch the path eagerly using a "query join" (separate SQL query).
* <p>
* This is the same as:
* <pre>{@code
*
* fetch(path, FetchConfig.ofQuery())
*
* }</pre>
* <p>
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
* part of the object graph rather than a SQL join.
* <p>
* We might typically get a performance benefit when the path to fetch is a OneToMany
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
* is high.
*
* @param path the property path we wish to fetch eagerly
*/
SELF fetchQuery(String path);
/**
* Fetch the path eagerly using L2 cache.
*/
SELF fetchCache(String path);
/**
* Fetch the path lazily (via batch lazy loading).
* <p>
* This is the same as:
* </p>
* <pre>{@code
*
* fetch(path, FetchConfig.ofLazy())
*
* }</pre>
* <p>
* The reason for using fetchLazy() is to either:
* </p>
* <ul>
* <li>Control/tune what is fetched as part of lazy loading</li>
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
* </ul>
*
* @param path the property path we wish to fetch lazily.
*/
SELF fetchLazy(String path);
/**
* Additionally specify a JoinConfig to specify a "query join" and or define
* the lazy loading query.
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers = DB.find(Customer.class)
* // lazy fetch contacts with a batch size of 100
* .fetch("contacts", FetchConfig.ofLazy(100))
* .findList();
*
* }</pre>
*/
SELF fetch(String path, FetchConfig fetchConfig);
}
@@ -141,14 +141,16 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
}
/**
* Set the actual underlying list.
* <p>
* This is primarily for the deferred fetching function.
*/
@SuppressWarnings("unchecked")
public void setActualList(List<?> list) {
this.list = (List<E>) list;
public BeanCollectionAdd collectionAdd() {
if (list == null) {
list = new ArrayList<>();
}
return this;
}
public void refresh(ModifyListenMode modifyListenMode, BeanList<E> newList) {
setModifyListening(modifyListenMode);
this.list = newList.actualList();
}
/**
@@ -1,9 +1,6 @@
package io.ebean.common;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.EntityBean;
import io.ebean.bean.ToStringBuilder;
import io.ebean.bean.*;
import java.util.*;
@@ -17,12 +14,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
/**
* The underlying map implementation.
*/
private Map<K, E> map;
private LinkedHashMap<K, E> map;
/**
* Create with a given Map.
*/
public BeanMap(Map<K, E> map) {
public BeanMap(LinkedHashMap<K, E> map) {
this.map = map;
}
@@ -160,18 +157,23 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
}
}
/**
* Set the actual underlying map. Used for performing lazy fetch.
*/
public LinkedHashMap<K, E> collectionAdd() {
if (map == null) {
map = new LinkedHashMap<>();
}
return map;
}
@SuppressWarnings("unchecked")
public void setActualMap(Map<?, ?> map) {
this.map = (Map<K, E>) map;
public void refresh(ModifyListenMode modifyListenMode, BeanMap<?, ?> newMap) {
setModifyListening(modifyListenMode);
this.map = (LinkedHashMap<K, E>) newMap.actualMap();
}
/**
* Return the actual underlying map.
*/
public Map<K, E> actualMap() {
public LinkedHashMap<K, E> actualMap() {
return map;
}
@@ -3,10 +3,7 @@ package io.ebean.common;
import io.ebean.bean.*;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.*;
/**
* Set capable of lazy loading and modification aware.
@@ -18,12 +15,12 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
/**
* The underlying Set implementation.
*/
private Set<E> set;
private LinkedHashSet<E> set;
/**
* Create with a specific Set implementation.
*/
public BeanSet(Set<E> set) {
public BeanSet(LinkedHashSet<E> set) {
this.set = set;
}
@@ -144,18 +141,22 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
}
/**
* Set the underlying set (used for lazy fetch).
*/
@SuppressWarnings("unchecked")
public void setActualSet(Set<?> set) {
this.set = (Set<E>) set;
public BeanCollectionAdd collectionAdd() {
if (set == null) {
set = new LinkedHashSet<>();
}
return this;
}
public void refresh(ModifyListenMode modifyListenMode, BeanSet<E> newSet) {
setModifyListening(modifyListenMode);
this.set = newSet.actualSet();
}
/**
* Return the actual underlying set.
*/
public Set<E> actualSet() {
public LinkedHashSet<E> actualSet() {
return set;
}
@@ -1,5 +1,8 @@
package io.ebean.config;
import io.avaje.config.Config;
import io.avaje.config.Configuration;
import java.util.Properties;
/**
@@ -16,6 +19,16 @@ public class ContainerConfig {
private String podName;
private int port;
private Properties properties;
private Configuration configuration;
public ContainerConfig() {
this.configuration = Config.asConfiguration();
this.active = configuration.getBool("ebean.cluster.active", active);
this.serviceName = configuration.getNullable("ebean.cluster.serviceName", serviceName);
this.namespace = configuration.getNullable("ebean.cluster.namespace", namespace);
this.podName = configuration.getNullable("ebean.cluster.podName", podName);
this.port = configuration.getInt("ebean.cluster.port", 0);
}
/**
* Return the service name.
@@ -91,7 +104,7 @@ public class ContainerConfig {
* Return the deployment properties.
*/
public Properties getProperties() {
return properties;
return properties != null ? properties : configuration.asProperties();
}
/**
@@ -101,25 +114,4 @@ public class ContainerConfig {
this.properties = properties;
}
/**
* Load the settings from properties.
*/
public void loadFromProperties(Properties properties) {
this.properties = properties;
this.active = getProperty(properties, "ebean.cluster.active", active);
this.serviceName = properties.getProperty("ebean.cluster.serviceName", serviceName);
this.namespace = properties.getProperty("ebean.cluster.namespace", namespace);
this.podName = properties.getProperty("ebean.cluster.podName", podName);
String portParam = properties.getProperty("ebean.cluster.port");
if (portParam != null) {
this.port = Integer.parseInt(portParam);
}
}
/**
* Return the boolean property setting.
*/
protected boolean getProperty(Properties properties, String key, boolean defaultValue) {
return "true".equalsIgnoreCase(properties.getProperty(key, Boolean.toString(defaultValue)));
}
}
@@ -125,12 +125,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
*/
private boolean loadModuleInfo = true;
/**
* When true then include a sql comment in generated SELECT queries with the query
* label or profile location label.
*/
private boolean includeLabelInSql;
/**
* Interesting classes such as entities, embedded, ScalarTypes,
* Listeners, Finders, Controllers, AttributeConverters etc.
@@ -242,7 +236,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
*/
private PersistBatch persistBatchOnCascade = PersistBatch.INHERIT;
private int persistBatchSize = 100;
private int persistBatchSize = 20;
private EnumType defaultEnumType = EnumType.ORDINAL;
@@ -551,8 +545,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
private String dumpMetricsOptions;
private LengthCheck lengthCheck = LengthCheck.OFF;
private Function<String, String> metricNaming = MetricNamingMatch.INSTANCE;
/**
@@ -2139,7 +2131,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
readOnlyDatabase = p.getBoolean("readOnlyDatabase", readOnlyDatabase);
autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates);
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
includeLabelInSql = p.getBoolean("includeLabelInSql", includeLabelInSql);
maxCallStack = p.getInt("maxCallStack", maxCallStack);
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
@@ -2204,7 +2195,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach);
jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList);
databasePlatformName = p.get("databasePlatformName", databasePlatformName);
lengthCheck = p.getEnum(LengthCheck.class, "lengthCheck", lengthCheck);
uuidVersion = p.getEnum(UuidVersion.class, "uuidVersion", uuidVersion);
uuidStateFile = p.get("uuidStateFile", uuidStateFile);
@@ -2554,11 +2544,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return loadModuleInfo;
}
@Override
public boolean isIncludeLabelInSql() {
return includeLabelInSql;
}
/**
* @deprecated - migrate to {@link #isLoadModuleInfo()}.
*/
@@ -2575,12 +2560,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return this;
}
@Override
public DatabaseConfig includeLabelInSql(boolean includeLabelInSql) {
this.includeLabelInSql = includeLabelInSql;
return this;
}
@Override
public Function<String, String> getMetricNaming() {
return metricNaming;
@@ -2592,19 +2571,6 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return this;
}
/**
* Returns the length check mode.
*/
public LengthCheck getLengthCheck() {
return lengthCheck;
}
@Override
public DatabaseConfig lengthCheck(LengthCheck lengthCheck) {
this.lengthCheck = lengthCheck;
return this;
}
public enum UuidVersion {
VERSION4,
VERSION1,
@@ -1,22 +0,0 @@
package io.ebean.config;
/**
* Defines the length-check mode.
*
* @author Roland Praml, FOCONIS AG
*/
public enum LengthCheck {
/**
* By default, length checking is off. This means, strings/jsons and files are passed to the DB and the DB might or might not check the length.
* The DB has to check the data length. Note this is not possible for certain datatypes (e.g. clob without size)
*/
OFF,
/**
* When enabling length check, ebean validates strings/json strings and files before saving them to DB.
*/
ON,
/**
* Same as "ON", but take the UTF8-bytelength for validation. This may be useful, if you have an UTF8 based charset (default for DB2)
*/
UTF8
}
@@ -1,29 +1,50 @@
package io.ebean.config;
import io.ebean.ProfileLocation;
import io.ebean.bean.ObjectGraphNode;
import java.util.List;
/**
* The data for the slow query.
* Slow query event.
*/
public interface SlowQueryEvent {
public class SlowQueryEvent {
private final String sql;
private final long timeMillis;
private final int rowCount;
private final ObjectGraphNode originNode;
/**
* Construct with the SQL and execution time in millis.
*/
public SlowQueryEvent(String sql, long timeMillis, int rowCount, ObjectGraphNode originNode) {
this.sql = sql;
this.timeMillis = timeMillis;
this.rowCount = rowCount;
this.originNode = originNode;
}
/**
* Return the SQL for the slow query.
*/
String getSql();
public String getSql() {
return sql;
}
/**
* Return the execution time in millis.
*/
long getTimeMillis();
public long getTimeMillis() {
return timeMillis;
}
/**
* Return the total row count associated with the query.
*/
int getRowCount();
public int getRowCount() {
return rowCount;
}
/**
* Return the origin point for the root query.
@@ -32,20 +53,7 @@ public interface SlowQueryEvent {
* shows the code that invoked the query.
* </p>
*/
ObjectGraphNode getOriginNode();
/**
* Return the bind parameters.
*/
List<Object> getBindParams();
/**
* Return the label.
*/
String getLabel();
/**
* Return the profile location.
*/
ProfileLocation getProfileLocation();
public ObjectGraphNode getOriginNode() {
return originNode;
}
}
@@ -199,21 +199,12 @@ public class DatabasePlatform {
protected SqlExceptionTranslator exceptionTranslator = new SqlCodeTranslator();
protected InsertSqlSyntaxExtension insertSqlSyntaxExtension = new StandardInsertSqlSyntax();
/**
* Instantiates a new database platform.
*/
public DatabasePlatform() {
}
/**
* Return the Insert SQL syntax helper.
*/
public InsertSqlSyntaxExtension insertSqlSyntaxExtension() {
return insertSqlSyntaxExtension;
}
/**
* Translate the SQLException into a specific persistence exception if possible.
*/
@@ -778,15 +769,4 @@ public class DatabasePlatform {
public boolean supportsNativeJavaTime() {
return supportsNativeJavaTime;
}
public String inlineSqlComment(String label) {
if (label == null) {
return "";
}
return "/* " + label + " */ ";
}
public String inlineSqlHint(String hint) {
return "/*+ " + hint + " */ ";
}
}
@@ -1,32 +0,0 @@
package io.ebean.config.dbplatform;
/**
* Insert SQL syntax to allow support for ClickHouse type optimisation for inserts.
*/
public interface InsertSqlSyntaxExtension {
/**
* Start the columns.
*/
String startColumns();
/**
* End of the columns.
*/
String endColumns();
/**
* Return true for insert to use standard binding.
*/
boolean useBinding();
/**
* Start types for non-standard binding (e.g. ClickHouse).
*/
String startTypes();
/**
* End types for non-standard binding (e.g. ClickHouse).
*/
String endTypes();
}
@@ -1,32 +0,0 @@
package io.ebean.config.dbplatform;
/**
* Standard Insert SQL syntax.
*/
public final class StandardInsertSqlSyntax implements InsertSqlSyntaxExtension {
@Override
public String startColumns() {
return " (";
}
@Override
public String endColumns() {
return ") values (";
}
@Override
public boolean useBinding() {
return true;
}
@Override
public String startTypes() {
throw new IllegalStateException();
}
@Override
public String endTypes() {
throw new IllegalStateException();
}
}
@@ -8,7 +8,6 @@ import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
@@ -24,7 +23,7 @@ public final class ShutdownManager {
private static final System.Logger log = EbeanVersion.log;
private static final ReentrantLock lock = new ReentrantLock();
private static final List<Database> databases = Collections.synchronizedList(new ArrayList<>());
private static final List<Database> databases = new ArrayList<>();
private static final ShutdownHook shutdownHook = new ShutdownHook();
private static boolean stopping;
@@ -178,7 +177,12 @@ public final class ShutdownManager {
* Register an ebeanServer to be shutdown when the JVM is shutdown.
*/
public static void registerDatabase(Database server) {
databases.add(server);
lock.lock();
try {
databases.add(server);
} finally {
lock.unlock();
}
}
/**
@@ -188,7 +192,12 @@ public final class ShutdownManager {
* </p>
*/
public static void unregisterDatabase(Database server) {
databases.remove(server);
lock.lock();
try {
databases.remove(server);
} finally {
lock.unlock();
}
}
private static class ShutdownHook extends Thread {
@@ -22,8 +22,6 @@ public class JsonWriteOptions {
protected JsonConfig.Include include;
protected boolean includeLoadedImplicit = true;
protected Map<String, JsonWriteBeanVisitor<?>> visitorMap;
/**
@@ -75,20 +73,6 @@ public class JsonWriteOptions {
this.include = include;
}
/**
* Should loaded properties be included implicit, if no other fetch path is specified (default = true).
*/
public boolean isIncludeLoadedImplicit() {
return includeLoadedImplicit;
}
/**
* Set include loaded properties implicit (default = true).
*/
public void setIncludeLoadedImplicit(boolean includeLoadedImplicit) {
this.includeLoadedImplicit = includeLoadedImplicit;
}
/**
* Register a JsonWriteBeanVisitor for the root level.
*/
@@ -0,0 +1,450 @@
package io.ebean.common;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.EntityBean;
import io.ebean.bean.ToStringBuilder;
import java.util.*;
/**
* Map capable of lazy loading and modification aware.
*/
public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements SequencedMap<K, E> {
private static final long serialVersionUID = 1L;
/**
* The underlying map implementation.
*/
private LinkedHashMap<K, E> map;
/**
* Create with a given Map.
*/
public BeanMap(LinkedHashMap<K, E> map) {
this.map = map;
}
/**
* Create using a underlying LinkedHashMap.
*/
public BeanMap() {
this(new LinkedHashMap<>());
}
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
super(ebeanServer, ownerBean, propertyName);
}
@Override
public void toString(ToStringBuilder builder) {
if (map == null || map.isEmpty()) {
builder.addRaw("{}");
} else {
builder.addRaw("{");
for (Entry<K, E> entry : map.entrySet()) {
builder.add(String.valueOf(entry.getKey()), entry.getValue());
}
builder.addRaw("}");
}
}
@Override
public void reset(EntityBean ownerBean, String propertyName) {
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.map = null;
}
@Override
public boolean isSkipSave() {
return map == null || (map.isEmpty() && !holdsModifications());
}
@Override
@SuppressWarnings("unchecked")
public void loadFrom(BeanCollection<?> other) {
BeanMap<K, E> otherMap = (BeanMap<K, E>) other;
internalPutNull();
map.putAll(otherMap.actualMap());
}
public void internalPutNull() {
if (map == null) {
map = new LinkedHashMap<>();
}
}
@SuppressWarnings("unchecked")
public void internalPut(Object key, Object bean) {
if (map == null) {
map = new LinkedHashMap<>();
}
if (key != null) {
map.put((K) key, (E) bean);
}
}
public void internalPutWithCheck(Object key, Object bean) {
if (map == null || key == null || !map.containsKey(key)) {
internalPut(key, bean);
}
}
@Override
public void internalAddWithCheck(Object bean) {
throw new RuntimeException("Not allowed for map");
}
@Override
public void internalAdd(Object bean) {
throw new RuntimeException("Not allowed for map");
}
/**
* Return true if the underlying map has been populated. Returns false if it
* has a deferred fetch pending.
*/
@Override
public boolean isPopulated() {
return map != null;
}
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
@Override
public boolean isReference() {
return map == null;
}
@Override
public boolean checkEmptyLazyLoad() {
if (map == null) {
map = new LinkedHashMap<>();
return true;
} else {
return false;
}
}
private void initClear() {
lock.lock();
try {
if (map == null) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
} else {
map = new LinkedHashMap<>();
}
}
} finally {
lock.unlock();
}
}
private void init() {
lock.lock();
try {
if (map == null) {
if (disableLazyLoad) {
map = new LinkedHashMap<>();
} else {
lazyLoadCollection(false);
}
}
} finally {
lock.unlock();
}
}
public LinkedHashMap<K, E> collectionAdd() {
if (map == null) {
map = new LinkedHashMap<>();
}
return map;
}
@SuppressWarnings("unchecked")
public void refresh(ModifyListenMode modifyListenMode, BeanMap<?, ?> newMap) {
setModifyListening(modifyListenMode);
this.map = (LinkedHashMap<K, E>) newMap.actualMap();
}
/**
* Return the actual underlying map.
*/
public LinkedHashMap<K, E> actualMap() {
return map;
}
/**
* Returns the collection of beans (map values).
*/
@Override
public Collection<E> actualDetails() {
return map.values();
}
/**
* Returns the map entrySet.
*/
@Override
public Collection<?> actualEntries() {
return map.entrySet();
}
@Override
public String toString() {
if (map == null) {
return "BeanMap<deferred>";
} else {
return map.toString();
}
}
/**
* Equal if object is a Map and equal in a Map sense.
*/
@Override
public boolean equals(Object object) {
init();
return map.equals(object);
}
@Override
public int hashCode() {
init();
return map.hashCode();
}
@Override
public void clear() {
checkReadOnly();
initClear();
if (modifyListening) {
// add all beans to the removal list
for (E bean : map.values()) {
modifyRemoval(bean);
}
}
map.clear();
}
@Override
public boolean containsKey(Object key) {
init();
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
init();
return map.containsValue(value);
}
@Override
public Set<Entry<K, E>> entrySet() {
init();
if (readOnly) {
return Collections.unmodifiableSet(map.entrySet());
}
return modifyListening ? new ModifyEntrySet<>(this, map.entrySet()) : map.entrySet();
}
@Override
public E get(Object key) {
init();
return map.get(key);
}
@Override
public boolean isEmpty() {
init();
return map.isEmpty();
}
@Override
public Set<K> keySet() {
init();
if (readOnly) {
return Collections.unmodifiableSet(map.keySet());
}
return modifyListening ? new ModifyKeySet<>(this, map.keySet()) : map.keySet();
}
@Override
public E put(K key, E value) {
checkReadOnly();
init();
if (modifyListening) {
E oldBean = map.put(key, value);
if (value != oldBean) {
// register the add of the new and the removal of the old
modifyAddition(value);
modifyRemoval(oldBean);
}
return oldBean;
} else {
return map.put(key, value);
}
}
@Override
public void putAll(Map<? extends K, ? extends E> puts) {
checkReadOnly();
init();
if (modifyListening) {
for (Entry<? extends K, ? extends E> entry : puts.entrySet()) {
Object oldBean = map.put(entry.getKey(), entry.getValue());
if (entry.getValue() != oldBean) {
modifyAddition(entry.getValue());
modifyRemoval(oldBean);
}
}
} else {
map.putAll(puts);
}
}
@Override
public void addBean(E bean) {
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
}
@Override
public void removeBean(E bean) {
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
}
@Override
public E remove(Object key) {
checkReadOnly();
init();
if (modifyListening) {
E o = map.remove(key);
modifyRemoval(o);
return o;
}
return map.remove(key);
}
@Override
public int size() {
init();
return map.size();
}
@Override
public Collection<E> values() {
init();
if (readOnly) {
return Collections.unmodifiableCollection(map.values());
}
return modifyListening ? new ModifyCollection<>(this, map.values()) : map.values();
}
@Override
public BeanCollection<E> shallowCopy() {
BeanMap<K, E> copy = new BeanMap<>(new LinkedHashMap<>(map));
copy.setFromOriginal(this);
return copy;
}
@Override
public SequencedMap<K, E> reversed() {
init();
if (modifyListening) {
throw new UnsupportedOperationException("Not supported on modify listening map");
}
return map.reversed();
}
@Override
public Entry<K, E> firstEntry() {
init();
return map.firstEntry();
}
@Override
public Entry<K, E> lastEntry() {
init();
return map.lastEntry();
}
@Override
public Entry<K, E> pollFirstEntry() {
checkReadOnly();
init();
var entry = map.pollFirstEntry();
if (modifyListening && entry != null) {
modifyRemoval(entry.getValue());
}
return entry;
}
@Override
public Entry<K, E> pollLastEntry() {
checkReadOnly();
init();
var entry = map.pollLastEntry();
if (modifyListening && entry != null) {
modifyRemoval(entry.getValue());
}
return entry;
}
@Override
public E putFirst(K key, E value) {
checkReadOnly();
init();
if (modifyListening) {
E oldBean = map.putFirst(key, value);
if (value != oldBean) {
// register the add of the new and the removal of the old
modifyAddition(value);
modifyRemoval(oldBean);
}
return oldBean;
} else {
return map.putFirst(key, value);
}
}
@Override
public E putLast(K key, E value) {
checkReadOnly();
init();
if (modifyListening) {
E oldBean = map.putLast(key, value);
if (value != oldBean) {
// register the add of the new and the removal of the old
modifyAddition(value);
modifyRemoval(oldBean);
}
return oldBean;
} else {
return map.putLast(key, value);
}
}
@Override
public SequencedSet<K> sequencedKeySet() {
init();
return map.sequencedKeySet();
}
@Override
public SequencedCollection<E> sequencedValues() {
init();
return map.sequencedValues();
}
@Override
public SequencedSet<Entry<K, E>> sequencedEntrySet() {
init();
return map.sequencedEntrySet();
}
}
@@ -0,0 +1,460 @@
package io.ebean.common;
import io.ebean.bean.*;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.SequencedSet;
/**
* Set capable of lazy loading and modification aware.
*/
public final class BeanSet<E> extends AbstractBeanCollection<E> implements SequencedSet<E>, BeanCollectionAdd {
private static final long serialVersionUID = 1L;
/**
* The underlying Set implementation.
*/
private LinkedHashSet<E> set;
/**
* Create with a specific Set implementation.
*/
public BeanSet(LinkedHashSet<E> set) {
this.set = set;
}
/**
* Create using an underlying LinkedHashSet.
*/
public BeanSet() {
this(new LinkedHashSet<>());
}
public BeanSet(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
super(loader, ownerBean, propertyName);
}
@Override
public void toString(ToStringBuilder builder) {
builder.addCollection(set);
}
@Override
public void reset(EntityBean ownerBean, String propertyName) {
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.set = null;
}
@Override
public boolean isSkipSave() {
return set == null || (set.isEmpty() && !holdsModifications());
}
@Override
@SuppressWarnings("unchecked")
public void addEntityBean(EntityBean bean) {
set.add((E) bean);
}
@Override
@SuppressWarnings("unchecked")
public void loadFrom(BeanCollection<?> other) {
if (set == null) {
set = new LinkedHashSet<>();
}
set.addAll((Collection<? extends E>) other.actualDetails());
}
@Override
public void internalAddWithCheck(Object bean) {
// set add() already de-dups so just add it
internalAdd(bean);
}
@Override
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (set == null) {
set = new LinkedHashSet<>();
}
if (bean != null) {
set.add((E) bean);
}
}
/**
* Returns true if the underlying set has its data.
*/
@Override
public boolean isPopulated() {
return set != null;
}
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
@Override
public boolean isReference() {
return set == null;
}
@Override
public boolean checkEmptyLazyLoad() {
if (set == null) {
set = new LinkedHashSet<>();
return true;
} else {
return false;
}
}
private void initClear() {
lock.lock();
try {
if (set == null) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(false);
} else {
set = new LinkedHashSet<>();
}
}
} finally {
lock.unlock();
}
}
private void init() {
lock.lock();
try {
if (set == null) {
if (disableLazyLoad) {
set = new LinkedHashSet<>();
} else {
lazyLoadCollection(false);
}
}
} finally {
lock.unlock();
}
}
public BeanCollectionAdd collectionAdd() {
if (set == null) {
set = new LinkedHashSet<>();
}
return this;
}
public void refresh(ModifyListenMode modifyListenMode, BeanSet<E> newSet) {
setModifyListening(modifyListenMode);
this.set = newSet.actualSet();
}
/**
* Return the actual underlying set.
*/
public LinkedHashSet<E> actualSet() {
return set;
}
@Override
public Collection<E> actualDetails() {
return set;
}
@Override
public Collection<?> actualEntries() {
return set;
}
@Override
public String toString() {
if (set == null) {
return "BeanSet<deferred>";
} else {
return set.toString();
}
}
/**
* Equal if obj is a Set and equal in a Set sense.
*/
@Override
public boolean equals(Object obj) {
init();
return set.equals(obj);
}
@Override
public int hashCode() {
init();
return set.hashCode();
}
@Override
public void addBean(E bean) {
add(bean);
}
@Override
public void removeBean(E bean) {
if (set.remove(bean)) {
getModifyHolder().modifyRemoval(bean);
}
}
// -----------------------------------------------------//
// proxy method for map
// -----------------------------------------------------//
@Override
public boolean add(E bean) {
checkReadOnly();
init();
if (modifyListening) {
if (set.add(bean)) {
modifyAddition(bean);
return true;
} else {
return false;
}
}
return set.add(bean);
}
@Override
public boolean addAll(Collection<? extends E> beans) {
checkReadOnly();
init();
if (modifyListening) {
boolean changed = false;
for (E bean : beans) {
if (set.add(bean)) {
// register the addition of the bean
modifyAddition(bean);
changed = true;
}
}
return changed;
}
return set.addAll(beans);
}
@Override
public void clear() {
checkReadOnly();
initClear();
if (modifyListening) {
for (E bean : set) {
modifyRemoval(bean);
}
}
set.clear();
}
@Override
public boolean contains(Object bean) {
init();
return set.contains(bean);
}
@Override
public boolean containsAll(Collection<?> beans) {
init();
return set.containsAll(beans);
}
@Override
public boolean isEmpty() {
init();
return set.isEmpty();
}
@Override
public Iterator<E> iterator() {
init();
if (readOnly) {
return new ReadOnlyIterator<>(set.iterator());
}
if (modifyListening) {
return new ModifyIterator<>(this, set.iterator());
}
return set.iterator();
}
@Override
public boolean remove(Object bean) {
checkReadOnly();
init();
if (modifyListening) {
if (set.remove(bean)) {
modifyRemoval(bean);
return true;
}
return false;
}
return set.remove(bean);
}
@Override
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyListening) {
boolean changed = false;
for (Object bean : beans) {
if (set.remove(bean)) {
modifyRemoval(bean);
changed = true;
}
}
return changed;
}
return set.removeAll(beans);
}
@Override
public boolean retainAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyListening) {
boolean changed = false;
Iterator<?> it = set.iterator();
while (it.hasNext()) {
Object bean = it.next();
if (!beans.contains(bean)) {
// not retaining this bean so add it to the removal list
it.remove();
modifyRemoval(bean);
changed = true;
}
}
return changed;
}
return set.retainAll(beans);
}
@Override
public int size() {
init();
return set.size();
}
@Override
public Object[] toArray() {
init();
return set.toArray();
}
@Override
public <T> T[] toArray(T[] array) {
init();
//noinspection SuspiciousToArrayCall
return set.toArray(array);
}
@Override
public SequencedSet<E> reversed() {
init();
if (modifyListening) {
throw new UnsupportedOperationException("Not supported on modify listening set");
}
return set.reversed();
}
@Override
public void addFirst(E bean) {
checkReadOnly();
init();
if (modifyListening) {
modifyAddition(bean);
}
set.addFirst(bean);
}
@Override
public void addLast(E bean) {
checkReadOnly();
init();
if (modifyListening) {
modifyAddition(bean);
}
set.addLast(bean);
}
@Override
public E getFirst() {
init();
return set.getFirst();
}
@Override
public E getLast() {
init();
return set.getLast();
}
@Override
public E removeFirst() {
checkReadOnly();
init();
if (modifyListening) {
var bean = set.removeFirst();
modifyRemoval(bean);
return bean;
}
return set.removeFirst();
}
@Override
public E removeLast() {
checkReadOnly();
init();
if (modifyListening) {
var bean = set.removeLast();
modifyRemoval(bean);
return bean;
}
return set.removeLast();
}
private static final class ReadOnlyIterator<E> implements Iterator<E>, Serializable {
private static final long serialVersionUID = 2577697326745352605L;
private final Iterator<E> it;
ReadOnlyIterator(Iterator<E> it) {
this.it = it;
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public E next() {
return it.next();
}
@Override
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
}
@Override
public BeanCollection<E> shallowCopy() {
BeanSet<E> copy = new BeanSet<>(new LinkedHashSet<>(set));
copy.setFromOriginal(this);
return copy;
}
}
@@ -136,13 +136,13 @@ class ToStringBuilderTest {
@Test
void beanSet_null_empty() {
assertThat(toStringFor(new BeanSet<String>(null))).isEqualTo("[]");
assertThat(toStringFor(new BeanSet<String>(Collections.emptySet()))).isEqualTo("[]");
assertThat(toStringFor(new BeanSet<String>(new LinkedHashSet<>()))).isEqualTo("[]");
}
@Test
void beanMap_null_empty() {
assertThat(toStringFor(new BeanMap<String, String>(null))).isEqualTo("{}");
assertThat(toStringFor(new BeanMap<String, String>(Collections.emptyMap()))).isEqualTo("{}");
assertThat(toStringFor(new BeanMap<String, String>(new LinkedHashMap<>()))).isEqualTo("{}");
}
@Test
@@ -159,7 +159,7 @@ class ToStringBuilderTest {
@Test
void beanMap_some() {
Map<String, Recurse> under = new LinkedHashMap<>();
var under = new LinkedHashMap<String, Recurse>();
under.put("a", new Recurse(1, "a"));
under.put("b", new Recurse(2, "b"));
BeanMap<String, Recurse> list = new BeanMap<>(under);
@@ -75,8 +75,6 @@ class DatabaseConfigTest {
props.setProperty("defaultServer", "false");
props.setProperty("skipDataSourceCheck", "true");
props.setProperty("readOnlyDatabase", "true");
props.setProperty("lengthCheck", "ON");
props.setProperty("includeLabelInSql", "true");
props.setProperty("queryPlan.enable", "true");
props.setProperty("queryPlan.thresholdMicros", "10000");
@@ -97,8 +95,6 @@ class DatabaseConfigTest {
assertTrue(settings.isLoadModuleInfo());
assertTrue(settings.skipDataSourceCheck());
assertTrue(settings.readOnlyDatabase());
assertTrue(settings.isIncludeLabelInSql());
assertThat(settings.getLengthCheck()).isEqualTo(LengthCheck.ON);
assertTrue(settings.isIdGeneratorAutomatic());
assertFalse(settings.getPlatformConfig().isCaseSensitiveCollation());
@@ -132,11 +128,8 @@ class DatabaseConfigTest {
assertThat(settings.getMappingLocations()).containsExactly("classpath:/foo","bar");
config.persistBatch(PersistBatch.NONE)
.persistBatchOnCascade(PersistBatch.NONE)
.lengthCheck(LengthCheck.ON)
.lengthCheck(LengthCheck.UTF8);
config.setPersistBatch(PersistBatch.NONE);
config.setPersistBatchOnCascade(PersistBatch.NONE);
Properties props1 = new Properties();
props1.setProperty("ebean.persistBatch", "ALL");
@@ -153,7 +146,6 @@ class DatabaseConfigTest {
assertEquals(PersistBatch.ALL, settings.getPersistBatch());
assertEquals(PersistBatch.ALL, settings.getPersistBatchOnCascade());
assertEquals(LengthCheck.UTF8, settings.getLengthCheck());
config.setEnabledL2Regions("r0,orgs");
assertEquals("r0,orgs", settings.getEnabledL2Regions());
@@ -182,8 +174,6 @@ class DatabaseConfigTest {
assertEquals(600, config.getQueryPlanCapturePeriodSecs());
assertEquals(10000L, config.getQueryPlanCaptureMaxTimeMillis());
assertEquals(10, config.getQueryPlanCaptureMaxCount());
assertThat(config.getLengthCheck()).isEqualTo(LengthCheck.OFF);
assertFalse(config.isIncludeLabelInSql());
config.setLoadModuleInfo(false);
assertFalse(config.isAutoLoadModuleInfo());
+31 -31
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</parent>
<name>ebean bom</name>
@@ -89,103 +89,103 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>14.0.0</version>
<version>13.24.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>14.0.0</version>
<version>13.24.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>14.0.0</version>
<version>13.18.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>14.0.0</version>
<version>13.18.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>14.0.0</version>
<version>13.18.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<!-- platforms -->
@@ -193,79 +193,79 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
</dependencies>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -30,7 +30,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.2</version>
<version>42.6.0</version>
<optional>true</optional>
</dependency>
@@ -174,9 +174,4 @@ public interface DataBinder {
*/
String popJson();
/**
* Returns the last bound object (e.g. for BindValidation). Note for InputStreams you'll get an InputStreamInfo.
*/
Object popLastObject();
}
@@ -1,27 +0,0 @@
package io.ebean.core.type;
import java.io.InputStream;
/**
* Helper to transports length info of DataBind.setBinaryStream(stream, length) to BindValidation
*
* @author Roland Praml, FOCONIS AG
*/
public final class InputStreamInfo {
private final InputStream stream;
private final long length;
public InputStreamInfo(InputStream stream, long length) {
this.stream = stream;
this.length = length;
}
public InputStream stream() {
return stream;
}
public long length() {
return length;
}
}
+8 -8
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -22,7 +22,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
@@ -46,13 +46,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>14.0.0</version>
<version>13.18.0</version>
</dependency>
<dependency>
@@ -151,7 +151,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.2</version>
<version>42.6.0</version>
<optional>true</optional>
</dependency>
@@ -159,21 +159,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>14.1.0</version>
<version>13.26.1-jakarta</version>
<scope>test</scope>
</dependency>
@@ -3,7 +3,6 @@ package io.ebeaninternal.api;
import io.ebean.CacheMode;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.server.core.BindPadding;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -58,22 +57,17 @@ public final class LoadManyRequest extends LoadRequest {
return loadContext.fullPath();
}
private List<Object> parentIdList(SpiEbeanServer server, BeanPropertyAssocMany<?> many, PersistenceContext pc) {
final var idList = new ArrayList<>(loadContext.size());
final var descriptor = many.descriptor();
private List<Object> parentIdList(SpiEbeanServer server) {
List<Object> idList = new ArrayList<>();
BeanPropertyAssocMany<?> many = many();
for (int i = 0; i < loadContext.size(); i++) {
final BeanCollection<?> bc = loadContext.get(i);
BeanCollection<?> bc = loadContext.get(i);
if (bc != null) {
final var parent = bc.owner();
final var parentId = descriptor.getId(parent);
idList.add(parentId);
bc.setLoader(server); // don't use the load buffer again
if (lazy) {
descriptor.contextPutIfAbsent(pc, parentId, parent);
if (!originIncluded && bc == originCollection) {
originIncluded = true;
}
if (lazy && !originIncluded && bc == originCollection) {
originIncluded = true;
}
idList.add(many.parentId(bc.owner()));
bc.setLoader(server); // don't use the load buffer again
}
}
if (originCollection != null && !originIncluded) {
@@ -81,7 +75,7 @@ public final class LoadManyRequest extends LoadRequest {
idList.add(many.parentId(originCollection.owner()));
originCollection.setLoader(server); // don't use the load buffer again
}
if (descriptor.isPadInExpression()) {
if (many.targetDescriptor().isPadInExpression()) {
BindPadding.padIds(idList);
}
return idList;
@@ -105,9 +99,8 @@ public final class LoadManyRequest extends LoadRequest {
query.where().raw(extraWhere.replace("${ta}", "t0").replace("${mta}", "int_"));
}
query.setLazyLoadForParents(many);
final var pc = loadContext.persistenceContext();
many.addWhereParentIdIn(query, parentIdList(server, many, pc), loadContext.isUseDocStore());
query.setPersistenceContext(pc);
many.addWhereParentIdIn(query, parentIdList(server), loadContext.isUseDocStore());
query.setPersistenceContext(loadContext.persistenceContext());
query.setLoadDescription(lazy ? "lazy" : "query", description());
if (lazy) {
query.setLazyLoadBatchSize(loadContext.batchSize());
@@ -3,8 +3,6 @@ package io.ebeaninternal.api;
import io.ebean.TxScope;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Used internally to handle the scoping of transactions for methods.
@@ -49,11 +47,6 @@ public final class ScopeTrans {
private boolean nestedCommit;
private boolean nestedUseSavepoint;
/**
* The UserObjects when using in nested transactions.
*/
private Map<String, Object> userObjects;
public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope) {
this.rollbackOnChecked = rollbackOnChecked;
this.created = created;
@@ -225,17 +218,4 @@ public final class ScopeTrans {
return e instanceof RuntimeException || rollbackOnChecked;
}
public void putUserObject(String name, Object value) {
if (userObjects == null) {
userObjects = new HashMap<>();
}
userObjects.put(name, value);
}
public Object getUserObject(String name) {
if (userObjects == null) {
return null;
}
return userObjects.get(name);
}
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.api;
import io.ebeaninternal.server.transaction.TransactionScopeManager;
import io.ebeaninternal.server.util.ArrayStack;
import jakarta.persistence.PersistenceException;
/**
@@ -172,31 +173,4 @@ public final class ScopedTransaction extends SpiTransactionProxy {
return current.caughtThrowable(e);
}
/**
* New user objects are always written to the current ScopeTrans.
*/
@Override
public void putUserObject(String name, Object value) {
current.putUserObject(name, value);
}
/**
* Returns the userObject in the stack, Herew we search
* the stack and return the first found userObject
*/
@Override
public Object getUserObject(String name) {
Object obj = current.getUserObject(name);
if (obj != null) {
return obj;
}
for (ScopeTrans trans : stack) {
obj = trans.getUserObject(name);
if (obj != null) {
return obj;
}
}
return transaction.getUserObject(name);
}
}
@@ -86,11 +86,6 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, BeanCollectio
*/
SpiTransactionManager transactionManager();
/**
* End the current transaction if it is active.
*/
void endTransaction();
/**
* Return all the descriptors.
*/
@@ -84,7 +84,7 @@ public interface SpiExpression extends Expression {
*
* @param request the associated request.
*/
void addBindValues(SpiExpressionBind request);
void addBindValues(SpiExpressionRequest request);
/**
* Validate all the properties/paths associated with this expression.
@@ -1,29 +0,0 @@
package io.ebeaninternal.api;
import io.ebeaninternal.server.deploy.BeanDescriptor;
/**
* Expression bind values capture.
*/
public interface SpiExpressionBind {
/**
* Return the bean descriptor for the root type.
*/
BeanDescriptor<?> descriptor();
/**
* Add an encryption key to bind to this request.
*/
void addBindEncryptKey(Object encryptKey);
/**
* Add a bind value to this request.
*/
void addBindValue(Object bindValue);
/**
* Escapes a string to use it as exact match in Like clause.
*/
String escapeLikeString(String value);
}
@@ -1,15 +1,15 @@
package io.ebeaninternal.api;
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
import io.ebeaninternal.server.expression.platform.DbExpressionRequest;
import java.util.List;
/**
* Request object used for gathering expression sql and bind values.
*/
public interface SpiExpressionRequest extends SpiExpressionBind, DbExpressionRequest {
public interface SpiExpressionRequest {
/**
* Return the DB specific handler for JSON and ARRAY expressions.
@@ -21,6 +21,11 @@ public interface SpiExpressionRequest extends SpiExpressionBind, DbExpressionReq
*/
String parseDeploy(String logicalProp);
/**
* Return the bean descriptor for the root type.
*/
BeanDescriptor<?> descriptor();
/**
* Return the associated QueryRequest.
*/
@@ -29,13 +34,11 @@ public interface SpiExpressionRequest extends SpiExpressionBind, DbExpressionReq
/**
* Append to the expression sql without any parsing.
*/
@Override
SpiExpressionRequest append(String expression);
/**
* Append to the expression sql without any parsing.
*/
@Override
SpiExpressionRequest append(char c);
/**
@@ -44,7 +47,6 @@ public interface SpiExpressionRequest extends SpiExpressionBind, DbExpressionReq
* This is a fast path case when expression is a bean property path and falls back to using parse()
* when that isn't the case.
*/
@Override
SpiExpressionRequest property(String expression);
/**
@@ -52,6 +54,16 @@ public interface SpiExpressionRequest extends SpiExpressionBind, DbExpressionReq
*/
SpiExpressionRequest parse(String expression);
/**
* Add an encryption key to bind to this request.
*/
void addBindEncryptKey(Object encryptKey);
/**
* Add a bind value to this request.
*/
void addBindValue(Object bindValue);
/**
* Return the accumulated expression sql for all expressions in this request.
*/
@@ -72,6 +84,11 @@ public interface SpiExpressionRequest extends SpiExpressionBind, DbExpressionReq
*/
void appendLike(boolean rawLikeExpression);
/**
* Escapes a string to use it as exact match in Like clause.
*/
String escapeLikeString(String value);
/**
* Append IN expression taking into account platform and type support for Multi-value.
*/
@@ -226,11 +226,6 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
*/
ProfileLocation profileLocation();
/**
* Return the SQL hint to include in the query.
*/
String hint();
/**
* Return the label set on the query.
*/
@@ -1,14 +1,10 @@
package io.ebeaninternal.server.bind;
import io.ebean.core.type.DataBinder;
import io.ebean.core.type.InputStreamInfo;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.server.core.timezone.DataTimeZone;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.*;
import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
@@ -27,8 +23,6 @@ public class DataBind implements DataBinder {
protected int pos;
private String json;
private Object lastObject = null;
public DataBind(DataTimeZone dataTimeZone, PreparedStatement pstmt, Connection connection) {
this.dataTimeZone = dataTimeZone;
this.pstmt = pstmt;
@@ -71,19 +65,16 @@ public class DataBind implements DataBinder {
@Override
public void setObject(Object value) throws SQLException {
pstmt.setObject(++pos, value);
lastObject = value;
}
@Override
public final void setObject(Object value, int sqlType) throws SQLException {
pstmt.setObject(++pos, value, sqlType);
lastObject = value;
}
@Override
public void setNull(int jdbcType) throws SQLException {
pstmt.setNull(++pos, jdbcType);
lastObject = null;
}
@Override
@@ -105,7 +96,7 @@ public class DataBind implements DataBinder {
}
}
public void closeInputStreams() {
private void closeInputStreams() {
if (inputStreams != null) {
for (InputStream inputStream : inputStreams) {
try {
@@ -126,43 +117,36 @@ public class DataBind implements DataBinder {
@Override
public void setString(String value) throws SQLException {
pstmt.setString(++pos, value);
lastObject = value;
}
@Override
public final void setInt(int value) throws SQLException {
pstmt.setInt(++pos, value);
lastObject = null;
}
@Override
public final void setLong(long value) throws SQLException {
pstmt.setLong(++pos, value);
lastObject = null;
}
@Override
public final void setShort(short value) throws SQLException {
pstmt.setShort(++pos, value);
lastObject = null;
}
@Override
public final void setFloat(float value) throws SQLException {
pstmt.setFloat(++pos, value);
lastObject = null;
}
@Override
public final void setDouble(double value) throws SQLException {
pstmt.setDouble(++pos, value);
lastObject = null;
}
@Override
public final void setBigDecimal(BigDecimal value) throws SQLException {
pstmt.setBigDecimal(++pos, value);
lastObject = null;
}
@Override
@@ -173,7 +157,6 @@ public class DataBind implements DataBinder {
} else {
pstmt.setDate(++pos, value);
}
lastObject = null;
}
@Override
@@ -184,7 +167,6 @@ public class DataBind implements DataBinder {
} else {
pstmt.setTimestamp(++pos, value);
}
lastObject = null;
}
@Override
@@ -195,31 +177,26 @@ public class DataBind implements DataBinder {
} else {
pstmt.setTime(++pos, value);
}
lastObject = null;
}
@Override
public void setBoolean(boolean value) throws SQLException {
pstmt.setBoolean(++pos, value);
lastObject = null;
}
@Override
public void setBytes(byte[] value) throws SQLException {
pstmt.setBytes(++pos, value);
lastObject = value;
}
@Override
public void setByte(byte value) throws SQLException {
pstmt.setByte(++pos, value);
lastObject = null;
}
@Override
public void setChar(char value) throws SQLException {
pstmt.setString(++pos, String.valueOf(value));
lastObject = null;
}
@Override
@@ -234,31 +211,21 @@ public class DataBind implements DataBinder {
}
inputStreams.add(inputStream);
pstmt.setBinaryStream(++pos, inputStream, length);
lastObject = new InputStreamInfo(inputStream, length);
}
@Override
public void setBlob(byte[] bytes) throws SQLException {
pstmt.setBinaryStream(++pos, new ByteArrayInputStream(bytes), bytes.length);
lastObject = bytes;
}
@Override
public void setClob(String content) throws SQLException {
pstmt.setCharacterStream(++pos, new StringReader(content), content.length());
lastObject = content;
}
@Override
public void setArray(String arrayType, Object[] elements) throws SQLException {
pstmt.setArray(++pos, connection.createArrayOf(arrayType, elements));
lastObject = null;
}
@Override
public Object popLastObject() {
Object ret = lastObject;
lastObject = null;
return ret;
}
}
@@ -1,70 +0,0 @@
package io.ebeaninternal.server.core;
import io.ebean.ProfileLocation;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.config.SlowQueryEvent;
import java.util.List;
/**
* Slow query event.
*/
final class DSlowQueryEvent implements SlowQueryEvent {
private final String sql;
private final long timeMillis;
private final int rowCount;
private final ObjectGraphNode originNode;
private final List<Object> bindParams;
private final String label;
private final ProfileLocation profileLocation;
/**
* Construct with the SQL and execution time in millis.
*/
DSlowQueryEvent(String sql, long timeMillis, int rowCount, ObjectGraphNode originNode,
List<Object> bindParams, String label, ProfileLocation profileLocation) {
this.sql = sql;
this.timeMillis = timeMillis;
this.rowCount = rowCount;
this.originNode = originNode;
this.bindParams = bindParams;
this.profileLocation = profileLocation;
this.label = label != null ? label : profileLocation == null ? null : profileLocation.label();
}
@Override
public String getSql() {
return sql;
}
@Override
public long getTimeMillis() {
return timeMillis;
}
@Override
public int getRowCount() {
return rowCount;
}
@Override
public ObjectGraphNode getOriginNode() {
return originNode;
}
@Override
public List<Object> getBindParams() {
return bindParams;
}
@Override
public String getLabel() {
return label;
}
@Override
public ProfileLocation getProfileLocation() {
return profileLocation;
}
}
@@ -63,8 +63,8 @@ final class DefaultBeanLoader {
Object parentId = parentDesc.getId(parentBean);
if (pc == null) {
pc = new DefaultPersistenceContext();
parentDesc.contextPut(pc, parentId, parentBean);
}
parentDesc.contextPutIfAbsent(pc, parentId, parentBean);
boolean useManyIdCache = beanCollection != null && parentDesc.isManyPropCaching() && many.isUseCache();
if (useManyIdCache) {
Boolean readOnly = null;
@@ -756,6 +756,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
currentTransaction().flush();
}
@Override
public void commitTransaction() {
currentTransaction().commit();
}
@Override
public void rollbackTransaction() {
currentTransaction().rollback();
}
@Override
public void endTransaction() {
Transaction transaction = transactionManager.inScope();
@@ -2184,9 +2194,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public void slowQueryCheck(long timeMicros, int rowCount, SpiQuery<?> query) {
if (timeMicros > slowQueryMicros && slowQueryListener != null) {
List<Object> bindParams = new SlowQueryBindCapture(query).capture();
slowQueryListener.process(new DSlowQueryEvent(query.getGeneratedSql(), timeMicros / 1000L, rowCount,
query.parentNode(), bindParams, query.label(), query.profileLocation()));
slowQueryListener.process(new SlowQueryEvent(query.getGeneratedSql(), timeMicros / 1000L, rowCount, query.parentNode()));
}
}
@@ -1,12 +1,10 @@
package io.ebeaninternal.server.core;
import io.avaje.applog.AppLog;
import io.ebean.ProfileLocation;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.config.SlowQueryEvent;
import io.ebean.config.SlowQueryListener;
import java.util.List;
import static java.lang.System.Logger.Level.WARNING;
/**
@@ -18,10 +16,11 @@ final class DefaultSlowQueryListener implements SlowQueryListener {
@Override
public void process(SlowQueryEvent event) {
ProfileLocation profileLocation = event.getProfileLocation();
String loc = profileLocation == null ? "" : profileLocation.fullLocation();
List<Object> bindParams = event.getBindParams();
log.log(WARNING, "Slow query warning - millis:{0} rows:{1} location:{2} sql[{3}] params{4}",
event.getTimeMillis(), event.getRowCount(), loc, event.getSql(), bindParams);
String firstStack = "";
ObjectGraphNode node = event.getOriginNode();
if (node != null) {
firstStack = node.origin().top();
}
log.log(WARNING, "Slow query warning - millis:{0} rows:{1} caller[{2}] sql[{3}]", event.getTimeMillis(), event.getRowCount(), firstStack, event.getSql());
}
}
@@ -773,10 +773,4 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
public int forwardOnlyFetchSize() {
return queryEngine.forwardOnlyFetchSize();
}
public void clearContext() {
if (!transaction.isAutoPersistUpdates()) {
beanDescriptor.contextClear(transaction.persistenceContext());
}
}
}
@@ -919,27 +919,21 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
private void controllerPost() {
boolean old = transaction.isFlushOnQuery();
transaction.setFlushOnQuery(false);
try {
switch (type) {
case INSERT:
controller.postInsert(this);
break;
case UPDATE:
controller.postUpdate(this);
break;
case DELETE_SOFT:
controller.postSoftDelete(this);
break;
case DELETE:
controller.postDelete(this);
break;
default:
break;
}
} finally {
transaction.setFlushOnQuery(old);
switch (type) {
case INSERT:
controller.postInsert(this);
break;
case UPDATE:
controller.postUpdate(this);
break;
case DELETE_SOFT:
controller.postSoftDelete(this);
break;
case DELETE:
controller.postDelete(this);
break;
default:
break;
}
}
@@ -77,13 +77,10 @@ public final class PersistRequestOrmUpdate extends PersistRequest {
*/
@Override
public void postExecute() {
OrmUpdateType ormUpdateType = ormUpdate.ormUpdateType();
if (OrmUpdateType.INSERT != ormUpdateType && !transaction.isAutoPersistUpdates()) {
beanDescriptor.contextClear(transaction.persistenceContext());
}
if (startNanos > 0) {
persistExecute.collectOrmUpdate(label, startNanos);
}
OrmUpdateType ormUpdateType = ormUpdate.ormUpdateType();
String tableName = ormUpdate.baseTable();
if (transaction.isLogSummary()) {
transaction.logSummary("{0} table[{1}] rows[{2}] bind[{3}]", ormUpdateType, tableName, rowCount, bindLog);
@@ -3,13 +3,10 @@ package io.ebeaninternal.server.core;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.persist.BatchControl;
import io.ebeaninternal.server.persist.PersistExecute;
import io.ebeaninternal.server.persist.TrimLogSql;
import java.util.List;
/**
* Persist request specifically for CallableSql.
*/
@@ -159,14 +156,6 @@ public final class PersistRequestUpdateSql extends PersistRequest {
*/
@Override
public void postExecute() {
if (sqlType != SqlType.SQL_INSERT && !transaction.isAutoPersistUpdates()) {
List<BeanDescriptor<?>> descriptors = server.descriptors(tableName);
if (descriptors != null) {
for (BeanDescriptor<?> descriptor : descriptors) {
descriptor.contextClear(transaction.persistenceContext());
}
}
}
if (startNanos > 0) {
persistExecute.collectSqlUpdate(label, startNanos);
}
@@ -1,71 +0,0 @@
package io.ebeaninternal.server.core;
import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionList;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.persist.MultiValueWrapper;
import java.util.ArrayList;
import java.util.List;
final class SlowQueryBindCapture implements SpiExpressionBind {
private final SpiQuery<?> query;
private final List<Object> bindParams = new ArrayList<>();
SlowQueryBindCapture(SpiQuery<?> query) {
this.query = query;
}
List<Object> capture() {
var params = query.bindParams();
if (params != null) {
var positionedParameters = params.positionedParameters();
for (BindParams.Param param : positionedParameters) {
if (param.isInParam()) {
add(param.inValue());
}
}
}
Object id = query.getId();
if (id != null) {
add(id);
}
SpiExpressionList<?> spiExpressionList = query.whereExpressions();
if (spiExpressionList != null) {
spiExpressionList.addBindValues(this);
}
return bindParams;
}
private void add(Object value) {
if (value instanceof MultiValueWrapper) {
var mvw = (MultiValueWrapper) value;
bindParams.add(mvw.getValues());
} else {
bindParams.add(value);
}
}
@Override
public BeanDescriptor<?> descriptor() {
return query.descriptor();
}
@Override
public void addBindValue(Object bindValue) {
add(bindValue);
}
@Override
public void addBindEncryptKey(Object encryptKey) {
bindParams.add("*");
}
@Override
public String escapeLikeString(String value) {
return query.descriptor().ebeanServer().databasePlatform().escapeLikeString(value);
}
}
@@ -1,12 +1,9 @@
package io.ebeaninternal.server.deploy;
import io.ebean.Transaction;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollectionAdd;
import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.query.CQueryCollectionAdd;
@@ -34,7 +31,7 @@ public interface BeanCollectionHelp<T> extends CQueryCollectionAdd<T> {
* For Map's this needs to take the mapKey.
* </p>
*/
BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey);
BeanCollectionAdd collectionAdd(Object bc, String mapKey);
/**
* Create an empty collection of the correct type without a parent bean.
@@ -2056,13 +2056,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
pc.clear(rootBeanType, idValue);
}
/**
* Clear a bean from the persistence context.
*/
public void contextClear(PersistenceContext pc) {
pc.clear(rootBeanType);
}
/**
* Delete a bean from the persistence context (such that we don't fetch it in the same transaction).
*/
@@ -5,7 +5,6 @@ import io.ebean.DatabaseBuilder;
import io.ebean.Model;
import io.ebean.RawSqlBuilder;
import io.ebean.annotation.ConstraintMode;
import io.ebean.annotation.Platform;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.config.*;
@@ -107,7 +106,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
private final String asOfViewSuffix;
private final boolean jacksonCorePresent;
private final int queryPlanTTLSeconds;
private final BindMaxLength bindMaxLength;
private int entityBeanCount;
private List<BeanDescriptor<?>> immutableDescriptorList;
/**
@@ -162,19 +160,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
this.changeLogListener = config.changeLogListener(bootupClasses.getChangeLogListener());
this.changeLogRegister = config.changeLogRegister(bootupClasses.getChangeLogRegister());
this.jacksonCorePresent = config.isJacksonCorePresent();
this.bindMaxLength = initMaxLength();
}
BindMaxLength initMaxLength() {
LengthCheck lengthCheck = this.config.getLengthCheck();
switch (lengthCheck) {
case OFF:
return null;
case UTF8:
return BindMaxLength.ofUtf8();
default:
return BindMaxLength.ofStandard();
}
}
@Override
@@ -414,7 +399,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
* Return the BeanDescriptors mapped to the table.
*/
public List<BeanDescriptor<?>> descriptors(String tableName) {
return tableName == null ? Collections.emptyList() : tableToDescMap.get(tableName.toLowerCase());
return tableToDescMap.get(tableName.toLowerCase());
}
/**
@@ -633,8 +618,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
private void registerDescriptor(DeployBeanInfo<?> info) {
platformUsesColumnDefinitions(info);
BeanDescriptor<?> desc = new BeanDescriptor<>(this, info.getDescriptor());
descMap.put(desc.type().getName(), desc);
if (desc.isDocStoreMapped()) {
@@ -647,23 +630,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
}
private void platformUsesColumnDefinitions(DeployBeanInfo<?> info) {
if (databasePlatform.isPlatform(Platform.CLICKHOUSE) && !DbOffline.isGenerateMigration()) {
// ClickHouse uses column definition to optimise JDBC bulk inserts
DbPlatformTypeMapping typeMapping = databasePlatform.dbTypeMap();
for (DeployBeanProperty property : info.getDescriptor().propertiesAll()) {
if (property.getDbColumnDefn() == null) {
DbPlatformType dbPlatformType = typeMapping.get(property.getDbType());
String columnDefn = dbPlatformType.renderType(property.getDbLength(), property.getDbScale());
if (property.isNullable()) {
columnDefn = "Nullable(" + columnDefn + ")";
}
property.setDbColumnDefn(columnDefn);
}
}
}
}
/**
* Read the initial deployment information for the entities.
* <p>
@@ -1535,10 +1501,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
return list;
}
public BindMaxLength bindMaxLength() {
return bindMaxLength;
}
/**
* Comparator to sort the BeanDescriptors by name.
*/
@@ -1,16 +1,12 @@
package io.ebeaninternal.server.deploy;
import io.ebean.Transaction;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollectionAdd;
import io.ebean.bean.EntityBean;
import io.ebean.common.BeanList;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.json.SpiJsonWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -23,19 +19,11 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
super(many);
}
BeanListHelp() {
super();
}
@Override
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
public final BeanCollectionAdd collectionAdd(Object bc, String mapKey) {
if (bc instanceof BeanList<?>) {
BeanList<?> bl = (BeanList<?>) bc;
if (bl.actualList() == null) {
bl.setActualList(new ArrayList<>());
}
return bl;
return bl.collectionAdd();
} else {
throw new RuntimeException("Unhandled type " + bc);
}
@@ -67,20 +55,20 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
return beanList;
}
@SuppressWarnings("unchecked")
@Override
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
BeanList<?> newBeanList = (BeanList<?>) bc;
BeanList<T> newBeanList = (BeanList<T>) bc;
List<?> currentList = (List<?>) many.getValue(parentBean);
newBeanList.setModifyListening(many.modifyListenMode());
if (currentList == null) {
// the currentList is null? Not really expecting this...
many.setValue(parentBean, newBeanList);
} else if (currentList instanceof BeanList<?>) {
} else if (currentList instanceof BeanList) {
// normally this case, replace just the underlying list
BeanList<?> currentBeanList = (BeanList<?>) currentList;
currentBeanList.setActualList(newBeanList.actualList());
currentBeanList.setModifyListening(many.modifyListenMode());
BeanList<T> currentBeanList = (BeanList<T>) currentList;
currentBeanList.refresh(many.modifyListenMode(), newBeanList);
} else {
// replace the entire list with the BeanList
@@ -1,17 +1,13 @@
package io.ebeaninternal.server.deploy;
import io.ebean.Transaction;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollectionAdd;
import io.ebean.bean.EntityBean;
import io.ebean.common.BeanMap;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.json.SpiJsonWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
@@ -37,20 +33,14 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
@Override
@SuppressWarnings("unchecked")
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
public final BeanCollectionAdd collectionAdd(Object bc, String mapKey) {
if (mapKey == null) {
mapKey = many.mapKey();
}
BeanProperty beanProp = targetDescriptor.beanProperty(mapKey);
if (bc instanceof BeanMap<?, ?>) {
BeanMap<Object, Object> bm = (BeanMap<Object, Object>) bc;
Map<Object, Object> actualMap = bm.actualMap();
if (actualMap == null) {
actualMap = new LinkedHashMap<>();
bm.setActualMap(actualMap);
}
return new Adder(beanProp, actualMap);
return new Adder(beanProp, bm.collectionAdd());
} else {
throw new RuntimeException("Unhandled type " + bc);
}
@@ -126,8 +116,7 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
} else if (current instanceof BeanMap<?, ?>) {
// normally this case, replace just the underlying list
BeanMap<?, ?> currentBeanMap = (BeanMap<?, ?>) current;
currentBeanMap.setActualMap(newBeanMap.actualMap());
currentBeanMap.setModifyListening(many.modifyListenMode());
currentBeanMap.refresh(many.modifyListenMode(), newBeanMap);
} else {
// replace the entire set
@@ -1,7 +1,6 @@
package io.ebeaninternal.server.deploy;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.DataIntegrityException;
import io.ebean.ValuePair;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
@@ -41,8 +40,8 @@ import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
import io.ebeanservice.docstore.api.support.DocStructure;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.PersistenceException;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
@@ -167,7 +166,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
*/
private final String dbComment;
private final DbEncryptFunction dbEncryptFunction;
private final BindMaxLength bindMaxLength;
private int deployOrder;
final boolean jsonSerialize;
final boolean jsonDeserialize;
@@ -260,7 +258,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
this.jsonSerialize = deploy.isJsonSerialize();
this.jsonDeserialize = deploy.isJsonDeserialize();
this.bindMaxLength = deploy.bindMaxLength();
}
private String tableAliasIntern(BeanDescriptor<?> descriptor, String s, boolean dbEncrypted, String dbColumn) {
@@ -348,7 +345,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.elPlaceHolderEncrypted = override.replace(source.elPlaceHolderEncrypted, source.dbColumn);
this.jsonSerialize = source.jsonSerialize;
this.jsonDeserialize = source.jsonDeserialize;
this.bindMaxLength = source.bindMaxLength;
}
/**
@@ -559,18 +555,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
@SuppressWarnings("unchecked")
public void bind(DataBind b, Object value) throws SQLException {
scalarType.bind(b, value);
if (bindMaxLength != null) {
Object obj = b.popLastObject();
long length = bindMaxLength.length(dbLength, obj);
if (length > dbLength) {
b.closeInputStreams();
String s = String.valueOf(value); // take original bind value here.
if (s.length() > 50) {
s = s.substring(0, 47) + "...";
}
throw new DataIntegrityException("Cannot bind value '" + s + "' (effective length=" + length + ") to column '" + dbColumn + "' (length=" + dbLength + ")");
}
}
}
@SuppressWarnings(value = "unchecked")
@@ -1182,14 +1166,14 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* Returns true if this <code>isLob()</code> or the type will effectively map to a lob.
*/
@Override
public boolean isLobForPlatform() {
public boolean isDbLob() {
if (lob) {
return true;
}
switch (dbType) {
case DbPlatformType.JSON:
case DbPlatformType.JSONB:
return dbLength == 0 || dbLength > 4000; // must be analog to DbPlatformTypeMapping.lookup
return dbLength == 0; // must be analog to DbPlatformTypeMapping.lookup
case DbPlatformType.JSONBlob:
case DbPlatformType.JSONClob:
return true;
@@ -379,9 +379,6 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
for (ExportedProperty exportedProperty : exportedProperties) {
row.addColumn(exportedProperty.getForeignDbColumn());
}
if (importedId == null) {
throw new PersistenceException("Missing @Id property on bean related to ManyToMany " + fullName());
}
importedId.buildImport(row);
return row.build();
}
@@ -588,9 +585,10 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
/**
* Set the parent bean to the child (update the relationship).
* Set the join properties from the parent bean to the child bean.
* This is only valid for OneToMany and NOT valid for ManyToMany.
*/
public void setParentToChild(EntityBean parent, EntityBean child, Object mapKeyValue) {
public void setJoinValuesToChild(EntityBean parent, EntityBean child, Object mapKeyValue) {
if (mapKeyProperty != null) {
mapKeyProperty.setValue(child, mapKeyValue);
}
@@ -601,31 +599,6 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
}
/**
* Return true if the parent bean has been set to the child (updated the relationship).
*/
public boolean setParentToChild(EntityBean parent, EntityBean child, Object mapKeyValue, BeanDescriptor<?> parentDesc) {
if (manyToMany
|| childMasterProperty == null
|| !child._ebean_getIntercept().isLoadedProperty(childMasterProperty.propertyIndex())) {
return false;
}
Object currentParent = childMasterProperty.getValue(child);
if (currentParent != null) {
Object newId = parentDesc.getId(parent);
Object oldId = parentDesc.id(currentParent);
if (Objects.equals(newId, oldId)) {
return false;
}
}
childMasterProperty.setValueIntercept(child, parent);
if (mapKeyProperty != null) {
mapKeyProperty.setValue(child, mapKeyValue);
}
return true;
}
/**
* Return the order by clause used to order the fetching of the data for
* this list, set or map.
@@ -682,7 +655,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
private BeanCollectionAdd beanCollectionAdd(Object bc) {
return help.getBeanCollectionAdd(bc, null);
return help.collectionAdd(bc, null);
}
public Object parentId(EntityBean parentBean) {
@@ -1,17 +1,13 @@
package io.ebeaninternal.server.deploy;
import io.ebean.Transaction;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollectionAdd;
import io.ebean.bean.EntityBean;
import io.ebean.common.BeanSet;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.json.SpiJsonWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
/**
@@ -26,21 +22,11 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
super(many);
}
/**
* For a query that returns a set.
*/
BeanSetHelp() {
super();
}
@Override
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
public final BeanCollectionAdd collectionAdd(Object bc, String mapKey) {
if (bc instanceof BeanSet<?>) {
BeanSet<?> beanSet = (BeanSet<?>) bc;
if (beanSet.actualSet() == null) {
beanSet.setActualSet(new LinkedHashSet<>());
}
return beanSet;
return beanSet.collectionAdd();
} else {
throw new RuntimeException("Unhandled type " + bc);
}
@@ -72,9 +58,10 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
return beanSet;
}
@SuppressWarnings("unchecked")
@Override
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
BeanSet<?> newBeanSet = (BeanSet<?>) bc;
BeanSet<T> newBeanSet = (BeanSet<T>) bc;
Set<?> current = (Set<?>) many.getValue(parentBean);
newBeanSet.setModifyListening(many.modifyListenMode());
if (current == null) {
@@ -83,9 +70,8 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
} else if (current instanceof BeanSet<?>) {
// normally this case, replace just the underlying list
BeanSet<?> currentBeanSet = (BeanSet<?>) current;
currentBeanSet.setActualSet(newBeanSet.actualSet());
currentBeanSet.setModifyListening(many.modifyListenMode());
BeanSet<T> currentBeanSet = (BeanSet<T>) current;
currentBeanSet.refresh(many.modifyListenMode(), newBeanSet);
} else {
// replace the entire set
@@ -1,90 +0,0 @@
package io.ebeaninternal.server.deploy;
import io.ebean.core.type.InputStreamInfo;
import java.nio.charset.StandardCharsets;
/**
* The max length check on bind values.
*/
public interface BindMaxLength {
/**
* Return a UTF8 based implementation.
*/
static BindMaxLength ofUtf8() {
return new UTF8();
}
/**
* Return a standard implementation.
*/
static BindMaxLength ofStandard() {
return new Standard();
}
/**
* Return the length of the object.
*/
long length(int dbLength, Object obj);
/**
* Length check based on UTF8 bytes.
*/
final class UTF8 implements BindMaxLength {
@Override
public long length(int dbLength, Object obj) {
if (obj == null) {
return -1;
} else if (obj instanceof String) {
String s = (String) obj;
return utf8String(dbLength, s);
} else if (obj instanceof byte[]) {
return ((byte[]) obj).length;
} else if (obj instanceof InputStreamInfo) {
return ((InputStreamInfo) obj).length();
} else if ("org.postgresql.util.PGobject".equals(obj.getClass().getCanonicalName())) {
String value = ((org.postgresql.util.PGobject) obj).getValue();
return value == null ? -1 : utf8String(dbLength, value);
} else {
return -1;
}
}
private static int utf8String(int dbLength, String s) {
int stringLength = s.length();
if (stringLength > dbLength) {
return stringLength;
} else if (stringLength * 4 <= dbLength) {
return -1;
} else {
return s.getBytes(StandardCharsets.UTF_8).length;
}
}
}
/**
* Standard string length implementation.
*/
final class Standard implements BindMaxLength {
@Override
public long length(int dbLength, Object obj) {
if (obj == null) {
return -1;
} else if (obj instanceof String) {
return ((String) obj).length();
} else if (obj instanceof byte[]) {
return ((byte[]) obj).length;
} else if (obj instanceof InputStreamInfo) {
return ((InputStreamInfo) obj).length();
} else if ("org.postgresql.util.PGobject".equals(obj.getClass().getCanonicalName())) {
String value = ((org.postgresql.util.PGobject) obj).getValue();
return value == null ? -1 : value.length();
} else {
return -1;
}
}
}
}
@@ -63,7 +63,7 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase {
}
@Override
public boolean isLobForPlatform() {
public boolean isDbLob() {
return false;
}
@@ -4,7 +4,6 @@ import io.ebean.bean.BeanCollection;
import io.ebean.common.BeanMap;
import java.util.LinkedHashMap;
import java.util.Map;
final class ElementHelpMap implements ElementHelp {
@@ -15,7 +14,7 @@ final class ElementHelpMap implements ElementHelp {
private static class Collector implements ElementCollector {
private final Map<Object, Object> map = new LinkedHashMap<>();
private final LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
@Override
public void addElement(Object element) {
@@ -4,7 +4,6 @@ import io.ebean.bean.BeanCollection;
import io.ebean.common.BeanSet;
import java.util.LinkedHashSet;
import java.util.Set;
final class ElementHelpSet implements ElementHelp {
@@ -15,7 +14,7 @@ final class ElementHelpSet implements ElementHelp {
private static class Collector implements ElementCollector {
private final Set<Object> set = new LinkedHashSet<>();
private final LinkedHashSet<Object> set = new LinkedHashSet<>();
@Override
public void addElement(Object element) {
@@ -1,7 +1,6 @@
package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.deploy.BeanProperty;
@@ -144,7 +143,7 @@ public interface IdBinder {
/**
* Binds multiple id value to a request.
*/
void addBindValues(SpiExpressionBind request, Collection<?> ids);
void addBindValues(SpiExpressionRequest request, Collection<?> ids);
/**
* Return the sql for binding the id using an IN clause.
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -270,7 +269,7 @@ public final class IdBinderEmbedded implements IdBinder {
}
@Override
public void addBindValues(SpiExpressionBind request, Collection<?> values) {
public void addBindValues(SpiExpressionRequest request, Collection<?> values) {
for (Object value : values) {
final EntityBean bean = (EntityBean) value;
for (BeanProperty prop : props) {
@@ -1,7 +1,6 @@
package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.bind.DataBind;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
@@ -131,7 +130,7 @@ final class IdBinderEmpty implements IdBinder {
}
@Override
public void addBindValues(SpiExpressionBind request, Collection<?> ids) {
public void addBindValues(SpiExpressionRequest request, Collection<?> ids) {
}
@Override
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.core.InternString;
@@ -144,7 +143,7 @@ public final class IdBinderSimple implements IdBinder {
}
@Override
public void addBindValues(SpiExpressionBind request, Collection<?> values) {
public void addBindValues(SpiExpressionRequest request, Collection<?> values) {
List<Object> copy = new ArrayList<>(values);
copy.replaceAll(idValue -> convertSetId(idValue, null));
request.addBindValue(new MultiValueWrapper(copy));
@@ -43,11 +43,6 @@ public interface ImportedId {
*/
void dmlAppend(GenerateDmlRequest request);
/**
* Append column and type for Insert (ClickHouse).
*/
void dmlType(GenerateDmlRequest request);
/**
* Bind the value from the bean.
*/
@@ -66,16 +66,6 @@ public final class ImportedIdEmbedded implements ImportedId {
}
}
@Override
public void dmlType(GenerateDmlRequest request) {
boolean update = request.isUpdate();
for (ImportedIdSimple anImported : imported) {
if (anImported.isInclude(update)) {
anImported.dmlType(request);
}
}
}
@Override
public String importedIdClause() {
StringBuilder sb = new StringBuilder();
@@ -37,7 +37,6 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
final BeanPropertyAssoc<?> owner;
final String localDbColumn;
private final String localColumnDefn;
private final String localSqlFormula;
final BeanProperty foreignProperty;
private final int position;
@@ -50,7 +49,6 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
this.localDbColumn = InternString.intern(localDbColumn);
this.localSqlFormula = InternString.intern(localSqlFormula);
this.foreignProperty = foreignProperty;
this.localColumnDefn = foreignProperty.dbColumnDefn();
this.position = position;
this.insertable = insertable;
this.updateable = updateable;
@@ -145,11 +143,6 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
request.appendColumn(localDbColumn);
}
@Override
public void dmlType(GenerateDmlRequest request) {
request.appendColumnDefn(localDbColumn, localColumnDefn);
}
@Override
public String importedIdClause() {
return localDbColumn + " = ?";
@@ -1,10 +1,10 @@
package io.ebeaninternal.server.deploy.meta;
import io.ebean.DatabaseBuilder;
import io.ebean.annotation.Cache;
import io.ebean.annotation.DocStore;
import io.ebean.annotation.DocStoreMode;
import io.ebean.annotation.Identity;
import io.ebean.DatabaseBuilder;
import io.ebean.config.TableName;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
@@ -21,6 +21,7 @@ import io.ebeaninternal.server.idgen.UuidV1IdGenerator;
import io.ebeaninternal.server.idgen.UuidV1RndIdGenerator;
import io.ebeaninternal.server.idgen.UuidV4IdGenerator;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import jakarta.persistence.Entity;
import jakarta.persistence.MappedSuperclass;
@@ -138,10 +139,6 @@ public class DeployBeanDescriptor<T> {
this.beanType = beanType;
}
public BindMaxLength bindMaxLength() {
return manager.bindMaxLength();
}
private String[] readPropertyNames() {
try {
Field field = beanType.getField("_ebean_props");
@@ -1,17 +1,14 @@
package io.ebeaninternal.server.deploy.meta;
import io.avaje.lang.Nullable;
import io.ebean.annotation.*;
import io.ebean.config.ScalarTypeConverter;
import io.ebean.config.dbplatform.DbDefaultValue;
import io.ebean.config.dbplatform.DbEncrypt;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebean.config.dbplatform.ExtraDbTypes;
import io.ebean.core.type.ScalarType;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BindMaxLength;
import io.ebeaninternal.server.deploy.DbMigrationInfo;
import io.ebeaninternal.server.deploy.DeployDocPropertyOptions;
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
@@ -1136,20 +1133,4 @@ public class DeployBeanProperty {
boolean isJsonType() {
return mutationDetection != null;
}
@Nullable
public BindMaxLength bindMaxLength() {
if (dbLength == 0) {
return null;
}
switch (dbType) {
case Types.VARCHAR:
case Types.BLOB:
case ExtraDbTypes.JSON:
return desc.bindMaxLength();
default:
return null;
}
}
}
@@ -122,7 +122,7 @@ public final class DeployCreateProperties {
return new DeployBeanProperty(desc, propertyType, field.getGenericType());
}
// check for Collection type (list, set or map)
ManyType manyType = determineManyType.getManyType(propertyType);
ManyType manyType = determineManyType.manyType(propertyType);
if (manyType != null) {
// List, Set or Map based object
Class<?> targetType = determineTargetType(field);
@@ -11,14 +11,14 @@ import java.util.Set;
*/
final class DetermineManyType {
ManyType getManyType(Class<?> type) {
ManyType manyType(Class<?> type) {
if (type.equals(List.class)) {
return ManyType.LIST;
}
if (type.equals(Set.class)) {
if (type.equals(Set.class) || type.getCanonicalName().equals("java.util.SequencedSet")) {
return ManyType.SET;
}
if (type.equals(Map.class)) {
if (type.equals(Map.class) || type.getCanonicalName().equals("java.util.SequencedMap")) {
return ManyType.MAP;
}
return null;
@@ -97,7 +97,7 @@ abstract class AbstractExpression implements SpiExpression {
validation.validate(propName);
}
protected final ElPropertyValue getElProp(SpiExpressionBind request) {
protected final ElPropertyValue getElProp(SpiExpressionRequest request) {
return request.descriptor().elGetValue(propName);
}
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
/**
@@ -29,7 +28,7 @@ abstract class AbstractTextExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
// do nothing, only execute against document store
}
@@ -51,7 +51,7 @@ final class AllEqualsExpression extends NonPrepareExpression {
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
if (propMap.isEmpty()) {
return;
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import java.io.IOException;
@@ -73,7 +72,7 @@ final class ArrayContainsExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
for (Object value : values) {
request.addBindValue(value);
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import java.io.IOException;
@@ -50,7 +49,7 @@ final class ArrayIsEmptyExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
// nothing to bind
}
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -35,7 +34,7 @@ final class BetweenExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
// bind the key as well as the value
@@ -75,7 +75,7 @@ final class BetweenPropertyExpression extends NonPrepareExpression {
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
request.addBindValue(val());
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
/**
@@ -53,7 +52,7 @@ final class BitwiseExpression extends AbstractExpression {
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
request.addBindValue(flags);
request.addBindValue(match);
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.expression;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionBind;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.el.ElPropertyValue;
@@ -34,7 +33,7 @@ final class CaseInsensitiveEqualExpression extends AbstractValueExpression {
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
ElPropertyValue prop = getElProp(request);
if (prop != null && prop.isDbEncrypted()) {
// bind the key as well as the value
@@ -5,7 +5,12 @@ import io.ebean.LikeType;
import io.ebean.bean.EntityBean;
import io.ebean.event.BeanQueryRequest;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.*;
import io.ebeaninternal.api.BindValuesKey;
import io.ebeaninternal.api.ManyWhereJoins;
import io.ebeaninternal.api.NaturalKeyQueryData;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
@@ -189,7 +194,8 @@ final class DefaultExampleExpression implements SpiExpression, ExampleExpression
* Adds bind values to the request.
*/
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
for (SpiExpression item : list) {
item.addBindValues(request);
}
@@ -591,7 +591,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
for (SpiExpression expr : list) {
expr.addBindValues(request);
}
@@ -99,7 +99,7 @@ final class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreE
}
@Override
public void addBindValues(SpiExpressionBind request) {
public void addBindValues(SpiExpressionRequest request) {
for (Object bindParam : bindParams) {
request.addBindValue(bindParam);
}

Some files were not shown because too many files have changed in this diff Show More