Compare commits

...
Author SHA1 Message Date
rob bygrave ec016cab17 [maven-release-plugin] prepare release ebean-12.3.9 2020-09-08 13:28:15 +12:00
rob bygrave 7c28f01923 Bump parent pom 2020-09-08 13:26:37 +12:00
Rob BygraveandGitHub 54da22eee6 Merge pull request #2056 from ebean-orm/feature/DbContext
#2055 - Refactor internals - Extract DbContext from Ebean and hold Database rather than EbeanServer
2020-09-08 09:33:10 +12:00
rob bygrave 6772b6e87e #2055 - Refactor internals - Extract DbContext from Ebean and hold Database rather than EbeanServer 2020-09-08 09:29:06 +12:00
rob bygrave 9856ebd540 #2055 - Refactor internals - Extract DbContext from Ebean and hold Database rather than EbeanServer 2020-09-08 09:25:32 +12:00
rob bygrave f96ac6e6fe No effective change - tidy Ebean, EbeanVersion 2020-09-07 21:55:21 +12:00
rob bygrave 4c5618b04b #2054 - Invalid SQL with History findVersions() on bean with @EmbeddedId - ... ORDER BY T0.NULL[*] ... 2020-09-07 18:25:25 +12:00
rob bygrave a77de9e5e6 No effective change - trim whitespace for IdBinderEmbedded 2020-09-07 18:00:12 +12:00
rob bygrave da29330a2a #2053 - Refactor tidy StringHelper.replace replacing with just String.replace where possible 2020-09-04 18:04:10 +12:00
rob bygrave d0f9d4a9a6 #2053 - Refactor tidy StringHelper.replaceString 2020-09-04 17:42:09 +12:00
rob bygrave 61ee67ee41 #2053 - Refactor tidy StringHelper.replaceString 2020-09-04 17:36:10 +12:00
rob bygrave 3117acd2d7 #2053 - Refactor tidy StringHelper.delimitedToMap 2020-09-04 13:37:25 +12:00
rob bygrave 4cee41d8d6 #2053 - Refactor tidy StringHelper - replace replaceStringMulti() with removeNewLines() 2020-09-04 13:21:13 +12:00
rob bygrave f4a58938bd #2053 - Refactor tidy StringHelper - just tidy 2020-09-04 13:09:55 +12:00
rob bygrave 4ce84f694f #2053 - Refactor tidy internals - Clean up StringHelper 2020-09-04 13:04:14 +12:00
rob bygrave 8eb248b966 #2052 - Refactor tidy internals - Use String.replace() rather than literal pattern replaceAll() 2020-09-04 12:53:43 +12:00
rob bygrave c294d8e568 #2051 - Bump config dependency from io.avaje:config to io.avaje:avaje-config 2020-09-03 17:18:14 +12:00
rob bygrave e923316ce9 Change to use maven <optional>true</optional> rather than scope provided 2020-09-03 17:13:23 +12:00
rob bygrave f611068a03 #2050 - Refactor internals - remove dependency on java.beans 2020-09-03 14:45:27 +12:00
rob bygrave dd880ac09b #2044 - Using @AttributeOverrides when override nullable 2020-08-31 14:38:23 +12:00
rob bygrave dbe24a4041 [maven-release-plugin] prepare for next development iteration 2020-08-26 11:37:29 +12:00
rob bygrave 1f32dc2dc5 [maven-release-plugin] prepare release ebean-12.3.8 2020-08-26 11:37:17 +12:00
rob bygrave b2ce9db8a8 #2048 - IllegalStateException: No query cache enabled on __. Need explicit @Cache(enableQueryCache=true) ... when ebean.disableL2Cache=true l2 2020-08-26 11:33:23 +12:00
rob bygrave a626690918 #2044 - Using @AttributeOverrides also override length, scale and columnDefinition 2020-08-25 09:48:01 +12:00
rob bygrave 0d511d51a6 #2044 - Using @AttributeOverrides breaking generated SQL (when override nullable and no column name) 2020-08-25 09:22:15 +12:00
rob bygrave 854f467504 No effective change - update ddl review h2 2020-08-25 09:08:11 +12:00
rob bygrave d3cc393edc No effective change - update ddl review postgres 2020-08-25 09:04:21 +12:00
Rob BygraveandGitHub 002014f930 For #2038 - updated from 12.3.6 to 12.3.7 - NPE BeanDescriptor.findPropertyFromPath(BeanDescriptor.java:1965) (#2047)
* #2038 - lazy loading ToMany with path

* #2038 - Failing test for NPE BeanDescriptor.findPropertyFromPath(BeanDescriptor.java:1965)

* #2038 Refactor internals DbReadContext use BeanPropertyAssocMany
2020-08-24 18:40:36 +12:00
rob bygrave c8d352b0a8 Add a better error message for #2038 NPE at BeanDescriptor.java:1965 2020-08-05 16:44:45 +12:00
rob bygrave 3796f2b267 No effective change - organise imports on tests 2020-08-05 16:39:10 +12:00
peterko2017andGitHub 4ef5abceca Add STI Discrimination on Reference Associations (#2041)
* Update SqlTreeNodeBean#appendFromBaseTable to add
discriminator values to the join
* Update tests to reflect new generated SQL
2020-08-05 16:33:34 +12:00
rob bygrave 4eda4201de Javadoc only change for RawSql 2020-07-30 16:22:09 +12:00
rob bygrave 933aa30149 Javadoc only change - replace at sign and fix javadoc 2020-07-27 16:41:30 +12:00
rob bygrave 0c80b3078a #2037 - Refactor simplify TransactionCallback to lambda
- Move to use generic try catch exception
- Convert to lambda method calls
2020-07-24 13:19:56 +12:00
rob bygrave 7317847aa7 #2037 - Allow PostCommit transaction callback to recursively add another PostCommit callback 2020-07-24 13:16:18 +12:00
rob bygrave 444644f759 #2037 - Allow PostCommit transaction callback to recursively add another PostCommit callback 2020-07-24 13:16:00 +12:00
rob bygrave f704da641d No effective change - Modify test only adding extra asserts for #2036 2020-07-24 11:54:15 +12:00
rob bygrave a1d2f4c1af [maven-release-plugin] prepare for next development iteration 2020-07-14 12:52:50 +12:00
rob bygrave b7469da5b1 [maven-release-plugin] prepare release ebean-12.3.7 2020-07-14 12:52:39 +12:00
rob bygrave 2897968a54 Bump maven plugin - no effective change 2020-07-14 12:50:47 +12:00
rob bygrave 6360fad701 Refactor tidy NoopCallOriginFactory 2020-07-14 11:11:14 +12:00
rob bygrave dbc97aa28c Remove the duplicate TestSoftDeleteBasic.testFindSoftDeletedList()
Hmmm, my bad. I merged the branch manually and that didn't remove the PR so I've merged this twice now and hence ended up with a duplicate method. All good, just removing this duplicate method.
2020-07-14 09:47:07 +12:00
SnōwballandGitHub a231c136a9 Add failing test case for softdeletes (#2034)
Example:
One X can have many Ys. Ys can be soft deleted.

Y1 -> X1 -> Y1

Y1 is soft deleted

When Y1 is loaded, lazy-loading X1 and then lazy-loading the list of Ys associated with X1,
the list should contain Y1. This test asserts that is true.
2020-07-14 09:43:54 +12:00
rob bygrave c6487e56cf Merge branch 'tobias--soft_deletes_not_included' 2020-07-14 09:33:26 +12:00
rob bygrave dac0a97a3f #2035 - lazy-loading soft-deleted list from lazy-loaded bean doesn't remember includeSoftDeletes 2020-07-14 09:32:52 +12:00
rob bygrave ff0274f72c Merge branch 'soft_deletes_not_included' of https://github.com/tobias-/ebean into tobias--soft_deletes_not_included 2020-07-13 18:02:04 +12:00
rob bygrave ddee202bcc No effective change - tidy SqlTreeNodeBean 2020-07-10 10:52:22 +12:00
rob bygrave e1522a4a68 No effective change - tidy test TestSoftDeleteBasic 2020-07-10 10:48:28 +12:00
rob bygrave 7bc6170587 #2032 - Objects that occur in query is not filtered by @SoftDelete (when query has predicates on a ToMany path the associated soft delete predicates are not included) 2020-07-10 10:00:52 +12:00
rob bygrave 0322c19261 Merge branch 'tobias--softdeleted_where' 2020-07-10 09:57:45 +12:00
Tobias 18ae0a7833 Add failing test case for softdeletes
Example:
One X can have many Ys. Ys can be soft deleted.

Y1 -> X1 -> Y1

Y1 is soft deleted

When Y1 is loaded, lazy-loading X1 and then lazy-loading the list of Ys associated with X1,
the list should contain Y1. This test asserts that is true.
2020-07-09 20:56:33 +02:00
Tobias e99db44ddf Add test for soft deleted children
When a child is referenced in the query, Ebean should make sure
that the child (or any of the objects connecting it in the query)
is deleted.

Ie. if a query requires a child to have a certain value, it should
filter out those children that are soft deleted. It should also perform
the deleted check on all objects leading up to that child.

E.g. assuming that all objects are soft deletable, the following where():

DB.find(Alpha.class).where()
.eq("alpha.beta.gamma.name", "bar")

should generate a query with
"t0.deleted = false AND t1.deleted = false AND t2.deleted = false AND t2.name = 'bar'"
2020-07-07 12:33:43 +02:00
rob bygrave 361de9ea99 Update error thrown to use DatabaseConfig rather than ServerConfig 2020-07-06 14:37:56 +12:00
rob bygrave 99732b30b1 No effective change - tidy test TestHstore 2020-07-01 15:38:58 +12:00
rob bygrave dd5e5819b8 No effective change - Javadoc for ServerConfig 2020-06-30 23:07:27 +12:00
rob bygrave b4330679b8 #2029 Opps, fix tests 2020-06-30 10:59:03 +12:00
rob bygrave 59447ad261 #2029 - ENH: Add database.getPlatform(); ... to obtain the underlying database platform being used 2020-06-29 21:56:18 +12:00
rob bygrave 3bd20a424a [maven-release-plugin] prepare for next development iteration 2020-06-29 18:07:38 +12:00
rob bygrave 4ac3a8d1ad [maven-release-plugin] prepare release ebean-12.3.6 2020-06-29 18:07:27 +12:00
rob bygrave 5a8f8b3a83 #2027 - querybean generator support for @EbeanComponent 2020-06-29 18:01:28 +12:00
rob bygrave 7c01cec466 [maven-release-plugin] prepare for next development iteration 2020-06-29 17:21:19 +12:00
rob bygrave 30ad4260f0 [maven-release-plugin] prepare release ebean-12.3.5 2020-06-29 17:21:08 +12:00
rob bygrave ab421d6f2b No effective change - trim whitespace in BaseTableDdl 2020-06-29 17:15:35 +12:00
rob bygrave 0b807addc7 No effective change - test tidy 2020-06-29 17:09:02 +12:00
rob bygrave bb03ef5693 No effective change - test tidy 2020-06-29 15:51:34 +12:00
rob bygrave 248a7b1062 #2004 - MariaDB DDL review 2020-06-29 15:50:08 +12:00
rob bygrave 9da28262b4 #2004 - MariaDB History useLegacyDatetimeCode=false required to properly handle server timezone 2020-06-29 14:51:24 +12:00
rob bygrave fc8dd18fd1 #2004 - MariaDB History DDL using add/drop system versioning 2020-06-29 14:03:21 +12:00
rob bygrave 70ba658442 #2026 - Postgres DDL - modify type generates wrong alter sql. Needs explicit cast / using clause. 2020-06-29 12:12:10 +12:00
rob bygrave 70b730657f #2028 - Refactor internals of smart persistence context to reference "parent" rather than copy beans (adjustment of #2021) 2020-06-29 08:48:24 +12:00
rob bygrave bf3cb7e2e2 No effective change - tidy test BeanDescriptor_registerTest 2020-06-26 15:49:35 +12:00
rob bygrave c2708ecc76 No effective change - Refactor tidy BeanDescriptor internals - trimQueryPlans() etc 2020-06-23 22:14:11 +12:00
rob bygrave 896aba3053 No effective change - trim whitespace 2020-06-23 22:03:21 +12:00
rob bygrave f78b602a90 No effective change - trim whitespace 2020-06-23 21:08:30 +12:00
rob bygrave 306c1b5cf6 No effective change - EntityBeanIntercept tidy javadoc 2020-06-23 20:57:31 +12:00
rob bygrave cdf2718ca9 No effective change - refactor EntityBeanIntercept reverse internal notEqual() method 2020-06-23 20:43:08 +12:00
rob bygrave 967ca0c9f3 No effective change - add some more tests for EntityBeanIntercept 2020-06-23 17:09:15 +12:00
rob bygrave 607acb1b4e No effective change - tidy DefaultPersistenceContext 2020-06-23 16:35:53 +12:00
rob bygrave 5f923945e9 No effective change - trim whitespace 2020-06-23 16:35:36 +12:00
rob bygrave 11fbe8bf5b [maven-release-plugin] prepare for next development iteration 2020-06-19 23:23:32 +12:00
124 changed files with 9391 additions and 1980 deletions
+14 -14
View File
@@ -4,12 +4,12 @@
<parent>
<groupId>org.avaje</groupId>
<artifactId>java8-oss</artifactId>
<version>2.1</version>
<version>2.2</version>
</parent>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.3.4</version>
<version>12.3.9</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -22,7 +22,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-12.3.4</tag>
<tag>ebean-12.3.9</tag>
</scm>
<profiles>
@@ -63,8 +63,8 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>config</artifactId>
<version>1.2</version>
<artifactId>avaje-config</artifactId>
<version>1.0</version>
</dependency>
<!--
@@ -87,7 +87,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>6.12</version>
<version>6.13</version>
</dependency>
<dependency>
@@ -126,14 +126,14 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- provided scope to read validation annotations Size etc -->
@@ -141,21 +141,21 @@
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.7</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Provided scope to compile with java 11 -->
@@ -170,7 +170,7 @@
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Provided scope for Postgres JSON/JSONB support -->
@@ -178,7 +178,7 @@
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.10</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Test scope -->
@@ -299,7 +299,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.3.4</version>
<version>12.3.7</version>
<executions>
<execution>
<id>test</id>
+1 -1
View File
@@ -14,7 +14,7 @@ import java.util.Optional;
*
* public class CustomerFinder extends BeanFinder<Long,Customer> {
*
* @Inject
* Inject
* public CustomerFinder(Database database) {
* super(Customer.class, database);
* }
+2 -2
View File
@@ -9,10 +9,10 @@ import java.util.Collection;
* <p>
* <pre>{@code
*
* @Repository
* Repository
* public class CustomerRepository extends BeanRepository<Long,Customer> {
*
* @Inject
* Inject
* public CustomerRepository(Database server) {
* super(Customer.class, server);
* }
+5 -20
View File
@@ -60,7 +60,9 @@ import java.util.concurrent.Callable;
*
* }</pre>
*/
public class DB {
public final class DB {
private static final DbContext context = DbContext.getInstance();
/**
* Hide constructor.
@@ -72,7 +74,7 @@ public class DB {
* Return the default database.
*/
public static Database getDefault() {
return Ebean.getDefaultServer();
return context.getDefault();
}
/**
@@ -81,26 +83,9 @@ public class DB {
* @param name The name of the database
*/
public static Database byName(String name) {
return Ebean.getServer(name);
return context.get(name);
}
// /**
// * Register the server with this Ebean singleton. Specify if the registered
// * server is the primary/default database.
// */
// public static void register(EbeanServer server, boolean defaultServer) {
// serverMgr.register(server, defaultServer);
// }
//
// /**
// * Backdoor for registering a mock implementation of EbeanServer as the default database.
// */
// protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
// EbeanServer originalPrimaryServer = serverMgr.defaultServer;
// serverMgr.registerWithName(name, server, defaultServer);
// return originalPrimaryServer;
// }
/**
* Return the ScriptRunner for the default database.
* <p>
+21 -1
View File
@@ -1,5 +1,6 @@
package io.ebean;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.DatabaseConfig;
@@ -132,6 +133,25 @@ public interface Database {
*/
MetaInfoManager getMetaInfoManager();
/**
* Return the platform used for this database instance.
* <p>
* Note many platforms have multiple specific platform types so often we want to
* get the base platform via {@link Platform#base()}.
* </p>
* <pre>{@code
*
* Platform platform = database.getPlatform().base();
* if (platform == Platform.MYSQL) {
* // do MySql specific function
* }
*
* }</pre>
*
* @return platform for this database instance
*/
Platform getPlatform();
/**
* Return the extended API intended for use by plugins.
*/
@@ -861,7 +881,7 @@ public interface Database {
* <pre>{@code
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* List<OrderDetail> details;
* ...
* }
+140
View File
@@ -0,0 +1,140 @@
package io.ebean;
import io.ebean.config.BeanNotEnhancedException;
import io.ebean.datasource.DataSourceConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
/**
* Holds Database instances.
*/
final class DbContext {
private static final Logger logger = LoggerFactory.getLogger(DbContext.class);
static {
EbeanVersion.getVersion();
}
private static final DbContext INSTANCE = new DbContext();
/**
* Cache for fast concurrent read access.
*/
private final ConcurrentHashMap<String, Database> concMap = new ConcurrentHashMap<>();
/**
* Cache for synchronized read, creation and put. Protected by the monitor object.
*/
private final HashMap<String, Database> syncMap = new HashMap<>();
private final Object monitor = new Object();
/**
* The 'default' Database.
*/
private Database defaultDatabase;
private DbContext() {
try {
if (!DbPrimary.isSkip()) {
// look to see if there is a default server defined
String defaultName = DbPrimary.getDefaultServerName();
logger.debug("defaultName:{}", defaultName);
if (defaultName != null && !defaultName.trim().isEmpty()) {
defaultDatabase = getWithCreate(defaultName.trim());
}
}
} catch (BeanNotEnhancedException e) {
throw e;
} catch (DataSourceConfigurationException e) {
String msg = "Configuration error creating DataSource for the default Database." +
" This typically means a missing application-test.yaml or missing ebean-test dependency." +
" See https://ebean.io/docs/trouble-shooting#datasource";
throw new DataSourceConfigurationException(msg, e);
} catch (Throwable e) {
logger.error("Error trying to create the default Database", e);
throw new RuntimeException(e);
}
}
/**
* Return the shared singleton instance.
*/
static DbContext getInstance() {
return INSTANCE;
}
/**
* Return the default database.
*/
Database getDefault() {
if (defaultDatabase == null) {
String msg = "The default Database has not been defined?";
msg += " This is normally set via the ebean.datasource.default property.";
msg += " Otherwise it should be registered programmatically via registerServer()";
throw new PersistenceException(msg);
}
return defaultDatabase;
}
/**
* Return the database by name.
*/
Database get(String name) {
if (name == null || name.isEmpty()) {
return defaultDatabase;
}
// non-synchronized read
Database server = concMap.get(name);
if (server != null) {
return server;
}
// synchronized read, create and put
return getWithCreate(name);
}
/**
* Synchronized read, create and put of Databases.
*/
private Database getWithCreate(String name) {
synchronized (monitor) {
Database server = syncMap.get(name);
if (server == null) {
// register when creating server this way
server = EbeanServerFactory.create(name);
register(server, false);
}
return server;
}
}
/**
* Register a server so we can get it by its name.
*/
void register(Database server, boolean isDefault) {
registerWithName(server.getName(), server, isDefault);
}
private void registerWithName(String name, Database server, boolean isDefault) {
synchronized (monitor) {
concMap.put(name, server);
syncMap.put(name, server);
if (isDefault) {
defaultDatabase = server;
}
}
}
Database mock(String name, Database server, boolean defaultServer) {
Database originalPrimaryServer = this.defaultDatabase;
registerWithName(name, server, defaultServer);
return originalPrimaryServer;
}
}
@@ -9,7 +9,7 @@ import java.util.Properties;
* <p/>
* Intended for internal use as part of bootup, construction, registration of the default database.
*/
class PrimaryServer {
class DbPrimary {
private static String defaultServerName;
@@ -19,7 +19,7 @@ class PrimaryServer {
* Set whether to skip automatically creating the primary database.
*/
static synchronized void setSkip(boolean skip) {
PrimaryServer.skip = skip;
DbPrimary.skip = skip;
}
/**
+1 -1
View File
@@ -149,7 +149,7 @@ public interface DocumentStore {
* .setUseDocStore(true)
* .where()... // perhaps add predicates
* .findEachWhile(new Predicate<Order>() {
* @Override
* Override
* public void accept(Order bean) {
* // process the bean
*
+84 -219
View File
@@ -2,26 +2,19 @@ package io.ebean;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.BeanNotEnhancedException;
import io.ebean.config.ServerConfig;
import io.ebean.datasource.DataSourceConfigurationException;
import io.ebean.plugin.Property;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
/**
* Deprecated - please migrate to use <code>io.ebean.DB</code>.
@@ -34,123 +27,8 @@ import java.util.concurrent.ConcurrentHashMap;
*/
@Deprecated
public final class Ebean {
private static final Logger logger = LoggerFactory.getLogger(Ebean.class);
static {
EbeanVersion.getVersion(); // initialises the version class and logs the version.
}
/**
* Manages creation and cache of Databases.
*/
private static final Ebean.ServerManager serverMgr = new Ebean.ServerManager();
/**
* Helper class for managing fast and safe access and creation of Databases.
*/
private static final class ServerManager {
/**
* Cache for fast concurrent read access.
*/
private final ConcurrentHashMap<String, EbeanServer> concMap = new ConcurrentHashMap<>();
/**
* Cache for synchronized read, creation and put. Protected by the monitor object.
*/
private final HashMap<String, EbeanServer> syncMap = new HashMap<>();
private final Object monitor = new Object();
/**
* The 'default' Database.
*/
private EbeanServer defaultServer;
private ServerManager() {
try {
if (!PrimaryServer.isSkip()) {
// look to see if there is a default server defined
String defaultName = PrimaryServer.getDefaultServerName();
logger.debug("defaultName:{}", defaultName);
if (defaultName != null && !defaultName.trim().isEmpty()) {
defaultServer = getWithCreate(defaultName.trim());
}
}
} catch (BeanNotEnhancedException e) {
throw e;
} catch (DataSourceConfigurationException e) {
String msg = "Configuration error creating DataSource for the default Database." +
" This typically means a missing application-test.yaml or missing ebean-test dependency." +
" See https://ebean.io/docs/trouble-shooting#datasource";
throw new DataSourceConfigurationException(msg, e);
} catch (Throwable e) {
logger.error("Error trying to create the default Database", e);
throw new RuntimeException(e);
}
}
private EbeanServer getDefaultServer() {
if (defaultServer == null) {
String msg = "The default Database has not been defined?";
msg += " This is normally set via the ebean.datasource.default property.";
msg += " Otherwise it should be registered programmatically via registerServer()";
throw new PersistenceException(msg);
}
return defaultServer;
}
private EbeanServer get(String name) {
if (name == null || name.isEmpty()) {
return defaultServer;
}
// non-synchronized read
EbeanServer server = concMap.get(name);
if (server != null) {
return server;
}
// synchronized read, create and put
return getWithCreate(name);
}
/**
* Synchronized read, create and put of Databases.
*/
private EbeanServer getWithCreate(String name) {
synchronized (monitor) {
EbeanServer server = syncMap.get(name);
if (server == null) {
// register when creating server this way
server = EbeanServerFactory.create(name);
register(server, false);
}
return server;
}
}
/**
* Register a server so we can get it by its name.
*/
private void register(EbeanServer server, boolean isDefaultServer) {
registerWithName(server.getName(), server, isDefaultServer);
}
private void registerWithName(String name, EbeanServer server, boolean isDefaultServer) {
synchronized (monitor) {
concMap.put(name, server);
syncMap.put(name, server);
if (isDefaultServer) {
defaultServer = server;
}
}
}
}
private static final DbContext context = DbContext.getInstance();
private Ebean() {
}
@@ -174,7 +52,7 @@ public final class Ebean {
* @param name the name of the server, can use null for the 'default server'
*/
public static EbeanServer getServer(String name) {
return serverMgr.get(name);
return (EbeanServer)context.get(name);
}
/**
@@ -184,7 +62,27 @@ public final class Ebean {
* </p>
*/
public static EbeanServer getDefaultServer() {
return serverMgr.getDefaultServer();
return (EbeanServer)context.getDefault();
}
/**
* Register the server with this Ebean singleton. Specify if the registered
* server is the primary/default database.
*/
@Deprecated
public static void register(EbeanServer server, boolean defaultServer) {
context.register(server, defaultServer);
}
/**
* Backdoor for registering a mock implementation of EbeanServer as the default database.
*/
protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
return (EbeanServer)context.mock(name, server, defaultServer);
}
private static Database getDefault() {
return context.getDefault();
}
/**
@@ -205,24 +103,7 @@ public final class Ebean {
* </p>
*/
public static ExpressionFactory getExpressionFactory() {
return serverMgr.getDefaultServer().getExpressionFactory();
}
/**
* Register the server with this Ebean singleton. Specify if the registered
* server is the primary/default database.
*/
public static void register(EbeanServer server, boolean defaultServer) {
serverMgr.register(server, defaultServer);
}
/**
* Backdoor for registering a mock implementation of EbeanServer as the default database.
*/
protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
EbeanServer originalPrimaryServer = serverMgr.defaultServer;
serverMgr.registerWithName(name, server, defaultServer);
return originalPrimaryServer;
return getDefault().getExpressionFactory();
}
/**
@@ -238,7 +119,7 @@ public final class Ebean {
* </p>
*/
public static Object nextId(Class<?> beanType) {
return serverMgr.getDefaultServer().nextId(beanType);
return getDefault().nextId(beanType);
}
/**
@@ -284,7 +165,7 @@ public final class Ebean {
* </p>
*/
public static Transaction beginTransaction() {
return serverMgr.getDefaultServer().beginTransaction();
return getDefault().beginTransaction();
}
/**
@@ -293,7 +174,7 @@ public final class Ebean {
* @param isolation the Transaction isolation level
*/
public static Transaction beginTransaction(TxIsolation isolation) {
return serverMgr.getDefaultServer().beginTransaction(isolation);
return getDefault().beginTransaction(isolation);
}
/**
@@ -346,7 +227,7 @@ public final class Ebean {
* }</pre>
*/
public static Transaction beginTransaction(TxScope scope) {
return serverMgr.getDefaultServer().beginTransaction(scope);
return getDefault().beginTransaction(scope);
}
/**
@@ -354,7 +235,7 @@ public final class Ebean {
* in scope.
*/
public static Transaction currentTransaction() {
return serverMgr.getDefaultServer().currentTransaction();
return getDefault().currentTransaction();
}
/**
@@ -384,21 +265,21 @@ public final class Ebean {
* @throws PersistenceException if there is no currently active transaction
*/
public static void register(TransactionCallback transactionCallback) throws PersistenceException {
serverMgr.getDefaultServer().register(transactionCallback);
getDefault().register(transactionCallback);
}
/**
* Commit the current transaction.
*/
public static void commitTransaction() {
serverMgr.getDefaultServer().commitTransaction();
getDefault().commitTransaction();
}
/**
* Rollback the current transaction.
*/
public static void rollbackTransaction() {
serverMgr.getDefaultServer().rollbackTransaction();
getDefault().rollbackTransaction();
}
/**
@@ -426,14 +307,14 @@ public final class Ebean {
* }</pre>
*/
public static void endTransaction() {
serverMgr.getDefaultServer().endTransaction();
getDefault().endTransaction();
}
/**
* Mark the current transaction as rollback only.
*/
public static void setRollbackOnly() {
serverMgr.getDefaultServer().currentTransaction().setRollbackOnly();
getDefault().currentTransaction().setRollbackOnly();
}
/**
@@ -444,7 +325,7 @@ public final class Ebean {
* </p>
*/
public static Map<String, ValuePair> diff(Object a, Object b) {
return serverMgr.getDefaultServer().diff(a, b);
return getDefault().diff(a, b);
}
/**
@@ -465,7 +346,7 @@ public final class Ebean {
* <pre>{@code
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* List<OrderDetail> details;
* ...
* }
@@ -478,7 +359,7 @@ public final class Ebean {
* </p>
*/
public static void save(Object bean) throws OptimisticLockException {
serverMgr.getDefaultServer().save(bean);
getDefault().save(bean);
}
/**
@@ -486,14 +367,14 @@ public final class Ebean {
* want to explicitly insert it.
*/
public static void insert(Object bean) {
serverMgr.getDefaultServer().insert(bean);
getDefault().insert(bean);
}
/**
* Insert a collection of beans.
*/
public static void insertAll(Collection<?> beans) {
serverMgr.getDefaultServer().insertAll(beans);
getDefault().insertAll(beans);
}
/**
@@ -516,7 +397,7 @@ public final class Ebean {
* }</pre>
*/
public static void markAsDirty(Object bean) throws OptimisticLockException {
serverMgr.getDefaultServer().markAsDirty(bean);
getDefault().markAsDirty(bean);
}
/**
@@ -531,16 +412,6 @@ public final class Ebean {
* <b>Optimistic Locking: </b> Note that if the version property is not set when update() is
* called then no optimistic locking is performed (internally ConcurrencyMode.NONE is used).
* </p>
* <p>
* <b>{@link ServerConfig#setUpdatesDeleteMissingChildren(boolean)}: </b> When cascade saving to a
* OneToMany or ManyToMany the updatesDeleteMissingChildren setting controls if any other children
* that are in the database but are not in the collection are deleted.
* </p>
* <p>
* <b>{@link ServerConfig#setUpdateChangesOnly(boolean)}: </b> The updateChangesOnly setting
* controls if only the changed properties are included in the update or if all the loaded
* properties are included instead.
* </p>
* <pre>{@code
*
* // A 'stateless update' example
@@ -553,14 +424,14 @@ public final class Ebean {
* }</pre>
*/
public static void update(Object bean) throws OptimisticLockException {
serverMgr.getDefaultServer().update(bean);
getDefault().update(bean);
}
/**
* Update the beans in the collection.
*/
public static void updateAll(Collection<?> beans) throws OptimisticLockException {
serverMgr.getDefaultServer().updateAll(beans);
getDefault().updateAll(beans);
}
/**
@@ -569,7 +440,7 @@ public final class Ebean {
* @param bean The bean to merge
*/
public static void merge(Object bean) {
serverMgr.getDefaultServer().merge(bean);
getDefault().merge(bean);
}
/**
@@ -579,14 +450,14 @@ public final class Ebean {
* @param options The options to control the merge
*/
public static void merge(Object bean, MergeOptions options) {
serverMgr.getDefaultServer().merge(bean, options);
getDefault().merge(bean, options);
}
/**
* Save all the beans from a Collection.
*/
public static int saveAll(Collection<?> beans) throws OptimisticLockException {
return serverMgr.getDefaultServer().saveAll(beans);
return getDefault().saveAll(beans);
}
/**
@@ -637,7 +508,7 @@ public final class Ebean {
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean) {
return serverMgr.getDefaultServer().checkUniqueness(bean);
return getDefault().checkUniqueness(bean);
}
/**
@@ -645,7 +516,7 @@ public final class Ebean {
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean, Transaction transaction) {
return serverMgr.getDefaultServer().checkUniqueness(bean, transaction);
return getDefault().checkUniqueness(bean, transaction);
}
/**
@@ -668,56 +539,56 @@ public final class Ebean {
* </p>
*/
public static boolean delete(Object bean) throws OptimisticLockException {
return serverMgr.getDefaultServer().delete(bean);
return getDefault().delete(bean);
}
/**
* Delete the bean in permanent fashion (will not use soft delete).
*/
public static boolean deletePermanent(Object bean) throws OptimisticLockException {
return serverMgr.getDefaultServer().deletePermanent(bean);
return getDefault().deletePermanent(bean);
}
/**
* Delete the bean given its type and id.
*/
public static int delete(Class<?> beanType, Object id) {
return serverMgr.getDefaultServer().delete(beanType, id);
return getDefault().delete(beanType, id);
}
/**
* Delete permanent the bean given its type and id.
*/
public static int deletePermanent(Class<?> beanType, Object id) {
return serverMgr.getDefaultServer().deletePermanent(beanType, id);
return getDefault().deletePermanent(beanType, id);
}
/**
* Delete several beans given their type and id values.
*/
public static int deleteAll(Class<?> beanType, Collection<?> ids) {
return serverMgr.getDefaultServer().deleteAll(beanType, ids);
return getDefault().deleteAll(beanType, ids);
}
/**
* Delete permanent several beans given their type and id values.
*/
public static int deleteAllPermanent(Class<?> beanType, Collection<?> ids) {
return serverMgr.getDefaultServer().deleteAllPermanent(beanType, ids);
return getDefault().deleteAllPermanent(beanType, ids);
}
/**
* Delete all the beans in the Collection.
*/
public static int deleteAll(Collection<?> beans) throws OptimisticLockException {
return serverMgr.getDefaultServer().deleteAll(beans);
return getDefault().deleteAll(beans);
}
/**
* Delete permanent all the beans in the Collection (will not use soft delete).
*/
public static int deleteAllPermanent(Collection<?> beans) throws OptimisticLockException {
return serverMgr.getDefaultServer().deleteAllPermanent(beans);
return getDefault().deleteAllPermanent(beans);
}
/**
@@ -728,7 +599,7 @@ public final class Ebean {
* </p>
*/
public static void refresh(Object bean) {
serverMgr.getDefaultServer().refresh(bean);
getDefault().refresh(bean);
}
/**
@@ -746,7 +617,7 @@ public final class Ebean {
* @param manyPropertyName the property name of the List Set or Map to refresh.
*/
public static void refreshMany(Object bean, String manyPropertyName) {
serverMgr.getDefaultServer().refreshMany(bean, manyPropertyName);
getDefault().refreshMany(bean, manyPropertyName);
}
/**
@@ -771,7 +642,7 @@ public final class Ebean {
* @param id the id value
*/
public static <T> T getReference(Class<T> beanType, Object id) {
return serverMgr.getDefaultServer().getReference(beanType, id);
return getDefault().getReference(beanType, id);
}
/**
@@ -814,7 +685,7 @@ public final class Ebean {
* @param sortByClause the properties to sort the list by
*/
public static <T> void sort(List<T> list, String sortByClause) {
serverMgr.getDefaultServer().sort(list, sortByClause);
getDefault().sort(list, sortByClause);
}
/**
@@ -864,7 +735,7 @@ public final class Ebean {
*/
@Nullable
public static <T> T find(Class<T> beanType, Object id) {
return serverMgr.getDefaultServer().find(beanType, id);
return getDefault().find(beanType, id);
}
/**
@@ -879,7 +750,7 @@ public final class Ebean {
*/
@Deprecated
public static SqlQuery createSqlQuery(String sql) {
return serverMgr.getDefaultServer().sqlQuery(sql);
return getDefault().sqlQuery(sql);
}
/**
@@ -894,7 +765,7 @@ public final class Ebean {
*/
@Deprecated
public static SqlUpdate createSqlUpdate(String sql) {
return serverMgr.getDefaultServer().sqlUpdate(sql);
return getDefault().sqlUpdate(sql);
}
/**
@@ -903,7 +774,7 @@ public final class Ebean {
* @see CallableSql
*/
public static CallableSql createCallableSql(String sql) {
return serverMgr.getDefaultServer().createCallableSql(sql);
return getDefault().createCallableSql(sql);
}
/**
@@ -935,16 +806,14 @@ public final class Ebean {
* }</pre>
*/
public static <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate) {
return serverMgr.getDefaultServer().createUpdate(beanType, ormUpdate);
return getDefault().createUpdate(beanType, ormUpdate);
}
/**
* Create a CsvReader for a given beanType.
*/
public static <T> CsvReader<T> createCsvReader(Class<T> beanType) {
return serverMgr.getDefaultServer().createCsvReader(beanType);
return getDefault().createCsvReader(beanType);
}
/**
@@ -959,7 +828,7 @@ public final class Ebean {
* @return The query
*/
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
return getDefault().createNamedQuery(beanType, namedQuery);
}
/**
@@ -982,8 +851,7 @@ public final class Ebean {
* @return A ORM Query object for this beanType
*/
public static <T> Query<T> createQuery(Class<T> beanType) {
return serverMgr.getDefaultServer().createQuery(beanType);
return getDefault().createQuery(beanType);
}
/**
@@ -1020,8 +888,7 @@ public final class Ebean {
* @return The query with expressions defined as per the parsed query statement
*/
public static <T> Query<T> createQuery(Class<T> beanType, String eql) {
return serverMgr.getDefaultServer().createQuery(beanType, eql);
return getDefault().createQuery(beanType, eql);
}
/**
@@ -1036,8 +903,7 @@ public final class Ebean {
* @return A ORM Query object for this beanType
*/
public static <T> Query<T> find(Class<T> beanType) {
return serverMgr.getDefaultServer().find(beanType);
return getDefault().find(beanType);
}
/**
@@ -1060,7 +926,7 @@ public final class Ebean {
* @return The query to set parameters and execute
*/
public static <T> Query<T> findNative(Class<T> beanType, String nativeSql) {
return serverMgr.getDefaultServer().findNative(beanType, nativeSql);
return getDefault().findNative(beanType, nativeSql);
}
/**
@@ -1075,7 +941,7 @@ public final class Ebean {
* @param <T> The type of the DTO bean.
*/
public static <T> DtoQuery<T> findDto(Class<T> dtoType, String sql) {
return serverMgr.getDefaultServer().findDto(dtoType, sql);
return getDefault().findDto(dtoType, sql);
}
/**
@@ -1097,7 +963,7 @@ public final class Ebean {
* @return The update query to use
*/
public static <T> UpdateQuery<T> update(Class<T> beanType) {
return serverMgr.getDefaultServer().update(beanType);
return getDefault().update(beanType);
}
/**
@@ -1111,7 +977,7 @@ public final class Ebean {
* </p>
*/
public static <T> Filter<T> filter(Class<T> beanType) {
return serverMgr.getDefaultServer().filter(beanType);
return getDefault().filter(beanType);
}
/**
@@ -1154,7 +1020,7 @@ public final class Ebean {
* @see Ebean#execute(CallableSql)
*/
public static int execute(SqlUpdate sqlUpdate) {
return serverMgr.getDefaultServer().execute(sqlUpdate);
return getDefault().execute(sqlUpdate);
}
/**
@@ -1182,7 +1048,7 @@ public final class Ebean {
* @see Ebean#execute(SqlUpdate)
*/
public static int execute(CallableSql callableSql) {
return serverMgr.getDefaultServer().execute(callableSql);
return getDefault().execute(callableSql);
}
/**
@@ -1206,7 +1072,7 @@ public final class Ebean {
* }</pre>
*/
public static void execute(TxScope scope, Runnable r) {
serverMgr.getDefaultServer().execute(scope, r);
getDefault().execute(scope, r);
}
/**
@@ -1233,7 +1099,7 @@ public final class Ebean {
* }</pre>
*/
public static void execute(Runnable r) {
serverMgr.getDefaultServer().execute(r);
getDefault().execute(r);
}
/**
@@ -1258,7 +1124,7 @@ public final class Ebean {
* }</pre>
*/
public static <T> T executeCall(TxScope scope, Callable<T> c) {
return serverMgr.getDefaultServer().executeCall(scope, c);
return getDefault().executeCall(scope, c);
}
/**
@@ -1291,7 +1157,7 @@ public final class Ebean {
* }</pre>
*/
public static <T> T executeCall(Callable<T> c) {
return serverMgr.getDefaultServer().executeCall(c);
return getDefault().executeCall(c);
}
/**
@@ -1325,8 +1191,7 @@ public final class Ebean {
* @param deletes true if rows on the table where deleted
*/
public static void externalModification(String tableName, boolean inserts, boolean updates, boolean deletes) {
serverMgr.getDefaultServer().externalModification(tableName, inserts, updates, deletes);
getDefault().externalModification(tableName, inserts, updates, deletes);
}
/**
@@ -1336,14 +1201,14 @@ public final class Ebean {
* </p>
*/
public static BeanState getBeanState(Object bean) {
return serverMgr.getDefaultServer().getBeanState(bean);
return getDefault().getBeanState(bean);
}
/**
* Return the manager of the server cache ("L2" cache).
*/
public static ServerCacheManager getServerCacheManager() {
return serverMgr.getDefaultServer().getServerCacheManager();
return getDefault().getServerCacheManager();
}
/**
@@ -1351,14 +1216,14 @@ public final class Ebean {
* queries.
*/
public static BackgroundExecutor getBackgroundExecutor() {
return serverMgr.getDefaultServer().getBackgroundExecutor();
return getDefault().getBackgroundExecutor();
}
/**
* Return the JsonContext for reading/writing JSON.
*/
public static JsonContext json() {
return serverMgr.getDefaultServer().json();
return getDefault().json();
}
}
@@ -73,7 +73,7 @@ public class EbeanServerFactory {
EbeanServer server = createInternal(config);
if (config.isRegister()) {
PrimaryServer.setSkip(true);
DbPrimary.setSkip(true);
Ebean.register(server, config.isDefaultServer());
}
@@ -126,7 +126,7 @@ public class EbeanServerFactory {
if (containerConfig == null) {
// effectively load configuration from ebean.properties
Properties properties = PrimaryServer.getProperties();
Properties properties = DbPrimary.getProperties();
containerConfig = new ContainerConfig();
containerConfig.loadFromProperties(properties);
}
+8 -4
View File
@@ -6,18 +6,18 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* Class to determine the ebean version. (
* @author Roland Praml, FOCONIS AG
* Class to determine the ebean version.
*
* @author Roland Praml, FOCONIS AG
*/
public class EbeanVersion {
private EbeanVersion() {
}
private static final Logger logger = LoggerFactory.getLogger(EbeanVersion.class);
private static String version = "unknown";
static {
try {
Properties prop = new Properties();
@@ -34,6 +34,10 @@ public class EbeanVersion {
}
}
private EbeanVersion() {
// hide
}
/**
* Returns the ebean version (read from /META-INF/maven/io.ebean/ebean/pom.properties)
*/
+1 -1
View File
@@ -53,7 +53,7 @@ public class Expr {
}
/**
* In Range - property >= value1 and property < value2.
* In Range - {@code property >= value1 and property < value2}.
* <p>
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
* </p>
@@ -155,7 +155,7 @@ public interface ExpressionFactory {
Expression ineObject(String propertyName, Object value);
/**
* In Range - property >= value1 and property < value2.
* In Range - {@code property >= value1 and property < value2}.
* <p>
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
* </p>
+2 -4
View File
@@ -859,7 +859,7 @@ public interface ExpressionList<T> {
ExpressionList<T> inRangeWith(String lowProperty, String highProperty, Object value);
/**
* In Range - property >= value1 and property < value2.
* In Range - {@code property >= value1 and property < value2}.
* <p>
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
* </p>
@@ -1254,12 +1254,10 @@ public interface ExpressionList<T> {
* The raw expression should contain a single ? or ?1
* at the location of the parameter. We use ?1 when binding a
* collection for an IN expression.
* </p>
* <p>>
* <p>
* When properties in the clause are fully qualified as table-column names
* then they are not translated. logical property name names (not fully
* qualified) will still be translated to their physical name.
* </p>
* <p>
* <h4>Examples:</h4>
* <pre>{@code
+4 -2
View File
@@ -37,12 +37,13 @@ import java.util.List;
* }
* }
*
* @Entity
* Entity
* public class Customer extends BaseModel {
*
* public static final CustomerFinder find = new CustomerFinder();
* ...
*
* }
* }</pre>
* <p>
* When the Finder is registered as a field on Customer it can then be used like:
@@ -79,12 +80,13 @@ public class Finder<I, T> {
* // ... add extra customer specific finder methods
* }
*
* @Entity
* Entity
* public class Customer extends BaseModel {
*
* public static final CustomerFinder find = new CustomerFinder();
* ...
*
* }
* }</pre>
*/
public Finder(Class<T> type) {
+9 -9
View File
@@ -32,19 +32,19 @@ import io.ebean.bean.EntityBean;
* // Typically there is a common base model that has some
* // common properties like the ones below
*
* @MappedSuperclass
* public class BaseModel extends Model {
* MappedSuperclass
* public class BaseModel extends Model {
*
* @Id Long id;
* Id Long id;
*
* @Version Long version;
* Version Long version;
*
* @WhenCreated Timestamp whenCreated;
* WhenCreated Timestamp whenCreated;
*
* @WhenUpdated Timestamp whenUpdated;
*
* ...
* WhenUpdated Timestamp whenUpdated;
*
* ...
* }
* }</pre>
* <p>
* <h3>Extend the Model</h3>
@@ -52,7 +52,7 @@ import io.ebean.bean.EntityBean;
*
* // Extend the mappedSuperclass
*
* @Entity @Table(name="o_account")
* Entity Table(name="o_account")
* public class Customer extends BaseModel {
*
* String name;
+1 -3
View File
@@ -1,7 +1,5 @@
package io.ebean;
import io.ebean.util.StringHelper;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@@ -341,7 +339,7 @@ public final class OrderBy<T> implements Serializable {
if (collation != null) {
if (collation.contains("${}")) {
// this is a complex collation, e.g. DB2 - we must replace the property
sb.append(StringHelper.replaceString(collation, "${}", property));
sb.append(collation.replace("${}", property));
} else {
sb.append(property);
sb.append(" collate ").append(collation);
+2 -2
View File
@@ -94,8 +94,8 @@ public interface PagedList<T> {
* Return the Future row count. You might get this if you wish to cancel the total row count query
* or specify a timeout for the row count query.
* <p>
* The loadRowCount() & getTotalRowCount() methods internally make use of this getFutureRowCount() method.
* Generally I expect people to prefer loadRowCount() & getTotalRowCount() over getFutureRowCount().
* The loadRowCount() and getTotalRowCount() methods internally make use of this getFutureRowCount() method.
* Generally I expect people to prefer loadRowCount() and getTotalRowCount() over getFutureRowCount().
* </p>
* <pre>{@code
*
+1 -1
View File
@@ -18,7 +18,7 @@ import java.util.List;
*
* // where a bean is annotated with a complex
* // natural key made of several properties
* @Cache(naturalKey = {"store","code","sku"})
* Cache(naturalKey = {"store","code","sku"})
*
*
* Pairs pairs = new Pairs("sku", "code");
+29 -42
View File
@@ -6,17 +6,13 @@ package io.ebean;
* <p>
* If you don't want to build object graphs you can use {@link SqlQuery} instead
* which returns {@link SqlRow} objects rather than entity beans.
* </p>
* <p>
* <b>Unparsed RawSql:</b>
* </p>
* <p>
* When RawSql is created via {@link RawSqlBuilder#unparsed(String)} then Ebean can not
* modify the SQL at all. It can't add any extra expressions into the SQL.
* </p>
* <p>
* <b>Parsed RawSql:</b>
* </p>
* <p>
* When RawSql is created via {@link RawSqlBuilder#parse(String)} then Ebean will parse the
* SQL and find places in the SQL where it can add extra where expressions, add
@@ -24,16 +20,13 @@ package io.ebean;
* explicitly tell Ebean where these insertion points are you can place special
* strings into your SQL ({@code ${where}} or {@code ${andWhere}} and {@code ${having}} or
* {@code ${andHaving})}.
* </p>
* <p>
* If the SQL already includes a WHERE clause put in {@code ${andWhere}} in the location
* you want Ebean to add any extra where expressions. If the SQL doesn't have a
* WHERE clause put {@code ${where}} in instead. Similarly you can put in {@code ${having}} or
* {@code ${andHaving}} where you want Ebean put add extra having expressions.
* </p>
* <p>
* <b>Aggregates:</b>
* </p>
* <p>
* Often RawSql will be used with Aggregate functions (sum, avg, max etc). The
* follow example shows an example based on Total Order Amount -
@@ -44,38 +37,37 @@ package io.ebean;
* on RawSql and not based on a real DB Table or DB View. It has some properties
* to hold the values for the aggregate functions (sum etc) and a &#064;OneToOne
* to Order.
* </p>
* <p>
* <h3>Example OrderAggregate</h3>
* <pre>{@code
* ...
* // @Sql indicates to that this bean
* // is based on RawSql rather than a table
* // Sql indicates to that this bean
* // is based on RawSql rather than a table
*
* @Entity
* @Sql
* public class OrderAggregate {
* Entity
* Sql
* public class OrderAggregate {
*
* @OneToOne
* Order order;
* OneToOne
* Order order;
*
* Double totalAmount;
* Double totalAmount;
*
* Double totalItems;
*
* // getters and setters
* ...
* Double totalItems;
*
* // getters and setters
* ...
* }
* }</pre>
* <p>
*
* <h3>Example 1:</h3>
* <p>
*
* <pre>{@code
*
* String sql = " select order_id, o.status, c.id, c.name, sum(d.order_qty*d.unit_price) as totalAmount"
* + " from o_order o"
* + " join o_customer c on c.id = o.kcustomer_id "
* + " join o_order_detail d on d.order_id = o.id " + " group by order_id, o.status ";
* String sql = " select order_id, o.status, c.id, c.name, sum(l.order_qty*l.unit_price) as totalAmount"
* + " from order o"
* + " join customer c on c.id = o.customer_id "
* + " join order_line l on l.order_id = o.id " + " group by order_id, o.status ";
*
* RawSql rawSql = RawSqlBuilder.parse(sql)
* // map the sql result columns to bean properties
@@ -95,18 +87,17 @@ package io.ebean;
*
*
* }</pre>
* <p>
*
* <h3>Example 2:</h3>
* <p>
* The following example uses a FetchConfig().query() so that after the initial
* RawSql query is executed Ebean executes a secondary query to fetch the
* associated order status, orderDate along with the customer name.
* </p>
* <p>
*
* <pre>{@code
*
* String sql = " select order_id, 'ignoreMe', sum(d.order_qty*d.unit_price) as totalAmount "
* + " from o_order_detail d"
* String sql = " select order_id, 'ignoreMe', sum(l.order_qty*l.unit_price) as totalAmount "
* + " from order_line l"
* + " group by order_id ";
*
* RawSql rawSql = RawSqlBuilder.parse(sql)
@@ -125,25 +116,23 @@ package io.ebean;
* .findList();
*
* }</pre>
* <p>
* <h3>Example 3: tableAliasMapping</h3>
* <p>
* Instead of mapping each column you can map each table alias to a path using tableAliasMapping().
* </p>
* <pre>{@code
*
* String rs = "select o.id, o.status, c.id, c.name, "+
* " d.id, d.order_qty, p.id, p.name " +
* "from o_order o join o_customer c on c.id = o.kcustomer_id " +
* "join o_order_detail d on d.order_id = o.id " +
* "join o_product p on p.id = d.product_id " +
* " l.id, l.order_qty, p.id, p.name " +
* "from orders o join o_customer c on c.id = o.customer_id " +
* "join order_line l on l.order_id = o.id " +
* "join product p on p.id = l.product_id " +
* "where o.id <= :maxOrderId and p.id = :productId "+
* "order by o.id, d.id asc";
* "order by o.id, l.id asc";
*
* RawSql rawSql = RawSqlBuilder.parse(rs)
* .tableAliasMapping("c", "customer")
* .tableAliasMapping("d", "details")
* .tableAliasMapping("p", "details.product")
* .tableAliasMapping("l", "lines")
* .tableAliasMapping("p", "lines.product")
* .create();
*
* List<Order> ordersFromRaw = DB.find(Order.class)
@@ -154,9 +143,7 @@ package io.ebean;
*
* }</pre>
* <p>
* <p>
* Note that lazy loading also works with object graphs built with RawSql.
* </p>
*/
public interface RawSql {
+1 -1
View File
@@ -22,7 +22,7 @@ import java.sql.SQLException;
* //
* class CustomerMapper implements RowMapper<CustomerDto> {
*
* @Override
* Override
* public CustomerDto map(ResultSet rset, int rowNum) throws SQLException {
*
* long id = rset.getLong(1);
+21 -20
View File
@@ -12,26 +12,27 @@ package io.ebean;
* The following is an example of named updates on an entity bean.
* </p>
* <pre>{@code
* ...
* @NamedUpdates(value = {
* @NamedUpdate(
* name = "setTitle",
* notifyCache = false,
* update = "update topic set title = :title, postCount = :count where id = :id"),
* @NamedUpdate(
* name = "setPostCount",
* notifyCache = false,
* update = "update f_topic set post_count = :postCount where id = :id"),
* @NamedUpdate(
* name = "incrementPostCount",
* notifyCache = false,
* update = "update Topic set postCount = postCount + 1 where id = :id")
* //update = "update f_topic set post_count = post_count + 1 where id = :id")
* })
* @Entity
* @Table(name = "f_topic")
* public class Topic {
* ...
* ...
* NamedUpdates(value = {
* NamedUpdate(
* name = "setTitle",
* notifyCache = false,
* update = "update topic set title = :title, postCount = :count where id = :id"),
* NamedUpdate(
* name = "setPostCount",
* notifyCache = false,
* update = "update f_topic set post_count = :postCount where id = :id"),
* NamedUpdate(
* name = "incrementPostCount",
* notifyCache = false,
* update = "update Topic set postCount = postCount + 1 where id = :id")
* //update = "update f_topic set post_count = post_count + 1 where id = :id")
* })
* Entity
* Table(name = "f_topic")
* public class Topic {
* ...
* }
* }</pre>
*
* <p>
@@ -82,14 +82,14 @@ public final class EntityBeanIntercept implements Serializable {
private static final byte FLAG_CHANGED_PROP = 2;
/**
* Flags indicating if a property is a dirty embedded bean. Used to distingush
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
* between an embedded bean being completely overwritten and one of its
* embedded properties being made dirty.
*/
private static final byte FLAG_EMBEDDED_DIRTY = 4;
/**
* Flags indicating if a property is a dirty embedded bean. Used to distingush
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
* between an embedded bean being completely overwritten and one of its
* embedded properties being made dirty.
*/
@@ -371,13 +371,11 @@ public final class EntityBeanIntercept implements Serializable {
/**
* Set the loaded state to true.
* <p>
* Calls to setter methods after the bean is loaded can result in 'Old Values'
* being created to support ConcurrencyMode.ALL
* </p>
* Calls to setter methods after the bean is loaded can result in
* 'Old Values' being created.
* <p>
* Worth noting that this is also set after a insert/update. By doing so it
* 'resets' the bean for making further changes and saving again.
* </p>
*/
public void setLoaded() {
this.state = STATE_LOADED;
@@ -391,8 +389,7 @@ public final class EntityBeanIntercept implements Serializable {
}
/**
* When finished loading for lazy or refresh on an already partially populated
* bean.
* When finished loading for lazy or refresh on an already partially populated bean.
*/
public void setLoadedLazy() {
this.state = STATE_LOADED;
@@ -423,9 +420,6 @@ public final class EntityBeanIntercept implements Serializable {
/**
* Set true to turn off lazy loading.
* <p>
* Typically used to disable lazy loading on SQL based report beans.
* </p>
*/
public void setDisableLazyLoad(boolean disableLazyLoad) {
this.disableLazyLoad = disableLazyLoad;
@@ -445,7 +439,6 @@ public final class EntityBeanIntercept implements Serializable {
* Return true if the embedded bean is new or dirty and hence needs saving.
*/
public boolean isEmbeddedNewOrDirty(Object embeddedBean) {
if (embeddedBean == null) {
// if it was previously set then the owning bean would
// have oldValues containing the previous embedded bean
@@ -453,7 +446,6 @@ public final class EntityBeanIntercept implements Serializable {
}
if (embeddedBean instanceof EntityBean) {
return ((EntityBean) embeddedBean)._ebean_getIntercept().isNewOrDirty();
} else {
// non-enhanced so must assume it is new and needs to be saved
return true;
@@ -471,8 +463,8 @@ public final class EntityBeanIntercept implements Serializable {
}
/**
* Finds the index position of a given property. Returns -1 if the property
* can not be found.
* Finds the index position of a given property. Returns -1 if the
* property can not be found.
*/
public int findProperty(String propertyName) {
String[] names = owner._ebean_getPropertyNames();
@@ -495,7 +487,7 @@ public final class EntityBeanIntercept implements Serializable {
}
/**
* Return the number of properties.s
* Return the number of properties.
*/
public int getPropertyLength() {
return owner._ebean_getPropertyNames().length;
@@ -517,8 +509,7 @@ public final class EntityBeanIntercept implements Serializable {
}
/**
* Set the property to be treated as unloaded. Used for properties initialised in default
* constructor.
* Set the property to be treated as unloaded. Used for properties initialised in default constructor.
*/
public void setPropertyUnloaded(int propertyIndex) {
flags[propertyIndex] &= ~FLAG_LOADED_PROP;
@@ -605,7 +596,6 @@ public final class EntityBeanIntercept implements Serializable {
* For forced update on a 'New' bean set all the loaded properties to changed.
*/
public void setNewBeanForUpdate() {
for (int i = 0; i < flags.length; i++) {
if ((flags[i] & FLAG_LOADED_PROP) != 0) {
flags[i] |= FLAG_CHANGED_PROP;
@@ -660,8 +650,7 @@ public final class EntityBeanIntercept implements Serializable {
for (int i = 0; i < len; i++) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
// the property has been changed on this bean
String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i));
props.add(propName);
props.add((prefix == null ? getProperty(i) : prefix + getProperty(i)));
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
// an embedded property has been changed - recurse
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
@@ -674,12 +663,10 @@ public final class EntityBeanIntercept implements Serializable {
* Return true if any of the given property names are dirty.
*/
public boolean hasDirtyProperty(Set<String> propertyNames) {
String[] names = owner._ebean_getPropertyNames();
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
// the property has been changed on this bean
if (propertyNames.contains(names[i])) {
return true;
}
@@ -712,10 +699,9 @@ public final class EntityBeanIntercept implements Serializable {
String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i));
Object newVal = owner._ebean_getField(i);
Object oldVal = getOrigValue(i);
if (!areEqual(oldVal, newVal)) {
if (notEqual(oldVal, newVal)) {
dirtyValues.put(propName, new ValuePair(newVal, oldVal));
}
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
// an embedded property has been changed - recurse
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
@@ -734,10 +720,9 @@ public final class EntityBeanIntercept implements Serializable {
// the property has been changed on this bean
Object newVal = owner._ebean_getField(i);
Object oldVal = getOrigValue(i);
if (!areEqual(oldVal, newVal)) {
if (notEqual(oldVal, newVal)) {
visitor.visit(i, newVal, oldVal);
}
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
// an embedded property has been changed - recurse
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
@@ -758,7 +743,7 @@ public final class EntityBeanIntercept implements Serializable {
}
/**
* Add and return a dirty property hash recursing into embedded beans.
* Add and return a dirty property hash.
*/
private void addDirtyPropertyKey(StringBuilder sb) {
if (sortOrder > 0) {
@@ -818,21 +803,18 @@ public final class EntityBeanIntercept implements Serializable {
* Load the bean when it is a reference.
*/
protected void loadBean(int loadProperty) {
synchronized (this) {
if (beanLoader == null) {
final Database database = DB.byName(ebeanServerName);
if (database == null) {
throw new PersistenceException("Database [" + ebeanServerName + "] was not found?");
}
// For stand alone reference bean or after deserialisation lazy load
// using the ebeanServer. Synchronise only on the bean.
loadBeanInternal(loadProperty, database.getPluginApi());
return;
}
}
synchronized (beanLoader) {
// Lazy loading using LoadBeanContext which supports batch loading
// Synchronise on the beanLoader (a 'node' of the LoadBeanContext 'tree')
@@ -844,32 +826,24 @@ public final class EntityBeanIntercept implements Serializable {
* Invoke the lazy loading. This method is synchronised externally.
*/
private void loadBeanInternal(int loadProperty, BeanLoader loader) {
if ((flags[loadProperty] & FLAG_LOADED_PROP) != 0) {
// race condition where multiple threads calling preGetter concurrently
return;
}
if (lazyLoadFailure) {
// failed when batch lazy loaded by another bean in the batch
throw new EntityNotFoundException("(Lazy) loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted");
}
if (lazyLoadProperty == -1) {
lazyLoadProperty = loadProperty;
if (nodeUsageCollector != null) {
nodeUsageCollector.setLoadProperty(getProperty(lazyLoadProperty));
}
loader.loadBean(this);
if (lazyLoadFailure) {
// failed when lazy loading this bean
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted.");
}
// bean should be loaded and intercepting now. setLoaded() has
// been called by the lazy loading mechanism
}
@@ -879,32 +853,31 @@ public final class EntityBeanIntercept implements Serializable {
* Helper method to check if two objects are equal.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
protected boolean areEqual(Object obj1, Object obj2) {
protected static boolean notEqual(Object obj1, Object obj2) {
if (obj1 == null) {
return (obj2 == null);
return (obj2 != null);
}
if (obj2 == null) {
return false;
return true;
}
if (obj1 == obj2) {
return true;
return false;
}
if (obj1 instanceof BigDecimal) {
// Use comparable for BigDecimal as equals
// uses scale in comparison...
if (obj2 instanceof BigDecimal) {
Comparable com1 = (Comparable) obj1;
return (com1.compareTo(obj2) == 0);
return (com1.compareTo(obj2) != 0);
} else {
return false;
return true;
}
}
if (obj1 instanceof URL) {
// use the string format to determine if dirty
return obj1.toString().equals(obj2.toString());
return !obj1.toString().equals(obj2.toString());
}
return obj1.equals(obj2);
return !obj1.equals(obj2);
}
/**
@@ -945,25 +918,20 @@ public final class EntityBeanIntercept implements Serializable {
}
/**
* OneToMany and ManyToMany don't have any interception so just check for
* PropertyChangeSupport.
* OneToMany and ManyToMany only set loaded state.
*/
public void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
if (readOnly) {
throw new IllegalStateException("This bean is readOnly");
}
setLoadedProperty(propertyIndex);
}
private void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) {
if (readOnly) {
throw new IllegalStateException("This bean is readOnly");
}
setChangedProperty(propertyIndex);
if (setDirtyState) {
setOriginalValue(propertyIndex, origValue);
setDirtyStatus();
@@ -988,10 +956,9 @@ public final class EntityBeanIntercept implements Serializable {
* the old values for use with ConcurrencyMode.ALL.
*/
public void preSetter(boolean intercept, int propertyIndex, Object oldValue, Object newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (!areEqual(oldValue, newValue)) {
} else if (notEqual(oldValue, newValue)) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
}
}
@@ -1001,7 +968,6 @@ public final class EntityBeanIntercept implements Serializable {
* Check for primitive boolean.
*/
public void preSetter(boolean intercept, int propertyIndex, boolean oldValue, boolean newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
@@ -1013,7 +979,6 @@ public final class EntityBeanIntercept implements Serializable {
* Check for primitive int.
*/
public void preSetter(boolean intercept, int propertyIndex, int oldValue, int newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
@@ -1025,7 +990,6 @@ public final class EntityBeanIntercept implements Serializable {
* long.
*/
public void preSetter(boolean intercept, int propertyIndex, long oldValue, long newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
@@ -1037,7 +1001,6 @@ public final class EntityBeanIntercept implements Serializable {
* double.
*/
public void preSetter(boolean intercept, int propertyIndex, double oldValue, double newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (Double.compare(oldValue, newValue) != 0) {
@@ -1049,7 +1012,6 @@ public final class EntityBeanIntercept implements Serializable {
* float.
*/
public void preSetter(boolean intercept, int propertyIndex, float oldValue, float newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (Float.compare(oldValue, newValue) != 0) {
@@ -1061,7 +1023,6 @@ public final class EntityBeanIntercept implements Serializable {
* short.
*/
public void preSetter(boolean intercept, int propertyIndex, short oldValue, short newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
@@ -1073,7 +1034,6 @@ public final class EntityBeanIntercept implements Serializable {
* char.
*/
public void preSetter(boolean intercept, int propertyIndex, char oldValue, char newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
@@ -1085,7 +1045,6 @@ public final class EntityBeanIntercept implements Serializable {
* byte.
*/
public void preSetter(boolean intercept, int propertyIndex, byte oldValue, byte newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
@@ -1097,7 +1056,6 @@ public final class EntityBeanIntercept implements Serializable {
* char[].
*/
public void preSetter(boolean intercept, int propertyIndex, char[] oldValue, char[] newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (!Arrays.equals(oldValue, newValue)) {
@@ -1109,7 +1067,6 @@ public final class EntityBeanIntercept implements Serializable {
* byte[].
*/
public void preSetter(boolean intercept, int propertyIndex, byte[] oldValue, byte[] newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (!Arrays.equals(oldValue, newValue)) {
@@ -3,8 +3,6 @@ package io.ebean.config;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.util.AnnotationUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Inheritance;
import javax.persistence.Table;
@@ -16,10 +14,6 @@ import javax.persistence.Table;
*/
public abstract class AbstractNamingConvention implements NamingConvention {
private static final Pattern TABLE_REPLACE = Pattern.compile("{table}", Pattern.LITERAL);
private static final Pattern COLUMN_REPLACE = Pattern.compile("{column}", Pattern.LITERAL);
/**
* The Constant DEFAULT_SEQ_FORMAT.
*/
@@ -85,13 +79,9 @@ public abstract class AbstractNamingConvention implements NamingConvention {
@Override
public String getSequenceName(String rawTableName, String pkColumn) {
final String tableNameUnquoted = databasePlatform.unQuote(rawTableName);
String s = TABLE_REPLACE.matcher(sequenceFormat).replaceAll(Matcher.quoteReplacement(tableNameUnquoted));
if (pkColumn == null) {
pkColumn = "";
} else {
pkColumn = databasePlatform.unQuote(pkColumn);
}
return COLUMN_REPLACE.matcher(s).replaceAll(Matcher.quoteReplacement(pkColumn));
String seqName = sequenceFormat.replace("{table}", tableNameUnquoted);
pkColumn = (pkColumn == null) ? "" : databasePlatform.unQuote(pkColumn);
return seqName.replace("{column}", pkColumn);
}
/**
@@ -13,6 +13,8 @@ import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Properties;
import static io.ebean.util.StringHelper.replace;
/**
* Configuration for the DB migration processing.
*/
@@ -375,8 +377,8 @@ public class DbMigrationConfig {
*/
public String getDdlHeader() {
if (ddlHeader != null && !ddlHeader.isEmpty()) {
ddlHeader = StringHelper.replaceString(ddlHeader, "${version}", EbeanVersion.getVersion());
ddlHeader = StringHelper.replaceString(ddlHeader, "${timestamp}", ZonedDateTime.now().format( DateTimeFormatter.ISO_INSTANT ));
ddlHeader = replace(ddlHeader, "${version}", EbeanVersion.getVersion());
ddlHeader = replace(ddlHeader, "${timestamp}", ZonedDateTime.now().format( DateTimeFormatter.ISO_INSTANT ));
}
return ddlHeader;
}
@@ -94,7 +94,7 @@ public class ServerConfig {
* Typically configuration type objects that are passed by this ServerConfig
* to plugins. For example - IgniteConfiguration passed to Ignite plugin.
*/
private Map<String, Object> serviceObject = new HashMap<>();
private final Map<String, Object> serviceObject = new HashMap<>();
private ContainerConfig containerConfig;
@@ -188,7 +188,7 @@ public class ServerConfig {
private JsonConfig.Date jsonDate = JsonConfig.Date.ISO8601;
/**
* For writing JSON specify if null values or empty collections should be exluded.
* For writing JSON specify if null values or empty collections should be excluded.
* By default all values are included.
*/
private JsonConfig.Include jsonInclude = JsonConfig.Include.ALL;
@@ -528,7 +528,6 @@ public class ServerConfig {
* Construct a Database Configuration for programmatically creating an Database.
*/
public ServerConfig() {
}
/**
@@ -593,7 +592,6 @@ public class ServerConfig {
* Put a service object into configuration such that it can be passed to a plugin.
* <p>
* For example, put IgniteConfiguration in to be passed to the Ignite plugin.
* </p>
*/
public void putServiceObject(String key, Object configObject) {
serviceObject.put(key, configObject);
@@ -704,8 +702,7 @@ public class ServerConfig {
/**
* Set the JSON include mode used when writing JSON.
* <p>
* Set to NON_NULL or NON_EMPTY to suppress nulls or null & empty collections respectively.
* </p>
* Set to NON_NULL or NON_EMPTY to suppress nulls or null and empty collections respectively.
*/
public void setJsonInclude(JsonConfig.Include jsonInclude) {
this.jsonInclude = jsonInclude;
@@ -750,7 +747,6 @@ public class ServerConfig {
* when it is created.
* <p>
* By default this is set to true.
* </p>
*/
public boolean isRegister() {
return register;
@@ -761,7 +757,6 @@ public class ServerConfig {
* singleton when it is created.
* <p>
* By default this is set to true.
* </p>
*/
public void setRegister(boolean register) {
this.register = register;
@@ -772,7 +767,6 @@ public class ServerConfig {
* with the Ebean singleton.
* <p>
* This is only used when {@link #setRegister(boolean)} is also true.
* </p>
*/
public boolean isDefaultServer() {
return defaultServer;
@@ -783,7 +777,6 @@ public class ServerConfig {
* with the DB singleton.
* <p>
* This is only used when {@link #setRegister(boolean)} is also true.
* </p>
*/
public void setDefaultServer(boolean defaultServer) {
this.defaultServer = defaultServer;
@@ -895,7 +888,6 @@ public class ServerConfig {
* When INSERT or ALL is used then save(), delete() etc do not execute immediately but instead go into
* a JDBC batch execute buffer that is flushed. The buffer is flushed if a query is executed, transaction ends
* or the batch size is meet.
* </p>
*/
public PersistBatch getPersistBatch() {
return persistBatch;
@@ -907,7 +899,6 @@ public class ServerConfig {
* When INSERT or ALL is used then save(), delete() etc do not execute immediately but instead go into
* a JDBC batch execute buffer that is flushed. The buffer is flushed if a query is executed, transaction ends
* or the batch size is meet.
* </p>
*/
public void setPersistBatch(PersistBatch persistBatch) {
this.persistBatch = persistBatch;
@@ -918,10 +909,8 @@ public class ServerConfig {
* <p>
* This makes sense when a save() or delete() cascades and executes multiple child statements. The best case
* for this is when saving a master/parent bean this cascade inserts many detail/child beans.
* </p>
* <p>
* This only takes effect when the persistBatch mode at the transaction level does not take effect.
* </p>
*/
public PersistBatch getPersistBatchOnCascade() {
return persistBatchOnCascade;
@@ -932,10 +921,8 @@ public class ServerConfig {
* <p>
* This makes sense when a save() or delete() etc cascades and executes multiple child statements. The best caase
* for this is when saving a master/parent bean this cascade inserts many detail/child beans.
* </p>
* <p>
* This only takes effect when the persistBatch mode at the transaction level does not take effect.
* </p>
*/
public void setPersistBatchOnCascade(PersistBatch persistBatchOnCascade) {
this.persistBatchOnCascade = persistBatchOnCascade;
@@ -944,17 +931,13 @@ public class ServerConfig {
/**
* Deprecated, please migrate to using setPersistBatch().
* <p>
* Set to true if you what to use JDBC batching for persisting and deleting
* beans.
* </p>
* Set to true if you what to use JDBC batching for persisting and deleting beans.
* <p>
* With this Ebean will batch up persist requests and use the JDBC batch api.
* This is a performance optimisation designed to reduce the network chatter.
* </p>
* <p>
* When true this is equivalent to {@code setPersistBatch(PersistBatch.ALL)} or
* when false to {@code setPersistBatch(PersistBatch.NONE)}
* </p>
*/
public void setPersistBatching(boolean persistBatching) {
this.persistBatch = (persistBatching) ? PersistBatch.ALL : PersistBatch.NONE;
@@ -971,7 +954,6 @@ public class ServerConfig {
* Set the batch size used for JDBC batching. If unset this defaults to 20.
* <p>
* You can also set the batch size on the transaction.
* </p>
*
* @see Transaction#setBatchSize(int)
*/
@@ -1033,14 +1015,11 @@ public class ServerConfig {
* <p>
* This is the number of beans or collections loaded when lazy loading is
* invoked by default.
* </p>
* <p>
* The default value is for this is 10 (load 10 beans or collections).
* </p>
* <p>
* You can explicitly control the lazy loading batch size for a given join on
* a query using +lazy(batchSize) or JoinConfig.
* </p>
*/
public void setLazyLoadBatchSize(int lazyLoadBatchSize) {
this.lazyLoadBatchSize = lazyLoadBatchSize;
@@ -1052,7 +1031,7 @@ public class ServerConfig {
* This is a performance optimisation to reduce the number times Ebean
* requests a sequence to be used as an Id for a bean (aka reduce network
* chatter).
* </p>
*/
public void setDatabaseSequenceBatchSize(int databaseSequenceBatchSize) {
platformConfig.setDatabaseSequenceBatchSize(databaseSequenceBatchSize);
@@ -1091,7 +1070,6 @@ public class ServerConfig {
* <p>
* This is used to set user context information to the ChangeSet in the
* foreground thread prior to the logging occurring in a background thread.
* </p>
*/
public ChangeLogPrepare getChangeLogPrepare() {
return changeLogPrepare;
@@ -1102,7 +1080,6 @@ public class ServerConfig {
* <p>
* This is used to set user context information to the ChangeSet in the
* foreground thread prior to the logging occurring in a background thread.
* </p>
*/
public void setChangeLogPrepare(ChangeLogPrepare changeLogPrepare) {
this.changeLogPrepare = changeLogPrepare;
@@ -1199,7 +1176,6 @@ public class ServerConfig {
* It is expected that an implementation is used that read user context information
* (user id, user ip address etc) and sets it on the ReadEvent bean before it is sent
* to the ReadAuditLogger.
* </p>
*/
public void setReadAuditPrepare(ReadAuditPrepare readAuditPrepare) {
this.readAuditPrepare = readAuditPrepare;
@@ -1270,7 +1246,6 @@ public class ServerConfig {
* Return the time zone to use when reading/writing Timestamps via JDBC.
* <p>
* When set a Calendar object is used in JDBC calls when reading/writing Timestamp objects.
* </p>
*/
public String getDataTimeZone() {
return System.getProperty("ebean.dataTimeZone", dataTimeZone);
@@ -1533,7 +1508,6 @@ public class ServerConfig {
* Return the NamingConvention.
* <p>
* If none has been set the default UnderscoreNamingConvention is used.
* </p>
*/
public NamingConvention getNamingConvention() {
return namingConvention;
@@ -1543,7 +1517,6 @@ public class ServerConfig {
* Set the NamingConvention.
* <p>
* If none is set the default UnderscoreNamingConvention is used.
* </p>
*/
public void setNamingConvention(NamingConvention namingConvention) {
this.namingConvention = namingConvention;
@@ -1655,11 +1628,9 @@ public class ServerConfig {
* <p>
* Note that the DataSource is expected to use AutoCommit true mode avoiding the need
* for explicit commit (or rollback).
* </p>
* <p>
* This read only DataSource will be used for implicit query only transactions. It is not
* used if the transaction is created explicitly or if the query is an update or delete query.
* </p>
*/
public void setReadOnlyDataSource(DataSource readOnlyDataSource) {
this.readOnlyDataSource = readOnlyDataSource;
@@ -1699,12 +1670,10 @@ public class ServerConfig {
* Return the configuration for the read only DataSource.
* <p>
* This is only used if autoReadOnlyDataSource is true.
* </p>
* <p>
* The driver, url, username and password default to the configuration for the main DataSource if they are not
* set on this configuration. This means there is actually no need to set any configuration here and we only
* set configuration for url, username and password etc if it is different from the main DataSource.
* </p>
*/
public DataSourceConfig getReadOnlyDataSourceConfig() {
return readOnlyDataSourceConfig;
@@ -1730,7 +1699,6 @@ public class ServerConfig {
* By default a prefix of "java:comp/env/jdbc/" is used to lookup the
* DataSource. This prefix is not used if dataSourceJndiName starts with
* "java:".
* </p>
*/
public void setDataSourceJndiName(String dataSourceJndiName) {
this.dataSourceJndiName = dataSourceJndiName;
@@ -1740,10 +1708,8 @@ public class ServerConfig {
* Return a value used to represent TRUE in the database.
* <p>
* This is used for databases that do not support boolean natively.
* </p>
* <p>
* The value returned is either a Integer or a String (e.g. "1", or "T").
* </p>
*/
public String getDatabaseBooleanTrue() {
return platformConfig.getDatabaseBooleanTrue();
@@ -1753,10 +1719,8 @@ public class ServerConfig {
* Set the value to represent TRUE in the database.
* <p>
* This is used for databases that do not support boolean natively.
* </p>
* <p>
* The value set is either a Integer or a String (e.g. "1", or "T").
* </p>
*/
public void setDatabaseBooleanTrue(String databaseTrue) {
platformConfig.setDatabaseBooleanTrue(databaseTrue);
@@ -1766,10 +1730,8 @@ public class ServerConfig {
* Return a value used to represent FALSE in the database.
* <p>
* This is used for databases that do not support boolean natively.
* </p>
* <p>
* The value returned is either a Integer or a String (e.g. "0", or "F").
* </p>
*/
public String getDatabaseBooleanFalse() {
return platformConfig.getDatabaseBooleanFalse();
@@ -1779,10 +1741,8 @@ public class ServerConfig {
* Set the value to represent FALSE in the database.
* <p>
* This is used for databases that do not support boolean natively.
* </p>
* <p>
* The value set is either a Integer or a String (e.g. "0", or "F").
* </p>
*/
public void setDatabaseBooleanFalse(String databaseFalse) {
this.platformConfig.setDatabaseBooleanFalse(databaseFalse);
@@ -1802,13 +1762,11 @@ public class ServerConfig {
* This is only used for DB's that use sequences and is a performance
* optimisation. This reduces the number of times Ebean needs to get a
* sequence value from the Database reducing network chatter.
* </p>
* <p>
* By default this value is 10 so when we need another Id (and don't have one
* in our cache) Ebean will fetch 10 id's from the database. Note that when
* the cache drops to have full (which is 5 by default) Ebean will fetch
* another batch of Id's in a background thread.
* </p>
*/
public void setDatabaseSequenceBatch(int databaseSequenceBatchSize) {
this.platformConfig.setDatabaseSequenceBatchSize(databaseSequenceBatchSize);
@@ -1819,7 +1777,6 @@ public class ServerConfig {
* <p>
* If null then the platform is determined automatically via the JDBC driver
* information.
* </p>
*/
public String getDatabasePlatformName() {
return databasePlatformName;
@@ -1830,16 +1787,13 @@ public class ServerConfig {
* <p>
* If none is set then the platform is determined automatically via the JDBC
* driver information.
* </p>
* <p>
* This can be used when the Database Platform can not be automatically
* detected from the JDBC driver (possibly 3rd party JDBC driver). It is also
* useful when you want to do offline DDL generation for a database platform
* that you don't have access to.
* </p>
* <p>
* Values are oracle, h2, postgres, mysql, sqlserver16, sqlserver17.
* </p>
*/
public void setDatabasePlatformName(String databasePlatformName) {
this.databasePlatformName = databasePlatformName;
@@ -1857,7 +1811,6 @@ public class ServerConfig {
* <p>
* If none is set then the platform is determined via the databasePlatformName
* or automatically via the JDBC driver information.
* </p>
*/
public void setDatabasePlatform(DatabasePlatform databasePlatform) {
this.databasePlatform = databasePlatform;
@@ -1888,10 +1841,8 @@ public class ServerConfig {
* Set the EncryptKeyManager.
* <p>
* This is required when you want to use encrypted properties.
* </p>
* <p>
* You can also set this in ebean.proprerties:
* </p>
* <p>
* <pre>{@code
* # set via ebean.properties
@@ -1907,7 +1858,6 @@ public class ServerConfig {
* <p>
* This is optionally used to programmatically define which columns are
* encrypted instead of using the {@link Encrypted} Annotation.
* </p>
*/
public EncryptDeployManager getEncryptDeployManager() {
return encryptDeployManager;
@@ -1918,7 +1868,6 @@ public class ServerConfig {
* <p>
* This is optionally used to programmatically define which columns are
* encrypted instead of using the {@link Encrypted} Annotation.
* </p>
*/
public void setEncryptDeployManager(EncryptDeployManager encryptDeployManager) {
this.encryptDeployManager = encryptDeployManager;
@@ -1938,7 +1887,6 @@ public class ServerConfig {
* <p>
* Ebean has a default implementation that it will use if you do not set your
* own Encryptor implementation.
* </p>
*/
public void setEncryptor(Encryptor encryptor) {
this.encryptor = encryptor;
@@ -1956,7 +1904,6 @@ public class ServerConfig {
* <p>
* Typically used to create an Database instance for DDL Migration generation
* without requiring a real DataSource / Database to connect to.
* </p>
*/
public void setDbOffline(boolean dbOffline) {
this.dbOffline = dbOffline;
@@ -1967,7 +1914,6 @@ public class ServerConfig {
* <p>
* Note that if this is not set then the DbPlatform may already have a
* DbEncrypt set and that will be used.
* </p>
*/
public DbEncrypt getDbEncrypt() {
return dbEncrypt;
@@ -1978,7 +1924,6 @@ public class ServerConfig {
* <p>
* Note that if this is not set then the DbPlatform may already have a
* DbEncrypt set (H2, MySql, Postgres and Oracle platforms have a DbEncrypt)
* </p>
*/
public void setDbEncrypt(DbEncrypt dbEncrypt) {
this.dbEncrypt = dbEncrypt;
@@ -2053,7 +1998,6 @@ public class ServerConfig {
* Set to true if LocalTime should be persisted with nanos precision.
* <p>
* Otherwise it is persisted using java.sql.Time which is seconds precision.
* </p>
*/
public void setLocalTimeWithNanos(boolean localTimeWithNanos) {
this.localTimeWithNanos = localTimeWithNanos;
@@ -2063,7 +2007,6 @@ public class ServerConfig {
* Return true if Duration should be persisted with nanos precision (SQL DECIMAL).
* <p>
* Otherwise it is persisted with second precision (SQL INTEGER).
* </p>
*/
public boolean isDurationWithNanos() {
return durationWithNanos;
@@ -2073,7 +2016,6 @@ public class ServerConfig {
* Set to true if Duration should be persisted with nanos precision (SQL DECIMAL).
* <p>
* Otherwise it is persisted with second precision (SQL INTEGER).
* </p>
*/
public void setDurationWithNanos(boolean durationWithNanos) {
this.durationWithNanos = durationWithNanos;
@@ -2144,7 +2086,6 @@ public class ServerConfig {
* <p>
* Typically this is a sql script that inserts test seed data when running tests.
* Place a sql script in src/test/resources that inserts test seed data.
* </p>
*/
public String getDdlSeedSql() {
return ddlSeedSql;
@@ -2155,7 +2096,6 @@ public class ServerConfig {
* <p>
* Typically this is a sql script that inserts test seed data when running tests.
* Place a sql script in src/test/resources that inserts test seed data.
* </p>
*/
public void setDdlSeedSql(String ddlSeedSql) {
this.ddlSeedSql = ddlSeedSql;
@@ -2232,14 +2172,11 @@ public class ServerConfig {
* <p>
* The class can be an Entity, Embedded type, ScalarType, BeanPersistListener,
* BeanFinder or BeanPersistController.
* </p>
* <p>
* If no classes are specified then the classes are found automatically via
* searching the class path.
* </p>
* <p>
* Alternatively the classes can be added via {@link #setClasses(List)}.
* </p>
*
* @param cls the entity type (or other type) that should be registered by this
* database.
@@ -2261,7 +2198,6 @@ public class ServerConfig {
* Add a package to search for entities via class path search.
* <p>
* This is only used if classes have not been explicitly specified.
* </p>
*/
public void addPackage(String packageName) {
packages.add(packageName);
@@ -2271,7 +2207,6 @@ public class ServerConfig {
* Return packages to search for entities via class path search.
* <p>
* This is only used if classes have not been explicitly specified.
* </p>
*/
public List<String> getPackages() {
return packages;
@@ -2281,7 +2216,6 @@ public class ServerConfig {
* Set packages to search for entities via class path search.
* <p>
* This is only used if classes have not been explicitly specified.
* </p>
*/
public void setPackages(List<String> packages) {
this.packages = packages;
@@ -2293,10 +2227,8 @@ public class ServerConfig {
* <p>
* If no classes are specified then the classes are found automatically via
* searching the class path.
* </p>
* <p>
* Alternatively the classes can contain added via {@link #addClass(Class)}.
* </p>
*/
public void setClasses(List<Class<?>> classes) {
this.classes = classes;
@@ -2316,7 +2248,6 @@ public class ServerConfig {
* This defaults to true and means that for "find by id" and "find by natural key"
* queries that normally hit L2 bean cache automatically will not do so after a write/persist
* on the transaction.
* </p>
* <p>
* <pre>{@code
*
@@ -2377,7 +2308,6 @@ public class ServerConfig {
* Set to false if by default updates in JDBC batch should not include all properties.
* <p>
* This mode can be explicitly set per transaction.
* </p>
*
* @see Transaction#setUpdateAllLoadedProperties(boolean)
*/
@@ -2445,7 +2375,6 @@ public class ServerConfig {
* <p>
* Note alternatively you can use {@link #setQueryAdapters(List)} to set all
* the BeanQueryAdapter instances.
* </p>
*/
public void add(BeanQueryAdapter beanQueryAdapter) {
queryAdapters.add(beanQueryAdapter);
@@ -2463,7 +2392,6 @@ public class ServerConfig {
* <p>
* Note alternatively you can use {@link #add(BeanQueryAdapter)} to add
* BeanQueryAdapter instances one at a time.
* </p>
*/
public void setQueryAdapters(List<BeanQueryAdapter> queryAdapters) {
this.queryAdapters = queryAdapters;
@@ -2495,7 +2423,6 @@ public class ServerConfig {
* <p>
* Note alternatively you can use {@link #setPersistControllers(List)} to set
* all the BeanPersistController instances.
* </p>
*/
public void add(BeanPersistController beanPersistController) {
persistControllers.add(beanPersistController);
@@ -2506,7 +2433,6 @@ public class ServerConfig {
* <p>
* Note alternatively you can use {@link #setPostLoaders(List)} to set
* all the BeanPostLoad instances.
* </p>
*/
public void add(BeanPostLoad postLoad) {
postLoaders.add(postLoad);
@@ -2517,7 +2443,6 @@ public class ServerConfig {
* <p>
* Note alternatively you can use {@link #setPostConstructListeners(List)} to set
* all the BeanPostConstructListener instances.
* </p>
*/
public void add(BeanPostConstructListener listener) {
postConstructListeners.add(listener);
@@ -2577,7 +2502,6 @@ public class ServerConfig {
* <p>
* Note alternatively you can use {@link #add(BeanPersistController)} to add
* BeanPersistController instances one at a time.
* </p>
*/
public void setPersistControllers(List<BeanPersistController> persistControllers) {
this.persistControllers = persistControllers;
@@ -2588,7 +2512,6 @@ public class ServerConfig {
* <p>
* Note alternatively you can use {@link #setPersistListeners(List)} to set
* all the BeanPersistListener instances.
* </p>
*/
public void add(BeanPersistListener beanPersistListener) {
persistListeners.add(beanPersistListener);
@@ -2634,7 +2557,6 @@ public class ServerConfig {
* <p>
* Note alternatively you can use {@link #add(BeanPersistListener)} to add
* BeanPersistListener instances one at a time.
* </p>
*/
public void setPersistListeners(List<BeanPersistListener> persistListeners) {
this.persistListeners = persistListeners;
@@ -2929,14 +2851,12 @@ public class ServerConfig {
* @return the classes
*/
private List<Class<?>> getClasses(PropertiesWrapper properties) {
String classNames = properties.get("classes", null);
if (classNames == null) {
return classes;
}
List<Class<?>> classList = new ArrayList<>();
String[] split = StringHelper.splitNames(classNames);
for (String cn : split) {
if (!"class".equalsIgnoreCase(cn)) {
@@ -2952,13 +2872,10 @@ public class ServerConfig {
}
private List<String> getSearchList(String searchNames, List<String> defaultValue) {
if (searchNames != null) {
String[] entries = StringHelper.splitNames(searchNames);
List<String> hitList = new ArrayList<>(entries.length);
Collections.addAll(hitList, entries);
return hitList;
} else {
return defaultValue;
@@ -2970,7 +2887,6 @@ public class ServerConfig {
* platform supports getGeneratedKeys in batch mode.
*/
public PersistBatch appliedPersistBatchOnCascade() {
if (persistBatchOnCascade == PersistBatch.INHERIT) {
// use the platform default (ALL except SQL Server which has NONE)
return databasePlatform.getPersistBatchOnCascade();
@@ -2982,7 +2898,6 @@ public class ServerConfig {
* Return the Jackson ObjectMapper.
* <p>
* Note that this is not strongly typed as Jackson ObjectMapper is an optional dependency.
* </p>
*/
public Object getObjectMapper() {
return objectMapper;
@@ -2992,7 +2907,6 @@ public class ServerConfig {
* Set the Jackson ObjectMapper.
* <p>
* Note that this is not strongly typed as Jackson ObjectMapper is an optional dependency.
* </p>
*/
public void setObjectMapper(Object objectMapper) {
this.objectMapper = objectMapper;
@@ -3011,7 +2925,6 @@ public class ServerConfig {
* Setting this to true has the effect that eq(propertyName, value), ieq(propertyName, value) and
* ne(propertyName, value) have no effect when the value is null. The expression factory adds a NoopExpression
* which will add "1=1" into the SQL rather than "is null".
* </p>
*/
public void setExpressionEqualsWithNullAsNoop(boolean expressionEqualsWithNullAsNoop) {
this.expressionEqualsWithNullAsNoop = expressionEqualsWithNullAsNoop;
@@ -3105,7 +3018,6 @@ public class ServerConfig {
* In general we don't want to do that as when we use a distributed cache (like Ignite, Hazelcast etc)
* we are making network calls and we prefer to do this in background and not impact the response time
* of the executing transaction.
* </p>
*/
public void setNotifyL2CacheInForeground(boolean notifyL2CacheInForeground) {
this.notifyL2CacheInForeground = notifyL2CacheInForeground;
@@ -3142,7 +3054,6 @@ public class ServerConfig {
* <p>
* Typically used in Db Migration generation for many platform targets that might have different
* configuration for IdType, UUID, quoted identifiers etc.
* </p>
*
* @param propertiesPath The properties path used for loading and setting properties
* @param platformPrefix The prefix used for loading and setting properties
@@ -3179,7 +3090,6 @@ public class ServerConfig {
* Set mapping locations to search for xml mapping via class path search.
* <p>
* This is only used if classes have not been explicitly specified.
* </p>
*/
public void setMappingLocations(List<String> mappingLocations) {
this.mappingLocations = mappingLocations;
@@ -3265,7 +3175,6 @@ public class ServerConfig {
* <p>
* When false we either register entity classes via application code or use classpath
* scanning to find and register entity classes.
* </p>
*/
public boolean isAutoLoadModuleInfo() {
return loadModuleInfo && classes.isEmpty();
@@ -15,7 +15,7 @@ package io.ebean.config;
*
* public class EbeanConfigProvider implements ServerConfigProvider {
*
* @Override
* Override
* public void apply(ServerConfig config) {
*
* // register the entity bean classes explicitly
@@ -1,8 +1,5 @@
package io.ebean.config.dbplatform;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Defines the identity/sequence behaviour for the database.
*/
@@ -10,8 +7,6 @@ public class DbIdentity {
private static final String TABLE_PLACEHOLDER = "{table}";
private static final Pattern TABLE_REPLACE = Pattern.compile(TABLE_PLACEHOLDER, Pattern.LITERAL);
/**
* Set if this DB supports sequences. Note some DB's support both Sequences
* and Identity.
@@ -55,10 +50,7 @@ public class DbIdentity {
if (selectLastInsertedIdTemplate == null) {
return null;
}
if (!selectLastInsertedIdTemplate.contains(TABLE_PLACEHOLDER)) {
return selectLastInsertedIdTemplate;
}
return TABLE_REPLACE.matcher(selectLastInsertedIdTemplate).replaceAll(Matcher.quoteReplacement(table));
return selectLastInsertedIdTemplate.replace(TABLE_PLACEHOLDER, table);
}
/**
@@ -25,7 +25,7 @@ public class MariaDbHistorySupport extends DbStandardHistorySupport {
*/
@Override
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
return tableAlias + "." + sysPeriod + "From";
return tableAlias + ".row_start";
}
/**
@@ -33,6 +33,6 @@ public class MariaDbHistorySupport extends DbStandardHistorySupport {
*/
@Override
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
return tableAlias + "." + sysPeriod + "To";
return tableAlias + ".row_end";
}
}
@@ -5,7 +5,7 @@ import io.ebean.config.dbplatform.DbStandardHistorySupport;
/**
* History support only valid on SqlServer 2016 or later.
*
* @author Vilmos Nagy <vilmos.nagy@outlook.com>
* @author Vilmos Nagy
*/
public class SqlServerHistorySupport extends DbStandardHistorySupport {
+56 -388
View File
@@ -1,6 +1,5 @@
package io.ebean.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
@@ -10,152 +9,10 @@ import java.util.regex.Pattern;
*/
public class StringHelper {
private static final char SINGLE_QUOTE = '\'';
private static final char DOUBLE_QUOTE = '"';
private static final Pattern SPLIT_NAMES = Pattern.compile("[\\s,;]+");
private static final String[] EMPTY_STRING_ARRAY = new String[0];
/**
* parses a String of the form name1='value1' name2='value2'. Note that you
* can use either single or double quotes for any particular name value pair
* and the end quote must match the begin quote.
*/
public static HashMap<String, String> parseNameQuotedValue(String tag) throws RuntimeException {
if (tag == null || tag.length() < 1) {
return null;
}
// make sure that the quotes are matched...
// int remainer = countOccurances(tag, ""+quote) % 2;
// if (remainer == 1) {
// dp("remainder = "+remainer);
// throw new StringParsingException("Unmatched quote in "+tag);
// }
// make sure that th last character is not an equals...
// (check now so I don't need to check this every time..)
if (tag.charAt(tag.length() - 1) == '=') {
throw new RuntimeException("missing quoted value at the end of " + tag);
}
HashMap<String, String> map = new HashMap<>();
// recursively parse out the name value pairs...
return parseNameQuotedValue(map, tag, 0);
}
/**
* recursively parse out name value pairs (where the value is quoted, with
* either single or double quotes).
*/
private static HashMap<String, String> parseNameQuotedValue(HashMap<String, String> map,
String tag, int pos) throws RuntimeException {
while (true) {
int equalsPos = tag.indexOf('=', pos);
if (equalsPos > -1) {
// check for begin quote...
char firstQuote = tag.charAt(equalsPos + 1);
if (firstQuote != SINGLE_QUOTE && firstQuote != DOUBLE_QUOTE) {
throw new RuntimeException("missing begin quote at " + (equalsPos) + "["
+ tag.charAt(equalsPos + 1) + "] in [" + tag + "]");
}
// check for end quote...
int endQuotePos = tag.indexOf(firstQuote, equalsPos + 2);
if (endQuotePos == -1) {
throw new RuntimeException("missing end quote [" + firstQuote + "] after " + pos + " in [" + tag + "]");
}
// we have a valid name and value...
// dp("pos="+pos+" equalsPos="+equalsPos+"
// endQuotePos="+endQuotePos);
String name = tag.substring(pos, equalsPos);
// dp("name="+name+"; value="+value+";");
// trim off any whitespace from the front of name...
name = trimFront(name, " ");
if ((name.indexOf(SINGLE_QUOTE) > -1) || (name.indexOf(DOUBLE_QUOTE) > -1)) {
throw new RuntimeException("attribute name contains a quote [" + name + "]");
}
String value = tag.substring(equalsPos + 2, endQuotePos);
map.put(name, value);
pos = endQuotePos + 1;
} else {
// no more equals... stop parsing...
return map;
}
}
}
/**
* Returns the number of times a particular String occurs in another String.
* e.g. count the number of single quotes.
*/
public static int countOccurances(String content, String occurs) {
return countOccurances(content, occurs, 0, 0);
}
private static int countOccurances(String content, String occurs, int pos, int countSoFar) {
while (true) {
int equalsPos = content.indexOf(occurs, pos);
if (equalsPos > -1) {
countSoFar += 1;
pos = equalsPos + occurs.length();
// dp("countSoFar="+countSoFar+" pos="+pos);
} else {
return countSoFar;
}
}
}
/**
* Parses out a list of Name Value pairs that are delimited together. Will
* always return a StringMap. If allNameValuePairs is null, or no name values
* can be parsed out an empty StringMap is returned.
*
* @param allNameValuePairs the entire string to be parsed.
* @param listDelimiter (typically ';') the delimited between the list
* @param nameValueSeparator (typically '=') the separator between the name and value
*/
public static Map<String, String> delimitedToMap(String allNameValuePairs,
String listDelimiter, String nameValueSeparator) {
HashMap<String, String> params = new HashMap<>();
if ((allNameValuePairs == null) || (allNameValuePairs.isEmpty())) {
return params;
}
// trim off any leading listDelimiter...
allNameValuePairs = trimFront(allNameValuePairs, listDelimiter);
return getKeyValue(params, 0, allNameValuePairs, listDelimiter, nameValueSeparator);
}
/**
* Trims off recurring strings from the front of a string.
*
* @param source the source string
* @param trim the string to trim off the front
*/
public static String trimFront(String source, String trim) {
while (true) {
if (source == null) {
return null;
}
if (source.indexOf(trim) == 0) {
// dp("trim ...");
source = source.substring(trim.length());
} else {
return source;
}
}
}
/**
* Return true if the value is null or an empty string.
*/
@@ -163,110 +20,76 @@ public class StringHelper {
return value == null || value.trim().isEmpty();
}
/**
* Parses out a list of Name Value pairs that are delimited together. Will
* always return a StringMap. If allNameValuePairs is null, or no name values
* can be parsed out an empty StringMap is returned.
*
* @param source the entire string to be parsed.
* @param listDelimiter (typically ';') the delimited between the list
* @param nameValueSeparator (typically '=') the separator between the name and value
*/
public static Map<String, String> delimitedToMap(String source, String listDelimiter, String nameValueSeparator) {
Map<String, String> params = new HashMap<>();
if (source == null || source.isEmpty()) {
return params;
}
// trim off any leading listDelimiter...
source = trimFront(source, listDelimiter);
return delimitedToMap(params, source, listDelimiter, nameValueSeparator);
}
/**
* Trims off recurring strings from the front of a string.
*
* @param source the source string
* @param trim the string to trim off the front
*/
private static String trimFront(String source, String trim) {
while (true) {
if (source.indexOf(trim) == 0) {
source = source.substring(trim.length());
} else {
return source;
}
}
}
/**
* Recursively pulls out the key value pairs from a raw string.
*/
private static HashMap<String, String> getKeyValue(HashMap<String, String> map, int pos,
String allNameValuePairs, String listDelimiter, String nameValueSeparator) {
private static Map<String, String> delimitedToMap(Map<String, String> map, String source, String listDelimiter, String nameValueSeparator) {
int pos = 0;
while (true) {
if (pos >= allNameValuePairs.length()) {
// dp("end as "+pos+" >= "+allNameValuePairs.length() );
if (pos >= source.length()) {
return map;
}
int equalsPos = allNameValuePairs.indexOf(nameValueSeparator, pos);
int delimPos = allNameValuePairs.indexOf(listDelimiter, pos);
int equalsPos = source.indexOf(nameValueSeparator, pos);
int delimPos = source.indexOf(listDelimiter, pos);
if (delimPos == -1) {
delimPos = allNameValuePairs.length();
delimPos = source.length();
}
if (equalsPos == -1) {
// dp("no more equals...");
return map;
}
if (delimPos == (equalsPos + 1)) {
// dp("Ignoring as nothing between delim and equals...
// delim:"+delimPos+" eq:"+equalsPos);
pos = delimPos + 1;
continue;
}
if (equalsPos > delimPos) {
// there is a key without a value?
String key = allNameValuePairs.substring(pos, delimPos);
String key = source.substring(pos, delimPos);
key = key.trim();
if (!key.isEmpty()) {
map.put(key, null);
}
pos = delimPos + 1;
continue;
}
String key = allNameValuePairs.substring(pos, equalsPos);
if (delimPos > -1) {
String value = allNameValuePairs.substring(equalsPos + 1, delimPos);
// dp("cont "+key+","+value+" pos:"+pos+"
// len:"+allNameValuePairs.length());
key = key.trim();
map.put(key, value);
pos = delimPos + 1;
// recurse the rest of the values...
} else {
// dp("ERROR: delimPos < 0 ???");
return map;
}
}
}
/**
* Convert a string that has delimited values (say comma delimited) in a
* String[]. You must explicitly choose whether or not to include empty values
* (say two commas that a right beside each other.
* <p>
* e.g. "alpha,beta,,theta"<br>
* With keepEmpties true, this results in a String[] of size 4 with the third
* one having a String of 0 length. With keepEmpties false, this results in a
* String[] of size 3.
* <p>
* e.g. ",alpha,beta,,theta,"<br>
* With keepEmpties true, this results in a String[] of size 6 with the
* 1st,4th and 6th one having a String of 0 length. With keepEmpties false,
* this results in a String[] of size 3.
*/
public static String[] delimitedToArray(String str, String delimiter, boolean keepEmpties) {
ArrayList<String> list = new ArrayList<>();
int startPos = 0;
delimiter(str, delimiter, keepEmpties, startPos, list);
String[] result = new String[list.size()];
return list.toArray(result);
}
private static void delimiter(String str, String delimiter, boolean keepEmpties, int startPos,
ArrayList<String> list) {
int endPos = str.indexOf(delimiter, startPos);
if (endPos == -1) {
if (startPos <= str.length()) {
String lastValue = str.substring(startPos, str.length());
if (keepEmpties || !lastValue.isEmpty()) {
list.add(lastValue);
}
}
// we have finished parsing the string...
} else {
// get the delimited value... add it..
String value = str.substring(startPos, endPos);
if (keepEmpties || !value.isEmpty()) {
list.add(value);
}
// recursively search as we are not at the end yet...
delimiter(str, delimiter, keepEmpties, endPos + 1, list);
String key = source.substring(pos, equalsPos);
String value = source.substring(equalsPos + 1, delimPos);
map.put(key.trim(), value);
pos = delimPos + 1;
}
}
@@ -279,177 +102,22 @@ public class StringHelper {
* @param replace the string used to replace match with
* @return the source string after the search and replace
*/
public static String replaceString(String source, String match, String replace) {
public static String replace(String source, String match, String replace) {
if (source == null) {
return null;
}
if (replace == null) {
return source;
}
if (match == null) {
throw new NullPointerException("match is null?");
}
if (match.equals(replace)) {
return source;
}
return replaceString(source, match, replace, 30, 0, source.length());
return source.replace(match, replace);
}
/**
* Additionally specify the additionalSize to add to the buffer. This will
* make the buffer bigger so that it doesn't have to grow when replacement
* occurs.
* Return new line and carriage return with space.
*/
public static String replaceString(String source, String match, String replace,
int additionalSize, int startPos, int endPos) {
if (source == null) {
return null;
}
char match0 = match.charAt(0);
int matchLength = match.length();
if (matchLength == 1 && replace.length() == 1) {
char replace0 = replace.charAt(0);
return source.replace(match0, replace0);
}
if (matchLength >= replace.length()) {
additionalSize = 0;
}
int sourceLength = source.length();
int lastMatch = endPos - matchLength;
StringBuilder sb = new StringBuilder(sourceLength + additionalSize);
if (startPos > 0) {
sb.append(source.substring(0, startPos));
}
char sourceChar;
boolean isMatch;
int sourceMatchPos;
for (int i = startPos; i < sourceLength; i++) {
sourceChar = source.charAt(i);
if (i > lastMatch || sourceChar != match0) {
sb.append(sourceChar);
} else {
// check to see if this is a match
isMatch = true;
sourceMatchPos = i;
// check each following character...
for (int j = 1; j < matchLength; j++) {
sourceMatchPos++;
if (source.charAt(sourceMatchPos) != match.charAt(j)) {
isMatch = false;
break;
}
}
if (isMatch) {
i = i + matchLength - 1;
sb.append(replace);
} else {
// was not a match
sb.append(sourceChar);
}
}
}
return sb.toString();
}
/**
* A search and replace with multiple matching strings.
* <p>
* Useful when converting CRNL CR and NL all to a BR tag for example.
* <pre>{@code
*
* String[] multi = { "\r\n", "\r", "\n" };
* content = StringHelper.replaceStringMulti(content, multi, "<br/>");
*
* }</pre>
*/
public static String replaceStringMulti(String source, String[] match, String replace) {
if (source == null) {
return null;
}
return replaceStringMulti(source, match, replace, 30, 0, source.length());
}
/**
* Additionally specify an additional size estimate for the buffer plus start
* and end positions.
* <p>
* The start and end positions can limit the search and replace. Otherwise
* these default to startPos = 0 and endPos = source.length().
* </p>
*/
public static String replaceStringMulti(String source, String[] match, String replace,
int additionalSize, int startPos, int endPos) {
if (source == null) {
return null;
}
int shortestMatch = match[0].length();
char[] match0 = new char[match.length];
for (int i = 0; i < match0.length; i++) {
match0[i] = match[i].charAt(0);
if (match[i].length() < shortestMatch) {
shortestMatch = match[i].length();
}
}
StringBuilder sb = new StringBuilder(source.length() + additionalSize);
char sourceChar;
int len = source.length();
int lastMatch = endPos - shortestMatch;
if (startPos > 0) {
sb.append(source.substring(0, startPos));
}
int matchCount;
for (int i = startPos; i < len; i++) {
sourceChar = source.charAt(i);
if (i > lastMatch) {
sb.append(sourceChar);
} else {
matchCount = 0;
for (int k = 0; k < match0.length; k++) {
if (matchCount == 0 && sourceChar == match0[k]) {
if (match[k].length() + i <= len) {
++matchCount;
int j = 1;
for (; j < match[k].length(); j++) {
if (source.charAt(i + j) != match[k].charAt(j)) {
--matchCount;
break;
}
}
if (matchCount > 0) {
i = i + j - 1;
sb.append(replace);
break;
}
}
}
}
if (matchCount == 0) {
sb.append(sourceChar);
}
}
}
return sb.toString();
public static String removeNewLines(String source) {
source = source.replace('\n', ' ');
return source.replace('\r', ' ');
}
/**
@@ -462,13 +130,13 @@ public class StringHelper {
}
String[] result = SPLIT_NAMES.split(names);
if (result.length == 0) {
return EMPTY_STRING_ARRAY; // don't know if this ever can happen
return EMPTY_STRING_ARRAY;
}
if ("".equals(result[0])) { // = input string starts with whitespace
if (result.length == 1) { // = input string contains only whitespace
if ("".equals(result[0])) { // input string starts with whitespace
if (result.length == 1) { // input string contains only whitespace
return EMPTY_STRING_ARRAY;
} else {
String ret[] = new String[result.length-1]; // remove first entry
String[] ret = new String[result.length-1]; // remove first entry
System.arraycopy(result, 1, ret, 0, ret.length);
return ret;
}
@@ -1,9 +1,16 @@
package io.ebeaninternal.api;
import io.ebean.bean.BeanCollection;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
/**
* Controls the loading of ManyToOne and OneToOne relationships.
*/
public interface LoadBeanContext extends LoadSecondaryQuery {
/**
* Register a BeanCollection into the load context.
*/
void register(BeanPropertyAssocMany<?> many, BeanCollection<?> collection);
}
@@ -5,6 +5,7 @@ import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
/**
@@ -56,6 +57,5 @@ public interface LoadContext {
/**
* Register a collection for lazy loading.
*/
void register(String path, BeanCollection<?> bc);
void register(String path, BeanPropertyAssocMany<?> many, BeanCollection<?> bc);
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.api;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.util.StringHelper;
import io.ebeaninternal.server.core.BindPadding;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -125,8 +124,7 @@ public class LoadManyRequest extends LoadRequest {
if (extraWhere != null) {
// replace special ${ta} placeholder with the base table alias
// which is always t0 and add the extra where clause
String ew = StringHelper.replaceString(extraWhere, "${ta}", "t0");
query.where().raw(ew);
query.where().raw(extraWhere.replace("${ta}", "t0"));
}
query.setLazyLoadForParents(many);
@@ -33,6 +33,11 @@ import java.util.function.Predicate;
*/
public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanCollectionLoader {
/**
* Return true if the L2 cache has been disabled.
*/
boolean isDisableL2Cache();
/**
* Return the log manager.
*/
@@ -33,13 +33,13 @@ import io.ebeaninternal.dbmigration.model.MTableIdentity;
import io.ebeaninternal.server.deploy.IdentityMode;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static io.ebean.util.StringHelper.replace;
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
@@ -111,11 +111,9 @@ public class BaseTableDdl implements TableDdl {
this.columnName = column.getName();
this.defaultValue = platformDdl.convertDefaultValue(column.getDefaultValue());
boolean alterNotNull = Boolean.TRUE.equals(column.isNotnull());
if (column.getBefore().isEmpty() && alterNotNull && defaultValue == null) {
handleStrictError(tableName, columnName);
}
before = getScriptsForPlatform(column.getBefore());
after = getScriptsForPlatform(column.getAfter());
this.withHistory = withHistory;
@@ -127,10 +125,8 @@ public class BaseTableDdl implements TableDdl {
DdlMigrationHelp(AlterColumn alter) {
this.tableName = alter.getTableName();
this.columnName = alter.getColumnName();
String tmp = alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue();
this.defaultValue = platformDdl.convertDefaultValue(tmp);
boolean alterNotNull = Boolean.TRUE.equals(alter.isNotnull());
// here we add the platform's default update script
withHistory = isTrue(alter.isWithHistory());
@@ -186,9 +182,9 @@ public class BaseTableDdl implements TableDdl {
* Replaces Table name (${table}), Column name (${column}) and default value (${default}) in DDL.
*/
private String translate(String ddl, String tableName, String columnName, String defaultValue) {
String ret = StringHelper.replaceString(ddl, "${table}", tableName);
ret = StringHelper.replaceString(ret, "${column}", columnName);
return StringHelper.replaceString(ret, "${default}", defaultValue);
String ret = replace(ddl, "${table}", tableName);
ret = replace(ret, "${column}", columnName);
return replace(ret, "${default}", defaultValue);
}
private void handleStrictError(String tableName, String columnName) {
@@ -201,7 +197,6 @@ public class BaseTableDdl implements TableDdl {
public String getDefaultValue() {
return defaultValue;
}
}
/**
@@ -241,7 +236,6 @@ public class BaseTableDdl implements TableDdl {
*/
@Override
public void generate(DdlWrite writer, CreateTable createTable) throws IOException {
reset();
String tableName = lowerTableName(createTable.getName());
@@ -275,7 +269,6 @@ public class BaseTableDdl implements TableDdl {
if (platformDdl.isInlineForeignKeys()) {
writeInlineForeignKeys(writer, createTable);
}
apply.newLine().append(")");
addTableStorageEngine(apply, createTable);
addTableCommentInline(apply, createTable);
@@ -285,9 +278,7 @@ public class BaseTableDdl implements TableDdl {
apply.endOfStatement();
addComments(apply, createTable);
writeUniqueOneToOneConstraints(writer, createTable);
if (isTrue(createTable.isWithHistory())) {
// create history with rollback before the
// associated drop table is written to rollback
@@ -305,7 +296,6 @@ public class BaseTableDdl implements TableDdl {
// add blank line for a bit of whitespace between tables
apply.end();
writer.dropAll().end();
if (!platformDdl.isInlineForeignKeys()) {
writeAddForeignKeys(writer, createTable);
}
@@ -324,7 +314,6 @@ public class BaseTableDdl implements TableDdl {
if (hasValue(tableComment)) {
platformDdl.addTableComment(apply, createTable.getName(), tableComment);
}
for (Column column : createTable.getColumn()) {
if (!StringHelper.isNull(column.getComment())) {
platformDdl.addColumnComment(apply, createTable.getName(), column.getName(), column.getComment());
@@ -427,7 +416,6 @@ public class BaseTableDdl implements TableDdl {
writeForeignKey(write, createTable.getName(), column);
}
}
writeAddCompoundForeignKeys(write, createTable);
}
@@ -448,7 +436,6 @@ public class BaseTableDdl implements TableDdl {
// no matching unique constraint so add the index
fkeyBuffer.appendStatement(platformDdl.createIndex(new WriteCreateIndex(request.indexName(), tableName, request.cols(), false)));
}
alterTableAddForeignKey(write.getOptions(), fkeyBuffer, request);
fkeyBuffer.end();
@@ -456,7 +443,6 @@ public class BaseTableDdl implements TableDdl {
if (hasValue(request.indexName())) {
write.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(request.indexName(), tableName));
}
write.dropAllForeignKeys().end();
}
@@ -513,9 +499,7 @@ public class BaseTableDdl implements TableDdl {
* Write the unique constraints inline with the create table statement.
*/
protected void writeUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
boolean inlineUniqueWhenNullable = platformDdl.isInlineUniqueWhenNullable();
List<Column> columns = new WriteUniqueConstraint(createTable.getColumn()).uniqueKeys();
for (Column column : columns) {
if (Boolean.TRUE.equals(column.isNotnull()) || inlineUniqueWhenNullable) {
@@ -532,12 +516,10 @@ public class BaseTableDdl implements TableDdl {
* Write the unique constraint inline with the create table statement.
*/
protected void inlineUniqueConstraintSingle(DdlBuffer buffer, Column column) throws IOException {
String uqName = column.getUnique();
if (uqName == null) {
uqName = column.getUniqueOneToOne();
}
buffer.append(",").newLine();
buffer.append(" constraint ").append(uqName).append(" unique ");
buffer.append("(");
@@ -549,7 +531,6 @@ public class BaseTableDdl implements TableDdl {
* Write the primary key constraint inline with the create table statement.
*/
protected void writePrimaryKeyConstraint(DdlBuffer buffer, String pkName, String[] pkColumns) throws IOException {
buffer.append(",").newLine();
buffer.append(" constraint ").append(pkName).append(" primary key");
appendColumns(pkColumns, buffer);
@@ -559,7 +540,6 @@ public class BaseTableDdl implements TableDdl {
* Return as an array of string column names.
*/
protected String[] toColumnNames(List<Column> columns) {
String[] cols = new String[columns.size()];
for (int i = 0; i < cols.length; i++) {
cols[i] = columns.get(i).getName();
@@ -682,13 +662,11 @@ public class BaseTableDdl implements TableDdl {
*/
@Override
public void generate(DdlWrite writer, AddColumn addColumn) throws IOException {
String tableName = addColumn.getTableName();
List<Column> columns = addColumn.getColumn();
for (Column column : columns) {
alterTableAddColumn(writer.apply(), tableName, column, false, isTrue(addColumn.isWithHistory()));
}
if (isTrue(addColumn.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) {
// make same changes to the history table
String historyTable = historyTable(tableName);
@@ -697,14 +675,11 @@ public class BaseTableDdl implements TableDdl {
alterTableAddColumn(writer.apply(), historyTable, column, true, true);
}
}
for (Column column : columns) {
if (hasValue(column.getReferences())) {
writeForeignKey(writer, tableName, column);
}
}
// add a bit of whitespace
writer.apply().end();
}
@@ -713,9 +688,7 @@ public class BaseTableDdl implements TableDdl {
*/
@Override
public void generate(DdlWrite writer, DropTable dropTable) throws IOException {
dropTable(writer.apply(), dropTable.getName());
if (hasValue(dropTable.getSequenceCol())
&& platformDdl.getPlatform().getDbIdentity().isSupportsSequence()) {
String sequenceName = dropTable.getSequenceName();
@@ -731,9 +704,7 @@ public class BaseTableDdl implements TableDdl {
*/
@Override
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
String tableName = dropColumn.getTableName();
alterTableDropColumn(writer.apply(), tableName, dropColumn.getColumnName());
if (isTrue(dropColumn.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) {
@@ -741,7 +712,6 @@ public class BaseTableDdl implements TableDdl {
regenerateHistoryTriggers(tableName, HistoryTableUpdate.Change.DROP, dropColumn.getColumnName());
alterTableDropColumn(writer.apply(), historyTable(tableName), dropColumn.getColumnName());
}
writer.apply().end();
}
@@ -826,7 +796,6 @@ public class BaseTableDdl implements TableDdl {
* Register the base table that we need to regenerate the history triggers on.
*/
protected void regenerateHistoryTriggers(String baseTableName, HistoryTableUpdate.Change change, String column) {
HistoryTableUpdate update = regenerateHistoryTriggers.computeIfAbsent(baseTableName, HistoryTableUpdate::new);
update.add(change, column);
}
@@ -836,7 +805,6 @@ public class BaseTableDdl implements TableDdl {
* Will be called, if there is a type, dbdefault or notnull change.
*/
protected void alterColumnBaseAttributes(DdlWrite writer, AlterColumn alter) throws IOException {
String ddl = platformDdl.alterColumnBaseAttributes(alter);
if (hasValue(ddl)) {
writer.apply().appendStatement(ddl);
@@ -857,27 +825,22 @@ public class BaseTableDdl implements TableDdl {
}
protected void alterColumnDefaultValue(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterColumnDefaultValue(alter.getTableName(), alter.getColumnName(), alter.getDefaultValue()));
}
protected void dropCheckConstraint(DdlWrite writer, AlterColumn alter, String constraintName) throws IOException {
writer.apply().appendStatement(platformDdl.alterTableDropConstraint(alter.getTableName(), constraintName));
}
protected void addCheckConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterTableAddCheckConstraint(alter.getTableName(), alter.getCheckConstraintName(), alter.getCheckConstraint()));
}
protected void alterColumnNotnull(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterColumnNotnull(alter.getTableName(), alter.getColumnName(), alter.isNotnull()));
}
protected void alterColumnType(DdlWrite writer, AlterColumn alter) throws IOException {
String ddl = platformDdl.alterColumnType(alter.getTableName(), alter.getColumnName(), alter.getType());
if (hasValue(ddl)) {
writer.apply().appendStatement(ddl);
@@ -891,33 +854,26 @@ public class BaseTableDdl implements TableDdl {
}
protected void alterColumnAddForeignKey(DdlWrite writer, AlterColumn alterColumn) throws IOException {
alterTableAddForeignKey(writer.getOptions(), writer.apply(), new WriteForeignKey(alterColumn));
}
protected void alterColumnDropForeignKey(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterTableDropForeignKey(alter.getTableName(), alter.getDropForeignKey()));
}
protected void alterColumnDropUniqueConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(alter.getTableName(), alter.getDropUnique()));
}
protected void alterColumnAddUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
addUniqueConstraint(writer, alter, alter.getUniqueOneToOne());
}
protected void alterColumnAddUniqueConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
addUniqueConstraint(writer, alter, alter.getUnique());
}
protected void addUniqueConstraint(DdlWrite writer, AlterColumn alter, String uqName) throws IOException {
String[] cols = {alter.getColumnName()};
boolean notNull = alter.isNotnull() != null ? alter.isNotnull() : Boolean.TRUE.equals(alter.isNotnull());
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(alter.getTableName(), uqName, cols, notNull ? null : cols));
@@ -965,11 +921,4 @@ public class BaseTableDdl implements TableDdl {
return Boolean.TRUE.equals(value);
}
/**
* Return as an int value with 0 when it is null.
*/
protected int toInt(BigInteger value) {
return (value == null) ? 0 : value.intValue();
}
}
@@ -14,15 +14,9 @@ import java.io.IOException;
*/
public class MariaDbHistoryDdl implements PlatformHistoryDdl {
private String systemPeriodStart;
private String systemPeriodEnd;
private PlatformDdl platformDdl;
@Override
public void configure(ServerConfig serverConfig, PlatformDdl platformDdl) {
this.systemPeriodStart = serverConfig.getAsOfSysPeriod() + "From";
this.systemPeriodEnd = serverConfig.getAsOfSysPeriod() + "To";
this.platformDdl = platformDdl;
// do nothing
}
@Override
@@ -31,50 +25,19 @@ public class MariaDbHistoryDdl implements PlatformHistoryDdl {
enableSystemVersioning(writer, baseTable);
}
String getHistoryTable(String baseTable) {
String historyTable = baseTable + "_history";
if (baseTable.startsWith("[")) {
historyTable = historyTable.replace("]", "") + "]";
}
if (historyTable.indexOf('.') == -1) {
// history must contain schema, add the default schema if none was specified
historyTable = "dbo." + historyTable;
}
return historyTable;
}
private void enableSystemVersioning(DdlWrite writer, String baseTable) throws IOException {
DdlBuffer apply = writer.applyHistoryView();
final String systemTime = String.format("system_time(%s, %s),", systemPeriodStart, systemPeriodEnd);
apply.append("alter table ").append(baseTable).newLine()
.append(" add column ").append(systemPeriodStart).append(" timestamp(6) generated always as row start,").newLine()
.append(" add column ").append(systemPeriodEnd).append(" timestamp(6) generated always as row end,").newLine()
.append(" add period for ").append(systemTime).newLine()
.append(" add system versioning;").newLine();
apply.append("alter table ").append(baseTable).append(" add system versioning").endOfStatement();
DdlBuffer drop = writer.dropAll();
//drop.append("IF OBJECT_ID('").append(baseTable).append("', 'U') IS NOT NULL alter table ").append(baseTable).append(" set (system_versioning = off)").endOfStatement();
//drop.append("IF OBJECT_ID('").append(baseTable).append("_history', 'U') IS NOT NULL drop table ").append(baseTable).append("_history").endOfStatement();
drop.append("alter table ").append(baseTable).append(" drop system versioning").endOfStatement();
}
@Override
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
String baseTable = dropHistoryTable.getBaseTable();
DdlBuffer apply = writer.applyHistoryView();
apply.append("-- dropping history support for ").append(baseTable).endOfStatement();
// drop default constraints
apply.append(platformDdl.alterColumnDefaultValue(baseTable, systemPeriodStart, DdlHelp.DROP_DEFAULT)).endOfStatement();
apply.append(platformDdl.alterColumnDefaultValue(baseTable, systemPeriodEnd, DdlHelp.DROP_DEFAULT)).endOfStatement();
// switch of versioning & period
apply.append("alter table ").append(baseTable).append(" set (system_versioning = off)").endOfStatement();
apply.append("alter table ").append(baseTable).append(" drop period for system_time").endOfStatement();
// now drop tables & columns
apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodStart).endOfStatement();
apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodEnd).endOfStatement();
//apply.append("IF OBJECT_ID('").append(baseTable).append("_history', 'U') IS NOT NULL drop table ").append(baseTable).append("_history").endOfStatement();
apply.end();
apply.append("alter table ").append(baseTable).append(" drop system versioning").endOfStatement();
}
@Override
@@ -84,15 +47,7 @@ public class MariaDbHistoryDdl implements PlatformHistoryDdl {
}
@Override
public void updateTriggers(DdlWrite writer, HistoryTableUpdate baseTable) throws IOException {
// SQL Server 2016 does not need triggers
DdlBuffer apply = writer.applyHistoryView();
String baseTableName = baseTable.getBaseTable();
apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = off (history_table=")
.append(getHistoryTable(baseTableName)).append("))").endOfStatement();
apply.append("-- history migration goes here").newLine();
apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = on (history_table=")
.append(getHistoryTable(baseTableName)).append("))").endOfStatement();
public void updateTriggers(DdlWrite writer, HistoryTableUpdate baseTable) {
// do nothing
}
}
@@ -54,4 +54,9 @@ public class PostgresDdl extends PlatformDdl {
public String asIdentityColumn(String columnDefn, DdlIdentity identity) {
return asIdentityStandardOptions(columnDefn, identity);
}
@Override
public String alterColumnType(String tableName, String columnName, String type) {
return super.alterColumnType(tableName, columnName, type) + " using " + columnName + "::" + convert(type);
}
}
@@ -161,7 +161,7 @@ public class DatabasePlatformFactory {
if (dbProductName.contains("oracle")) {
return new OraclePlatform();
} else if (dbProductName.contains("microsoft")) {
throw new IllegalArgumentException("For SqlServer please explicitly choose either sqlserver16 or sqlserver17 as the platform via ServerConfig.setDatabasePlatformName. Refer to issue #1340 for more details");
throw new IllegalArgumentException("For SqlServer please explicitly choose either sqlserver16 or sqlserver17 as the platform via DatabaseConfig.setDatabasePlatformName. Refer to issue #1340 for more details");
} else if (dbProductName.contains("h2")) {
return new H2Platform();
} else if (dbProductName.contains("hsql database engine")) {
@@ -33,6 +33,7 @@ import io.ebean.Update;
import io.ebean.UpdateQuery;
import io.ebean.ValuePair;
import io.ebean.Version;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.CallOrigin;
@@ -248,6 +249,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
private final SlowQueryListener slowQueryListener;
private final boolean disableL2Cache;
/**
* Create the DefaultServer.
*/
@@ -255,6 +258,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
this.logManager = config.getLogManager();
this.dtoBeanManager = config.getDtoBeanManager();
this.serverConfig = config.getServerConfig();
this.disableL2Cache = serverConfig.isDisableL2Cache();
this.serverCacheManager = cache;
this.databasePlatform = config.getDatabasePlatform();
this.backgroundExecutor = config.getBackgroundExecutor();
@@ -311,9 +315,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
private void configureServerPlugins() {
autoTuneService.startup();
for (Plugin plugin : serverPlugins) {
plugin.configure(this);
}
@@ -323,7 +325,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* Execute all the plugins with an online flag indicating the DB is up or not.
*/
public void executePlugins(boolean online) {
if (!serverConfig.isDocStoreOnly()) {
ddlGenerator.execute(online);
}
@@ -332,6 +333,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
@Override
public boolean isDisableL2Cache() {
return disableL2Cache;
}
@Override
public SpiLogManager log() {
return logManager;
@@ -386,6 +392,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return metaInfoManager;
}
@Override
public Platform getPlatform() {
return databasePlatform.getPlatform();
}
@Override
public SpiServer getPluginApi() {
return this;
@@ -471,14 +482,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* Shutdown the services like threads and DataSource.
*/
private void shutdownInternal(boolean shutdownDataSource, boolean deregisterDriver) {
logger.debug("Shutting down instance:{}", serverName);
if (shutdown) {
// already shutdown
return;
}
shutdownPlugins();
autoTuneService.shutdown();
// shutdown background threads
backgroundExecutor.shutdown();
@@ -492,11 +501,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
private void shutdownPlugins() {
if (serverConfig.isDumpMetricsOnShutdown()) {
new DumpMetrics(this, serverConfig.getDumpMetricsOptions()).dump();
}
for (Plugin plugin : serverPlugins) {
try {
plugin.shutdown();
@@ -601,7 +608,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (a == null) {
return null;
}
BeanDescriptor<?> desc = getBeanDescriptor(a.getClass());
return DiffHelp.diff(a, b, desc);
}
@@ -626,10 +632,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public void externalModification(String tableName, boolean inserts, boolean updates, boolean deletes) {
TransactionEventTable evt = new TransactionEventTable();
evt.add(tableName, inserts, updates, deletes);
externalModification(evt);
}
@@ -697,14 +701,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public <T> T getReference(Class<T> type, Object id) {
if (id == null) {
throw new NullPointerException("The id is null");
}
BeanDescriptor desc = getBeanDescriptor(type);
id = desc.convertId(id);
PersistenceContext pc = null;
SpiTransaction t = transactionManager.getActive();
if (t != null) {
@@ -719,12 +720,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (inheritInfo == null || inheritInfo.isConcrete()) {
return (T) desc.contextRef(pc, null, false, id);
}
BeanProperty idProp = desc.getIdProperty();
if (idProp == null) {
throw new PersistenceException("No ID properties for this type? " + desc);
}
// we actually need to do a query because we don't know the type without the discriminator
// value, just select the id property and discriminator column (auto added)
return find(type).select(idProp.getName()).setId(id).findOne();
@@ -769,13 +768,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
ScopedTransaction scopeTrans = transactionManager.beginScopedTransaction(scope);
try {
return c.call();
} catch (Error e) {
throw scopeTrans.caughtError(e);
} catch (Exception e) {
throw new PersistenceException(scopeTrans.caughtThrowable(e));
} finally {
scopeTrans.complete();
}
@@ -791,13 +787,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
ScopedTransaction t = transactionManager.beginScopedTransaction(scope);
try {
r.run();
} catch (Error e) {
throw t.caughtError(e);
} catch (Exception e) {
throw new PersistenceException(t.caughtThrowable(e));
} finally {
t.complete();
}
@@ -879,7 +872,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
@SuppressWarnings("unchecked")
public <T> void sort(List<T> list, String sortByClause) {
if (list == null) {
throw new NullPointerException("list is null");
}
@@ -901,7 +893,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> Set<String> validateQuery(Query<T> query) {
BeanDescriptor<T> beanDescriptor = getBeanDescriptor(query.getBeanType());
if (beanDescriptor == null) {
throw new PersistenceException("BeanDescriptor not found, is [" + query.getBeanType() + "] an entity bean?");
@@ -1010,13 +1001,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
String m = beanType.getName() + " is NOT an Entity Bean registered with this server?";
throw new PersistenceException(m);
}
return new DefaultOrmUpdate<>(beanType, this, desc.getBaseTable(), ormUpdate);
}
@Override
public <T> DtoQuery<T> findDto(Class<T> dtoType, String sql) {
DtoBeanDescriptor<T> descriptor = dtoBeanManager.getDescriptor(dtoType);
return new DefaultDtoQuery<>(this, descriptor, sql.trim());
}
@@ -1033,14 +1022,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> DtoQuery<T> findDto(Class<T> dtoType, SpiQuery<?> ormQuery) {
DtoBeanDescriptor<T> descriptor = dtoBeanManager.getDescriptor(dtoType);
return new DefaultDtoQuery<>(this, descriptor, ormQuery);
}
@Override
public SpiResultSet findResultSet(SpiQuery<?> ormQuery, SpiTransaction transaction) {
SpiOrmQueryRequest<?> request = createQueryRequest(ormQuery.getType(), ormQuery, transaction);
request.initTransIfRequired();
return request.findResultSet();
@@ -1073,7 +1060,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> T find(Class<T> beanType, Object uid) {
return find(beanType, uid, null);
}
@@ -1082,33 +1068,27 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public <T> T find(Class<T> beanType, Object id, Transaction t) {
if (id == null) {
throw new NullPointerException("The id is null");
}
Query<T> query = createQuery(beanType).setId(id);
return findId(query, t);
}
<T> SpiOrmQueryRequest<T> createQueryRequest(Type type, Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = buildQueryRequest(type, query, t);
request.prepareQuery();
return request;
}
<T> SpiOrmQueryRequest<T> buildQueryRequest(Type type, Query<T> query, Transaction t) {
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
spiQuery.setType(type);
spiQuery.checkNamedParameters();
return buildQueryRequest(spiQuery, t);
}
private <T> SpiOrmQueryRequest<T> buildQueryRequest(SpiQuery<T> query, Transaction t) {
if (t == null) {
t = currentServerTransaction();
}
@@ -1118,9 +1098,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
// to define the 'default' select clause
query.setDefaultSelectClause();
}
query.selectAllForLazyLoadProperty();
ProfileLocation profileLocation = query.getProfileLocation();
if (profileLocation != null) {
profileLocation.obtain();
@@ -1129,7 +1107,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (query.getParentNode() == null) {
query.setOrigin(createCallOrigin());
}
return new OrmQueryRequest<>(this, queryEngine, query, (SpiTransaction) t);
}
@@ -1138,15 +1115,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@SuppressWarnings("unchecked")
private <T> T findIdCheckPersistenceContextAndCache(Transaction transaction, SpiQuery<T> query, Object id) {
SpiTransaction t = (SpiTransaction) transaction;
if (t == null) {
t = currentServerTransaction();
}
BeanDescriptor<T> desc = query.getBeanDescriptor();
id = desc.convertId(id);
PersistenceContext pc = null;
if (t != null && useTransactionPersistenceContext(query)) {
// first look in the transaction scoped persistence context
@@ -1162,11 +1136,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
}
if (!query.isBeanCacheGet() || (t != null && t.isSkipCache())) {
return null;
}
// Hit the L2 bean cache
return desc.cacheBeanGet(id, query.isReadOnly(), pc);
}
@@ -1189,7 +1161,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@SuppressWarnings("unchecked")
private <T> T findId(Query<T> query, Transaction t) {
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
spiQuery.setType(Type.BEAN);
if (SpiQuery.Mode.NORMAL == spiQuery.getMode() && !spiQuery.isForceHitDatabase()) {
@@ -1200,7 +1171,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return bean;
}
}
SpiOrmQueryRequest<T> request = buildQueryRequest(spiQuery, t);
request.prepareQuery();
if (request.isUseDocStore()) {
@@ -1209,7 +1179,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
try {
request.initTransIfRequired();
return (T) request.findId();
} finally {
request.endTransIfRequired();
}
@@ -1222,17 +1191,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> T findOne(Query<T> query, Transaction transaction) {
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
if (spiQuery.isFindById()) {
// actually a find by Id query
return findId(query, transaction);
}
if (transaction == null) {
transaction = currentServerTransaction();
}
// a query that is expected to return either 0 or 1 beans
List<T> list = findList(query, transaction, true);
return extractUnique(list);
@@ -1241,10 +1207,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
private <T> T extractUnique(List<T> list) {
if (list.isEmpty()) {
return null;
} else if (list.size() > 1) {
throw new NonUniqueResultException("Unique expecting 0 or 1 results but got [" + list.size() + "]");
} else {
return list.get(0);
}
@@ -1253,7 +1217,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public <T> Set<T> findSet(Query<T> query, Transaction t) {
SpiOrmQueryRequest request = createQueryRequest(Type.SET, query, t);
Object result = request.getFromQueryCache();
if (result != null) {
@@ -1270,7 +1233,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public <K, T> Map<K, T> findMap(Query<T> query, Transaction t) {
SpiOrmQueryRequest request = createQueryRequest(Type.MAP, query, t);
request.resetBeanCacheAutoMode(false);
if ((t == null || !t.isSkipCache()) && request.getFromBeanCache()) {
@@ -1292,7 +1254,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
@SuppressWarnings("unchecked")
public <A, T> List<A> findSingleAttributeList(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ATTRIBUTE, query, t);
Object result = request.getFromQueryCache();
if (result != null) {
@@ -1301,7 +1262,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
try {
request.initTransIfRequired();
return (List<A>) request.findSingleAttributeList();
} finally {
request.endTransIfRequired();
}
@@ -1309,7 +1269,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> int findCount(Query<T> query, Transaction t) {
SpiQuery<T> spiQuery = ((SpiQuery<T>) query);
if (!spiQuery.isDistinct()) {
spiQuery = spiQuery.copy();
@@ -1319,7 +1278,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> int findCountWithCopy(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.COUNT, query, t);
Integer result = request.getFromQueryCache();
if (result != null) {
@@ -1328,7 +1286,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
try {
request.initTransIfRequired();
return request.findCount();
} finally {
request.endTransIfRequired();
}
@@ -1342,7 +1299,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> boolean exists(Query<?> ormQuery, Transaction transaction) {
Query<?> ormQueryCopy = ormQuery.copy();
ormQueryCopy.setMaxRows(1);
SpiOrmQueryRequest<?> request = createQueryRequest(Type.ID_LIST, ormQueryCopy, transaction);
@@ -1350,7 +1306,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
request.initTransIfRequired();
List<Object> ids = request.findIds();
return !ids.isEmpty();
} finally {
request.endTransIfRequired();
}
@@ -1358,14 +1313,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <A, T> List<A> findIds(Query<T> query, Transaction t) {
return findIdsWithCopy(((SpiQuery<T>) query).copy(), t);
}
@SuppressWarnings("unchecked")
@Override
public <A, T> List<A> findIdsWithCopy(Query<T> query, Transaction t) {
SpiOrmQueryRequest<?> request = createQueryRequest(Type.ID_LIST, query, t);
Object result = request.getFromQueryCache();
if (result != null) {
@@ -1378,7 +1331,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
try {
request.initTransIfRequired();
return request.findIds();
} finally {
request.endTransIfRequired();
}
@@ -1386,7 +1338,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> int delete(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.DELETE, query, t);
try {
request.initTransIfRequired();
@@ -1410,7 +1361,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> int update(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.UPDATE, query, t);
try {
request.initTransIfRequired();
@@ -1423,82 +1373,60 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> FutureRowCount<T> findFutureCount(Query<T> q, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) q).copy();
copy.setFutureFetch(true);
Transaction newTxn = createTransaction();
CallableQueryCount<T> call = new CallableQueryCount<>(this, copy, newTxn);
QueryFutureRowCount<T> queryFuture = new QueryFutureRowCount<>(call);
QueryFutureRowCount<T> queryFuture = new QueryFutureRowCount<>(new CallableQueryCount<T>(this, copy, newTxn));
backgroundExecutor.execute(queryFuture.getFutureTask());
return queryFuture;
}
@Override
public <T> FutureIds<T> findFutureIds(Query<T> query, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
copy.setFutureFetch(true);
Transaction newTxn = createTransaction();
CallableQueryIds<T> call = new CallableQueryIds<>(this, copy, newTxn);
QueryFutureIds<T> queryFuture = new QueryFutureIds<>(call);
QueryFutureIds<T> queryFuture = new QueryFutureIds<>(new CallableQueryIds<T>(this, copy, newTxn));
backgroundExecutor.execute(queryFuture.getFutureTask());
return queryFuture;
}
@Override
public <T> FutureList<T> findFutureList(Query<T> query, Transaction t) {
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
spiQuery.setFutureFetch(true);
// FutureList query always run in it's own persistence content
spiQuery.setPersistenceContext(new DefaultPersistenceContext());
if (!spiQuery.isDisableReadAudit()) {
BeanDescriptor<T> desc = beanDescriptorManager.getBeanDescriptor(spiQuery.getBeanType());
desc.readAuditFutureList(spiQuery);
}
// Create a new transaction solely to execute the findList() at some future time
Transaction newTxn = createTransaction();
CallableQueryList<T> call = new CallableQueryList<>(this, spiQuery, newTxn);
QueryFutureList<T> queryFuture = new QueryFutureList<>(call);
QueryFutureList<T> queryFuture = new QueryFutureList<>(new CallableQueryList<T>(this, spiQuery, newTxn));
backgroundExecutor.execute(queryFuture.getFutureTask());
return queryFuture;
}
@Override
public <T> PagedList<T> findPagedList(Query<T> query, Transaction transaction) {
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
int maxRows = spiQuery.getMaxRows();
if (maxRows == 0) {
throw new PersistenceException("maxRows must be specified for findPagedList() query");
}
if (spiQuery.isUseDocStore()) {
return docStore().findPagedList(createQueryRequest(Type.LIST, query, transaction));
}
return new LimitOffsetPagedList<>(this, spiQuery);
}
@Override
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
try {
request.initTransIfRequired();
return request.findIterate();
} catch (RuntimeException ex) {
request.endTransIfRequired();
throw ex;
@@ -1542,14 +1470,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> void findEach(Query<T> query, Consumer<T> consumer, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
if (request.isUseDocStore()) {
docStore().findEach(request, consumer);
return;
}
request.initTransIfRequired();
request.findEach(consumer);
// no try finally - findEach guarantee's cleanup of the transaction if required
@@ -1557,13 +1482,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> void findEachWhile(Query<T> query, Predicate<T> consumer, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
if (request.isUseDocStore()) {
docStore().findEachWhile(request, consumer);
return;
}
request.initTransIfRequired();
request.findEachWhile(consumer);
// no try finally - findEachWhile guarantee's cleanup of the transaction if required
@@ -1571,12 +1494,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> List<Version<T>> findVersions(Query<T> query, Transaction transaction) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, transaction);
try {
request.initTransIfRequired();
return request.findVersions();
} finally {
request.endTransIfRequired();
}
@@ -1589,14 +1510,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@SuppressWarnings("unchecked")
private <T> List<T> findList(Query<T> query, Transaction t, boolean findOne) {
SpiOrmQueryRequest<T> request = buildQueryRequest(Type.LIST, query, t);
request.resetBeanCacheAutoMode(findOne);
if ((t == null || !t.isSkipCache()) && request.getFromBeanCache()) {
// hit bean cache and got all results from cache
return request.getBeanCacheHits();
}
request.prepareQuery();
Object result = request.getFromQueryCache();
if (result != null) {
@@ -1605,11 +1524,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (request.isUseDocStore()) {
return docStore().findList(request);
}
try {
request.initTransIfRequired();
return request.findList();
} finally {
request.endTransIfRequired();
}
@@ -1617,7 +1534,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public SqlRow findOne(SqlQuery query, Transaction t) {
// no findId() method for SqlQuery...
// a query that is expected to return either 0 or 1 rows
List<SqlRow> list = findList(query, t);
@@ -1626,7 +1542,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public void findEach(SqlQuery query, Consumer<SqlRow> consumer, Transaction transaction) {
RelationalQueryRequest request = new RelationalQueryRequest(this, relationalQueryEngine, query, transaction);
try {
request.initTransIfRequired();
@@ -1638,7 +1553,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public void findEachWhile(SqlQuery query, Predicate<SqlRow> consumer, Transaction transaction) {
RelationalQueryRequest request = new RelationalQueryRequest(this, relationalQueryEngine, query, transaction);
try {
request.initTransIfRequired();
@@ -1650,12 +1564,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public List<SqlRow> findList(SqlQuery query, Transaction t) {
RelationalQueryRequest request = new RelationalQueryRequest(this, relationalQueryEngine, query, t);
try {
request.initTransIfRequired();
return request.findList();
} finally {
request.endTransIfRequired();
}
@@ -1702,7 +1614,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
try {
request.initTransIfRequired();
request.findEach(consumer);
} finally {
request.endTransIfRequired();
}
@@ -1714,7 +1625,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
try {
request.initTransIfRequired();
request.findEachWhile(consumer);
} finally {
request.endTransIfRequired();
}
@@ -1726,7 +1636,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
try {
request.initTransIfRequired();
return request.findList();
} finally {
request.endTransIfRequired();
}
@@ -1738,7 +1647,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
try {
request.initTransIfRequired();
return extractUnique(request.findList());
} finally {
request.endTransIfRequired();
}
@@ -1789,7 +1697,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public void updateAll(Collection<?> beans, Transaction transaction) {
if (beans == null || beans.isEmpty()) {
return;
}
@@ -1830,7 +1737,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public void insertAll(Collection<?> beans, Transaction transaction) {
if (beans == null || beans.isEmpty()) {
return;
}
@@ -1844,7 +1750,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> List<T> publish(Query<T> query, Transaction transaction) {
return executeInTrans((txn) -> persister.publish(query, txn), transaction);
}
@@ -1860,7 +1765,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> T publish(Class<T> beanType, Object id, Transaction transaction) {
Query<T> query = find(beanType).setId(id);
List<T> liveBeans = publish(query, transaction);
return (liveBeans.size() == 1) ? liveBeans.get(0) : null;
@@ -1868,13 +1772,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public <T> List<T> draftRestore(Query<T> query, Transaction transaction) {
return executeInTrans((txn) -> persister.draftRestore(query, txn), transaction);
}
@Override
public <T> T draftRestore(Class<T> beanType, Object id, Transaction transaction) {
Query<T> query = find(beanType).setId(id);
List<T> beans = draftRestore(query, transaction);
return (beans.size() == 1) ? beans.get(0) : null;
@@ -1919,7 +1821,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* Save all beans in the iterator with an explicit transaction.
*/
private int saveAllInternal(Collection<?> beans, Transaction transaction) {
if (beans == null || beans.isEmpty()) {
return 0;
}
@@ -1930,7 +1831,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
persister.save(checkEntityBean(bean), txn);
saveCount++;
}
txn.flushBatchOnCollection();
return saveCount;
}, transaction);
@@ -1957,7 +1857,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
private int delete(Class<?> beanType, Object id, Transaction transaction, boolean permanent) {
return executeInTrans((txn) -> persister.delete(beanType, id, txn, permanent), transaction);
}
@@ -2043,19 +1942,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* Delete all the beans in the iterator with an explicit transaction.
*/
private int deleteAllInternal(Collection<?> beans, Transaction transaction, boolean permanent) {
if (beans == null || beans.isEmpty()) {
return 0;
}
return executeInTrans((txn) -> {
txn.checkBatchEscalationOnCollection();
int deleteCount = 0;
for (Object bean : beans) {
persister.delete(checkEntityBean(bean), txn, permanent);
deleteCount++;
}
txn.flushBatchOnCollection();
return deleteCount;
}, transaction);
@@ -2156,7 +2052,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public boolean isSupportedType(java.lang.reflect.Type genericType) {
TypeInfo typeInfo = ParamTypeHelper.getTypeInfo(genericType);
return typeInfo != null && getBeanDescriptor(typeInfo.getBeanType()) != null;
}
@@ -2279,7 +2174,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
P result = fun.apply(wrap.transaction());
wrap.commitIfCreated();
return result;
} catch (RuntimeException e) {
wrap.endIfCreated();
throw e;
@@ -2292,7 +2186,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* Create a transaction if one is not currently active.
*/
ObtainedTransaction initTransIfRequired(Transaction t) {
if (t != null) {
return new ObtainedTransaction((SpiTransaction) t);
}
@@ -2361,16 +2254,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public Set<Property> checkUniqueness(Object bean, Transaction transaction) {
EntityBean entityBean = checkEntityBean(bean);
BeanDescriptor<?> beanDesc = getBeanDescriptor(entityBean.getClass());
BeanProperty idProperty = beanDesc.getIdProperty();
// if the ID of the Property is null we are unable to check uniqueness
if (idProperty == null) {
return Collections.emptySet();
}
Object id = idProperty.getVal(entityBean);
if (entityBean._ebean_getIntercept().isNew() && id != null) {
// Primary Key is changeable only on new models - so skip check if we are not
@@ -2383,7 +2273,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return ret;
}
}
for (BeanProperty[] props : beanDesc.getUniqueProps()) {
Set<Property> ret = checkUniqueness(entityBean, beanDesc, props, transaction);
if (ret != null) {
@@ -2400,12 +2289,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
BeanProperty idProperty = beanDesc.getIdProperty();
Query<?> query = new DefaultOrmQuery<>(beanDesc, this, expressionFactory);
ExpressionList<?> exprList = query.where();
if (!entityBean._ebean_getIntercept().isNew()) {
// if model is not new, exclude ourself.
exprList.ne(idProperty.getName(), idProperty.getVal(entityBean));
}
for (Property prop : props) {
Object value = prop.getVal(entityBean);
if (value == null) {
@@ -2413,7 +2300,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
exprList.eq(prop.getName(), value);
}
if (findCount(query, transaction) > 0) {
Set<Property> ret = new LinkedHashSet<>();
Collections.addAll(ret, props);
@@ -7,22 +7,18 @@ import java.util.HashMap;
* <p>
* Using this for now instead of String.intern() to avoid any unexpected
* increase in PermGen space.
* </p>
*/
public final class InternString {
private static final HashMap<String, String> map = new HashMap<>();
/**
* Return the shared instance of this string.
*/
public static String intern(String s) {
if (s == null) {
return null;
}
//noinspection SynchronizationOnStaticField
synchronized (map) {
String v = map.get(s);
@@ -32,7 +28,6 @@ public final class InternString {
map.put(s, s);
return s;
}
}
}
}
@@ -505,7 +505,7 @@ public class InternalConfiguration {
private DataTimeZone initDataTimeZone() {
String tz = serverConfig.getDataTimeZone();
if (tz == null) {
if (isMySqlOrMariaDB(getPlatform())) {
if (isMySql(getPlatform())) {
return new MySqlDataTimeZone();
}
return new NoDataTimeZone();
@@ -517,8 +517,8 @@ public class InternalConfiguration {
}
}
private boolean isMySqlOrMariaDB(Platform platform) {
return platform.base() == Platform.MYSQL || platform.base() == Platform.MARIADB;
private boolean isMySql(Platform platform) {
return platform.base() == Platform.MYSQL;
}
public DataTimeZone getDataTimeZone() {
@@ -8,7 +8,9 @@ import io.ebean.bean.CallStack;
*/
class NoopCallOriginFactory implements CallOriginFactory {
private final CallOrigin COMMON = new CallStack(Thread.currentThread().getStackTrace(), 0, 0);
private static final StackTraceElement E0 = new StackTraceElement("none", "none", "none", 0);
private final CallOrigin COMMON = new CallStack(new StackTraceElement[]{E0}, 0, 0);
@Override
public CallOrigin createCallOrigin() {
@@ -698,8 +698,9 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
@Override
@SuppressWarnings("unchecked")
public Object getFromQueryCache() {
if (query.getUseQueryCache() == CacheMode.OFF || (transaction != null && transaction.isSkipCache())) {
if (query.getUseQueryCache() == CacheMode.OFF
|| (transaction != null && transaction.isSkipCache())
|| ebeanServer.isDisableL2Cache()) {
return null;
} else {
cacheKey = query.queryHash();
@@ -188,7 +188,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
PersistExecute persistExecute, PersistRequest.Type type, int flags) {
super(server, t, persistExecute);
this.entityBean = (EntityBean) bean;
this.intercept = entityBean._ebean_getIntercept();
@@ -204,7 +203,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
if (Flags.isRecurse(flags)) {
this.persistCascade = t.isPersistCascade();
}
if (this.type == Type.UPDATE) {
if (intercept.isNew()) {
// 'stateless update' - set loaded properties as dirty
@@ -279,7 +277,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Init the transaction and also check for batch on cascade escalation.
*/
public void initTransIfRequiredWithBatchCascade() {
if (createImplicitTransIfRequired()) {
docStoreMode = calcDocStoreMode(transaction, type);
}
@@ -317,9 +314,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
private void onUpdateGeneratedProperties() {
for (BeanProperty prop : beanDescriptor.propertiesGenUpdate()) {
GeneratedProperty generatedProperty = prop.getGeneratedProperty();
if (prop.isVersion()) {
if (isLoadedProperty(prop)) {
@@ -451,7 +446,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Return true if any of the given properties are dirty.
*/
public boolean hasDirtyProperty(int[] propertyPositions) {
for (int propertyPosition : propertyPositions) {
if (dirtyProperties[propertyPosition]) {
return true;
@@ -517,7 +511,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
*/
@Override
public void docStoreUpdate(DocStoreUpdateContext txn) throws IOException {
switch (type) {
case INSERT:
beanDescriptor.docStoreInsert(idValue, this, txn);
@@ -554,7 +547,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
public void addToPersistMap(BeanPersistIdMap beanPersistMap) {
beanPersistMap.add(beanDescriptor, type, idValue);
}
@@ -564,19 +556,15 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
case INSERT:
beanPersistListener.inserted(bean);
break;
case UPDATE:
beanPersistListener.updated(bean, updatedProperties);
break;
case DELETE:
beanPersistListener.deleted(bean);
break;
case DELETE_SOFT:
beanPersistListener.softDeleted(bean);
break;
default:
}
}
@@ -785,7 +773,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
case INSERT:
executeInsert();
return -1;
case UPDATE:
if (beanPersistListener != null) {
// store the updated properties for sending later
@@ -793,15 +780,12 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
executeUpdate();
return -1;
case DELETE_SOFT:
prepareForSoftDelete();
executeSoftDelete();
return -1;
case DELETE:
return executeDelete();
default:
throw new RuntimeException("Invalid type " + type);
}
@@ -811,13 +795,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Soft delete is executed as update so we want to set deleted=true property.
*/
private void prepareForSoftDelete() {
beanDescriptor.setSoftDeleteValue(entityBean);
}
@Override
public int executeOrQueue() {
boolean batch = isBatchThisRequest();
try {
BatchControl control = transaction.getBatchControl();
@@ -827,7 +809,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
if (batch) {
control = persistExecute.createBatchControl(transaction);
return control.executeOrQueue(this, true);
} else {
return executeNoBatch();
}
@@ -926,7 +907,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
controllerPost();
}
setNotifyCache();
boolean isChangeLog = beanDescriptor.isChangeLog();
if (type == Type.UPDATE && (isChangeLog || notifyCache || docStoreMode == DocStoreMode.UPDATE)) {
// get the dirty properties for update notification to the doc store
@@ -935,16 +915,13 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
if (isChangeLog) {
changeLog();
}
// if bean persisted again then should result in an update
intercept.setLoaded();
if (isInsert()) {
postInsert();
}
addPostCommitListeners();
notifyCacheOnPostExecute();
if (isLogSummary()) {
logSummary();
}
@@ -994,7 +971,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
private void logSummary() {
String draft = (beanDescriptor.isDraftable() && !publish) ? " draft[true]" : "";
String name = beanDescriptor.getName();
switch (type) {
@@ -1136,7 +1112,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* of queue events or list of update events.
*/
public void addDocStoreUpdates(DocStoreUpdates docStoreUpdates) {
if (type == Type.UPDATE) {
beanDescriptor.docStoreUpdateEmbedded(this, docStoreUpdates);
}
@@ -1165,7 +1140,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* </p>
*/
private boolean determineUpdateAllLoadedProperties() {
Boolean txnUpdateAll = transaction.isUpdateAllLoadedProperties();
if (txnUpdateAll != null) {
// use the setting explicitly set on the transaction
@@ -1174,7 +1148,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
// if using batch use the server default setting
requestUpdateAllLoadedProps = isBatchThisRequest() && ebeanServer.isUpdateAllPropertiesInBatch();
}
return requestUpdateAllLoadedProps;
}
@@ -1196,25 +1169,21 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Return the key for an update persist request.
*/
public String getUpdatePlanHash() {
StringBuilder key;
if (determineUpdateAllLoadedProperties()) {
key = intercept.getLoadedPropertyKey();
} else {
key = intercept.getDirtyPropertyKey();
}
BeanProperty versionProperty = beanDescriptor.getVersionProperty();
if (versionProperty != null) {
if (intercept.isLoadedProperty(versionProperty.getPropertyIndex())) {
key.append('v');
}
}
if (publish) {
key.append('p');
}
return key.toString();
}
@@ -1380,13 +1349,10 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Build the bean update for the L2 cache.
*/
public void addBeanUpdate(CacheChangeSet changeSet) {
if (!updatedManysOnly || collectionChanges != null) {
boolean updateNaturalKey = false;
String key = beanDescriptor.cacheKey(idValue);
Map<String, Object> changes = new LinkedHashMap<>();
EntityBean bean = getEntityBean();
boolean[] dirtyProperties = getDirtyProperties();
@@ -1410,7 +1376,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
// add element collection update
changes.putAll(collectionChanges);
}
changeSet.addBeanUpdate(beanDescriptor, key, changes, updateNaturalKey, getVersion());
}
}
@@ -39,6 +39,7 @@ import io.ebean.util.SplitName;
import io.ebeaninternal.api.BeanCacheResult;
import io.ebeaninternal.api.CQueryPlanKey;
import io.ebeaninternal.api.ConcurrencyMode;
import io.ebeaninternal.api.LoadBeanContext;
import io.ebeaninternal.api.LoadContext;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
@@ -105,7 +106,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -219,9 +219,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
private final BeanProperty draftDirty;
/**
* Map of BeanProperty Linked so as to preserve order.
*/
private final LinkedHashMap<String, BeanProperty> propMap;
/**
@@ -234,44 +231,17 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
*/
private final Map<String, BeanPropertyAssoc<?>> tablePath = new HashMap<>();
/**
* The type of bean this describes.
*/
final Class<T> beanType;
final Class<?> rootBeanType;
/**
* This is not sent to a remote client.
*/
private final BeanDescriptorMap owner;
final String[] properties;
/**
* Intercept pre post on insert,update, and delete .
*/
private volatile BeanPersistController persistController;
private final BeanPostLoad beanPostLoad;
private final BeanPostConstructListener beanPostConstructListener;
/**
* Listens for post commit insert update and delete events.
*/
private volatile BeanPersistController persistController;
private volatile BeanPersistListener persistListener;
private final BeanQueryAdapter queryAdapter;
/**
* If set overrides the find implementation. Server side only.
*/
private final BeanFindController beanFinder;
/**
* Used for fine grain filtering for the change log.
*/
private final ChangeLogFilter changeLogFilter;
/**
@@ -281,22 +251,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
private final boolean abstractType;
/**
* Derived list of properties that make up the unique id.
*/
private final BeanProperty idProperty;
private final int idPropertyIndex;
/**
* Derived list of properties that are used for version concurrency checking.
*/
private final BeanProperty versionProperty;
private final int versionPropertyIndex;
private final BeanProperty whenModifiedProperty;
private final BeanProperty whenCreatedProperty;
/**
@@ -313,14 +273,9 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Scalar mutable properties (need to dirty check on update).
*/
private final BeanProperty[] propertiesMutable;
private final BeanPropertyAssocOne<?> unidirectional;
private final BeanProperty orderColumn;
/**
* list of properties that are Lists/Sets/Maps (Derived).
*/
private final BeanProperty[] propertiesNonMany;
private final BeanProperty[] propertiesAggregate;
private final BeanPropertyAssocMany<?>[] propertiesMany;
@@ -332,25 +287,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* list of properties that are associated beans and not embedded (Derived).
*/
private final BeanPropertyAssocOne<?>[] propertiesOne;
private final BeanPropertyAssocOne<?>[] propertiesOneImported;
private final BeanPropertyAssocOne<?>[] propertiesOneImportedSave;
private final BeanPropertyAssocOne<?>[] propertiesOneImportedDelete;
//private final BeanPropertyAssocOne<?>[] propertiesOneExported;
private final BeanPropertyAssocOne<?>[] propertiesOneExportedSave;
private final BeanPropertyAssocOne<?>[] propertiesOneExportedDelete;
/**
* list of properties that are embedded beans.
*/
private final BeanPropertyAssocOne<?>[] propertiesEmbedded;
/**
* List of the scalar properties excluding id and secondary table properties.
*/
private final BeanProperty[] propertiesBaseScalar;
private final BeanProperty[] propertiesTransient;
/**
@@ -382,11 +326,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
private final EntityBean prototypeEntityBean;
private final IdBinder idBinder;
private String idBinderInLHSSql;
private String idBinderIdSql;
private String deleteByIdSql;
private String deleteByIdInSql;
private String whereIdInSql;
@@ -394,29 +335,19 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
private String softDeleteByIdInSql;
private final String name;
private final String baseTableAlias;
private final boolean cacheSharableBeans;
private final String docStoreQueueId;
private final BeanDescriptorDraftHelp<T> draftHelp;
private final BeanDescriptorCacheHelp<T> cacheHelp;
private final BeanDescriptorJsonHelp<T> jsonHelp;
private DocStoreBeanAdapter<T> docStoreAdapter;
private DocumentMapping docMapping;
private boolean docStoreEmbeddedInvalidation;
private final String defaultSelectClause;
private SpiEbeanServer ebeanServer;
/**
* Construct the BeanDescriptor.
*/
public BeanDescriptor(BeanDescriptorMap owner, DeployBeanDescriptor<T> deploy) {
this.owner = owner;
this.multiValueSupported = owner.isMultiValueSupported();
this.entityType = deploy.getEntityType();
@@ -431,7 +362,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.namedQuery = deploy.getNamedQuery();
this.namedRawSql = deploy.getNamedRawSql();
this.inheritInfo = deploy.getInheritInfo();
this.beanFinder = deploy.getBeanFinder();
this.persistController = deploy.getPersistController();
this.persistListener = deploy.getPersistListener();
@@ -439,7 +369,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.beanPostLoad = deploy.getPostLoad();
this.queryAdapter = deploy.getQueryAdapter();
this.changeLogFilter = deploy.getChangeLogFilter();
this.defaultSelectClause = deploy.getDefaultSelectClause();
this.identityMode = deploy.buildIdentityMode();
this.idType = identityMode.getIdType();
@@ -449,7 +378,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.selectLastInsertedIdDraft = deploy.getSelectLastInsertedIdDraft();
this.concurrencyMode = deploy.getConcurrencyMode();
this.indexDefinitions = deploy.getIndexDefinitions();
this.readAuditing = deploy.isReadAuditing();
this.draftable = deploy.isDraftable();
this.draftableElement = deploy.isDraftableElement();
@@ -464,10 +392,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.partitionMeta = deploy.getPartitionMeta();
this.storageEngine = deploy.getStorageEngine();
this.autoTunable = beanFinder == null && (entityType == EntityType.ORM || entityType == EntityType.VIEW);
// helper object used to derive lists of properties
DeployBeanPropertyLists listHelper = new DeployBeanPropertyLists(owner, this, deploy);
this.softDeleteProperty = listHelper.getSoftDeleteProperty();
// if formula is set, the property is virtual only (there is no column in db) the formula must evaluate to true,
// if there is a join to a deleted bean. Example: '@Formula(select = "${ta}.user_id is null")'
@@ -503,22 +429,17 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.propertiesGenInsert = listHelper.getGeneratedInsert();
this.propertiesGenUpdate = listHelper.getGeneratedUpdate();
this.idOnlyReference = isIdOnlyReference(propertiesBaseScalar);
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
this.cacheHelp = new BeanDescriptorCacheHelp<>(this, owner.getCacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported);
this.jsonHelp = new BeanDescriptorJsonHelp<>(this);
this.draftHelp = new BeanDescriptorDraftHelp<>(this);
this.docStoreAdapter = owner.createDocStoreBeanAdapter(this, deploy);
this.docStoreQueueId = docStoreAdapter.getQueueId();
// Check if there are no cascade save associated beans ( subject to change
// in initialiseOther()). Note that if we are in an inheritance hierarchy
// then we also need to check every BeanDescriptors in the InheritInfo as
// well. We do that later in initialiseOther().
saveRecurseSkippable = (0 == (propertiesOneExportedSave.length + propertiesOneImportedSave.length + propertiesManySave.length));
// Check if there are no cascade delete associated beans (also subject to
@@ -529,7 +450,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.idBinder = owner.createIdBinder(idProperty);
this.whenModifiedProperty = findWhenModifiedProperty();
this.whenCreatedProperty = findWhenCreatedProperty();
// derive the index position of the Id and Version properties
this.abstractType = Modifier.isAbstract(beanType.getModifiers());
if (abstractType) {
@@ -537,7 +457,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.versionPropertyIndex = -1;
this.unloadProperties = new int[0];
this.propertiesIndex = new BeanProperty[0];
} else {
EntityBeanIntercept ebi = prototypeEntityBean._ebean_getIntercept();
this.idPropertyIndex = (idProperty == null) ? -1 : ebi.findProperty(idProperty.getName());
@@ -568,23 +487,19 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* These properties need to be unloaded when populating beans for queries.
*/
private int[] derivePropertiesToUnload(EntityBean prototypeEntityBean) {
boolean[] loaded = prototypeEntityBean._ebean_getIntercept().getLoaded();
int[] props = new int[loaded.length];
int pos = 0;
// collect the positions of the properties initialised in the default constructor.
for (int i = 0; i < loaded.length; i++) {
if (loaded[i]) {
props[pos++] = i;
}
}
if (pos == 0) {
// nothing set in the constructor
return new int[0];
}
// populate a smaller/minimal array
int[] unload = new int[pos];
System.arraycopy(props, 0, unload, 0, pos);
@@ -665,14 +580,11 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* <p>
* These properties need to be initialised prior to the association properties
* as they are used to get the imported and exported properties.
* </p>
*/
void initialiseId(BeanDescriptorInitContext initContext) {
if (logger.isTraceEnabled()) {
logger.trace("BeanDescriptor initialise " + fullName);
}
if (draftable) {
initContext.addDraft(baseTable, draftTable);
}
@@ -680,7 +592,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
// add mapping (used to swap out baseTable for asOf queries)
initContext.addHistory(baseTable, baseTableAsOf);
}
if (inheritInfo != null) {
inheritInfo.setDescriptor(this);
}
@@ -695,19 +606,17 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Initialise the exported and imported parts for associated properties.
*/
public void initialiseOther(BeanDescriptorInitContext initContext) {
for (BeanPropertyAssocMany<?> many : propertiesManyToMany) {
// register associated draft table for M2M intersection
many.registerDraftIntersectionTable(initContext);
}
if (historySupport) {
// history support on this bean so check all associated intersection tables
// and if they are not excluded register the associated 'with history' table
for (BeanPropertyAssocMany<?> aPropertiesManyToMany : propertiesManyToMany) {
for (BeanPropertyAssocMany<?> manyToMany : propertiesManyToMany) {
// register associated history table for M2M intersection
if (!aPropertiesManyToMany.isExcludedFromHistory()) {
TableJoin intersectionTableJoin = aPropertiesManyToMany.getIntersectionTableJoin();
if (!manyToMany.isExcludedFromHistory()) {
TableJoin intersectionTableJoin = manyToMany.getIntersectionTableJoin();
initContext.addHistoryIntersection(intersectionTableJoin.getTable());
}
}
@@ -730,11 +639,9 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
idBinderIdSql = idBinder.getBindIdSql(baseTableAlias);
String idBinderInLHSSqlNoAlias = idBinder.getBindIdInSql(null);
String idEqualsSql = idBinder.getBindIdSql(null);
deleteByIdSql = "delete from " + baseTable + " where " + idEqualsSql;
whereIdInSql = " where " + idBinderInLHSSqlNoAlias + " ";
deleteByIdInSql = "delete from " + baseTable + whereIdInSql;
if (softDelete) {
softDeleteByIdSql = "update " + baseTable + " set " + getSoftDeleteDbSet() + " where " + idEqualsSql;
softDeleteByIdInSql = "update " + baseTable + " set " + getSoftDeleteDbSet() + " where " + idBinderInLHSSqlNoAlias + " ";
@@ -765,7 +672,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return false;
}
boolean hasCircularImportedIdTo(BeanDescriptor sourceDesc) {
boolean hasCircularImportedIdTo(BeanDescriptor<?> sourceDesc) {
for (BeanPropertyAssocOne<?> assocOne : propertiesOneImportedSave) {
if (assocOne.getTargetDescriptor() == sourceDesc) {
return true;
@@ -792,7 +699,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Perform last initialisation for the descriptor.
*/
void initLast() {
for (BeanProperty prop : propertiesNonTransient) {
if (prop.isUnique()) {
propertiesUnique.add(new BeanProperty[]{prop});
@@ -895,13 +801,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
public void merge(EntityBean bean, EntityBean existing) {
EntityBeanIntercept fromEbi = bean._ebean_getIntercept();
EntityBeanIntercept toEbi = existing._ebean_getIntercept();
int propertyLength = toEbi.getPropertyLength();
String[] names = getProperties();
for (int i = 0; i < propertyLength; i++) {
if (fromEbi.isLoadedProperty(i)) {
@@ -977,14 +880,11 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Return the bean change for an update generating 'new values' and 'old values' in JSON form.
*/
private BeanChange updateBeanChange(PersistRequestBean<T> request) {
try {
BeanChangeJson changeJson = new BeanChangeJson(this, request.isStatelessUpdate());
request.getEntityBeanIntercept().addDirtyPropertyValues(changeJson);
changeJson.flush();
return beanChange(ChangeType.UPDATE, request.getBeanId(), changeJson.newJson(), changeJson.oldJson());
} catch (RuntimeException e) {
logger.error("Failed to write ChangeLog entry for update", e);
return null;
@@ -995,16 +895,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Return the bean change for an insert.
*/
private BeanChange insertBeanChange(PersistRequestBean<T> request) {
try {
StringWriter writer = new StringWriter(200);
SpiJsonWriter jsonWriter = createJsonWriter(writer);
jsonWriteForInsert(jsonWriter, request.getEntityBean());
jsonWriter.flush();
return beanChange(ChangeType.INSERT, request.getBeanId(), writer.toString(), null);
} catch (IOException e) {
logger.error("Failed to write ChangeLog entry for insert", e);
return null;
@@ -1063,12 +959,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* concurrency checking.
*/
private SqlUpdate deleteByIdList(List<Object> idList, DeleteMode mode) {
String baseSql = mode.isHard() ? deleteByIdInSql : softDeleteByIdInSql;
StringBuilder sb = new StringBuilder(baseSql);
String inClause = idBinder.getIdInValueExprDelete(idList.size());
sb.append(inClause);
DefaultSqlUpdate delete = new DefaultSqlUpdate(sb.toString());
idBinder.addIdInBindValues(delete, idList);
return delete;
@@ -1079,15 +973,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* concurrency checking.
*/
private SqlUpdate deleteById(Object id, DeleteMode mode) {
String baseSql = mode.isHard() ? deleteByIdSql : softDeleteByIdSql;
DefaultSqlUpdate sqlDelete = new DefaultSqlUpdate(baseSql);
Object[] bindValues = idBinder.getBindValues(id);
for (Object bindValue : bindValues) {
sqlDelete.setParameter(bindValue);
}
return sqlDelete;
}
@@ -1100,9 +991,9 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
void initialiseFkeys() {
for (BeanPropertyAssocOne<?> aPropertiesOneImported : propertiesOneImported) {
if (!aPropertiesOneImported.isFormula()) {
aPropertiesOneImported.addFkey();
for (BeanPropertyAssocOne<?> oneImported : propertiesOneImported) {
if (!oneImported.isFormula()) {
oneImported.addFkey();
}
}
}
@@ -1210,12 +1101,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Build the Document mapping recursively with the given prefix relative to the root of the document.
*/
public void docStoreMapping(final DocMappingBuilder mapping, final String prefix) {
if (prefix != null && idProperty != null) {
// id property not included in the
idProperty.docStoreMapping(mapping, prefix);
}
if (inheritInfo != null) {
String discCol = inheritInfo.getDiscriminatorColumn();
if (Types.VARCHAR == inheritInfo.getDiscriminatorType()) {
@@ -1702,13 +1591,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Trim query plans not used since the passed in epoch time.
*/
void trimQueryPlans(long unusedSince) {
Iterator<CQueryPlan> it = queryPlanCache.values().iterator();
while (it.hasNext()) {
CQueryPlan queryPlan = it.next();
if (queryPlan.getLastQueryTime() < unusedSince) {
it.remove();
}
}
queryPlanCache.values().removeIf(queryPlan -> queryPlan.getLastQueryTime() < unusedSince);
}
/**
@@ -1804,9 +1687,9 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Find a property annotated with @WhenCreated or @CreatedTimestamp.
*/
private BeanProperty findWhenCreatedProperty() {
for (BeanProperty aPropertiesBaseScalar : propertiesBaseScalar) {
if (aPropertiesBaseScalar.isGeneratedWhenCreated()) {
return aPropertiesBaseScalar;
for (BeanProperty baseScalar : propertiesBaseScalar) {
if (baseScalar.isGeneratedWhenCreated()) {
return baseScalar;
}
}
return null;
@@ -1816,10 +1699,9 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Find a property annotated with @WhenModified or @UpdatedTimestamp.
*/
private BeanProperty findWhenModifiedProperty() {
for (BeanProperty aPropertiesBaseScalar : propertiesBaseScalar) {
if (aPropertiesBaseScalar.isGeneratedWhenModified()) {
return aPropertiesBaseScalar;
for (BeanProperty baseScalar : propertiesBaseScalar) {
if (baseScalar.isGeneratedWhenModified()) {
return baseScalar;
}
}
return null;
@@ -1829,14 +1711,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Return the many property included in the query or null if one is not.
*/
public BeanPropertyAssocMany<?> getManyProperty(SpiQuery<?> query) {
OrmQueryDetail detail = query.getDetail();
for (BeanPropertyAssocMany<?> aPropertiesMany : propertiesMany) {
if (detail.includesPath(aPropertiesMany.getName())) {
return aPropertiesMany;
for (BeanPropertyAssocMany<?> many : propertiesMany) {
if (detail.includesPath(many.getName())) {
return many;
}
}
return null;
}
@@ -1905,7 +1785,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Bind the idValue to the preparedStatement.
* <p>
* This takes care of the various id types such as embedded beans etc.
* </p>
*/
public void bindId(DataBind dataBind, Object idValue) throws SQLException {
idBinder.bindId(dataBind, idValue);
@@ -1915,7 +1794,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Return the id as an array of scalar bindable values.
* <p>
* This 'flattens' any EmbeddedId or multiple Id property cases.
* </p>
*/
public Object[] getBindIdValues(Object idValue) {
return idBinder.getBindValues(idValue);
@@ -1940,7 +1818,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
try {
EntityBean bean = (EntityBean) prototypeEntityBean._ebean_newInstance();
if (beanPostConstructListener != null) {
beanPostConstructListener.autowire(bean); // calls all registered listeners
beanPostConstructListener.postConstruct(bean); // calls first the @PostConstruct method and then the listeners
@@ -1959,7 +1836,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
}
return bean;
} catch (Exception ex) {
throw new PersistenceException(ex);
}
@@ -1999,7 +1875,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
*/
@SuppressWarnings("unchecked")
public T createReference(Boolean readOnly, boolean disableLazyLoad, Object id, PersistenceContext pc) {
if (cacheSharableBeans && !disableLazyLoad && !Boolean.FALSE.equals(readOnly)) {
CachedBeanData d = cacheHelp.beanCacheGetData(cacheKey(id));
if (d != null) {
@@ -2016,10 +1891,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
if (inheritInfo != null && !inheritInfo.isConcrete()) {
return findReferenceBean(id, pc);
}
EntityBean eb = createEntityBean();
id = convertSetId(id, eb);
EntityBeanIntercept ebi = eb._ebean_getIntercept();
if (disableLazyLoad) {
ebi.setDisableLazyLoad(true);
@@ -2034,9 +1907,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
contextPut(pc, id, eb);
ebi.setPersistenceContext(pc);
}
return (T) eb;
} catch (Exception ex) {
throw new PersistenceException(ex);
}
@@ -2086,14 +1957,15 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
public BeanProperty findPropertyFromPath(String path) {
BeanDescriptor<?> other = this;
while (true) {
String[] split = SplitName.splitBegin(path);
if (split[1] == null) {
return other._findBeanProperty(split[0]);
}
BeanPropertyAssoc<?> assocProp = (BeanPropertyAssoc<?>) other._findBeanProperty(split[0]);
if (assocProp == null) {
throw new IllegalStateException("Unknown property path [" + split[0] + "] from[" + path + "]");
}
BeanDescriptor<?> targetDesc = assocProp.getTargetDescriptor();
path = split[1];
other = targetDesc;
}
@@ -2114,13 +1986,11 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return result;
}
String[] splitBegin = SplitName.splitBegin(path);
BeanProperty beanProperty = result.findProperty(splitBegin[0]);
if (beanProperty instanceof BeanPropertyAssoc<?>) {
BeanPropertyAssoc<?> assocProp = (BeanPropertyAssoc<?>) beanProperty;
path = splitBegin[1];
result = assocProp.getTargetDescriptor();
} else {
throw new PersistenceException("Invalid path " + path + " from " + result.getFullName());
}
@@ -2147,7 +2017,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* For bidirectional this is a real property on the bean. For unidirectional
* relationships we have this 'shadow' property which is not externally
* visible.
* </p>
*/
public BeanPropertyAssocOne<?> getUnidirectional() {
BeanDescriptor<?> other = this;
@@ -2168,7 +2037,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* <p>
* If this is false and the Id is null it is assumed that a database auto
* increment feature is being used to populate the id.
* </p>
*/
public boolean isUseIdGenerator() {
return idGenerator != null;
@@ -2195,7 +2063,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* <p>
* If this BeanDescriptor is for a table then this returns the table name
* instead.
* </p>
*/
@Override
@Nonnull
@@ -2315,7 +2182,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Return the Id value for the bean with embeddedId beans converted into maps.
* <p>
* The usage is to provide simple id types for JSON processing (for embeddedId's).
* </p>
*/
public Object getIdForJson(Object bean) {
return idBinder.getIdForJson((EntityBean) bean);
@@ -2325,7 +2191,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Convert the idValue assuming embeddedId values are Maps.
* <p>
* The usage is to provide simple id types for JSON processing (for embeddedId's).
* </p>
*/
Object convertIdFromJson(Object idValue) {
return idBinder.convertIdFromJson(idValue);
@@ -2359,7 +2224,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* <p>
* If the bean is not null, the id value is set to the id property of the bean
* after it has been converted to the correct type.
* </p>
*/
public Object convertSetId(Object idValue, EntityBean bean) {
return idBinder.convertSetId(idValue, bean);
@@ -2385,9 +2249,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
public void sort(List<T> list, String sortByClause) {
ElComparator<T> comparator = getElComparator(sortByClause);
list.sort(comparator);
list.sort(getElComparator(sortByClause));
}
public ElComparator<T> getElComparator(String propNameOrSortBy) {
@@ -2398,10 +2260,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Register all the assoc many properties on this bean that are not populated with the load context.
* <p>
* This provides further lazy loading via the load context.
* </p>
*/
public void lazyLoadRegister(String prefix, EntityBeanIntercept ebi, EntityBean bean, LoadContext loadContext) {
// load the List/Set/Map proxy objects (deferred fetching of lists)
BeanPropertyAssocMany<?>[] manys = propertiesMany();
for (BeanPropertyAssocMany<?> many : manys) {
@@ -2409,7 +2269,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
BeanCollection<?> ref = many.createReferenceIfNull(bean);
if (ref != null && !ref.isRegisteredWithLoadContext()) {
String path = SplitName.add(prefix, many.getName());
loadContext.register(path, ref);
loadContext.register(path, many, ref);
}
}
}
@@ -2420,16 +2280,18 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* define a Reference for the collection and not invoke a query.
*/
public boolean lazyLoadMany(EntityBeanIntercept ebi) {
return lazyLoadMany(ebi, null);
}
public boolean lazyLoadMany(EntityBeanIntercept ebi, LoadBeanContext parent) {
int lazyLoadProperty = ebi.getLazyLoadPropertyIndex();
if (lazyLoadProperty == -1) {
return false;
}
if (inheritInfo != null) {
return descOf(ebi.getOwner().getClass()).lazyLoadMany(ebi, lazyLoadProperty);
return descOf(ebi.getOwner().getClass()).lazyLoadMany(ebi, lazyLoadProperty, parent);
}
return lazyLoadMany(ebi, lazyLoadProperty);
return lazyLoadMany(ebi, lazyLoadProperty, parent);
}
/**
@@ -2442,13 +2304,15 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
/**
* Check for lazy loading of many property.
*/
private boolean lazyLoadMany(EntityBeanIntercept ebi, int lazyLoadProperty) {
private boolean lazyLoadMany(EntityBeanIntercept ebi, int lazyLoadProperty, LoadBeanContext loadBeanContext) {
BeanProperty lazyLoadBeanProp = propertiesIndex[lazyLoadProperty];
if (lazyLoadBeanProp instanceof BeanPropertyAssocMany<?>) {
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>) lazyLoadBeanProp;
manyProp.createReference(ebi.getOwner());
final BeanCollection<?> collection = manyProp.createReference(ebi.getOwner());
ebi.setLoadedLazy();
if (loadBeanContext != null) {
loadBeanContext.register(manyProp, collection);
}
return true;
}
return false;
@@ -2468,7 +2332,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
*/
@SuppressWarnings("unchecked")
private ElComparator<T> createComparator(String sortByClause) {
SortByClause sortBy = SortByClauseParser.parse(sortByClause);
if (sortBy.size() == 1) {
// simple comparator for a single property
@@ -2477,24 +2340,20 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
// create a compound comparator based on the list of properties
ElComparator<T>[] comparators = new ElComparator[sortBy.size()];
List<SortByClause.Property> sortProps = sortBy.getProperties();
for (int i = 0; i < sortProps.size(); i++) {
SortByClause.Property sortProperty = sortProps.get(i);
comparators[i] = createPropertyComparator(sortProperty);
}
return new ElComparatorCompound<>(comparators);
}
private ElComparator<T> createPropertyComparator(SortByClause.Property sortProp) {
ElPropertyValue elGetValue = getElGetValue(sortProp.getName());
if (elGetValue == null) {
logger.error("Sort property [" + sortProp + "] not found in " + beanType + ". Cannot sort.");
return new ElComparatorNoop<>();
}
if (elGetValue.isAssocMany()) {
logger.error("Sort property [" + sortProp + "] in " + beanType + " is a many-property. Cannot sort.");
return new ElComparatorNoop<>();
@@ -2539,7 +2398,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Similar to ElPropertyValue but also uses foreign key shortcuts.
* <p>
* The foreign key shortcuts means we can avoid unnecessary joins.
* </p>
*/
public ElPropertyDeploy getElPropertyDeploy(String propName) {
ElPropertyDeploy elProp = elDeployCache.get(propName);
@@ -2560,7 +2418,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
ElPropertyValue buildElGetValue(String propName, ElPropertyChainBuilder chain, boolean propertyDeploy) {
if (propertyDeploy && chain != null) {
ElPropertyDeploy fk = elDeployCache.get(propName);
if (fk instanceof BeanFkeyProperty) {
@@ -2568,17 +2425,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return ((BeanFkeyProperty) fk).create(chain.getExpression(), chain.isContainsMany());
}
}
int basePos = propName.indexOf('.');
if (basePos > -1) {
// nested or embedded property
String baseName = propName.substring(0, basePos);
BeanProperty assocProp = _findBeanProperty(baseName);
if (assocProp == null) {
return null;
}
String remainder = propName.substring(basePos + 1);
return assocProp.buildElPropertyValue(propName, remainder, chain, propertyDeploy);
}
@@ -2639,7 +2493,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* <p>
* This searches this BeanDescriptor and then searches further down the
* inheritance tree (not up).
* </p>
*/
@Override
public BeanProperty findProperty(String propName) {
@@ -2666,11 +2519,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Reset the many properties to empty state ready for reloading.
*/
public void resetManyProperties(Object dbBean) {
EntityBean bean = (EntityBean) dbBean;
for (BeanPropertyAssocMany<?> aPropertiesMany : propertiesMany) {
if (aPropertiesMany.isCascadeRefresh()) {
aPropertiesMany.resetMany(bean);
for (BeanPropertyAssocMany<?> many : propertiesMany) {
if (many.isCascadeRefresh()) {
many.resetMany(bean);
}
}
}
@@ -2680,7 +2532,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* <p>
* This means is has no relationships and has readOnly=true in its cache
* options.
* </p>
*/
public boolean isCacheSharableBeans() {
return cacheSharableBeans;
@@ -2781,8 +2632,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* De-register the BeanPersistListener.
*/
public void deregister(BeanPersistListener listener) {
// volatile read...
BeanPersistListener currentListener = persistListener;
if (currentListener != null) {
if (currentListener instanceof ChainedBeanPersistListener) {
@@ -2798,8 +2647,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* De-register the BeanPersistController.
*/
public void deregister(BeanPersistController controller) {
// volatile read...
BeanPersistController currentController = persistController;
if (currentController != null) {
if (currentController instanceof ChainedBeanPersistController) {
@@ -2815,9 +2662,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Register the new BeanPersistController.
*/
public void register(BeanPersistListener newPersistListener) {
if (newPersistListener.isRegisterFor(beanType)) {
// volatile read...
BeanPersistListener currentListener = persistListener;
if (currentListener == null) {
persistListener = newPersistListener;
@@ -2837,18 +2682,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Register the new BeanPersistController.
*/
public void register(BeanPersistController newController) {
if (newController.isRegisterFor(beanType)) {
// volatile read...
BeanPersistController currentController = persistController;
if (currentController == null) {
persistController = newController;
} else {
if (currentController instanceof ChainedBeanPersistController) {
// add it to the existing chain
persistController = ((ChainedBeanPersistController) currentController).register(newController);
} else {
// build new chain of the 2
persistController = new ChainedBeanPersistController(currentController, newController);
}
}
@@ -2901,17 +2742,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
/**
* Return the dependent tables for a view based entity.
* <p>
* These tables
* </p>
*/
public String[] getDependentTables() {
return dependentTables;
}
/**
* Return the base table. Only properties mapped to the base table are by
* default persisted.
* Return the base table. Only properties mapped to the base table are by default persisted.
*/
@Override
public String getBaseTable() {
@@ -3012,7 +2849,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
@Override
public ExtraJoin extraJoin(String propertyPath) {
ElPropertyValue elGetValue = getElGetValue(propertyPath);
if (elGetValue != null) {
BeanProperty beanProperty = elGetValue.getBeanProperty();
@@ -3150,7 +2986,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* <p>
* This is only used with Identity columns and getGeneratedKeys is not
* supported.
* </p>
*/
public String getSelectLastInsertedId(boolean publish) {
return publish ? selectLastInsertedId : selectLastInsertedIdDraft;
@@ -3198,8 +3033,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
/**
* Return the beans that are embedded. These share the base table with the
* owner bean.
* Return the beans that are embedded. These share the base table with the owner bean.
*/
public BeanPropertyAssocOne<?>[] propertiesEmbedded() {
return propertiesEmbedded;
@@ -3252,12 +3086,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* @param insertMode true if the 'root request' was an insert rather than an update
*/
public boolean isInsertMode(EntityBeanIntercept ebi, boolean insertMode) {
if (ebi.isLoaded()) {
// must be an update as the bean is loaded
return false;
}
if (idProperty.isEmbedded()) {
// not using Id generator so just base on isLoaded()
return !ebi.isLoaded();
@@ -3329,7 +3161,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
public ConcurrencyMode getConcurrencyMode(EntityBeanIntercept ebi) {
if (!hasVersionProperty(ebi)) {
return ConcurrencyMode.NONE;
} else {
@@ -3350,15 +3181,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Populate the diff for updates with flattened non-null property values.
*/
public void diff(String prefix, Map<String, ValuePair> map, EntityBean newBean, EntityBean oldBean) {
for (BeanProperty aPropertiesBaseScalar : propertiesBaseScalar) {
aPropertiesBaseScalar.diff(prefix, map, newBean, oldBean);
for (BeanProperty baseScalar : propertiesBaseScalar) {
baseScalar.diff(prefix, map, newBean, oldBean);
}
for (BeanPropertyAssocOne<?> aPropertiesOne : propertiesOne) {
aPropertiesOne.diff(prefix, map, newBean, oldBean);
for (BeanPropertyAssocOne<?> one : propertiesOne) {
one.diff(prefix, map, newBean, oldBean);
}
for (BeanPropertyAssocOne<?> aPropertiesEmbedded : propertiesEmbedded) {
aPropertiesEmbedded.diff(prefix, map, newBean, oldBean);
for (BeanPropertyAssocOne<?> embedded : propertiesEmbedded) {
embedded.diff(prefix, map, newBean, oldBean);
}
}
@@ -3368,10 +3198,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* <p>
* This is primarily used for paging queries to ensure that an order by clause is provided and that the order by
* provides unique ordering of the rows (so that the paging is predicable).
* </p>
*/
public void appendOrderById(SpiQuery<T> query) {
if (idProperty != null && !idProperty.isEmbedded() && !query.order().containsProperty(idProperty.getName())) {
query.order().asc(idProperty.getName());
}
@@ -3409,7 +3237,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Returns ManyToOnes and OneToOnes on the imported owning side.
* <p>
* Excludes OneToOnes on the exported side.
* </p>
*/
public BeanPropertyAssocOne<?>[] propertiesOneImported() {
return propertiesOneImported;
@@ -3483,7 +3310,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* no version property exists on the bean.
* <p>
* Note that this DOES NOT find a version property on an embedded bean.
* </p>
*/
public BeanProperty getVersionProperty() {
return versionProperty;
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy;
import io.ebean.config.BeanNotRegisteredException;
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
import javax.persistence.Column;
import java.util.Map;
/**
@@ -15,7 +16,6 @@ class BeanEmbeddedMetaFactory {
* Create BeanProperties for embedded beans using the deployment specific DB column name and table alias.
*/
public static BeanEmbeddedMeta create(BeanDescriptorMap owner, DeployBeanPropertyAssocOne<?> prop) {
// we can get a BeanDescriptor for an Embedded bean
// and know that it is NOT recursive, as Embedded beans are
// only allow to hold simple scalar types...
@@ -28,23 +28,20 @@ class BeanEmbeddedMetaFactory {
// deployment override information (column names)
String columnPrefix = prop.getColumnPrefix();
Map<String, String> propColMap = prop.getDeployEmbedded().getPropertyColumnMap();
Map<String, Column> propColMap = prop.getDeployEmbedded().getPropertyColumnMap();
BeanProperty[] sourceProperties = targetDesc.propertiesNonTransient();
BeanProperty[] embeddedProperties = new BeanProperty[sourceProperties.length];
for (int i = 0; i < sourceProperties.length; i++) {
String propertyName = sourceProperties[i].getName();
String dbColumn = propColMap.get(propertyName);
if (dbColumn == null) {
// dbColumn not overridden so take original
dbColumn = sourceProperties[i].getDbColumn();
if (columnPrefix != null) {
dbColumn = columnPrefix + dbColumn;
}
}
BeanPropertyOverride overrides = new BeanPropertyOverride(dbColumn);
Column column = propColMap.get(propertyName);
String dbColumn = dbColumn(columnPrefix, column, sourceProperties[i]);
boolean dbNullable = dbNullable(column, sourceProperties[i]);
int dbLength = dbLength(column, sourceProperties[i]);
int dbScale = dbScale(column, sourceProperties[i]);
String colDefn = getDbColumnDefn(column, sourceProperties[i]);
BeanPropertyOverride overrides = new BeanPropertyOverride(dbColumn, dbNullable, dbLength, dbScale, colDefn);
if (sourceProperties[i] instanceof BeanPropertyAssocOne) {
embeddedProperties[i] = new BeanPropertyAssocOne((BeanPropertyAssocOne)sourceProperties[i], overrides);
} else {
@@ -54,4 +51,26 @@ class BeanEmbeddedMetaFactory {
return new BeanEmbeddedMeta(embeddedProperties);
}
private static String dbColumn(String prefix, Column override, BeanProperty source) {
String dbCol = (override != null && !override.name().isEmpty()) ? override.name() : source.getDbColumn();
return prefix == null ? dbCol : prefix + dbCol;
}
private static boolean dbNullable(Column override, BeanProperty source) {
return (override != null) ? override.nullable() : source.isNullable();
}
private static int dbLength(Column override, BeanProperty source) {
return (override != null && (override.length() != 255)) ? override.length() : source.getDbLength();
}
private static int dbScale(Column override, BeanProperty source) {
return (override != null && (override.scale() != 0)) ? override.scale() : source.getDbScale();
}
private static String getDbColumnDefn(Column override, BeanProperty source) {
return (override != null && !override.columnDefinition().isEmpty()) ? override.columnDefinition() : source.getDbColumnDefn();
}
}
@@ -55,6 +55,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static io.ebean.util.StringHelper.replace;
/**
* Description of a property of a bean. Includes its deployment information such
* as database column mapping information.
@@ -274,7 +276,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
public BeanProperty(BeanDescriptor<?> descriptor, DeployBeanProperty deploy) {
this.descriptor = descriptor;
this.name = InternString.intern(deploy.getName());
this.propertyIndex = deploy.getPropertyIndex();
@@ -314,36 +315,30 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.dbColumnDefn = InternString.intern(deploy.getDbColumnDefn());
this.dbColumnDefault = deploy.getDbColumnDefaultSqlLiteral();
this.dbMigrationInfos = deploy.getDbMigrationInfos();
this.inherited = false;// deploy.isInherited();
this.owningType = deploy.getOwningType();
this.local = deploy.isLocal();
this.version = deploy.isVersionColumn();
this.embedded = deploy.isEmbedded();
this.id = deploy.isId();
this.generatedProperty = deploy.getGeneratedProperty();
this.getter = deploy.getGetter();
this.setter = deploy.getSetter();
this.dbColumn = tableAliasIntern(descriptor, deploy.getDbColumn(), false, null);
this.dbComment = deploy.getDbComment();
this.aggregation = deploy.parseAggregation();
this.sqlFormulaJoin = InternString.intern(deploy.getSqlFormulaJoin());
this.sqlFormulaSelect = InternString.intern(deploy.getSqlFormulaSelect());
this.formula = sqlFormulaSelect != null;
this.dbType = deploy.getDbType();
this.scalarType = deploy.getScalarType();
this.lob = isLobType(dbType);
this.propertyType = deploy.getPropertyType();
this.field = deploy.getField();
this.docOptions = deploy.getDocPropertyOptions();
this.elPlaceHolder = tableAliasIntern(descriptor, deploy.getElPlaceHolder(), false, null);
this.elPlaceHolderEncrypted = tableAliasIntern(descriptor, deploy.getElPlaceHolder(), dbEncrypted, dbColumn);
this.elPrefix = deploy.getElPrefix();
this.softDelete = deploy.isSoftDelete();
if (softDelete) {
ScalarTypeBoolean.BooleanBase boolType = (ScalarTypeBoolean.BooleanBase) scalarType;
@@ -353,20 +348,18 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.softDeleteDbSet = null;
this.softDeleteDbPredicate = null;
}
this.jsonSerialize = deploy.isJsonSerialize();
this.jsonDeserialize = deploy.isJsonDeserialize();
}
private String tableAliasIntern(BeanDescriptor<?> descriptor, String s, boolean dbEncrypted, String dbColumn) {
if (descriptor != null) {
s = StringHelper.replaceString(s, "${ta}.", "${}");
s = StringHelper.replaceString(s, "${ta}", "${}");
s = replace(s, "${ta}.", "${}");
s = replace(s, "${ta}", "${}");
if (dbEncrypted) {
s = dbEncryptFunction.getDecryptSql(s);
String namedParam = ":encryptkey_" + descriptor.getBaseTable() + "___" + dbColumn;
s = StringHelper.replaceString(s, "?", namedParam);
s = replace(s, "?", namedParam);
}
}
return InternString.intern(s);
@@ -377,20 +370,21 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* <p>
* Primarily for supporting Embedded beans with overridden dbColumn
* mappings.
* </p>
*/
public BeanProperty(BeanProperty source, BeanPropertyOverride override) {
this.descriptor = source.descriptor;
this.name = InternString.intern(source.getName());
this.propertyIndex = source.propertyIndex;
this.dbColumn = InternString.intern(override.getDbColumn());
this.name = source.getName();
this.dbColumn = override.getDbColumn();
this.nullable = override.isDbNullable();
this.dbLength = override.getDbLength();
this.dbScale = override.getDbScale();
this.dbColumnDefn = InternString.intern(override.getDbColumnDefn());
// override with sqlFormula not currently supported
this.sqlFormulaJoin = null;
this.sqlFormulaSelect = null;
this.formula = false;
this.aggregation = null;
this.excludedFromHistory = source.excludedFromHistory;
this.tenantId = source.tenantId;
this.draft = source.draft;
@@ -409,7 +403,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.secondaryTable = source.isSecondaryTable();
this.secondaryTableJoin = source.secondaryTableJoin;
this.secondaryTableJoinPrefix = source.secondaryTableJoinPrefix;
this.dbComment = source.dbComment;
this.dbBind = source.getDbBind();
this.dbEncrypted = source.isDbEncrypted();
@@ -418,19 +411,13 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.dbRead = source.isDbRead();
this.dbInsertable = source.isDbInsertable();
this.dbUpdatable = source.isDbUpdatable();
this.nullable = source.isNullable();
this.unique = source.isUnique();
this.naturalKey = source.isNaturalKey();
this.dbLength = source.getDbLength();
this.dbScale = source.getDbScale();
this.dbColumnDefn = InternString.intern(source.getDbColumnDefn());
this.dbColumnDefault = source.dbColumnDefault;
this.dbMigrationInfos = source.dbMigrationInfos;
this.inherited = source.isInherited();
this.owningType = source.owningType;
this.local = owningType.equals(descriptor.getBeanType());
this.version = source.isVersion();
this.embedded = source.isEmbedded();
this.id = source.isId();
@@ -444,11 +431,9 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.field = source.getField();
this.docOptions = source.docOptions;
this.unmappedJson = source.unmappedJson;
this.elPrefix = override.replace(source.elPrefix, source.dbColumn);
this.elPlaceHolder = override.replace(source.elPlaceHolder, source.dbColumn);
this.elPlaceHolderEncrypted = override.replace(source.elPlaceHolderEncrypted, source.dbColumn);
this.jsonSerialize = source.jsonSerialize;
this.jsonDeserialize = source.jsonDeserialize;
}
@@ -563,9 +548,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
if (formula && sqlFormulaJoin != null) {
ctx.appendFormulaJoin(sqlFormulaJoin, joinType);
} else if (secondaryTableJoin != null) {
String relativePrefix = ctx.getRelativePrefix(secondaryTableJoinPrefix);
secondaryTableJoin.addJoin(joinType, relativePrefix, ctx);
}
@@ -586,7 +569,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
@Override
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
if (aggregation != null) {
ctx.appendFormulaSelect(aggregation);
} else if (formula) {
@@ -597,15 +579,12 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
if (secondaryTableJoin != null) {
ctx.pushTableAlias(ctx.getRelativePrefix(secondaryTableJoinPrefix));
}
if (dbEncrypted) {
ctx.appendRawColumn(getDecryptSqlWithColumnAlias(ctx.peekTableAlias()));
ctx.addEncryptedProp(this);
} else {
ctx.appendColumn(dbColumn);
}
if (secondaryTableJoin != null) {
ctx.popTableAlias();
}
@@ -662,7 +641,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
try {
Object value = scalarType.read(ctx.getDataReader());
if (bean != null) {
@@ -716,7 +694,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* Copy/set the property value from the draft bean to the live bean.
*/
public void publish(EntityBean draftBean, EntityBean liveBean) {
if (!version && !draftOnly) {
// set property value from draft to live
Object value = getValueIntercept(draftBean);
@@ -899,7 +876,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
@Override
public void pathSet(Object bean, Object value) {
if (bean != null) {
Object logicalVal = convertToLogicalType(value);
setValueIntercept((EntityBean) bean, logicalVal);
@@ -1074,14 +1050,14 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
/**
* Return the DB scale for numeric columns.
*/
private int getDbScale() {
public int getDbScale() {
return dbScale;
}
/**
* Return a specific column DDL definition if specified (otherwise null).
*/
private String getDbColumnDefn() {
public String getDbColumnDefn() {
return dbColumnDefn;
}
@@ -1279,7 +1255,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
case Types.LONGVARCHAR:
case Types.LONGVARBINARY:
return true;
default:
return false;
}
@@ -1500,7 +1475,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
public void jsonRead(SpiJsonReader ctx, EntityBean bean) throws IOException {
JsonToken event = ctx.nextToken();
if (JsonToken.VALUE_NULL == event) {
if (jsonDeserialize) {
@@ -1551,7 +1525,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* Add to the document mapping if this property is included for this index.
*/
public void docStoreMapping(DocMappingBuilder mapping, String prefix) {
if (mapping.includesProperty(prefix, name)) {
DocPropertyType type = scalarType.getDocType();
DocPropertyOptions options = docOptions.copy();
@@ -1571,7 +1544,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
public void registerColumn(BeanDescriptor<?> desc, String prefix) {
String path = SplitName.add(prefix, name);
if (formula && dbColumn != null) {
// trim off table alias placeholder if found
@@ -213,6 +213,11 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
}
@Override
public BeanPropertyAssocMany<?> asMany() {
return this;
}
@Override
public boolean isManyToManyWithHistory() {
return manyToMany && !excludedFromHistory && descriptor.isHistorySupport();
@@ -12,16 +12,40 @@ import io.ebeaninternal.server.core.InternString;
class BeanPropertyOverride {
private final String dbColumn;
private final boolean dbNullable;
private final int dbLength;
private final int dbScale;
private final String dbColumnDefn;
BeanPropertyOverride(String dbColumn) {
BeanPropertyOverride(String dbColumn, boolean dbNullable, int dbLength, int dbScale, String dbColumnDefn) {
this.dbColumn = InternString.intern(dbColumn);
this.dbNullable = dbNullable;
this.dbLength = dbLength;
this.dbScale = dbScale;
this.dbColumnDefn = dbColumnDefn;
}
public String getDbColumn() {
String getDbColumn() {
return dbColumn;
}
public String replace(String src, String srcDbColumn) {
return StringHelper.replaceString(src, srcDbColumn, dbColumn);
boolean isDbNullable() {
return dbNullable;
}
int getDbLength() {
return dbLength;
}
int getDbScale() {
return dbScale;
}
String getDbColumnDefn() {
return dbColumnDefn;
}
String replace(String src, String srcDbColumn) {
return StringHelper.replace(src, srcDbColumn, dbColumn);
}
}
@@ -68,7 +68,7 @@ public interface DbReadContext {
/**
* Register a collection for lazy loading.
*/
void register(String path, BeanCollection<?> bc);
void register(BeanPropertyAssocMany<?> many, BeanCollection<?> bc);
/**
* Return the property that is associated with the many. There can only be
@@ -53,7 +53,6 @@ public final class IdBinderEmbedded implements IdBinder {
}
private String idInExpanded() {
StringBuilder sb = new StringBuilder(30);
sb.append("(");
for (int i = 0; i < props.length; i++) {
@@ -66,13 +65,11 @@ public final class IdBinderEmbedded implements IdBinder {
sb.append("=?");
}
sb.append(")");
return sb.toString();
}
private String idInCompressed() {
StringBuilder sb = new StringBuilder();
sb.append("(");
StringBuilder sb = new StringBuilder(20).append("(");
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(",");
@@ -80,7 +77,6 @@ public final class IdBinderEmbedded implements IdBinder {
sb.append("?");
}
sb.append(")");
return sb.toString();
}
@@ -99,7 +95,6 @@ public final class IdBinderEmbedded implements IdBinder {
if (pathPrefix != null) {
sb.append(pathPrefix).append(".");
}
sb.append(embIdProperty.getName()).append(".");
sb.append(props[i].getName());
if (!ascending) {
@@ -120,9 +115,7 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
prefix = SplitName.add(prefix, embIdProperty.getName());
for (BeanProperty prop : props) {
prop.buildRawSqlSelectChain(prefix, selectChain);
}
@@ -145,18 +138,15 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public String getDefaultOrderBy() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(",");
}
sb.append(embIdProperty.getName());
sb.append(".");
sb.append(props[i].getName());
}
return sb.toString();
}
@@ -172,10 +162,8 @@ public final class IdBinderEmbedded implements IdBinder {
if (!idInExpandedForm) {
return getIdInValueExpr(false, size);
}
StringBuilder sb = new StringBuilder();
sb.append("(");
for (int j = 0; j < size; j++) {
if (j > 0) {
sb.append(" or ");
@@ -233,12 +221,11 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public Object[] getBindValues(Object value) {
Object[] bindvalues = new Object[props.length];
Object[] bindValues = new Object[props.length];
for (int i = 0; i < props.length; i++) {
bindvalues[i] = props[i].getValue((EntityBean) value);
bindValues[i] = props[i].getValue((EntityBean) value);
}
return bindvalues;
return bindValues;
}
/**
@@ -246,7 +233,6 @@ public final class IdBinderEmbedded implements IdBinder {
*/
@Override
public Object getIdForJson(EntityBean bean) {
EntityBean ebValue = (EntityBean) embIdProperty.getValue(bean);
Map<String, Object> map = new LinkedHashMap<>();
for (BeanProperty prop : props) {
@@ -261,7 +247,6 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
@SuppressWarnings("unchecked")
public Object convertIdFromJson(Object value) {
Map<String, Object> map = (Map<String, Object>) value;
EntityBean idValue = idDesc.createEntityBean();
for (BeanProperty prop : props) {
@@ -270,7 +255,6 @@ public final class IdBinderEmbedded implements IdBinder {
return idValue;
}
@Override
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
for (BeanProperty prop : props) {
@@ -281,7 +265,6 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public void bindId(DataBind dataBind, Object value) throws SQLException {
for (BeanProperty prop : props) {
Object embFieldValue = prop.getValue((EntityBean) value);
prop.bind(dataBind, embFieldValue);
@@ -306,10 +289,8 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public Object readData(DataInput dataInput) throws IOException {
EntityBean embId = idDesc.createEntityBean();
boolean notNull = true;
for (BeanProperty prop : props) {
Object value = prop.readData(dataInput);
prop.setValue(embId, value);
@@ -317,12 +298,7 @@ public final class IdBinderEmbedded implements IdBinder {
notNull = false;
}
}
if (notNull) {
return embId;
} else {
return null;
}
return notNull ? embId : null;
}
@Override
@@ -342,10 +318,8 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public Object read(DbReadContext ctx) throws SQLException {
EntityBean embId = idDesc.createEntityBean();
boolean nullValue = true;
for (BeanProperty prop : props) {
Object value = prop.read(ctx);
if (value != null) {
@@ -353,17 +327,11 @@ public final class IdBinderEmbedded implements IdBinder {
nullValue = false;
}
}
if (nullValue) {
return null;
} else {
return embId;
}
return nullValue ? null : embId;
}
@Override
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
Object embId = read(ctx);
if (embId != null) {
embIdProperty.setValue(bean, embId);
@@ -382,7 +350,6 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public String getAssocIdInExpr(String prefix) {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (int i = 0; i < props.length; i++) {
@@ -401,7 +368,6 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public String getAssocOneIdExpr(String prefix, String operator) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < props.length; i++) {
if (i > 0) {
@@ -411,7 +377,6 @@ public final class IdBinderEmbedded implements IdBinder {
sb.append(prefix);
sb.append(".");
}
sb.append(embIdProperty.getName());
sb.append(".");
sb.append(props[i].getName());
@@ -422,7 +387,6 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public String getBindIdSql(String baseTableAlias) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < props.length; i++) {
if (i > 0) {
@@ -440,11 +404,9 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public String getBindIdInSql(String baseTableAlias) {
if (idInExpandedForm) {
return "";
}
StringBuilder sb = new StringBuilder();
sb.append("(");
for (int i = 0; i < props.length; i++) {
@@ -476,19 +438,16 @@ public final class IdBinderEmbedded implements IdBinder {
@Override
public Object convertSetId(Object idValue, EntityBean bean) {
// can not cast/convert if it is embedded
if (bean != null) {
// support PropertyChangeSupport
embIdProperty.setValueIntercept(bean, idValue);
}
return idValue;
}
@Override
public String cacheKey(Object value) {
EntityBean bean = (EntityBean)value;
StringBuilder sb = new StringBuilder();
for (BeanProperty prop : props) {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.deploy.meta;
import javax.persistence.Column;
import java.util.HashMap;
import java.util.Map;
@@ -8,28 +9,26 @@ import java.util.Map;
* <p>
* Typically collects the overridden column names mapped
* to the Embedded bean.
* </p>
*/
public class DeployBeanEmbedded {
/**
* A map of property names to dbColumns.
*/
private final Map<String, String> propMap = new HashMap<>();
private final Map<String, Column> propMap = new HashMap<>();
/**
* Set a Map of property names to dbColumns.
*/
public void putAll(Map<String, String> propertyColumnMap) {
public void putAll(Map<String, Column> propertyColumnMap) {
propMap.putAll(propertyColumnMap);
}
/**
* Return a map of property names to dbColumns.
*/
public Map<String, String> getPropertyColumnMap() {
public Map<String, Column> getPropertyColumnMap() {
return propMap;
}
}
@@ -11,6 +11,7 @@ import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.validation.groups.Default;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -89,9 +90,9 @@ public abstract class AnnotationParser extends AnnotationBase {
Set<AttributeOverride> attrOverrides = annotationAttributeOverrides(prop);
if (!attrOverrides.isEmpty()) {
HashMap<String, String> propMap = new HashMap<>(attrOverrides.size());
Map<String, Column> propMap = new HashMap<>(attrOverrides.size());
for (AttributeOverride attrOverride : attrOverrides) {
propMap.put(attrOverride.name(), attrOverride.column().name());
propMap.put(attrOverride.name(), attrOverride.column());
}
prop.getDeployEmbedded().putAll(propMap);
}
@@ -5,8 +5,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static io.ebean.util.StringHelper.replaceString;
/**
* Holds property and constructor meta data for a given DTO bean type.
*
@@ -88,7 +86,7 @@ class DtoMeta {
property = propMap.get(upperLabel.substring(3));
}
if (property == null) {
property = propMap.get(replaceString(upperLabel, "_", ""));
property = propMap.get(upperLabel.replace("_", ""));
}
return property;
}
@@ -4,11 +4,9 @@ import io.ebeaninternal.server.type.TypeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
@@ -34,32 +32,49 @@ class DtoMetaBuilder {
this.typeManager = typeManager;
}
public DtoMeta build() throws IntrospectionException {
DtoMeta build() {
readConstructors();
readProperties();
return new DtoMeta(dtoType, constructorList, properties);
}
private void readProperties() throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(dtoType);
for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) {
if (include(propertyDescriptor)) {
private void readProperties() {
for (Method method : dtoType.getMethods()) {
if (includeMethod(method)) {
try {
properties.add(new DtoMetaProperty(typeManager, propertyDescriptor, dtoType));
final String name = propertyName(method.getName());
final Class<?> propertyType = propertyType(method);
properties.add(new DtoMetaProperty(typeManager, dtoType, method, name, propertyType));
} catch (Exception e) {
log.debug("exclude on " + dtoType + " property " + propertyDescriptor.getName(), e);
log.debug("exclude on " + dtoType + " method " + method, e);
}
}
}
}
static Class<?> propertyType(Method method) {
return method.getParameterTypes()[0];
}
static String propertyName(String methodName) {
final String name = methodName.substring(3);
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
}
/**
* Include a public "setter" method - 1 argument, returns void.
*/
static boolean includeMethod(Method method) {
final int modifiers = method.getModifiers();
return Modifier.isPublic(modifiers)
&& !Modifier.isStatic(modifiers)
&& Void.TYPE.equals(method.getReturnType())
&& method.getParameterTypes().length == 1
&& method.getName().startsWith("set") && method.getName().length() > 3;
}
private void readConstructors() {
Constructor<?>[] constructors = dtoType.getConstructors();
for (Constructor<?> constructor : constructors) {
try {
constructorList.add(new DtoMetaConstructor(typeManager, constructor, dtoType));
@@ -70,8 +85,4 @@ class DtoMetaBuilder {
}
}
private boolean include(PropertyDescriptor property) {
return !property.getName().equals("class");
}
}
@@ -4,7 +4,6 @@ import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.TypeManager;
import java.beans.PropertyDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -20,19 +19,12 @@ class DtoMetaProperty implements DtoReadSet {
private final MethodHandle setter;
private final ScalarType<?> scalarType;
DtoMetaProperty(TypeManager typeManager, PropertyDescriptor descriptor, Class<?> dtoType) throws IllegalAccessException, NoSuchMethodException {
DtoMetaProperty(TypeManager typeManager, Class<?> dtoType, Method writeMethod, String name, Class<?> propertyType) throws IllegalAccessException, NoSuchMethodException {
this.dtoType = dtoType;
this.name = descriptor.getName();
Method writeMethod = descriptor.getWriteMethod();
this.name = name;
if (writeMethod != null) {
Class<?> propertyType = descriptor.getPropertyType();
this.setter = LOOKUP.findVirtual(dtoType, writeMethod.getName(), MethodType.methodType(void.class, propertyType));
this.scalarType = typeManager.getScalarType(propertyType);
} else {
this.scalarType = null;
this.setter = null;
@@ -58,11 +50,11 @@ class DtoMetaProperty implements DtoReadSet {
try {
setter.invoke(instance, arg);
} catch (Throwable e) {
throw new RuntimeException("Error calling setter for property " + fullname() + " with arg: " + arg, e);
throw new RuntimeException("Error calling setter for property " + fullName() + " with arg: " + arg, e);
}
}
private String fullname() {
private String fullName() {
return dtoType.getName() + "." + name;
}
@@ -4,7 +4,6 @@ import io.ebean.bean.EntityBean;
import io.ebean.plugin.Property;
import io.ebean.text.StringParser;
import io.ebean.util.SplitName;
import io.ebean.util.StringHelper;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.type.ScalarType;
@@ -99,14 +98,12 @@ public class ElPropertyChain implements ElPropertyValue {
if (prefix == null) {
return lastElPropertyValue.getElPlaceholder(encrypted);
}
String el = lastElPropertyValue.getElPlaceholder(encrypted);
if (!el.contains("${}")) {
// typically a secondary table property
return StringHelper.replaceString(el, "${", "${" + prefix + ".");
return el.replace("${", "${" + prefix + ".");
} else {
return StringHelper.replaceString(el, ROOT_ELPREFIX, "${" + prefix + "}");
return el.replace(ROOT_ELPREFIX, "${" + prefix + "}");
}
}
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.loadcontext;
import io.ebean.CacheMode;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanLoader;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
@@ -10,6 +11,7 @@ import io.ebeaninternal.api.LoadBeanRequest;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import java.util.ArrayList;
@@ -32,7 +34,13 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
// bufferList only required when using query joins (queryFetch)
this.bufferList = (!queryFetch) ? null : new ArrayList<>();
this.currentBuffer = createBuffer(firstBatchSize);
this.cache = (queryProps == null) ? false : queryProps.isCache();
this.cache = (queryProps != null) && queryProps.isCache();
}
@Override
public void register(BeanPropertyAssocMany<?> many, BeanCollection<?> collection) {
String path = fullPath + "." + many.getName();
parent.register(path, many, collection);
}
/**
@@ -175,7 +183,7 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
@Override
public void loadBean(EntityBeanIntercept ebi) {
// A synchronized (this) is effectively held by EntityBeanIntercept.loadBean()
if (context.desc.lazyLoadMany(ebi)) {
if (context.desc.lazyLoadMany(ebi, context)) {
// lazy load property was a Many
return;
}
@@ -283,8 +283,8 @@ public class DLoadContext implements LoadContext {
}
@Override
public void register(String path, BeanCollection<?> bc) {
getManyContext(path).register(bc);
public void register(String path, BeanPropertyAssocMany<?> many, BeanCollection<?> bc) {
getManyContext(path, many).register(bc);
}
DLoadBeanContext getBeanContext(String path) {
@@ -315,11 +315,12 @@ public class DLoadContext implements LoadContext {
}
}
DLoadManyContext getManyContext(String path) {
if (path == null) {
throw new RuntimeException("path is null?");
}
return manyMap.computeIfAbsent(path, p -> createManyContext(p, defaultBatchSize, null));
DLoadManyContext getManyContext(String path, BeanPropertyAssocMany<?> many) {
return manyMap.computeIfAbsent(path, p -> createManyContext(p, many, defaultBatchSize));
}
private DLoadManyContext createManyContext(String path, BeanPropertyAssocMany<?> many, int batchSize) {
return new DLoadManyContext(this, many, path, batchSize, null);
}
private DLoadManyContext createManyContext(String path, int batchSize, OrmQueryProperties queryProps) {
@@ -1,22 +1,14 @@
package io.ebeaninternal.server.persist;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Utility to improve logging of raw SQL that contains new line characters.
*/
public class TrimLogSql {
/**
* Statically compiled Regex, to avoid having it be compiled every time it is used.
*/
private static final Pattern LINUX_NEW_LINE_REPLACE_PATTERN = Pattern.compile("\n", Pattern.LITERAL);
/**
* Replace new line chars for nicer logging of multi-line sql strings.
*/
public static String trim(String sql) {
return LINUX_NEW_LINE_REPLACE_PATTERN.matcher(sql).replaceAll(Matcher.quoteReplacement("\\n "));
return sql.replace("\n","\\n ");
}
}
@@ -75,8 +75,7 @@ public final class DmlBeanPersister implements BeanPersister {
} catch (SQLException e) {
// log the error to the transaction log
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[]{"\r", "\n"}, " ");
String msg = "Error[" + errMsg + "]";
String msg = "Error[" + StringHelper.removeNewLines(e.getMessage()) + "]";
if (request.getTransaction().isLogSummary()) {
request.getTransaction().logSummary(msg);
}
@@ -636,10 +636,9 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
}
@Override
public void register(String path, BeanCollection<?> bc) {
path = getPath(path);
request.getGraphContext().register(path, bc);
public void register(BeanPropertyAssocMany<?> many, BeanCollection<?> bc) {
String path = getPath(many.getName());
request.getGraphContext().register(path, many, bc);
}
/**
@@ -13,7 +13,6 @@ import io.ebean.config.dbplatform.SqlLimiter;
import io.ebean.event.readaudit.ReadAuditQueryPlan;
import io.ebean.text.PathProperties;
import io.ebean.util.SplitName;
import io.ebean.util.StringHelper;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -176,16 +175,14 @@ class CQueryBuilder {
* Strip the root table alias.
*/
private String aliasStrip(String sql) {
sql = StringHelper.replaceString(sql, "${RTA}.", "");
return StringHelper.replaceString(sql, " ${RTA}", "");
return sql.replace("${RTA}.", "").replace(" ${RTA}", "");
}
/**
* Replace the root table alias.
*/
private String aliasReplace(String sql, String replaceWith) {
sql = StringHelper.replaceString(sql, "${RTA}.", replaceWith + ".");
return StringHelper.replaceString(sql, "${RTA}", replaceWith);
return sql.replace("${RTA}.", replaceWith + ".").replace("${RTA}", replaceWith);
}
CQueryFetchSingleAttribute buildFetchAttributeQuery(OrmQueryRequest<?> request) {
@@ -680,7 +677,7 @@ class CQueryBuilder {
}
if (updateStatement) {
// strip the table alias for use in update statement
idSql = StringHelper.replaceString(idSql, "t0.", "");
idSql = idSql.replace("t0.", "");
}
sb.append(idSql).append(" ");
hasWhere = true;
@@ -136,8 +136,7 @@ public class CQueryEngine {
SpiTransaction t = request.getTransaction();
if (t.isLogSummary()) {
// log the error to the transaction log
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[]{"\r", "\n"}, "\\n ");
String msg = "ERROR executing query, bindLog[" + bindLog + "] error[" + errMsg + "]";
String msg = "ERROR executing query, bindLog[" + bindLog + "] error[" + StringHelper.removeNewLines(e.getMessage()) + "]";
t.logSummary(msg);
}
@@ -260,10 +259,8 @@ public class CQueryEngine {
query.where().lt(sysPeriodLower, query.getVersionEnd());
}
// order by id asc, lower sys period desc
query.order().asc(request.getBeanDescriptor().getIdProperty().getName());
// order by lower sys period desc
query.order().desc(sysPeriodLower);
CQuery<T> cquery = queryBuilder.buildQuery(request);
try {
cquery.prepareBindExecuteQuery();
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.query;
import io.ebean.util.StringHelper;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoinColumn;
@@ -150,26 +149,21 @@ class DefaultDbSqlContext implements DbSqlContext {
if (i > 0) {
sb.append(" and ");
}
if (pair.getForeignSqlFormula() != null) {
sb.append(StringHelper.replaceString(pair.getForeignSqlFormula(), tableAliasPlaceHolder, a2));
sb.append(pair.getForeignSqlFormula().replace(tableAliasPlaceHolder, a2));
} else {
sb.append(a2).append(".").append(pair.getForeignDbColumn());
}
sb.append(" = ");
if (pair.getLocalSqlFormula() != null) {
sb.append(StringHelper.replaceString(pair.getLocalSqlFormula(), tableAliasPlaceHolder, a1));
sb.append(pair.getLocalSqlFormula().replace(tableAliasPlaceHolder, a1));
} else {
sb.append(a1).append(".").append(pair.getLocalDbColumn());
}
}
if (addAsOfOnClause) {
sb.append(" and ").append(historySupport.getAsOfPredicate(a2));
}
sb.append(" ");
}
@@ -228,7 +222,7 @@ class DefaultDbSqlContext implements DbSqlContext {
// replace ${ta} place holder with the real table alias...
String tableAlias = tableAliasStack.peek();
String converted = StringHelper.replaceString(sqlFormulaJoin, tableAliasPlaceHolder, tableAlias);
String converted = sqlFormulaJoin.replace(tableAliasPlaceHolder, tableAlias);
if (formulaJoins == null) {
formulaJoins = new HashSet<>();
@@ -268,12 +262,9 @@ class DefaultDbSqlContext implements DbSqlContext {
@Override
public void appendFormulaSelect(String sqlFormulaSelect) {
String tableAlias = tableAliasStack.peek();
String converted = StringHelper.replaceString(sqlFormulaSelect, tableAliasPlaceHolder, tableAlias);
sb.append(COMMA);
sb.append(converted);
sb.append(sqlFormulaSelect.replace(tableAliasPlaceHolder, tableAlias));
appendColumnAlias();
}
@@ -308,12 +299,10 @@ class DefaultDbSqlContext implements DbSqlContext {
@Override
public void appendColumn(String tableAlias, String column) {
sb.append(COMMA);
if (column.contains("${}")) {
// support DB functions such as lower() etc
// with the use of secondary columns
String x = StringHelper.replaceString(column, "${}", tableAlias);
sb.append(x);
sb.append(column.replace("${}", tableAlias));
} else {
sb.append(tableAlias);
sb.append(PERIOD);
@@ -2,11 +2,17 @@ package io.ebeaninternal.server.query;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
public interface STreePropertyAssocMany extends STreePropertyAssoc {
/**
* Return as BeanPropertyAssocMany.
*/
BeanPropertyAssocMany<?> asMany();
/**
* Append exported columns to the select.
*/
@@ -8,16 +8,12 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Special Map of the logical property joins to table alias.
*/
class SqlTreeAlias {
private static final Pattern TABLE_ALIAS_REPLACE = Pattern.compile("${}", Pattern.LITERAL);
private final SpiQuery.TemporalMode temporalMode;
private int counter;
@@ -87,15 +83,12 @@ class SqlTreeAlias {
* Build a set of table alias for the given bean and fetch joined properties.
*/
void buildAlias() {
for (String joinProp : joinProps) {
calcAlias(joinProp);
}
for (String joinProp : manyWhereJoinProps) {
calcAliasManyWhere(joinProp);
}
mapEmbeddedPropertyAlias();
}
@@ -111,14 +104,12 @@ class SqlTreeAlias {
}
private String calcAlias(String prefix) {
String alias = nextTableAlias();
aliasMap.put(prefix, alias);
return alias;
}
private void calcAliasManyWhere(String prefix) {
String alias = nextManyWhereTableAlias();
manyWhereAliasMap.put(prefix, alias);
}
@@ -176,12 +167,11 @@ class SqlTreeAlias {
/**
* Parse the clause replacing the table alias place holders.
*/
private String parseRootAlias(String clause) {
String parseRootAlias(String clause) {
if (rootTableAlias == null) {
return TABLE_ALIAS_REPLACE.matcher(clause).replaceAll("");
return clause.replace("${}", "");
} else {
return TABLE_ALIAS_REPLACE.matcher(clause).replaceAll(Matcher.quoteReplacement(rootTableAlias + "."));
return clause.replace("${}", rootTableAlias + ".");
}
}
@@ -189,12 +179,10 @@ class SqlTreeAlias {
* Parse the clause replacing the table alias place holders.
*/
private String parseAliasMap(String clause, HashMap<String, String> parseAliasMap) {
for (Map.Entry<String, String> e : parseAliasMap.entrySet()) {
String k = "${" + e.getKey() + "}";
clause = clause.replace(k, e.getValue() + ".");
}
return clause;
}
@@ -299,7 +299,7 @@ public final class SqlTreeBuilder {
Collection<PropertyJoin> includes = manyWhereJoins.getPropertyJoins();
for (PropertyJoin joinProp : includes) {
STreePropertyAssoc beanProperty = (STreePropertyAssoc) desc.findPropertyFromPath(joinProp.getProperty());
SqlTreeNodeManyWhereJoin nodeJoin = new SqlTreeNodeManyWhereJoin(joinProp.getProperty(), beanProperty, joinProp.getSqlJoinType());
SqlTreeNodeManyWhereJoin nodeJoin = new SqlTreeNodeManyWhereJoin(joinProp.getProperty(), beanProperty, joinProp.getSqlJoinType(), temporalMode);
myJoinList.add(nodeJoin);
}
if (manyWhereJoins.isFormulaWithJoin()) {
@@ -6,7 +6,6 @@ import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.util.SplitName;
import io.ebean.util.StringHelper;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.deploy.DbReadContext;
@@ -107,7 +106,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
private SqlTreeNodeBean(String prefix, STreePropertyAssoc beanProp, STreeType desc, SqlTreeProperties props,
List<SqlTreeNode> myChildren, boolean withId, STreePropertyAssocMany lazyLoadParent,
SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
this.lazyLoadParent = lazyLoadParent;
this.lazyLoadParentIdBinder = (lazyLoadParent == null) ? null : lazyLoadParent.getIdBinder();
this.prefix = prefix;
@@ -116,21 +114,16 @@ class SqlTreeNodeBean implements SqlTreeNode {
this.idBinder = desc.getIdBinder();
this.temporalMode = temporalMode;
this.temporalVersions = temporalMode == SpiQuery.TemporalMode.VERSIONS;
this.nodeBeanProp = beanProp;
this.extraWhere = (beanProp == null) ? null : beanProp.getExtraWhere();
this.aggregation = props.isAggregation();
boolean aggregationRoot = props.isAggregationRoot();
// the bean has an Id property and we want to use it
this.readId = !aggregationRoot && withId && desc.hasId();
this.disableLazyLoad = disableLazyLoad || !readId || desc.isRawSqlBased() || temporalVersions;
this.partialObject = props.isPartialObject();
this.properties = props.getProps();
this.children = myChildren == null ? NO_CHILDREN : myChildren.toArray(new SqlTreeNode[0]);
pathMap = createPathMap(prefix, desc);
}
@@ -163,7 +156,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
}
private Map<String, String> createPathMap(String prefix, STreeType desc) {
HashMap<String, String> m = new HashMap<>();
for (STreePropertyAssocMany many : desc.propsMany()) {
String name = many.getName();
@@ -206,13 +198,11 @@ class SqlTreeNodeBean implements SqlTreeNode {
@Override
@SuppressWarnings("unchecked")
public <T> Version<T> loadVersion(DbReadContext ctx) throws SQLException {
// read the sys period lower and upper bounds
// these are always the first 2 columns in the resultSet
Timestamp start = ctx.getDataReader().getTimestamp();
Timestamp end = ctx.getDataReader().getTimestamp();
T bean = (T) load(ctx, null, null);
return new Version<>(bean, start, end);
}
@@ -326,7 +316,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
private void readIdNullBean() {
// bean must be null...
localBean = null;
// ... but there may exist as reference bean in parent which has to be marked as deleted.
if (parentBean != null && nodeBeanProp instanceof STreePropertyAssocOne) {
contextBean = ((STreePropertyAssocOne)nodeBeanProp).getValueAsEntityBean(parentBean);
@@ -355,7 +344,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
localBean = contextBean;
lazyLoadMany = true;
}
// recursively continue reading...
for (SqlTreeNode aChildren : children) {
// read each child... and let them set their
@@ -430,7 +418,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
ref.setDisableLazyLoad(true);
}
if (!ref.isRegisteredWithLoadContext()) {
ctx.register(many.getName(), ref);
ctx.register(many.asMany(), ref);
}
}
}
@@ -476,7 +464,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
*/
@Override
public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException {
Load load = (inheritInfo != null) ? new LoadInherit(ctx, parentBean) : new Load(ctx, parentBean);
load.initialise();
if (load.isLazyLoadManyRoot()) {
@@ -489,7 +476,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
@Override
public void appendGroupBy(DbSqlContext ctx, boolean subQuery) {
ctx.pushJoin(prefix);
ctx.pushTableAlias(prefix);
if (lazyLoadParent != null) {
@@ -525,19 +511,15 @@ class SqlTreeNodeBean implements SqlTreeNode {
*/
@Override
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
ctx.pushJoin(prefix);
ctx.pushTableAlias(prefix);
if (temporalVersions) {
// select sys_period lower and upper columns
ctx.appendHistorySysPeriod();
}
if (lazyLoadParent != null) {
lazyLoadParent.addSelectExported(ctx, prefix);
}
if (readId) {
if (!subQuery && inheritInfo != null) {
ctx.appendColumn(inheritInfo.getDiscriminatorColumn());
@@ -551,7 +533,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
// values back to this localBean
aChildren.appendSelect(ctx, subQuery);
}
ctx.popTableAlias();
ctx.popJoin();
}
@@ -586,7 +567,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
@Override
public void appendWhere(DbSqlContext ctx) {
// Only apply inheritance to root node as any join will already have the inheritance join include - see TableJoin
if (inheritInfo != null && nodeBeanProp == null) {
if (!inheritInfo.isRoot()) {
@@ -598,9 +578,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
ctx.append(inheritInfo.getWhere());
}
}
appendExtraWhere(ctx);
for (SqlTreeNode aChildren : children) {
// recursively add to the where clause any
// fixed predicates (extraWhere etc)
@@ -614,8 +592,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
ctx.append(" and");
}
String ta = ctx.getTableAlias(prefix);
String ew = StringHelper.replaceString(extraWhere, "${ta}", ta);
ctx.append(" ").append(ew).append(" ");
ctx.append(" ").append(extraWhere.replace("${ta}", ta)).append(" ");
}
}
@@ -651,7 +628,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
@Override
public void addSoftDeletePredicate(SpiQuery<?> query) {
if (desc.isSoftDelete()) {
query.addSoftDeletePredicate(desc.getSoftDeletePredicate(baseTableAlias));
}
@@ -688,17 +664,17 @@ class SqlTreeNodeBean implements SqlTreeNode {
* table if this is a ManyToMany node.
*/
SqlJoinType appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) {
SqlJoinType sqlJoinType = appendFromAsJoin(ctx, joinType);
if (temporalMode != SpiQuery.TemporalMode.SOFT_DELETED && desc.isSoftDelete()) {
// add the soft delete predicate to the join clause
if (inheritInfo != null) {
appendJoinDiscriminator(ctx);
}
if (desc.isSoftDelete() && temporalMode != SpiQuery.TemporalMode.SOFT_DELETED) {
ctx.append("and ").append(desc.getSoftDeletePredicate(ctx.getTableAlias(prefix))).append(" ");
}
return sqlJoinType;
}
SqlJoinType appendFromAsJoin(DbSqlContext ctx, SqlJoinType joinType) {
if (nodeBeanProp instanceof STreePropertyAssocMany) {
STreePropertyAssocMany manyProp = (STreePropertyAssocMany) nodeBeanProp;
if (manyProp.hasJoinTable()) {
@@ -714,14 +690,18 @@ class SqlTreeNodeBean implements SqlTreeNode {
if (!manyProp.isExcludedFromHistory()) {
intersectionAsOfTableAlias = true;
}
return nodeBeanProp.addJoin(joinType, alias2, alias, ctx);
}
}
return nodeBeanProp.addJoin(joinType, prefix, ctx);
}
void appendJoinDiscriminator(DbSqlContext ctx) {
if (inheritInfo.getWhere() == null) return;
String alias = ctx.getTableAlias(prefix);
ctx.append(" and ").append(alias).append(".").append(inheritInfo.getWhere());
}
/**
* Summary description.
*/
@@ -735,14 +715,12 @@ class SqlTreeNodeBean implements SqlTreeNode {
if (queryMode.isLoadContextBean()) {
return true;
}
// reload if contextBean is partial object
return !contextBean._ebean_getIntercept().isFullyLoadedBean();
}
@Override
public boolean hasMany() {
for (SqlTreeNode child : children) {
if (child.hasMany()) {
return true;
@@ -23,16 +23,21 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
private final STreePropertyAssoc nodeBeanProp;
private final STreeType target;
/**
* The many where join which is either INNER or OUTER.
*/
private final SqlJoinType manyJoinType;
SqlTreeNodeManyWhereJoin(String prefix, STreePropertyAssoc prop, SqlJoinType manyJoinType) {
private final boolean softDelete;
SqlTreeNodeManyWhereJoin(String prefix, STreePropertyAssoc prop, SqlJoinType manyJoinType, SpiQuery.TemporalMode temporalMode) {
this.nodeBeanProp = prop;
this.prefix = prefix;
this.manyJoinType = manyJoinType;
this.target = nodeBeanProp.target();
this.softDelete = (temporalMode != SpiQuery.TemporalMode.SOFT_DELETED && target.isSoftDelete());
String[] split = SplitName.split(prefix);
this.parentPrefix = split[0];
}
@@ -94,12 +99,16 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
if (nodeBeanProp instanceof STreePropertyAssocOne) {
nodeBeanProp.addJoin(joinType, parentAlias, alias, ctx);
if (softDelete) {
ctx.append("and ").append(target.getSoftDeletePredicate(alias)).append(" ");
}
} else {
STreePropertyAssocMany manyProp = (STreePropertyAssocMany) nodeBeanProp;
if (!manyProp.hasJoinTable()) {
manyProp.addJoin(joinType, parentAlias, alias, ctx);
if (softDelete) {
ctx.append("and ").append(target.getSoftDeletePredicate(alias)).append(" ");
}
} else {
String alias2 = alias + "z_";
@@ -1,7 +1,6 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.FetchConfig;
import io.ebean.util.StringHelper;
import io.ebeaninternal.server.util.DSelectColumnsParser;
import java.util.LinkedHashSet;
@@ -77,12 +76,12 @@ class OrmQueryPropertiesParser {
}
int pos = inputProperties.indexOf("+readonly");
if (pos > -1) {
inputProperties = StringHelper.replaceString(inputProperties, "+readonly", "");
inputProperties = inputProperties.replace("+readonly", "");
readOnly = true;
}
pos = inputProperties.indexOf("+cache");
if (pos > -1) {
inputProperties = StringHelper.replaceString(inputProperties, "+cache", "");
inputProperties = inputProperties.replace("+cache", "");
cache = true;
}
pos = inputProperties.indexOf("+query");
@@ -162,7 +161,7 @@ class OrmQueryPropertiesParser {
int startPos = pos + option.length();
int endPos = findEndPos(startPos, inputProperties);
if (endPos == -1) {
inputProperties = StringHelper.replaceString(inputProperties, option, "");
inputProperties = inputProperties.replace(option, "");
return 0;
} else {
@@ -8,7 +8,6 @@ import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
/**
* Set properties for a UpdateQuery.
@@ -19,8 +18,6 @@ public class OrmUpdateProperties {
private static final NoneValue NONE_VALUE = new NoneValue();
private static final Pattern TABLE_ALIAS_REPLACE = Pattern.compile("${}", Pattern.LITERAL);
/**
* Bind value used in the set clause for update query.
* It may/may not have bind values etc.
@@ -172,21 +169,22 @@ public class OrmUpdateProperties {
* Build the actual set clause converting logical property names to db columns etc.
*/
public String buildSetClause(DeployParser deployParser) {
int setCount = 0;
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Value> entry : values.entrySet()) {
String property = entry.getKey();
if (setCount++ > 0) {
sb.append(", ");
}
// translate to db columns and remove table alias placeholders
sb.append(TABLE_ALIAS_REPLACE.matcher(deployParser.parse(property)).replaceAll(""));
sb.append(trim(deployParser.parse(property)));
sb.append(entry.getValue().bindClause());
}
return sb.toString();
}
static String trim(String dbColumn) {
return dbColumn.replace("${}", "");
}
}
@@ -189,27 +189,34 @@ public final class DefaultPersistenceContext implements PersistenceContext {
private int initialSize;
private ClassContext parent;
private ClassContext() {
}
/**
* Create as a shallow copy.
*/
private ClassContext(ClassContext parent, boolean initial) {
if (initial || parent.isInitialSize()) {
this.map.putAll(parent.map);
this.initialSize = map.size();
if (parent.deleteSet != null) {
this.deleteSet = new HashSet<>(parent.deleteSet);
private ClassContext(ClassContext source, boolean initial) {
if (initial || source.isTransfer()) {
parent = source.transferParent();
initialSize = parent.size();
if (source.deleteSet != null) {
deleteSet = new HashSet<>(source.deleteSet);
}
}
}
/**
* True if the map has not changed from it's initial size (no additions).
* True if this should be transferred to a new iterator persistence context.
*/
private boolean isInitialSize() {
return map.size() == initialSize;
private boolean isTransfer() {
// map not added to and has some original/parent beans
return map.isEmpty() && initialSize > 0;
}
private ClassContext transferParent() {
return (parent != null) ? parent : this;
}
/**
@@ -220,10 +227,10 @@ public final class DefaultPersistenceContext implements PersistenceContext {
}
/**
* Return true if grown above the reset limit size.
* Return true if grown above the reset limit size of 1000.
*/
private boolean resetLimit() {
return map.size() > initialSize + 1000;
return map.size() > 1000;
}
@Override
@@ -231,20 +238,21 @@ public final class DefaultPersistenceContext implements PersistenceContext {
return "size:" + map.size();
}
private Object get(Object id) {
Object bean = (parent == null) ? null : parent.get(id);
return bean != null ? bean : map.get(id);
}
private WithOption getWithOption(Object id) {
if (deleteSet != null && deleteSet.contains(id)) {
return WithOption.DELETED;
}
Object bean = map.get(id);
Object bean = get(id);
return (bean == null) ? null : new WithOption(bean);
}
private Object get(Object id) {
return map.get(id);
}
private Object putIfAbsent(Object id, Object bean) {
Object existingValue = map.get(id);
Object existingValue = get(id);
if (existingValue != null) {
// it is not absent
return existingValue;
@@ -259,7 +267,7 @@ public final class DefaultPersistenceContext implements PersistenceContext {
}
private int size() {
return map.size();
return map.size() + initialSize;
}
private void clear() {
@@ -31,6 +31,7 @@ import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* JDBC Connection based transaction.
@@ -346,55 +347,36 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
callbackList.add(callback);
}
private void firePreRollback() {
private void withEachCallback(Consumer<TransactionCallback> consumer) {
if (callbackList != null) {
for (TransactionCallback callback : callbackList) {
// using old style loop to cater for case when new callbacks are added recursively (as otherwise iterator fails fast)
for (int i = 0; i < callbackList.size(); i++) {
try {
callback.preRollback();
consumer.accept(callbackList.get(i));
} catch (Exception e) {
logger.error("Error executing preRollback callback", e);
logger.error("Error executing transaction callback", e);
}
}
}
}
private void firePreRollback() {
withEachCallback(TransactionCallback::preRollback);
}
private void firePostRollback() {
if (callbackList != null) {
for (TransactionCallback callback : callbackList) {
try {
callback.postRollback();
} catch (Exception e) {
logger.error("Error executing postRollback callback", e);
}
}
}
withEachCallback(TransactionCallback::postRollback);
if (changeLogHolder != null) {
changeLogHolder.postRollback();
}
}
private void firePreCommit() {
if (callbackList != null) {
for (TransactionCallback callback : callbackList) {
try {
callback.preCommit();
} catch (Exception e) {
logger.error("Error executing preCommit callback", e);
}
}
}
withEachCallback(TransactionCallback::preCommit);
}
private void firePostCommit() {
if (callbackList != null) {
for (TransactionCallback callback : callbackList) {
try {
callback.postCommit();
} catch (Exception e) {
logger.error("Error executing postCommit callback", e);
}
}
}
withEachCallback(TransactionCallback::postCommit);
if (changeLogHolder != null) {
changeLogHolder.postCommit();
}
+219 -32
View File
@@ -1,4 +1,4 @@
-- Generated by ebean unknown at 2020-03-04T11:05:12.077911Z
-- Generated by ebean unknown at 2020-08-31T02:36:16.679053Z
create table asimple_bean (
id bigint generated by default as identity not null,
name varchar(255),
@@ -275,7 +275,7 @@ create table drel_booking (
constraint uq_drel_booking_client_invoice unique (client_invoice),
constraint pk_drel_booking primary key (id)
);
create sequence drel_booking_seq increment by 50;
create sequence drel_booking_seq increment by 1;
create table bw_bean (
id bigint generated by default as identity not null,
@@ -307,6 +307,28 @@ create table cepproduct_category (
priority integer
);
create table ciaddress (
id bigint generated by default as identity not null,
street_id bigint,
constraint pk_ciaddress primary key (id)
);
create table cicustomer_parent (
dtype integer(31) not null,
id bigint generated by default as identity not null,
address_id bigint,
notes varchar(255),
constraint pk_cicustomer_parent primary key (id)
);
create table cistreet_parent (
dtype integer(31) not null,
id bigint generated by default as identity not null,
name varchar(255),
num varchar(255),
constraint pk_cistreet_parent primary key (id)
);
create table cinh_ref (
id integer generated by default as identity not null,
ref_id integer,
@@ -396,7 +418,7 @@ create table sp_car_car (
version integer not null,
constraint pk_sp_car_car primary key (id)
);
create sequence sp_car_car_seq increment by 50;
create sequence sp_car_car_seq increment by 1;
create table sp_car_car_wheels (
car bigint not null,
@@ -417,7 +439,7 @@ create table sa_car (
version integer not null,
constraint pk_sa_car primary key (id)
);
create sequence sa_car_seq increment by 50;
create sequence sa_car_seq increment by 1;
create table car_accessory (
id integer generated by default as identity not null,
@@ -641,7 +663,7 @@ create table d_machine_aux_use (
name varchar(255),
edate date,
use_secs bigint not null,
fuel decimal(38),
fuel decimal(16,3),
version bigint not null,
constraint pk_d_machine_aux_use primary key (id)
);
@@ -652,8 +674,8 @@ create table d_machine_stats (
edate date,
total_kms bigint not null,
hours bigint not null,
rate decimal(38),
cost decimal(38),
rate decimal(16,3),
cost decimal(16,3),
version bigint not null,
constraint pk_d_machine_stats primary key (id)
);
@@ -664,7 +686,7 @@ create table d_machine_use (
edate date,
distance_kms bigint not null,
time_secs bigint not null,
fuel decimal(38),
fuel decimal(9,3),
version bigint not null,
constraint pk_d_machine_use primary key (id)
);
@@ -680,7 +702,7 @@ create table dperson (
id bigint generated by default as identity not null,
first_name varchar(255),
last_name varchar(255),
salary decimal(38),
salary decimal(16,3),
constraint pk_dperson primary key (id)
);
@@ -729,6 +751,16 @@ create table dc_master (
constraint pk_dc_master primary key (id)
);
create table defaults_model (
id integer generated by default as identity not null,
constraint pk_defaults_model primary key (id)
);
create table defaults_model_draft (
id integer generated by default as identity not null,
constraint pk_defaults_model_draft primary key (id)
);
create table dfk_cascade (
id bigint generated by default as identity not null,
name varchar(255),
@@ -864,7 +896,7 @@ create table sp_car_door (
version integer not null,
constraint pk_sp_car_door primary key (id)
);
create sequence sp_car_door_seq increment by 50;
create sequence sp_car_door_seq increment by 1;
create table earray_bean (
id bigint generated by default as identity not null,
@@ -1309,11 +1341,11 @@ create table einvoice (
invoice_date timestamp,
state integer,
person_id bigint,
ship_street varchar(255),
ship_street varchar(255) not null,
ship_suburb varchar(255),
ship_city varchar(255),
ship_status varchar(3),
bill_street varchar(255),
bill_street varchar(255) not null,
bill_suburb varchar(255),
bill_city varchar(255),
bill_status varchar(3),
@@ -1389,7 +1421,7 @@ create table eperson (
id bigint generated by default as identity not null,
name varchar(255),
notes varchar(255),
street varchar(255),
street varchar(255) not null,
suburb varchar(255),
addr_city varchar(255),
addr_status varchar(3),
@@ -1398,6 +1430,31 @@ create table eperson (
constraint pk_eperson primary key (id)
);
create table eperson2 (
id bigint generated by default as identity not null,
name varchar(255),
notes varchar(255),
street varchar(10),
suburb varchar(100),
city varchar(255) not null,
status varchar(3) not null,
version bigint not null,
constraint ck_eperson2_status check ( status in ('ONE','TWO')),
constraint pk_eperson2 primary key (id)
);
create table eperson3 (
id bigint generated by default as identity not null,
name varchar(255),
street varchar(255),
suburb varchar(255),
city varchar(255),
status varchar(3),
version bigint not null,
constraint ck_eperson3_status check ( status in ('ONE','TWO')),
constraint pk_eperson3 primary key (id)
);
create table e_person_online (
id bigint generated by default as identity not null,
email varchar(127),
@@ -1511,7 +1568,7 @@ create table esoft_del_user_esoft_del_role (
create table esome_convert_type (
id bigint generated by default as identity not null,
name varchar(255),
money decimal(38),
money decimal(16,3),
constraint pk_esome_convert_type primary key (id)
);
@@ -1801,13 +1858,7 @@ create table gen_key_sequence (
description varchar(255),
constraint pk_gen_key_sequence primary key (id)
);
create sequence SEQ start with 1 increment by 50;
create table gen_key_table (
id bigint generated by default as identity not null,
description varchar(255),
constraint pk_gen_key_table primary key (id)
);
create sequence SEQ_NAME increment by 1;
create table grand_parent_person (
identifier integer generated by default as identity not null,
@@ -2018,7 +2069,7 @@ create table drel_invoice (
version integer not null,
constraint pk_drel_invoice primary key (id)
);
create sequence drel_invoice_seq increment by 50;
create sequence drel_invoice_seq increment by 1;
create table item (
customer integer not null,
@@ -2739,6 +2790,23 @@ create table om_ordered_master (
constraint pk_om_ordered_master primary key (id)
);
create table oml_bar (
id bigint generated by default as identity not null,
constraint pk_oml_bar primary key (id)
);
create table oml_baz (
id bigint generated by default as identity not null,
foo_id bigint not null,
constraint pk_oml_baz primary key (id)
);
create table oml_foo (
id bigint generated by default as identity not null,
bar_id bigint not null,
constraint pk_oml_foo primary key (id)
);
create table only_id_entity (
id bigint generated by default as identity not null,
constraint pk_only_id_entity primary key (id)
@@ -2778,10 +2846,30 @@ create table s_order_items (
product_variant_uuid varchar(255),
order_uuid varchar(40),
quantity integer not null,
amount decimal(38),
amount decimal(16,3),
constraint pk_s_order_items primary key (uuid)
);
create table order_master (
id bigint generated by default as identity not null,
constraint pk_order_master primary key (id)
);
create table order_master_inheritance (
id integer generated by default as identity not null,
constraint pk_order_master_inheritance primary key (id)
);
create table order_referenced_parent (
type varchar(31) not null,
id bigint generated by default as identity not null,
name varchar(255),
child_name varchar(255),
master_id bigint,
sort_order integer,
constraint pk_order_referenced_parent primary key (id)
);
create table or_order_ship (
id integer generated by default as identity not null,
order_id integer,
@@ -2792,6 +2880,25 @@ create table or_order_ship (
constraint pk_or_order_ship primary key (id)
);
create table order_toy (
id integer generated by default as identity not null,
title varchar(255),
child_id bigint,
sort_order integer,
constraint pk_order_toy primary key (id)
);
create table ordered_parent (
dtype varchar(31) not null,
id integer generated by default as identity not null,
order_master_inheritance_id integer not null,
common_name varchar(255),
sort_order integer,
ordered_aname varchar(255),
ordered_bname varchar(255),
constraint pk_ordered_parent primary key (id)
);
create table organisation (
id bigint generated by default as identity not null,
name varchar(255),
@@ -3305,6 +3412,20 @@ create table r_orders (
constraint pk_r_orders primary key (company,order_number)
);
create table referenced_defaults_model (
id integer generated by default as identity not null,
defaults_model_id integer not null,
name varchar(255),
constraint pk_referenced_defaults_model primary key (id)
);
create table referenced_defaults_model_draft (
id integer generated by default as identity not null,
defaults_model_id integer not null,
name varchar(255),
constraint pk_referenced_defaults_model_draft primary key (id)
);
create table referencing_bean (
id uuid not null,
constraint pk_referencing_bean primary key (id)
@@ -3614,7 +3735,7 @@ create table t_detail_with_other_namexxxyy (
constraint uq_t_detail_with_other_namexxxyy_some_unique_value unique (some_unique_value),
constraint pk_t_detail_with_other_namexxxyy primary key (id)
);
create sequence t_atable_detail_seq increment by 50;
create sequence t_atable_detail_seq increment by 1;
create table t_atable_thatisrelatively (
id integer not null,
@@ -3623,7 +3744,7 @@ create table t_atable_thatisrelatively (
active boolean default false not null,
constraint pk_t_atable_thatisrelatively primary key (id)
);
create sequence t_atable_master_seq increment by 50;
create sequence t_atable_master_seq increment by 1;
create table ttruck_holder (
id bigint generated by default as identity not null,
@@ -3692,14 +3813,14 @@ create table tire (
constraint uq_tire_wheel unique (wheel),
constraint pk_tire primary key (id)
);
create sequence tire_seq increment by 50;
create sequence tire_seq increment by 1;
create table sa_tire (
id bigint not null,
version integer not null,
constraint pk_sa_tire primary key (id)
);
create sequence sa_tire_seq increment by 50;
create sequence sa_tire_seq increment by 1;
create table tree_entity (
id integer generated by default as identity not null,
@@ -3900,13 +4021,38 @@ create table vehicle_lease (
active_start date,
active_end date,
version bigint not null,
bond decimal(38),
bond decimal(16,3),
min_duration integer not null,
day_rate decimal(38),
day_rate decimal(16,3),
max_days integer,
constraint pk_vehicle_lease primary key (id)
);
create table version_child (
id integer generated by default as identity not null,
name varchar(255),
parent_id integer,
version integer not null,
position integer,
constraint pk_version_child primary key (id)
);
create table version_parent (
id integer generated by default as identity not null,
name varchar(255),
version integer not null,
constraint pk_version_parent primary key (id)
);
create table version_toy (
id integer generated by default as identity not null,
name varchar(255),
child_id integer,
version integer not null,
position integer,
constraint pk_version_toy primary key (id)
);
create table warehouses (
id integer generated by default as identity not null,
officezoneid integer,
@@ -3924,7 +4070,7 @@ create table wheel (
version integer not null,
constraint pk_wheel primary key (id)
);
create sequence wheel_seq increment by 50;
create sequence wheel_seq increment by 1;
create table sa_wheel (
id bigint not null,
@@ -3933,7 +4079,7 @@ create table sa_wheel (
version integer not null,
constraint pk_sa_wheel primary key (id)
);
create sequence sa_wheel_seq increment by 50;
create sequence sa_wheel_seq increment by 1;
create table sp_car_wheel (
id bigint not null,
@@ -3941,7 +4087,7 @@ create table sp_car_wheel (
version integer not null,
constraint pk_sp_car_wheel primary key (id)
);
create sequence sp_car_wheel_seq increment by 50;
create sequence sp_car_wheel_seq increment by 1;
create table g_who_props_otm (
id bigint generated by default as identity not null,
@@ -3987,7 +4133,11 @@ create index ix_contact_last_name_first_name on contact (last_name,first_name);
create index ix_e_basic_name on e_basic (name);
create index ix_efile2_no_fk_owner_id on efile2_no_fk (owner_id);
create index ix_ecsm_values_host_id on ecsm_values (host_id);
create index ix_order_referenced_parent_type on order_referenced_parent (type);
create index ix_organization_node_kind on organization_node (kind);
create index ano_3 on test_annotation_base_entity (direct);
create index ano_1 on test_annotation_base_entity (direct);
create index ano_2 on test_annotation_base_entity (direct);
create index ix_bar_foo_id on bar (foo_id);
alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id) on delete restrict on update restrict;
@@ -4053,6 +4203,12 @@ alter table cepproduct_category add constraint fk_cepproduct_category_category_i
create index ix_cepproduct_category_product_id on cepproduct_category (product_id);
alter table cepproduct_category add constraint fk_cepproduct_category_product_id foreign key (product_id) references cepproduct (id) on delete restrict on update restrict;
create index ix_ciaddress_street_id on ciaddress (street_id);
alter table ciaddress add constraint fk_ciaddress_street_id foreign key (street_id) references cistreet_parent (id) on delete restrict on update restrict;
create index ix_cicustomer_parent_address_id on cicustomer_parent (address_id);
alter table cicustomer_parent add constraint fk_cicustomer_parent_address_id foreign key (address_id) references ciaddress (id) on delete restrict on update restrict;
create index ix_cinh_ref_ref_id on cinh_ref (ref_id);
alter table cinh_ref add constraint fk_cinh_ref_ref_id foreign key (ref_id) references cinh_root (id) on delete restrict on update restrict;
@@ -4160,6 +4316,8 @@ alter table drot_drol add constraint fk_drot_drol_drol foreign key (drol_id) ref
create index ix_dc_detail_master_id on dc_detail (master_id);
alter table dc_detail add constraint fk_dc_detail_master_id foreign key (master_id) references dc_master (id) on delete restrict on update restrict;
alter table defaults_model add constraint fk_defaults_model_id foreign key (id) references defaults_model_draft (id) on delete restrict on update restrict;
create index ix_dfk_cascade_one_id on dfk_cascade (one_id);
alter table dfk_cascade add constraint fk_dfk_cascade_one_id foreign key (one_id) references dfk_cascade_one (id) on delete cascade on update cascade;
@@ -4540,6 +4698,12 @@ alter table om_basic_child add constraint fk_om_basic_child_parent_id foreign ke
create index ix_om_ordered_detail_master_id on om_ordered_detail (master_id);
alter table om_ordered_detail add constraint fk_om_ordered_detail_master_id foreign key (master_id) references om_ordered_master (id) on delete restrict on update restrict;
create index ix_oml_baz_foo_id on oml_baz (foo_id);
alter table oml_baz add constraint fk_oml_baz_foo_id foreign key (foo_id) references oml_foo (id) on delete restrict on update restrict;
create index ix_oml_foo_bar_id on oml_foo (bar_id);
alter table oml_foo add constraint fk_oml_foo_bar_id foreign key (bar_id) references oml_bar (id) on delete restrict on update restrict;
create index ix_o_order_kcustomer_id on o_order (kcustomer_id);
alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id) on delete restrict on update restrict;
@@ -4552,9 +4716,18 @@ alter table o_order_detail add constraint fk_o_order_detail_product_id foreign k
create index ix_s_order_items_order_uuid on s_order_items (order_uuid);
alter table s_order_items add constraint fk_s_order_items_order_uuid foreign key (order_uuid) references s_orders (uuid) on delete restrict on update restrict;
create index ix_order_referenced_parent_master_id on order_referenced_parent (master_id);
alter table order_referenced_parent add constraint fk_order_referenced_parent_master_id foreign key (master_id) references order_master (id) on delete restrict on update restrict;
create index ix_or_order_ship_order_id on or_order_ship (order_id);
alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict;
create index ix_order_toy_child_id on order_toy (child_id);
alter table order_toy add constraint fk_order_toy_child_id foreign key (child_id) references order_referenced_parent (id) on delete restrict on update restrict;
create index ix_ordered_parent_order_master_inheritance_id on ordered_parent (order_master_inheritance_id);
alter table ordered_parent add constraint fk_ordered_parent_order_master_inheritance_id foreign key (order_master_inheritance_id) references order_master_inheritance (id) on delete restrict on update restrict;
alter table organization_node add constraint fk_organization_node_parent_tree_node_id foreign key (parent_tree_node_id) references organization_tree_node (id) on delete restrict on update restrict;
create index ix_orp_detail_master_id on orp_detail (master_id);
@@ -4656,6 +4829,14 @@ alter table question add constraint fk_question_groupobjectid foreign key (group
create index ix_r_orders_customer on r_orders (company,customername);
alter table r_orders add constraint fk_r_orders_customer foreign key (company,customername) references rcustomer (company,name) on delete restrict on update restrict;
alter table referenced_defaults_model add constraint fk_referenced_defaults_model_id foreign key (id) references referenced_defaults_model_draft (id) on delete restrict on update restrict;
create index ix_referenced_defaults_model_defaults_model_id on referenced_defaults_model (defaults_model_id);
alter table referenced_defaults_model add constraint fk_referenced_defaults_model_defaults_model_id foreign key (defaults_model_id) references defaults_model (id) on delete restrict on update restrict;
create index ix_referenced_defaults_model_draft_defaults_model_id on referenced_defaults_model_draft (defaults_model_id);
alter table referenced_defaults_model_draft add constraint fk_referenced_defaults_model_draft_defaults_model_id foreign key (defaults_model_id) references defaults_model_draft (id) on delete restrict on update restrict;
create index ix_rel_master_detail_id on rel_master (detail_id);
alter table rel_master add constraint fk_rel_master_detail_id foreign key (detail_id) references rel_detail (id) on delete restrict on update restrict;
@@ -4777,6 +4958,12 @@ alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign k
create index ix_vehicle_driver_address_id on vehicle_driver (address_id);
alter table vehicle_driver add constraint fk_vehicle_driver_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict;
create index ix_version_child_parent_id on version_child (parent_id);
alter table version_child add constraint fk_version_child_parent_id foreign key (parent_id) references version_parent (id) on delete restrict on update restrict;
create index ix_version_toy_child_id on version_toy (child_id);
alter table version_toy add constraint fk_version_toy_child_id foreign key (child_id) references version_child (id) on delete restrict on update restrict;
create index ix_warehouses_officezoneid on warehouses (officezoneid);
alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id) on delete restrict on update restrict;
+81 -4
View File
@@ -1,4 +1,4 @@
-- Generated by ebean unknown at 2020-03-04T11:05:12.077911Z
-- Generated by ebean unknown at 2020-08-24T21:11:54.586122Z
alter table bar drop constraint if exists fk_bar_foo_id;
drop index if exists ix_bar_foo_id;
@@ -64,6 +64,12 @@ drop index if exists ix_cepproduct_category_category_id;
alter table cepproduct_category drop constraint if exists fk_cepproduct_category_product_id;
drop index if exists ix_cepproduct_category_product_id;
alter table ciaddress drop constraint if exists fk_ciaddress_street_id;
drop index if exists ix_ciaddress_street_id;
alter table cicustomer_parent drop constraint if exists fk_cicustomer_parent_address_id;
drop index if exists ix_cicustomer_parent_address_id;
alter table cinh_ref drop constraint if exists fk_cinh_ref_ref_id;
drop index if exists ix_cinh_ref_ref_id;
@@ -171,6 +177,8 @@ drop index if exists ix_drot_drol_drol;
alter table dc_detail drop constraint if exists fk_dc_detail_master_id;
drop index if exists ix_dc_detail_master_id;
alter table defaults_model drop constraint if exists fk_defaults_model_id;
alter table dfk_cascade drop constraint if exists fk_dfk_cascade_one_id;
drop index if exists ix_dfk_cascade_one_id;
@@ -551,6 +559,12 @@ drop index if exists ix_om_basic_child_parent_id;
alter table om_ordered_detail drop constraint if exists fk_om_ordered_detail_master_id;
drop index if exists ix_om_ordered_detail_master_id;
alter table oml_baz drop constraint if exists fk_oml_baz_foo_id;
drop index if exists ix_oml_baz_foo_id;
alter table oml_foo drop constraint if exists fk_oml_foo_bar_id;
drop index if exists ix_oml_foo_bar_id;
alter table o_order drop constraint if exists fk_o_order_kcustomer_id;
drop index if exists ix_o_order_kcustomer_id;
@@ -563,9 +577,18 @@ drop index if exists ix_o_order_detail_product_id;
alter table s_order_items drop constraint if exists fk_s_order_items_order_uuid;
drop index if exists ix_s_order_items_order_uuid;
alter table order_referenced_parent drop constraint if exists fk_order_referenced_parent_master_id;
drop index if exists ix_order_referenced_parent_master_id;
alter table or_order_ship drop constraint if exists fk_or_order_ship_order_id;
drop index if exists ix_or_order_ship_order_id;
alter table order_toy drop constraint if exists fk_order_toy_child_id;
drop index if exists ix_order_toy_child_id;
alter table ordered_parent drop constraint if exists fk_ordered_parent_order_master_inheritance_id;
drop index if exists ix_ordered_parent_order_master_inheritance_id;
alter table organization_node drop constraint if exists fk_organization_node_parent_tree_node_id;
alter table orp_detail drop constraint if exists fk_orp_detail_master_id;
@@ -667,6 +690,14 @@ drop index if exists ix_question_groupobjectid;
alter table r_orders drop constraint if exists fk_r_orders_customer;
drop index if exists ix_r_orders_customer;
alter table referenced_defaults_model drop constraint if exists fk_referenced_defaults_model_id;
alter table referenced_defaults_model drop constraint if exists fk_referenced_defaults_model_defaults_model_id;
drop index if exists ix_referenced_defaults_model_defaults_model_id;
alter table referenced_defaults_model_draft drop constraint if exists fk_referenced_defaults_model_draft_defaults_model_id;
drop index if exists ix_referenced_defaults_model_draft_defaults_model_id;
alter table rel_master drop constraint if exists fk_rel_master_detail_id;
drop index if exists ix_rel_master_detail_id;
@@ -788,6 +819,12 @@ drop index if exists ix_vehicle_driver_vehicle_id;
alter table vehicle_driver drop constraint if exists fk_vehicle_driver_address_id;
drop index if exists ix_vehicle_driver_address_id;
alter table version_child drop constraint if exists fk_version_child_parent_id;
drop index if exists ix_version_child_parent_id;
alter table version_toy drop constraint if exists fk_version_toy_child_id;
drop index if exists ix_version_toy_child_id;
alter table warehouses drop constraint if exists fk_warehouses_officezoneid;
drop index if exists ix_warehouses_officezoneid;
@@ -887,6 +924,12 @@ drop table if exists cepproduct;
drop table if exists cepproduct_category;
drop table if exists ciaddress;
drop table if exists cicustomer_parent;
drop table if exists cistreet_parent;
drop table if exists cinh_ref;
drop table if exists cinh_root;
@@ -991,6 +1034,10 @@ drop table if exists dc_detail;
drop table if exists dc_master;
drop table if exists defaults_model;
drop table if exists defaults_model_draft;
drop table if exists dfk_cascade;
drop table if exists dfk_cascade_one;
@@ -1142,6 +1189,8 @@ drop table if exists eper_addr;
drop table if exists eperson;
drop table if exists eperson2;
drop table if exists e_person_online;
drop table if exists esimple;
@@ -1253,9 +1302,7 @@ drop table if exists foo;
drop table if exists gen_key_identity;
drop table if exists gen_key_sequence;
drop sequence if exists SEQ;
drop table if exists gen_key_table;
drop sequence if exists SEQ_NAME;
drop table if exists grand_parent_person;
@@ -1548,6 +1595,12 @@ drop table if exists om_ordered_detail;
drop table if exists om_ordered_master;
drop table if exists oml_bar;
drop table if exists oml_baz;
drop table if exists oml_foo;
drop table if exists only_id_entity;
drop table if exists o_order;
@@ -1558,8 +1611,18 @@ drop table if exists s_orders;
drop table if exists s_order_items;
drop table if exists order_master;
drop table if exists order_master_inheritance;
drop table if exists order_referenced_parent;
drop table if exists or_order_ship;
drop table if exists order_toy;
drop table if exists ordered_parent;
drop table if exists organisation;
drop table if exists organization_node;
@@ -1688,6 +1751,10 @@ drop table if exists rcustomer;
drop table if exists r_orders;
drop table if exists referenced_defaults_model;
drop table if exists referenced_defaults_model_draft;
drop table if exists referencing_bean;
drop table if exists region;
@@ -1840,6 +1907,12 @@ drop table if exists vehicle_driver;
drop table if exists vehicle_lease;
drop table if exists version_child;
drop table if exists version_parent;
drop table if exists version_toy;
drop table if exists warehouses;
drop table if exists warehousesshippingzones;
@@ -1867,4 +1940,8 @@ drop index if exists ix_contact_last_name_first_name;
drop index if exists ix_e_basic_name;
drop index if exists ix_efile2_no_fk_owner_id;
drop index if exists ix_ecsm_values_host_id;
drop index if exists ix_order_referenced_parent_type;
drop index if exists ix_organization_node_kind;
drop index if exists ano_3;
drop index if exists ano_1;
drop index if exists ano_2;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+179 -17
View File
@@ -1,4 +1,4 @@
-- Generated by ebean unknown at 2020-03-04T11:18:31.280668Z
-- Generated by ebean unknown at 2020-08-24T21:02:32.420817Z
create table asimple_bean (
id bigint generated by default as identity not null,
name varchar(255),
@@ -307,6 +307,28 @@ create table cepproduct_category (
priority integer
);
create table ciaddress (
id bigint generated by default as identity not null,
street_id bigint,
constraint pk_ciaddress primary key (id)
);
create table cicustomer_parent (
dtype integer not null,
id bigint generated by default as identity not null,
address_id bigint,
notes varchar(255),
constraint pk_cicustomer_parent primary key (id)
);
create table cistreet_parent (
dtype integer not null,
id bigint generated by default as identity not null,
name varchar(255),
num varchar(255),
constraint pk_cistreet_parent primary key (id)
);
create table cinh_ref (
id integer generated by default as identity not null,
ref_id integer,
@@ -641,7 +663,7 @@ create table d_machine_aux_use (
name varchar(255),
edate date,
use_secs bigint not null,
fuel decimal(38),
fuel decimal(16,3),
version bigint not null,
constraint pk_d_machine_aux_use primary key (id)
);
@@ -652,8 +674,8 @@ create table d_machine_stats (
edate date,
total_kms bigint not null,
hours bigint not null,
rate decimal(38),
cost decimal(38),
rate decimal(16,3),
cost decimal(16,3),
version bigint not null,
constraint pk_d_machine_stats primary key (id)
);
@@ -664,7 +686,7 @@ create table d_machine_use (
edate date,
distance_kms bigint not null,
time_secs bigint not null,
fuel decimal(38),
fuel decimal(9,3),
version bigint not null,
constraint pk_d_machine_use primary key (id)
);
@@ -680,7 +702,7 @@ create table dperson (
id bigint generated by default as identity not null,
first_name varchar(255),
last_name varchar(255),
salary decimal(38),
salary decimal(16,3),
constraint pk_dperson primary key (id)
);
@@ -729,6 +751,16 @@ create table dc_master (
constraint pk_dc_master primary key (id)
);
create table defaults_model (
id integer generated by default as identity not null,
constraint pk_defaults_model primary key (id)
);
create table defaults_model_draft (
id integer generated by default as identity not null,
constraint pk_defaults_model_draft primary key (id)
);
create table dfk_cascade (
id bigint generated by default as identity not null,
name varchar(255),
@@ -1511,7 +1543,7 @@ create table esoft_del_user_esoft_del_role (
create table esome_convert_type (
id bigint generated by default as identity not null,
name varchar(255),
money decimal(38),
money decimal(16,3),
constraint pk_esome_convert_type primary key (id)
);
@@ -1801,13 +1833,7 @@ create table gen_key_sequence (
description varchar(255),
constraint pk_gen_key_sequence primary key (id)
);
create sequence SEQ start with 1 increment by 1;
create table gen_key_table (
id bigint generated by default as identity not null,
description varchar(255),
constraint pk_gen_key_table primary key (id)
);
create sequence SEQ_NAME increment by 1;
create table grand_parent_person (
identifier integer generated by default as identity not null,
@@ -2739,6 +2765,23 @@ create table om_ordered_master (
constraint pk_om_ordered_master primary key (id)
);
create table oml_bar (
id bigint generated by default as identity not null,
constraint pk_oml_bar primary key (id)
);
create table oml_baz (
id bigint generated by default as identity not null,
foo_id bigint not null,
constraint pk_oml_baz primary key (id)
);
create table oml_foo (
id bigint generated by default as identity not null,
bar_id bigint not null,
constraint pk_oml_foo primary key (id)
);
create table only_id_entity (
id bigint generated by default as identity not null,
constraint pk_only_id_entity primary key (id)
@@ -2778,10 +2821,30 @@ create table s_order_items (
product_variant_uuid varchar(255),
order_uuid varchar(40),
quantity integer not null,
amount decimal(38),
amount decimal(16,3),
constraint pk_s_order_items primary key (uuid)
);
create table order_master (
id bigint generated by default as identity not null,
constraint pk_order_master primary key (id)
);
create table order_master_inheritance (
id integer generated by default as identity not null,
constraint pk_order_master_inheritance primary key (id)
);
create table order_referenced_parent (
type varchar(31) not null,
id bigint generated by default as identity not null,
name varchar(255),
child_name varchar(255),
master_id bigint,
sort_order integer,
constraint pk_order_referenced_parent primary key (id)
);
create table or_order_ship (
id integer generated by default as identity not null,
order_id integer,
@@ -2792,6 +2855,25 @@ create table or_order_ship (
constraint pk_or_order_ship primary key (id)
);
create table order_toy (
id integer generated by default as identity not null,
title varchar(255),
child_id bigint,
sort_order integer,
constraint pk_order_toy primary key (id)
);
create table ordered_parent (
dtype varchar(31) not null,
id integer generated by default as identity not null,
order_master_inheritance_id integer not null,
common_name varchar(255),
sort_order integer,
ordered_aname varchar(255),
ordered_bname varchar(255),
constraint pk_ordered_parent primary key (id)
);
create table organisation (
id bigint generated by default as identity not null,
name varchar(255),
@@ -3305,6 +3387,20 @@ create table r_orders (
constraint pk_r_orders primary key (company,order_number)
);
create table referenced_defaults_model (
id integer generated by default as identity not null,
defaults_model_id integer not null,
name varchar(255),
constraint pk_referenced_defaults_model primary key (id)
);
create table referenced_defaults_model_draft (
id integer generated by default as identity not null,
defaults_model_id integer not null,
name varchar(255),
constraint pk_referenced_defaults_model_draft primary key (id)
);
create table referencing_bean (
id uuid not null,
constraint pk_referencing_bean primary key (id)
@@ -3900,13 +3996,38 @@ create table vehicle_lease (
active_start date,
active_end date,
version bigint not null,
bond decimal(38),
bond decimal(16,3),
min_duration integer not null,
day_rate decimal(38),
day_rate decimal(16,3),
max_days integer,
constraint pk_vehicle_lease primary key (id)
);
create table version_child (
id integer generated by default as identity not null,
name varchar(255),
parent_id integer,
version integer not null,
position integer,
constraint pk_version_child primary key (id)
);
create table version_parent (
id integer generated by default as identity not null,
name varchar(255),
version integer not null,
constraint pk_version_parent primary key (id)
);
create table version_toy (
id integer generated by default as identity not null,
name varchar(255),
child_id integer,
version integer not null,
position integer,
constraint pk_version_toy primary key (id)
);
create table warehouses (
id integer generated by default as identity not null,
officezoneid integer,
@@ -3987,9 +4108,13 @@ create index ix_contact_last_name_first_name on contact (last_name,first_name);
create index ix_e_basic_name on e_basic (name);
create index ix_efile2_no_fk_owner_id on efile2_no_fk (owner_id);
create index ix_ecsm_values_host_id on ecsm_values (host_id);
create index ix_order_referenced_parent_type on order_referenced_parent (type);
create index ix_organization_node_kind on organization_node (kind);
create unique index concurrently ix_t_detail_with_other_namexxxyy_lowername on t_detail_with_other_namexxxyy (lower(name));
create index ix_t_detail_with_other_namexxxyy_defn on t_detail_with_other_namexxxyy using hash (lower(name)) where lower(name) like 'r%';
create index ano_3 on test_annotation_base_entity (direct);
create index ano_1 on test_annotation_base_entity (direct);
create index ano_2 on test_annotation_base_entity (direct);
create index ix_bar_foo_id on bar (foo_id);
alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id) on delete restrict on update restrict;
@@ -4055,6 +4180,12 @@ alter table cepproduct_category add constraint fk_cepproduct_category_category_i
create index ix_cepproduct_category_product_id on cepproduct_category (product_id);
alter table cepproduct_category add constraint fk_cepproduct_category_product_id foreign key (product_id) references cepproduct (id) on delete restrict on update restrict;
create index ix_ciaddress_street_id on ciaddress (street_id);
alter table ciaddress add constraint fk_ciaddress_street_id foreign key (street_id) references cistreet_parent (id) on delete restrict on update restrict;
create index ix_cicustomer_parent_address_id on cicustomer_parent (address_id);
alter table cicustomer_parent add constraint fk_cicustomer_parent_address_id foreign key (address_id) references ciaddress (id) on delete restrict on update restrict;
create index ix_cinh_ref_ref_id on cinh_ref (ref_id);
alter table cinh_ref add constraint fk_cinh_ref_ref_id foreign key (ref_id) references cinh_root (id) on delete restrict on update restrict;
@@ -4162,6 +4293,8 @@ alter table drot_drol add constraint fk_drot_drol_drol foreign key (drol_id) ref
create index ix_dc_detail_master_id on dc_detail (master_id);
alter table dc_detail add constraint fk_dc_detail_master_id foreign key (master_id) references dc_master (id) on delete restrict on update restrict;
alter table defaults_model add constraint fk_defaults_model_id foreign key (id) references defaults_model_draft (id) on delete restrict on update restrict;
create index ix_dfk_cascade_one_id on dfk_cascade (one_id);
alter table dfk_cascade add constraint fk_dfk_cascade_one_id foreign key (one_id) references dfk_cascade_one (id) on delete cascade on update cascade;
@@ -4542,6 +4675,12 @@ alter table om_basic_child add constraint fk_om_basic_child_parent_id foreign ke
create index ix_om_ordered_detail_master_id on om_ordered_detail (master_id);
alter table om_ordered_detail add constraint fk_om_ordered_detail_master_id foreign key (master_id) references om_ordered_master (id) on delete restrict on update restrict;
create index ix_oml_baz_foo_id on oml_baz (foo_id);
alter table oml_baz add constraint fk_oml_baz_foo_id foreign key (foo_id) references oml_foo (id) on delete restrict on update restrict;
create index ix_oml_foo_bar_id on oml_foo (bar_id);
alter table oml_foo add constraint fk_oml_foo_bar_id foreign key (bar_id) references oml_bar (id) on delete restrict on update restrict;
create index ix_o_order_kcustomer_id on o_order (kcustomer_id);
alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id) on delete restrict on update restrict;
@@ -4554,9 +4693,18 @@ alter table o_order_detail add constraint fk_o_order_detail_product_id foreign k
create index ix_s_order_items_order_uuid on s_order_items (order_uuid);
alter table s_order_items add constraint fk_s_order_items_order_uuid foreign key (order_uuid) references s_orders (uuid) on delete restrict on update restrict;
create index ix_order_referenced_parent_master_id on order_referenced_parent (master_id);
alter table order_referenced_parent add constraint fk_order_referenced_parent_master_id foreign key (master_id) references order_master (id) on delete restrict on update restrict;
create index ix_or_order_ship_order_id on or_order_ship (order_id);
alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict;
create index ix_order_toy_child_id on order_toy (child_id);
alter table order_toy add constraint fk_order_toy_child_id foreign key (child_id) references order_referenced_parent (id) on delete restrict on update restrict;
create index ix_ordered_parent_order_master_inheritance_id on ordered_parent (order_master_inheritance_id);
alter table ordered_parent add constraint fk_ordered_parent_order_master_inheritance_id foreign key (order_master_inheritance_id) references order_master_inheritance (id) on delete restrict on update restrict;
alter table organization_node add constraint fk_organization_node_parent_tree_node_id foreign key (parent_tree_node_id) references organization_tree_node (id) on delete restrict on update restrict;
create index ix_orp_detail_master_id on orp_detail (master_id);
@@ -4658,6 +4806,14 @@ alter table question add constraint fk_question_groupobjectid foreign key (group
create index ix_r_orders_customer on r_orders (company,customername);
alter table r_orders add constraint fk_r_orders_customer foreign key (company,customername) references rcustomer (company,name) on delete restrict on update restrict;
alter table referenced_defaults_model add constraint fk_referenced_defaults_model_id foreign key (id) references referenced_defaults_model_draft (id) on delete restrict on update restrict;
create index ix_referenced_defaults_model_defaults_model_id on referenced_defaults_model (defaults_model_id);
alter table referenced_defaults_model add constraint fk_referenced_defaults_model_defaults_model_id foreign key (defaults_model_id) references defaults_model (id) on delete restrict on update restrict;
create index ix_referenced_defaults_model_draft_defaults_model_id on referenced_defaults_model_draft (defaults_model_id);
alter table referenced_defaults_model_draft add constraint fk_referenced_defaults_model_draft_defaults_model_id foreign key (defaults_model_id) references defaults_model_draft (id) on delete restrict on update restrict;
create index ix_rel_master_detail_id on rel_master (detail_id);
alter table rel_master add constraint fk_rel_master_detail_id foreign key (detail_id) references rel_detail (id) on delete restrict on update restrict;
@@ -4779,6 +4935,12 @@ alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign k
create index ix_vehicle_driver_address_id on vehicle_driver (address_id);
alter table vehicle_driver add constraint fk_vehicle_driver_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict;
create index ix_version_child_parent_id on version_child (parent_id);
alter table version_child add constraint fk_version_child_parent_id foreign key (parent_id) references version_parent (id) on delete restrict on update restrict;
create index ix_version_toy_child_id on version_toy (child_id);
alter table version_toy add constraint fk_version_toy_child_id foreign key (child_id) references version_child (id) on delete restrict on update restrict;
create index ix_warehouses_officezoneid on warehouses (officezoneid);
alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id) on delete restrict on update restrict;
+79 -4
View File
@@ -1,4 +1,4 @@
-- Generated by ebean unknown at 2020-03-04T11:18:31.280668Z
-- Generated by ebean unknown at 2020-08-24T21:02:32.420817Z
alter table if exists bar drop constraint if exists fk_bar_foo_id;
drop index if exists ix_bar_foo_id;
@@ -64,6 +64,12 @@ drop index if exists ix_cepproduct_category_category_id;
alter table if exists cepproduct_category drop constraint if exists fk_cepproduct_category_product_id;
drop index if exists ix_cepproduct_category_product_id;
alter table if exists ciaddress drop constraint if exists fk_ciaddress_street_id;
drop index if exists ix_ciaddress_street_id;
alter table if exists cicustomer_parent drop constraint if exists fk_cicustomer_parent_address_id;
drop index if exists ix_cicustomer_parent_address_id;
alter table if exists cinh_ref drop constraint if exists fk_cinh_ref_ref_id;
drop index if exists ix_cinh_ref_ref_id;
@@ -171,6 +177,8 @@ drop index if exists ix_drot_drol_drol;
alter table if exists dc_detail drop constraint if exists fk_dc_detail_master_id;
drop index if exists ix_dc_detail_master_id;
alter table if exists defaults_model drop constraint if exists fk_defaults_model_id;
alter table if exists dfk_cascade drop constraint if exists fk_dfk_cascade_one_id;
drop index if exists ix_dfk_cascade_one_id;
@@ -551,6 +559,12 @@ drop index if exists ix_om_basic_child_parent_id;
alter table if exists om_ordered_detail drop constraint if exists fk_om_ordered_detail_master_id;
drop index if exists ix_om_ordered_detail_master_id;
alter table if exists oml_baz drop constraint if exists fk_oml_baz_foo_id;
drop index if exists ix_oml_baz_foo_id;
alter table if exists oml_foo drop constraint if exists fk_oml_foo_bar_id;
drop index if exists ix_oml_foo_bar_id;
alter table if exists o_order drop constraint if exists fk_o_order_kcustomer_id;
drop index if exists ix_o_order_kcustomer_id;
@@ -563,9 +577,18 @@ drop index if exists ix_o_order_detail_product_id;
alter table if exists s_order_items drop constraint if exists fk_s_order_items_order_uuid;
drop index if exists ix_s_order_items_order_uuid;
alter table if exists order_referenced_parent drop constraint if exists fk_order_referenced_parent_master_id;
drop index if exists ix_order_referenced_parent_master_id;
alter table if exists or_order_ship drop constraint if exists fk_or_order_ship_order_id;
drop index if exists ix_or_order_ship_order_id;
alter table if exists order_toy drop constraint if exists fk_order_toy_child_id;
drop index if exists ix_order_toy_child_id;
alter table if exists ordered_parent drop constraint if exists fk_ordered_parent_order_master_inheritance_id;
drop index if exists ix_ordered_parent_order_master_inheritance_id;
alter table if exists organization_node drop constraint if exists fk_organization_node_parent_tree_node_id;
alter table if exists orp_detail drop constraint if exists fk_orp_detail_master_id;
@@ -667,6 +690,14 @@ drop index if exists ix_question_groupobjectid;
alter table if exists r_orders drop constraint if exists fk_r_orders_customer;
drop index if exists ix_r_orders_customer;
alter table if exists referenced_defaults_model drop constraint if exists fk_referenced_defaults_model_id;
alter table if exists referenced_defaults_model drop constraint if exists fk_referenced_defaults_model_defaults_model_id;
drop index if exists ix_referenced_defaults_model_defaults_model_id;
alter table if exists referenced_defaults_model_draft drop constraint if exists fk_referenced_defaults_model_draft_defaults_model_id;
drop index if exists ix_referenced_defaults_model_draft_defaults_model_id;
alter table if exists rel_master drop constraint if exists fk_rel_master_detail_id;
drop index if exists ix_rel_master_detail_id;
@@ -788,6 +819,12 @@ drop index if exists ix_vehicle_driver_vehicle_id;
alter table if exists vehicle_driver drop constraint if exists fk_vehicle_driver_address_id;
drop index if exists ix_vehicle_driver_address_id;
alter table if exists version_child drop constraint if exists fk_version_child_parent_id;
drop index if exists ix_version_child_parent_id;
alter table if exists version_toy drop constraint if exists fk_version_toy_child_id;
drop index if exists ix_version_toy_child_id;
alter table if exists warehouses drop constraint if exists fk_warehouses_officezoneid;
drop index if exists ix_warehouses_officezoneid;
@@ -887,6 +924,12 @@ drop table if exists cepproduct cascade;
drop table if exists cepproduct_category cascade;
drop table if exists ciaddress cascade;
drop table if exists cicustomer_parent cascade;
drop table if exists cistreet_parent cascade;
drop table if exists cinh_ref cascade;
drop table if exists cinh_root cascade;
@@ -991,6 +1034,10 @@ drop table if exists dc_detail cascade;
drop table if exists dc_master cascade;
drop table if exists defaults_model cascade;
drop table if exists defaults_model_draft cascade;
drop table if exists dfk_cascade cascade;
drop table if exists dfk_cascade_one cascade;
@@ -1253,9 +1300,7 @@ drop table if exists foo cascade;
drop table if exists gen_key_identity cascade;
drop table if exists gen_key_sequence cascade;
drop sequence if exists SEQ;
drop table if exists gen_key_table cascade;
drop sequence if exists SEQ_NAME;
drop table if exists grand_parent_person cascade;
@@ -1557,6 +1602,12 @@ drop table if exists om_ordered_detail cascade;
drop table if exists om_ordered_master cascade;
drop table if exists oml_bar cascade;
drop table if exists oml_baz cascade;
drop table if exists oml_foo cascade;
drop table if exists only_id_entity cascade;
drop table if exists o_order cascade;
@@ -1567,8 +1618,18 @@ drop table if exists s_orders cascade;
drop table if exists s_order_items cascade;
drop table if exists order_master cascade;
drop table if exists order_master_inheritance cascade;
drop table if exists order_referenced_parent cascade;
drop table if exists or_order_ship cascade;
drop table if exists order_toy cascade;
drop table if exists ordered_parent cascade;
drop table if exists organisation cascade;
drop table if exists organization_node cascade;
@@ -1697,6 +1758,10 @@ drop table if exists rcustomer cascade;
drop table if exists r_orders cascade;
drop table if exists referenced_defaults_model cascade;
drop table if exists referenced_defaults_model_draft cascade;
drop table if exists referencing_bean cascade;
drop table if exists region cascade;
@@ -1850,6 +1915,12 @@ drop table if exists vehicle_driver cascade;
drop table if exists vehicle_lease cascade;
drop table if exists version_child cascade;
drop table if exists version_parent cascade;
drop table if exists version_toy cascade;
drop table if exists warehouses cascade;
drop table if exists warehousesshippingzones cascade;
@@ -1877,6 +1948,10 @@ drop index if exists ix_contact_last_name_first_name;
drop index if exists ix_e_basic_name;
drop index if exists ix_efile2_no_fk_owner_id;
drop index if exists ix_ecsm_values_host_id;
drop index if exists ix_order_referenced_parent_type;
drop index if exists ix_organization_node_kind;
drop index concurrently if exists ix_t_detail_with_other_namexxxyy_lowername;
drop index if exists ix_t_detail_with_other_namexxxyy_defn;
drop index if exists ano_3;
drop index if exists ano_1;
drop index if exists ano_2;
+2 -2
View File
@@ -158,10 +158,10 @@ public abstract class BaseTestCase {
*/
protected String trimSql(String sql, int columns) {
for (int i = 0; i <= columns; i++) {
sql = StringHelper.replaceString(sql, " c" + i + ",", ",");
sql = StringHelper.replace(sql, " c" + i + ",", ",");
}
for (int i = 0; i <= columns; i++) {
sql = StringHelper.replaceString(sql, " c" + i + " ", " ");
sql = StringHelper.replace(sql, " c" + i + " ", " ");
}
return sql;
}
@@ -37,7 +37,7 @@ public class ConditionalTestRunner extends BlockJUnit4ClassRunner {
}
private boolean platformMath(Platform[] platforms) {
Platform basePlatform = DB.getDefault().getPluginApi().getDatabasePlatform().getPlatform().base();
Platform basePlatform = DB.getDefault().getPlatform().base();
for (Platform platform : platforms) {
if (platform.equals(basePlatform)) {
return true;
@@ -10,29 +10,29 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class PrimaryServerTest extends BaseTestCase {
public class DbPrimaryTest extends BaseTestCase {
@Test
public void testIsSkipPrimaryServer() {
PrimaryServer.setSkip(true);
assertTrue(PrimaryServer.isSkip());
PrimaryServer.setSkip(false);
assertFalse(PrimaryServer.isSkip());
DbPrimary.setSkip(true);
assertTrue(DbPrimary.isSkip());
DbPrimary.setSkip(false);
assertFalse(DbPrimary.isSkip());
}
@Test
@ForPlatform(Platform.H2)
public void testGetPrimaryServerName() {
String primaryServerName = PrimaryServer.getDefaultServerName();
String primaryServerName = DbPrimary.getDefaultServerName();
assertEquals("h2", primaryServerName);
}
@Test
public void testLoadProperties() {
Properties properties = PrimaryServer.getProperties();
Properties properties = DbPrimary.getProperties();
assertTrue(!properties.isEmpty());
}
}
+76 -44
View File
@@ -1,16 +1,33 @@
package io.ebean;
import static org.assertj.core.api.Assertions.assertThat;
import io.ebean.util.StringHelper;
import org.junit.Test;
import java.util.Map;
import org.junit.Test;
import io.ebean.util.StringHelper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class StringHelperTest {
@Test
public void isNull() {
assertTrue(StringHelper.isNull(null));
assertTrue(StringHelper.isNull(""));
assertTrue(StringHelper.isNull(" "));
assertFalse(StringHelper.isNull("a"));
}
@Test
public void replaceString() {
assertEquals("sJmethJng", StringHelper.replace("somethong", "o","J"));
assertEquals("somethong", StringHelper.replace("somethong", "o", null));
assertNull(StringHelper.replace(null, "o","J"));
}
@Test
public void testSplitNames() {
assertThat(StringHelper.splitNames("")).hasSize(0);
@@ -22,56 +39,71 @@ public class StringHelperTest {
assertThat(StringHelper.splitNames("foo, bar baz")).containsExactly("foo", "bar", "baz");
assertThat(StringHelper.splitNames("foo, bar\nbaz")).containsExactly("foo", "bar", "baz");
}
@Test
public void testReplaceStringMulti() {
public void removeNewLines() {
String content = "This is\na\rmultiline\r\ntext\n\r";
String[] multi = { "\r\n", "\r", "\n" };
content = StringHelper.replaceStringMulti(content, multi, "<br/>");
assertThat(content).isEqualTo("This is<br/>a<br/>multiline<br/>text<br/><br/>");
content = StringHelper.removeNewLines(content);
assertThat(content).isEqualTo("This is a multiline text ");
}
@Test
public void testParseNameQuotedValue() {
String content = "name1='value1' name2='value2'";
Map<String, String> map = StringHelper.parseNameQuotedValue(content);
assertThat(map).containsEntry("name1", "value1").containsEntry("name2", "value2");
// now check with double quotes
content = "name1=\"value1\" name2=\"value2\"";
map = StringHelper.parseNameQuotedValue(content);
assertThat(map).containsEntry("name1", "value1").containsEntry("name2", "value2");
// now check mix
content = "name1=\"value'1\" name2='value\"2'";
map = StringHelper.parseNameQuotedValue(content);
assertThat(map).containsEntry("name1", "value'1").containsEntry("name2", "value\"2");
}
@Test
public void testCountOccurances() {
String content = "blablabla, bla bla blubb, blubblubb blablub blubblabla ";
assertThat(StringHelper.countOccurances(content , "bla")).isEqualTo(8);
assertThat(StringHelper.countOccurances(content , "blubb")).isEqualTo(3);
assertThat(StringHelper.countOccurances(content , "blah")).isEqualTo(0);
}
@Test
public void testDelimitedToMap() {
String content = "name1=blah; name2 = blubb ;name3\n=foo";
Map<String, String> map = StringHelper.delimitedToMap(content , ";", "=");
Map<String, String> map = StringHelper.delimitedToMap(content, ";", "=");
assertThat(map)
.containsEntry("name1", "blah")
.containsEntry("name2", " blubb ") // white space is not trimmed
.containsEntry("name3", "foo");
}
@Test
public void testDelimitedToArray() {
String content = "foo, bar, bla,blubb,,bla, ,bla";
String[] arr = StringHelper.delimitedToArray(content, ",", true);
assertThat(arr).containsExactly("foo"," bar"," bla","blubb","","bla"," ","bla");
arr = StringHelper.delimitedToArray(content, ",", false);
assertThat(arr).containsExactly("foo"," bar"," bla","blubb","bla"," ","bla");
public void testDelimitedToMap_expect_trimLeading() {
String content = ";name1=foo;name2=bar;";
Map<String, String> map = StringHelper.delimitedToMap(content, ";", "=");
assertThat(map).hasSize(2)
.containsEntry("name1", "foo")
.containsEntry("name2", "bar");
}
@Test
public void testDelimitedToMap_when_emptyEntry() {
String content = ";name1=foo;=;name2=bar;";
Map<String, String> map = StringHelper.delimitedToMap(content, ";", "=");
assertThat(map).hasSize(2)
.containsEntry("name1", "foo")
.containsEntry("name2", "bar");
}
@Test
public void testDelimitedToMap_when_missingValue() {
String content = ";name1=foo;nameX;name2=bar;";
Map<String, String> map = StringHelper.delimitedToMap(content, ";", "=");
assertThat(map).hasSize(3)
.containsEntry("nameX", null)
.containsEntry("name1", "foo")
.containsEntry("name2", "bar");
}
@Test
public void testDelimitedToMap_when_missingValueAtEnd() {
String content = ";name1=foo;nameX;name2=bar;nameX2";
Map<String, String> map = StringHelper.delimitedToMap(content, ";", "=");
assertThat(map).hasSize(3)
.containsEntry("nameX", null)
.containsEntry("name1", "foo")
.containsEntry("name2", "bar");
}
@Test
public void testDelimitedToMap_when_null() {
Map<String, String> map = StringHelper.delimitedToMap(null, ";", "=");
assertThat(map).isEmpty();
}
@Test
public void testDelimitedToMap_when_empty() {
Map<String, String> map = StringHelper.delimitedToMap("", ";", "=");
assertThat(map).isEmpty();
}
}
@@ -1,7 +1,8 @@
package io.ebean.bean;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import org.tests.compositekeys.db.AuditInfo;
import org.tests.model.basic.Customer;
import org.tests.model.basic.EBasic;
import org.tests.model.basic.ResetBasicData;
@@ -19,12 +20,11 @@ import static org.junit.Assert.assertTrue;
public class EntityBeanInterceptTest extends BaseTestCase {
@Test
public void testHasDirtyProperty() throws Exception {
public void testHasDirtyProperty() {
ResetBasicData.reset();
List<Customer> list = Ebean.find(Customer.class).findList();
List<Customer> list = DB.find(Customer.class).findList();
Set<String> propertyNames = new HashSet<>();
propertyNames.add("name");
@@ -32,7 +32,7 @@ public class EntityBeanInterceptTest extends BaseTestCase {
Customer customer = list.get(0);
EntityBeanIntercept ebi = ((EntityBean) customer)._ebean_getIntercept();
EntityBeanIntercept ebi = ebi(customer);
assertFalse(ebi.hasDirtyProperty(propertyNames));
@@ -48,7 +48,7 @@ public class EntityBeanInterceptTest extends BaseTestCase {
public void isPartial_when_new() {
EBasic basic = new EBasic();
EntityBeanIntercept ebi = ((EntityBean) basic)._ebean_getIntercept();
EntityBeanIntercept ebi = ebi(basic);
assertThat(ebi.isPartial()).isTrue();
}
@@ -58,7 +58,7 @@ public class EntityBeanInterceptTest extends BaseTestCase {
EBasic basic = new EBasic();
basic.setId(42);
basic.setName("some");
EntityBeanIntercept ebi = ((EntityBean) basic)._ebean_getIntercept();
EntityBeanIntercept ebi = ebi(basic);
assertThat(ebi.isPartial()).isTrue();
}
@@ -72,8 +72,64 @@ public class EntityBeanInterceptTest extends BaseTestCase {
basic.setSomeDate(null);
basic.setStatus(EBasic.Status.ACTIVE);
EntityBeanIntercept ebi = ((EntityBean) basic)._ebean_getIntercept();
EntityBeanIntercept ebi = ebi(basic);
assertThat(ebi.isPartial()).isFalse();
}
@Test
public void isEmbeddedNewOrDirty() {
AuditInfo auditInfo = new AuditInfo();
EntityBeanIntercept ebi = ebi(auditInfo);
assertTrue(ebi.isNew());
assertTrue(ebi.isEmbeddedNewOrDirty(auditInfo));
auditInfo.setUpdatedBy("initial");
ebi.setLoaded();
assertTrue(ebi.isLoaded());
assertFalse(ebi.isEmbeddedNewOrDirty(auditInfo));
auditInfo.setUpdatedBy("nowDirty");
assertTrue(ebi.isDirty());
assertTrue(ebi.isEmbeddedNewOrDirty(auditInfo));
assertFalse(ebi.isEmbeddedNewOrDirty(null));
}
@Test
public void setEmbeddedLoaded() {
AuditInfo auditInfo = new AuditInfo();
EntityBeanIntercept ebi = ebi(auditInfo);
assertFalse(ebi.isLoaded());
ebi.setEmbeddedLoaded(auditInfo);
assertTrue(ebi.isLoaded());
}
@Test
public void initialisedMany() {
Customer customer = new Customer();
EntityBeanIntercept ebi = ebi(customer);
final int contactsPos = findProperty("contacts", ebi);
assertFalse(ebi.isLoadedProperty(contactsPos));
ebi.initialisedMany(contactsPos);
assertTrue(ebi.isLoadedProperty(contactsPos));
}
private int findProperty(String name, EntityBeanIntercept eb) {
final String[] names = eb.getOwner()._ebean_getPropertyNames();
for (int i = 0; i < names.length; i++) {
if (names[i].equals(name)) {
return i;
}
}
throw new RuntimeException("property not found");
}
@SuppressWarnings("unchecked")
private EntityBeanIntercept ebi(Object bean) {
return ((EntityBean)bean)._ebean_getIntercept();
}
}
@@ -54,9 +54,7 @@ public class MatchingNamingConventionTest {
@Test
public void getSequenceName() {
MatchingNamingConvention nc = createMatchingNamingConventionAllQuoted();
final String sequenceName = nc.getSequenceName("[Customer]", null);
assertEquals("Customer_seq", sequenceName);
assertEquals("Customer_seq", nc.getSequenceName("[Customer]", null));
}
@Test
@@ -1,5 +1,8 @@
package io.ebean.config.dbplatform;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import io.ebean.annotation.ForPlatform;
import io.ebean.annotation.Platform;
import io.ebean.config.MatchingNamingConvention;
import io.ebean.config.PlatformConfig;
@@ -9,9 +12,45 @@ import io.ebean.config.dbplatform.postgres.PostgresPlatform;
import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
public class DatabasePlatformTest {
public class DatabasePlatformTest extends BaseTestCase {
@Test
@ForPlatform(Platform.H2)
public void h2_platform() {
final Platform platform = DB.getDefault().getPlatform();
assertThat(platform).isSameAs(Platform.H2);
}
@Test
@ForPlatform(Platform.POSTGRES)
public void postgres_platform() {
final Platform platform = DB.getDefault().getPlatform().base();
assertThat(platform).isSameAs(Platform.POSTGRES);
}
@Test
@ForPlatform(Platform.MYSQL)
public void mysql_platform() {
final Platform platform = DB.getDefault().getPlatform().base();
assertThat(platform).isSameAs(Platform.MYSQL);
}
@Test
@ForPlatform(Platform.MARIADB)
public void mariadb_platform() {
final Platform platform = DB.getDefault().getPlatform().base();
assertThat(platform).isSameAs(Platform.MARIADB);
}
@Test
@ForPlatform(Platform.SQLSERVER)
public void sqlserver_platform() {
final Platform platform = DB.getDefault().getPlatform().base();
assertThat(platform).isSameAs(Platform.SQLSERVER);
}
@Test
public void convertQuotedIdentifiers_when_allQuotedIdentifier_sqlServer() {
@@ -0,0 +1,44 @@
package io.ebean.config.dbplatform;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class DbIdentityTest {
@Test
public void getSelectLastInsertedId() {
DbIdentity identity = new DbIdentity();
identity.setSelectLastInsertedIdTemplate("lastid for {table}");
assertEquals("lastid for customer",identity.getSelectLastInsertedId("customer"));
assertEquals("lastid for contact",identity.getSelectLastInsertedId("contact"));
identity.setSelectLastInsertedIdTemplate("A{table}B{table}C");
assertEquals("AoneBoneC",identity.getSelectLastInsertedId("one"));
identity.setSelectLastInsertedIdTemplate("{table}A{table}");
assertEquals("oneAone",identity.getSelectLastInsertedId("one"));
}
@Test
public void getSelectLastInsertedId_when_null() {
DbIdentity identity = new DbIdentity();
assertNull(identity.getSelectLastInsertedId("customer"));
assertNull(identity.getSelectLastInsertedId("contact"));
}
@Test
public void getSelectLastInsertedId_when_noPlaceHolder() {
DbIdentity identity = new DbIdentity();
identity.setSelectLastInsertedIdTemplate("lastid");
assertEquals("lastid",identity.getSelectLastInsertedId("customer"));
assertEquals("lastid",identity.getSelectLastInsertedId("contact"));
}
}
@@ -30,10 +30,10 @@ import io.ebean.Update;
import io.ebean.UpdateQuery;
import io.ebean.ValuePair;
import io.ebean.Version;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
@@ -96,6 +96,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
public void setClock(Clock clock) {
}
@Override
public boolean isDisableL2Cache() {
return false;
}
@Override
public SpiLogManager log() {
return null;
@@ -137,6 +142,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
return null;
}
@Override
public Platform getPlatform() {
return Platform.GENERIC;
}
@Override
public SpiServer getPluginApi() {
return null;
@@ -20,12 +20,12 @@ import static org.junit.Assert.assertTrue;
public class PlatformDdl_AlterColumnTest {
private PlatformDdl h2Ddl = PlatformDdlBuilder.create(new H2Platform());
private PlatformDdl pgDdl = PlatformDdlBuilder.create(new PostgresPlatform());
private PlatformDdl mysqlDdl = PlatformDdlBuilder.create(new MySqlPlatform());
private PlatformDdl oraDdl = PlatformDdlBuilder.create(new OraclePlatform());
private PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServer17Platform());
private PlatformDdl hanaDdl = PlatformDdlBuilder.create(new HanaPlatform());
private final PlatformDdl h2Ddl = PlatformDdlBuilder.create(new H2Platform());
private final PlatformDdl pgDdl = PlatformDdlBuilder.create(new PostgresPlatform());
private final PlatformDdl mysqlDdl = PlatformDdlBuilder.create(new MySqlPlatform());
private final PlatformDdl oraDdl = PlatformDdlBuilder.create(new OraclePlatform());
private final PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServer17Platform());
private final PlatformDdl hanaDdl = PlatformDdlBuilder.create(new HanaPlatform());
{
ServerConfig serverConfig = Ebean.getDefaultServer().getPluginApi().getServerConfig();
@@ -122,7 +122,9 @@ public class PlatformDdl_AlterColumnTest {
assertEquals("alter table mytab alter column acol varchar(20)", sql);
sql = pgDdl.alterColumnType("mytab", "acol", "varchar(20)");
assertEquals("alter table mytab alter column acol type varchar(20)", sql);
assertEquals("alter table mytab alter column acol type varchar(20) using acol::varchar(20)", sql);
sql = pgDdl.alterColumnType("mytab", "acol", "bigint");
assertEquals("alter table mytab alter column acol type bigint using acol::bigint", sql);
sql = oraDdl.alterColumnType("mytab", "acol", "varchar(20)");
assertEquals("alter table mytab modify acol varchar2(20)", sql);
@@ -1,7 +1,7 @@
package io.ebeaninternal.server.deploy;
import io.ebean.EbeanServerFactory;
import io.ebean.config.ServerConfig;
import io.ebean.DatabaseFactory;
import io.ebean.config.DatabaseConfig;
import io.ebean.event.AbstractBeanPersistListener;
import io.ebean.event.BeanPersistAdapter;
import io.ebean.event.BeanPersistListener;
@@ -14,9 +14,9 @@ import static org.junit.Assert.*;
public class BeanDescriptor_registerTest {
@Test
public void testRegisterDeregister() throws Exception {
public void testRegisterDeregister() {
ServerConfig config = new ServerConfig();
DatabaseConfig config = new DatabaseConfig();
config.setName("h2other");
config.loadFromProperties();
@@ -25,7 +25,7 @@ public class BeanDescriptor_registerTest {
config.setDefaultServer(false);
config.getClasses().add(EBasic.class);
SpiEbeanServer ebeanServer = (SpiEbeanServer) EbeanServerFactory.create(config);
SpiEbeanServer ebeanServer = (SpiEbeanServer)DatabaseFactory.create(config);
BeanDescriptor<EBasic> desc = ebeanServer.getBeanDescriptor(EBasic.class);
persistListenerRegistrationTests(desc);
@@ -0,0 +1,120 @@
package io.ebeaninternal.server.dto;
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
public class DtoMetaBuilderTest {
@Test
public void includeMethod() {
Map<String, Method> methods = getIncludedMethodsFor(D0.class);
assertThat(methods).hasSize(2);
assertThat(methods.get("setName")).isNotNull();
assertThat(methods.get("setId")).isNotNull();
}
@Test
public void includeMethod_when_notStrictlySetters() {
Map<String, Method> methods = getIncludedMethodsFor(D1.class);
assertThat(methods).hasSize(3);
assertThat(methods.get("setNameThen")).isNotNull();
assertThat(methods.get("setIdFor")).isNotNull();
assertThat(methods.get("setI")).isNotNull();
}
@Test
public void propertyType() {
Map<String, Method> methods = getIncludedMethodsFor(D0.class);
assertThat(methods).hasSize(2);
assertThat(DtoMetaBuilder.propertyType(methods.get("setName"))).isEqualTo(String.class);
assertThat(DtoMetaBuilder.propertyType(methods.get("setId"))).isEqualTo(long.class);
}
@Test
public void propertyName() {
assertThat(DtoMetaBuilder.propertyName("setName")).isEqualTo("name");
assertThat(DtoMetaBuilder.propertyName("setId")).isEqualTo("id");
assertThat(DtoMetaBuilder.propertyName("setI")).isEqualTo("i");
assertThat(DtoMetaBuilder.propertyName("setfoo")).isEqualTo("foo");
}
private Map<String, Method> getIncludedMethodsFor(Class<?> cls) {
Map<String,Method> included = new HashMap<>();
for (Method method : cls.getMethods()) {
if (DtoMetaBuilder.includeMethod(method)) {
included.put(method.getName(), method);
}
}
return included;
}
@SuppressWarnings("unused")
static class D0 {
private String name;
private long id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setId(long id) {
this.id = id;
}
public void setNamePlus(String name, long id) {
this.name = name;
this.id = id;
}
public static void setFoo(String foo) {
}
protected void setProtected(String foo) {
}
private void setPrivate(String foo) {
}
private void setPackage(String foo) {
}
}
@SuppressWarnings("unused")
static class D1 {
public void setNameThen(String name) {
}
public void setIdFor(long id) {
}
public void setI(long val) {
}
public void set(long val) {
}
public D1 setA(long val) {
return this;
}
}
}
@@ -5,6 +5,7 @@ import io.ebean.FetchConfig;
import io.ebean.Query;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.core.OrmQueryRequestTestHelper;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import org.tests.model.basic.Order;
import org.junit.Test;
@@ -94,13 +95,14 @@ public class DLoadContextTest extends BaseTestCase {
@Test
public void construct_when_fetch_expect_100_100_batchSize() {
BeanPropertyAssocMany<?> many = (BeanPropertyAssocMany<?>)getBeanDescriptor(Order.class).getBeanProperty("details");
// the fetch is converted to a query join due to the maxRows
OrmQueryRequest<Order> queryRequest = queryRequest(query().fetch("details").setMaxRows(100));
queryRequest.initTransIfRequired();
queryRequest.endTransIfRequired();
DLoadContext graphContext = (DLoadContext) queryRequest.getGraphContext();
DLoadManyContext details = graphContext.getManyContext("details");
DLoadManyContext details = graphContext.getManyContext("details", many);
assertThat(details.firstBatchSize).isEqualTo(100);
assertThat(details.secondaryBatchSize).isEqualTo(100);
@@ -7,10 +7,12 @@ import static org.assertj.core.api.Assertions.assertThat;
public class TrimLogSqlTest {
@Test
public void trim() throws Exception {
public void trim() {
assertThat(TrimLogSql.trim("hello")).isEqualTo("hello");
assertThat(TrimLogSql.trim("hello\nthere")).isEqualTo("hello\\n there");
assertThat(TrimLogSql.trim("a\nb\nc\nd")).isEqualTo("a\\n b\\n c\\n d");
assertThat(TrimLogSql.trim("a\n\nb")).isEqualTo("a\\n \\n b");
assertThat(TrimLogSql.trim("\n\n\n")).isEqualTo("\\n \\n \\n ");
}
}
@@ -0,0 +1,29 @@
package io.ebeaninternal.server.query;
import io.ebeaninternal.api.SpiQuery;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class SqlTreeAliasTest {
@Test
public void parseRootAlias_when_rootAliasIsNull() {
SqlTreeAlias treeAlias = new SqlTreeAlias(null, SpiQuery.TemporalMode.CURRENT);
assertEquals("A B", treeAlias.parseRootAlias("${}A ${}B"));
assertEquals("ABC", treeAlias.parseRootAlias("A${}B${}C"));
}
@Test
public void parseRootAlias_when_rootAliasHasValue() {
SqlTreeAlias treeAlias = new SqlTreeAlias("t0", SpiQuery.TemporalMode.CURRENT);
assertEquals("t0.A t0.B", treeAlias.parseRootAlias("${}A ${}B"));
assertEquals("At0.Bt0.C", treeAlias.parseRootAlias("A${}B${}C"));
}
}
@@ -0,0 +1,14 @@
package io.ebeaninternal.server.querydefn;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class OrmUpdatePropertiesTest {
@Test
public void trim() {
assertEquals("ship_id", OrmUpdateProperties.trim("${}ship_id"));
assertEquals("(ship_id)", OrmUpdateProperties.trim("(${}ship_id)"));
}
}
@@ -15,14 +15,13 @@ import static org.junit.Assert.assertTrue;
public class DefaultPersistenceContextTest {
Customer customer42;
private final Customer customer42;
Car car1;
private final Car car1;
public DefaultPersistenceContextTest() {
customer42 = new Customer();
customer42.setId(42);
car1 = new Car();
car1.setId(1);
}
@@ -167,10 +166,18 @@ public class DefaultPersistenceContextTest {
@Test
public void forIterate() {
final DefaultPersistenceContext pc = pcWith42();
final Object origCustomer42 = pc.get(Customer.class, 42);
// act
final PersistenceContext pcIterate = pc.forIterate();
assertThat(pc).isNotSameAs(pcIterate);
assertThat(pcIterate.size(Customer.class)).isEqualTo(1);
// assert same instance (bean effectively transferred to iterator persistence context
final Object customer42 = pcIterate.get(Customer.class, 42);
assertThat(customer42).isSameAs(origCustomer42);
final PersistenceContext.WithOption option = pcIterate.getWithOption(Customer.class, 42);
assertThat(option.getBean()).isSameAs(origCustomer42);
}
@Test
@@ -217,7 +224,7 @@ public class DefaultPersistenceContextTest {
// ACT - obtain new PC forIterateReset
PersistenceContext pcReset = pcIterate.forIterateReset();
// keeps original customer beans as new added beans there
// keeps original customer beans as no new added beans there
assertThat(pcReset.size(Customer.class)).isEqualTo(100); // customers didn't change
// added beans to contacts and products so those where reset
assertThat(pcReset.size(Contact.class)).isEqualTo(0);
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.transaction;
import io.ebean.DB;
import io.ebean.Transaction;
import io.ebean.TransactionCallbackAdapter;
import io.ebean.cache.ServerCache;
import io.ebean.cache.ServerCacheManager;
import org.junit.Test;
@@ -9,6 +10,8 @@ import org.tests.model.basic.Contact;
import org.tests.model.basic.Customer;
import org.tests.model.basic.EBasic;
import java.util.concurrent.atomic.AtomicInteger;
import static org.assertj.core.api.Assertions.assertThat;
public class JdbcTransactionTest {
@@ -66,4 +69,40 @@ public class JdbcTransactionTest {
}
}
@Test
public void postNestedCallback() {
// test both pre-commit and post-commit to ensure callbacks don't disappear and new ones can be added
AtomicInteger preCommitCallCount = new AtomicInteger();
AtomicInteger postCommitCallCount = new AtomicInteger();
try (Transaction transaction = DB.beginTransaction()) {
DB.currentTransaction().register(
new TransactionCallbackAdapter() {
@Override
public void postCommit() {
postCommitCallCount.incrementAndGet();
DB.currentTransaction().register(
new TransactionCallbackAdapter() {
@Override
public void postCommit() {
postCommitCallCount.incrementAndGet();
}
}
);
}
@Override
public void preCommit() {
preCommitCallCount.incrementAndGet();
}
}
);
EBasic basic = new EBasic("b1");
DB.save(basic);
transaction.commit(); // transaction will fail if recursive post-commit is failing
assertThat(preCommitCallCount.get()).isEqualTo(1); // precommit executed once
assertThat(postCommitCallCount.get()).isEqualTo(2); // postcommit executed twice
}
}
}
@@ -1,23 +1,21 @@
package org.tests.embedded;
import io.ebean.Ebean;
import io.ebean.DB;
import org.junit.Test;
import org.tests.model.embedded.EAddress;
import org.tests.model.embedded.EAddressStatus;
import org.tests.model.embedded.EPerson;
import org.tests.model.embedded.EPerson3;
public class TestEmbeddedEmpty {
@Test
public void insertEmptyEmbedded() {
EPerson person = new EPerson();
EPerson3 person = new EPerson3();
person.setName("with empty embedded");
// set empty embedded bean
person.setAddress(new EAddress());
Ebean.save(person);
DB.save(person);
// treat all embedded properties as loaded
person.getAddress().getCity();
@@ -28,7 +26,7 @@ public class TestEmbeddedEmpty {
EAddressStatus.TWO.doIt();
Ebean.find(EPerson.class)
DB.find(EPerson3.class)
.where().eq("address.status", EAddressStatus.TWO)
.findList();

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