Compare commits

..
Author SHA1 Message Date
rob bygrave 7ec5fe6a85 [maven-release-plugin] prepare release ebean-parent-12.6.6 2021-01-24 17:42:38 +13:00
rob bygrave 9ea5505214 Bump to ebean agent 12.6.6 2021-01-24 17:40:13 +13:00
Robin Bygrave 75d3b566a7 Merge branch 'FOCONIS-prePersist-postPersist-fix-batch-flush-12' 2021-01-22 14:01:19 +13:00
Robin Bygrave e38059f52c #2149 - Fix for ADD: jdbc batch flush doesnt execute sql statements created in lifecycle methods (e.g. beans saved in PostInsert etc)
Note that the foconis fork has a onPersist extension which is removed from the test.
2021-01-22 14:00:48 +13:00
Robin Bygrave 72331aa945 Merge branch 'prePersist-postPersist-fix-batch-flush-12' of https://github.com/FOCONIS/ebean into FOCONIS-prePersist-postPersist-fix-batch-flush-12 2021-01-22 13:14:05 +13:00
Robin Bygrave e497c54f82 No effective change - modify test redis ClusterTest to have 20ms wait 2021-01-21 17:01:36 +13:00
Robin Bygrave b44091ff3a #2147 Fix for ADD: multiple to many outer joins cause wrong count in distinct count…
Copy of Rolands fix in FOCONIS branch. This also brings over some of the extra tests found there.

Note that the SQL is slightly different from the FOCONIS branch in that there is additional foreign key columns included in the sub-query select clause.
2021-01-21 16:56:42 +13:00
Robin Bygrave 2ab889f889 Merge branch 'FOCONIS-count-distinct-with-two-joins-12' 2021-01-21 14:50:32 +13:00
Robin Bygrave 23541e661e Merge branch 'count-distinct-with-two-joins-12' of https://github.com/FOCONIS/ebean into FOCONIS-count-distinct-with-two-joins-12 2021-01-21 14:45:56 +13:00
trojo 6778e37652 ADD: batch flash doesnt execute sql statements created in lifecycle methods 2021-01-20 17:43:14 +01:00
rob bygrave 5eac31283d #2148 - PersistenceException: No ScalarType registered for class java.util.LinkedHashMap 2021-01-20 23:31:45 +13:00
trojo 38016773d4 added comments 2021-01-20 10:47:53 +01:00
trojo ad80eb267f ADD: multiple to many outer joins cause wrong count in distinct count queries 2021-01-20 09:57:25 +01:00
rob bygrave 449e0832e0 Merge branch 'FOCONIS-cache-with-lazyload-wrong-12' 2021-01-20 21:37:57 +13:00
rob bygrave f28f5c9a01 #2146 - no change - Tidy test only TestWithCacheAndLazyLoad 2021-01-20 21:37:29 +13:00
rob bygrave 9dd28d8879 #2146 - Fix for Cache with lazy load doesnt work
When the list is empty() it has already been loaded and loading should skip the l2 cache
2021-01-20 21:10:49 +13:00
rob bygrave b47eec99a5 Merge branch 'cache-with-lazyload-wrong-12' of https://github.com/FOCONIS/ebean into FOCONIS-cache-with-lazyload-wrong-12 2021-01-20 20:36:18 +13:00
Robin Bygrave 99bb55efa0 No change - update ebean-test test configuration only for windows 2021-01-20 17:22:00 +13:00
Robin Bygrave 4408eb618a No change - update test only - TestHistoryOneToMany with wait for when run on windows 2021-01-20 17:11:07 +13:00
rob bygrave 9ccd1b1b27 No effective change - tidy whitespace in SqlTreeBuilder and SqlTreeNodeExtraJoin 2021-01-20 00:10:09 +13:00
rob bygrave 0c1657fef5 #2145 - SoftDelete predicate missing on join to ManyToOne supporting predicate expression 2021-01-20 00:00:27 +13:00
Noemi Szemenyei ee393c6485 ADD: testcase for wrong lazyload with cache 2021-01-19 11:41:19 +01:00
rob bygrave 7f68b9d846 No effective change - tidy whitespace in BeanDescriptorCacheHelp 2021-01-19 22:48:29 +13:00
rob bygrave 2035a3344e Merge branch 'FOCONIS-persistcontext-wrong' 2021-01-19 22:37:45 +13:00
rob bygrave ade36582a0 #2144 - Fix for NPE via Wrong beans in PersistContext avoid proper lazy load 2021-01-19 22:37:15 +13:00
Roland Praml a4b8be61e3 ADD: some suggestions/debug hints 2021-01-11 11:50:25 +01:00
Roland Praml b7feb62ecd ADD: testcase for broken lazyload 2021-01-11 11:50:05 +01:00
rob bygrave 7e48f7c8eb [maven-release-plugin] prepare for next development iteration 2021-01-05 18:02:21 +13:00
rob bygrave 501f8111fe [maven-release-plugin] prepare release ebean-parent-12.6.5 2021-01-05 18:02:09 +13:00
rob bygrave d8f4503d98 #2141 - Fix for failing test, revert of fix for #2127 2021-01-05 17:56:55 +13:00
Rob BygraveandGitHub 0d83978c58 Merge pull request #2141 from tobias-/failing_cascade_test_case_2
Failing testcase that shows wipe of all old children on save
2021-01-05 17:30:56 +13:00
Tobias 69e56be459 Failing testcase that shows wipe of all old children on save
When adding a child to a newly saved bean (A), all other children are
killed on save of A.
2020-12-28 15:35:15 +01:00
rob bygrave 35a721039d [maven-release-plugin] prepare for next development iteration 2020-12-23 20:25:47 +13:00
rob bygrave 98b4ac5029 [maven-release-plugin] prepare release ebean-parent-12.6.4 2020-12-23 20:25:22 +13:00
rob bygrave fe874c946d #2140 - Bump ebean-migration dependency of ebean-ddl-generator to 12.4.0 (update ebean-test) 2020-12-23 20:22:50 +13:00
rob bygrave 53386e9bf4 Update ebean-core-type name and description only 2020-12-22 16:12:20 +13:00
rob bygrave 5435055f5c Add ebean-redis, ebean-postgis and ebean-core-type to ebean-bom 2020-12-22 16:08:59 +13:00
rob bygrave 583e10f5c6 #2139 - Fix for - Failing testcase that shows wipe of all children on save (related to #2127) 2020-12-22 15:49:37 +13:00
Rob BygraveandGitHub 5393d709a3 Merge pull request #2139 from tobias-/failing_cascade_test_case
Failing testcase that shows wipe of all children on save
2020-12-22 14:55:12 +13:00
Tobias fc1c9392aa Failing testcase that shows wipe of all children on save
When adding a newly saved bean (A) to another bean (B), all children
in A are wiped on saving B.
2020-12-21 15:32:40 +01:00
rob bygrave 6b2c48d4f6 #2135 - ebean doest not support Spring @Transactional(propagation = Propagation.REQUIRES_NEW) 2020-12-21 16:40:19 +13:00
rob bygrave 400ae3cf4b #2138 - Mark Transaction.flushBatch() as deprecated - migrate to flush(); 2020-12-21 14:58:04 +13:00
rob bygrave f22a322104 No effective change - Refactor tidy AbstractSqlQueryRequest after #2137
- Rename trans to transaction
- Tidy whitespace
2020-12-21 14:18:13 +13:00
rob bygrave e98ff952bf #2137 - Expected Transaction flush on SqlQuery and DtoQuery not occurring 2020-12-21 14:11:28 +13:00
rob bygrave 573e1b553c [maven-release-plugin] prepare for next development iteration 2020-12-18 15:04:05 +13:00
64 changed files with 1292 additions and 392 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<name>ebean api</name>
@@ -519,11 +519,11 @@ public interface Transaction extends AutoCloseable {
void flush() throws PersistenceException;
/**
* This is a synonym for flush() and will be deprecated.
* Deprecated - migrate to flush().
* <p>
* flush() is preferred as it matches the JPA flush() method.
* </p>
*/
@Deprecated
void flushBatch() throws PersistenceException;
/**
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.3</tag>
<tag>ebean-parent-12.6.6</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
+32 -14
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<name>ebean bom</name>
@@ -18,8 +18,8 @@
<ebean-migration.version>12.4.0</ebean-migration.version>
<ebean-test-docker.version>4.1</ebean-test-docker.version>
<ebean-datasource.version>7.0</ebean-datasource.version>
<ebean-agent.version>12.6.2</ebean-agent.version>
<ebean-maven-plugin.version>12.6.2</ebean-maven-plugin.version>
<ebean-agent.version>12.6.6</ebean-agent.version>
<ebean-maven-plugin.version>12.6.6</ebean-maven-plugin.version>
</properties>
<dependencyManagement>
@@ -81,72 +81,90 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>12.6.6</version>
</dependency>
</dependencies>
</dependencyManagement>
+4 -2
View File
@@ -4,10 +4,12 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<artifactId>ebean-core-type</artifactId>
<name>ebean core type</name>
<description>ebean scalar types api</description>
<properties>
<jackson-core.version>2.11.3</jackson-core.version>
@@ -19,7 +21,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
+7 -7
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,7 +15,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.3</tag>
<tag>ebean-parent-12.6.6</tag>
</scm>
<properties>
@@ -70,7 +70,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>12.2.0</version>
<version>12.4.0</version>
<scope>test</scope>
</dependency>
@@ -92,19 +92,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
@@ -301,7 +301,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.5.0</version>
<version>12.6.6</version>
<executions>
<execution>
<id>test</id>
@@ -27,7 +27,7 @@ public abstract class AbstractSqlQueryRequest {
protected final SpiEbeanServer server;
protected SpiTransaction trans;
protected SpiTransaction transaction;
private boolean createdTransaction;
@@ -47,18 +47,18 @@ public abstract class AbstractSqlQueryRequest {
AbstractSqlQueryRequest(SpiEbeanServer server, SpiSqlBinding query, Transaction t) {
this.server = server;
this.query = query;
this.trans = (SpiTransaction) t;
this.transaction = (SpiTransaction) t;
}
/**
* Create a transaction if none currently exists.
*/
public void initTransIfRequired() {
if (trans == null) {
trans = server.currentServerTransaction();
if (trans == null || !trans.isActive()) {
if (transaction == null) {
transaction = server.currentServerTransaction();
if (transaction == null || !transaction.isActive()) {
// create a local readOnly transaction
trans = server.createReadOnlyTransaction(null);
transaction = server.createReadOnlyTransaction(null);
createdTransaction = true;
}
}
@@ -69,20 +69,18 @@ public abstract class AbstractSqlQueryRequest {
*/
public void endTransIfRequired() {
if (createdTransaction) {
trans.commit();
transaction.commit();
}
}
public EbeanServer getServer() {
return server;
}
public SpiTransaction getTransaction() {
return trans;
protected void flushJdbcBatchOnQuery() {
if (transaction.isFlushOnQuery()) {
transaction.flush();
}
}
public boolean isLogSql() {
return trans.isLogSql();
return transaction.isLogSql();
}
/**
@@ -120,7 +118,6 @@ public abstract class AbstractSqlQueryRequest {
* Prepare the SQL taking into account named bind parameters.
*/
private void prepareSql() {
String sql = query.getQuery();
BindParams bindParams = query.getBindParams();
if (!bindParams.isEmpty()) {
@@ -131,7 +128,6 @@ public abstract class AbstractSqlQueryRequest {
}
private String limitOffset(String sql) {
int firstRow = query.getFirstRow();
int maxRows = query.getMaxRows();
if (firstRow > 0 || maxRows > 0) {
@@ -149,10 +145,8 @@ public abstract class AbstractSqlQueryRequest {
}
protected void executeAsSql(Binder binder) throws SQLException {
prepareSql();
Connection conn = trans.getInternalConnection();
Connection conn = transaction.getInternalConnection();
pstmt = conn.prepareStatement(sql);
if (query.getTimeout() > 0) {
pstmt.setQueryTimeout(query.getTimeout());
@@ -160,14 +154,12 @@ public abstract class AbstractSqlQueryRequest {
if (query.getBufferFetchSizeHint() > 0) {
pstmt.setFetchSize(query.getBufferFetchSizeHint());
}
BindParams bindParams = query.getBindParams();
if (!bindParams.isEmpty()) {
this.bindLog = binder.bind(bindParams, pstmt, conn);
}
if (isLogSql()) {
trans.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ")"));
transaction.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ")"));
}
setResultSet(pstmt.executeQuery(), null);
@@ -215,7 +215,6 @@ class DefaultBeanLoader {
desc.contextPut(pc, id, bean);
ebi.setPersistenceContext(pc);
}
boolean draft = desc.isDraftInstance(bean);
if (embeddedOwnerIndex == -1) {
@@ -245,7 +244,6 @@ class DefaultBeanLoader {
// and put the data into the original bean
query.setUsageProfiling(false);
query.setPersistenceContext(pc);
query.setMode(mode);
query.setId(id);
@@ -50,7 +50,7 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
ormQuery.setManualId();
// execute the underlying ORM query returning the ResultSet
SpiResultSet result = server.findResultSet(ormQuery, trans);
SpiResultSet result = server.findResultSet(ormQuery, transaction);
this.pstmt = result.getStatement();
this.sql = ormQuery.getGeneratedSql();
setResultSet(result.getResultSet(), ormQuery.getQueryPlanKey());
@@ -88,14 +88,17 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
}
public void findEach(Consumer<T> consumer) {
flushJdbcBatchOnQuery();
queryEngine.findEach(this, consumer);
}
public void findEachWhile(Predicate<T> consumer) {
flushJdbcBatchOnQuery();
queryEngine.findEachWhile(this, consumer);
}
public List<T> findList() {
flushJdbcBatchOnQuery();
return queryEngine.findList(this);
}
@@ -388,7 +388,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
@Override
public void preGetterTrigger(int propertyIndex) {
if (flushBatchOnGetter(propertyIndex)) {
transaction.flushBatch();
transaction.flush();
}
}
@@ -56,35 +56,43 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
}
boolean findEachRow(RowConsumer mapper) {
flushJdbcBatchOnQuery();
queryEngine.findEachRow(this, mapper);
return true;
}
<T> List<T> findListMapper(RowMapper<T> mapper) {
flushJdbcBatchOnQuery();
return queryEngine.findListMapper(this, mapper);
}
<T> T findOneMapper(RowMapper<T> mapper) {
flushJdbcBatchOnQuery();
return queryEngine.findOneMapper(this, mapper);
}
public <T> List<T> findSingleAttributeList(Class<T> cls) {
flushJdbcBatchOnQuery();
return queryEngine.findSingleAttributeList(this, cls);
}
public <T> T findSingleAttribute(Class<T> cls) {
flushJdbcBatchOnQuery();
return queryEngine.findSingleAttribute(this, cls);
}
public void findEach(Consumer<SqlRow> consumer) {
flushJdbcBatchOnQuery();
queryEngine.findEach(this, consumer);
}
public void findEachWhile(Predicate<SqlRow> consumer) {
flushJdbcBatchOnQuery();
queryEngine.findEach(this, consumer);
}
public List<SqlRow> findList() {
flushJdbcBatchOnQuery();
return queryEngine.findList(this);
}
@@ -92,9 +100,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
* Build the list of property names.
*/
private String[] getPropertyNames() throws SQLException {
ResultSetMetaData metaData = resultSet.getMetaData();
int columnsPlusOne = metaData.getColumnCount() + 1;
ArrayList<String> propNames = new ArrayList<>(columnsPlusOne - 1);
for (int i = 1; i < columnsPlusOne; i++) {
@@ -107,9 +113,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
* Read and return the next SqlRow.
*/
public SqlRow createNewRow() throws SQLException {
rows++;
SqlRow sqlRow = queryEngine.createSqlRow(estimateCapacity);
int index = 0;
for (String propertyName : propertyNames) {
@@ -121,9 +125,9 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
}
public void logSummary() {
if (trans.isLogSummary()) {
if (transaction.isLogSummary()) {
long micros = (System.nanoTime() - startNano) / 1000L;
trans.logSummary("SqlQuery rows[" + rows + "] micros[" + micros + "] bind[" + bindLog + "]");
transaction.logSummary("SqlQuery rows[" + rows + "] micros[" + micros + "] bind[" + bindLog + "]");
}
}
@@ -136,7 +140,6 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
}
public <T> List<T> mapList(RowMapper<T> mapper) throws SQLException {
List<T> list = new ArrayList<>();
while (next()) {
list.add(mapper.map(resultSet, rows++));
@@ -1872,6 +1872,17 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return query.setId(id).findOne();
}
/**
* Create a reference with a check for the bean in the persistence context.
*/
public EntityBean createReference(Boolean readOnly, Object id, PersistenceContext pc) {
Object refBean = contextGet(pc, id);
if (refBean == null) {
refBean = createReference(readOnly, false, id, pc);
}
return (EntityBean)refBean;
}
/**
* Create a reference bean based on the id.
*/
@@ -89,7 +89,6 @@ final class BeanDescriptorCacheHelp<T> {
BeanDescriptorCacheHelp(BeanDescriptor<T> desc, SpiCacheManager cacheManager, CacheOptions cacheOptions,
boolean cacheSharableBeans, BeanPropertyAssocOne<?>[] propertiesOneImported) {
this.desc = desc;
this.beanType = desc.rootBeanType;
this.cacheName = beanType.getSimpleName();
@@ -99,7 +98,6 @@ final class BeanDescriptorCacheHelp<T> {
this.cacheSharableBeans = cacheSharableBeans;
this.propertiesOneImported = propertiesOneImported;
this.naturalKey = cacheOptions.getNaturalKey();
if (!cacheOptions.isEnableQueryCache()) {
this.queryCache = null;
} else {
@@ -133,7 +131,6 @@ final class BeanDescriptorCacheHelp<T> {
void deriveNotifyFlags() {
cacheNotifyOnAll = (invalidateQueryCache || beanCache != null || queryCache != null);
cacheNotifyOnDelete = !cacheNotifyOnAll && isNotifyOnDeletes();
if (logger.isDebugEnabled()) {
if (cacheNotifyOnAll || cacheNotifyOnDelete) {
String notifyMode = cacheNotifyOnAll ? "All" : "Delete";
@@ -292,7 +289,6 @@ final class BeanDescriptorCacheHelp<T> {
* Try to load the bean collection from cache return true if successful.
*/
boolean manyPropLoad(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {
if (many.isElementCollection()) {
// held as part of the bean cache so skip
return false;
@@ -307,14 +303,12 @@ final class BeanDescriptorCacheHelp<T> {
EntityBean ownerBean = bc.getOwnerBean();
EntityBeanIntercept ebi = ownerBean._ebean_getIntercept();
PersistenceContext persistenceContext = ebi.getPersistenceContext();
BeanDescriptor<?> targetDescriptor = many.getTargetDescriptor();
List<Object> idList = entry.getIdList();
bc.checkEmptyLazyLoad();
for (Object id : idList) {
Object refBean = targetDescriptor.createReference(readOnly, false, id, persistenceContext);
many.add(bc, (EntityBean) refBean);
many.add(bc, targetDescriptor.createReference(readOnly, id, persistenceContext));
}
return true;
}
@@ -323,7 +317,6 @@ final class BeanDescriptorCacheHelp<T> {
* Put the beanCollection into the cache.
*/
void manyPropPut(BeanPropertyAssocMany<?> many, Object details, Object parentId) {
if (many.isElementCollection()) {
CachedBeanData data = (CachedBeanData) beanCache.get(parentId);
if (data != null) {
@@ -351,7 +344,6 @@ final class BeanDescriptorCacheHelp<T> {
}
void cachePutManyIds(Object parentId, String manyName, CachedManyIds entry) {
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, manyName);
if (manyLog.isDebugEnabled()) {
manyLog.debug(" PUT {}({}).{} - ids:{}", cacheName, parentId, manyName, entry);
@@ -360,7 +352,6 @@ final class BeanDescriptorCacheHelp<T> {
}
private CachedManyIds createManyIds(BeanPropertyAssocMany<?> many, Object details) {
Collection<?> actualDetails = BeanCollectionUtil.getActualDetails(details);
if (actualDetails == null) {
return null;
@@ -378,7 +369,6 @@ final class BeanDescriptorCacheHelp<T> {
* Hit the bean cache with the given ids returning the hits.
*/
BeanCacheResult<T> cacheIdLookup(PersistenceContext context, Collection<?> ids) {
Set<Object> keys = new HashSet<>(ids.size());
for (Object id : ids) {
keys.add(desc.cacheKey(id));
@@ -395,7 +385,6 @@ final class BeanDescriptorCacheHelp<T> {
T bean = convertToBean(entry.getKey(), false, context, cachedBeanData);
result.add(bean, desc.getBeanId(bean));
}
return result;
}
@@ -403,14 +392,12 @@ final class BeanDescriptorCacheHelp<T> {
* Use natural keys to hit the bean cache and return resulting hits.
*/
BeanCacheResult<T> naturalKeyLookup(PersistenceContext context, Set<Object> keys) {
if (context == null) {
context = new DefaultPersistenceContext();
}
// naturalKey -> Id map
Map<Object, Object> naturalKeyMap = naturalKeyCache.getAll(keys);
if (natLog.isTraceEnabled()) {
natLog.trace(" MLOOKUP {}({}) - hits:{}", cacheName, keys, naturalKeyMap);
}
@@ -433,15 +420,12 @@ final class BeanDescriptorCacheHelp<T> {
}
// process the hits into beans etc
for (Map.Entry<Object, Object> entry : beanDataMap.entrySet()) {
Object id = entry.getKey();
CachedBeanData cachedBeanData = (CachedBeanData) entry.getValue();
T bean = convertToBean(id, false, context, cachedBeanData);
Object naturalKey = reverseMap.get(id);
result.add(bean, naturalKey);
}
return result;
}
@@ -452,7 +436,6 @@ final class BeanDescriptorCacheHelp<T> {
if (context == null) {
context = new DefaultPersistenceContext();
}
// Not using a loadContext for beans coming out of L2 cache
// so that means no batch lazy loading for these beans
EntityBean entityBean = (EntityBean) bean;
@@ -522,7 +505,6 @@ final class BeanDescriptorCacheHelp<T> {
* Put a bean into the bean cache.
*/
void beanCachePut(EntityBean bean) {
if (desc.inheritInfo != null) {
desc.descOf(bean.getClass()).cacheBeanPutDirect(bean);
} else {
@@ -531,7 +513,6 @@ final class BeanDescriptorCacheHelp<T> {
}
void beanCachePutAllDirect(Collection<EntityBean> beans) {
Map<Object, Object> natKeys = null;
if (naturalKey != null) {
natKeys = new LinkedHashMap<>();
@@ -566,15 +547,12 @@ final class BeanDescriptorCacheHelp<T> {
* Put the bean into the bean cache.
*/
void beanCachePutDirect(EntityBean bean) {
CachedBeanData beanData = beanExtractData(desc, bean);
String key = desc.cacheKeyForBean(bean);
if (beanLog.isDebugEnabled()) {
beanLog.debug(" PUT {}({}) data:{}", cacheName, key, beanData);
}
getBeanCache().put(key, beanData);
if (naturalKey != null) {
String naturalKey = calculateNaturalKey(beanData);
if (naturalKey != null) {
@@ -618,7 +596,6 @@ final class BeanDescriptorCacheHelp<T> {
* Return a bean from the bean cache.
*/
private T beanCacheGetInternal(String key, Boolean readOnly, PersistenceContext context) {
CachedBeanData data = (CachedBeanData) getBeanCache().get(key);
if (data == null) {
if (beanLog.isTraceEnabled()) {
@@ -646,7 +623,6 @@ final class BeanDescriptorCacheHelp<T> {
return (T) bean;
}
}
return (T) loadBean(id, readOnly, data, context);
}
@@ -654,7 +630,6 @@ final class BeanDescriptorCacheHelp<T> {
* Load the entity bean taking into account inheritance.
*/
private EntityBean loadBean(Object id, Boolean readOnly, CachedBeanData data, PersistenceContext context) {
String discValue = data.getDiscValue();
if (discValue == null) {
return loadBeanDirect(id, readOnly, data, context);
@@ -674,7 +649,6 @@ final class BeanDescriptorCacheHelp<T> {
* Load the entity bean from cache data given this is the root bean type.
*/
EntityBean loadBeanDirect(Object id, Boolean readOnly, CachedBeanData data, PersistenceContext context) {
id = desc.convertId(id);
EntityBean bean = null;
if (context == null) {
@@ -682,7 +656,6 @@ final class BeanDescriptorCacheHelp<T> {
} else {
bean = (EntityBean) desc.contextGet(context, id);
}
if (bean == null) {
bean = desc.createEntityBean();
desc.setId(id, bean);
@@ -698,7 +671,6 @@ final class BeanDescriptorCacheHelp<T> {
}
CachedBeanDataToBean.load(desc, bean, data, context);
if (desc.isReadAuditing()) {
desc.readAuditBean("l2", "", bean);
}
@@ -709,7 +681,6 @@ final class BeanDescriptorCacheHelp<T> {
* Load the embedded bean checking for inheritance.
*/
EntityBean embeddedBeanLoad(CachedBeanData data, PersistenceContext context) {
String discValue = data.getDiscValue();
if (discValue == null) {
return embeddedBeanLoadDirect(data, context);
@@ -746,25 +717,20 @@ final class BeanDescriptorCacheHelp<T> {
* Load a batch of entities from L2 bean cache checking the lazy loaded property is loaded.
*/
Set<EntityBeanIntercept> beanCacheLoadAll(List<EntityBeanIntercept> list, PersistenceContext context, int lazyLoadProperty, String propertyName) {
Map<Object, EntityBeanIntercept> ebis = new HashMap<>();
for (EntityBeanIntercept ebi : list) {
ebis.put(desc.cacheKeyForBean(ebi.getOwner()), ebi);
}
Map<Object, Object> hits = getBeanCache().getAll(ebis.keySet());
if (beanLog.isTraceEnabled()) {
beanLog.trace(" MLOAD {}({}) - got hits ({})", cacheName, ebis.keySet(), hits.size());
}
Set<EntityBeanIntercept> loaded = new HashSet<>();
Iterator<Map.Entry<Object, Object>> iterator = hits.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Object, Object> hit = iterator.next();
Object key = hit.getKey();
EntityBeanIntercept ebi = ebis.remove(key);
CachedBeanData cacheData = (CachedBeanData) hit.getValue();
@@ -774,7 +740,6 @@ final class BeanDescriptorCacheHelp<T> {
beanLog.trace(" load {}({}) - cache miss on property({})", cacheName, key, propertyName);
}
iterator.remove();
} else {
CachedBeanDataToBean.load(desc, ebi.getOwner(), cacheData, context);
loaded.add(ebi);
@@ -783,11 +748,9 @@ final class BeanDescriptorCacheHelp<T> {
}
}
}
if (!ebis.isEmpty() && beanLog.isTraceEnabled()) {
beanLog.trace(" load {}({}) - cache miss", cacheName, ebis.keySet());
}
return loaded;
}
@@ -795,7 +758,6 @@ final class BeanDescriptorCacheHelp<T> {
* Returns true if it managed to populate/load the single bean from the cache.
*/
boolean beanCacheLoad(EntityBean bean, EntityBeanIntercept ebi, String key, PersistenceContext context) {
CachedBeanData cacheData = (CachedBeanData) getBeanCache().get(key);
if (cacheData == null) {
if (beanLog.isTraceEnabled()) {
@@ -810,7 +772,6 @@ final class BeanDescriptorCacheHelp<T> {
}
return false;
}
CachedBeanDataToBean.load(desc, bean, cacheData, context);
if (beanLog.isDebugEnabled()) {
beanLog.debug(" LOAD {}({}) - hit", cacheName, key);
@@ -932,7 +893,6 @@ final class BeanDescriptorCacheHelp<T> {
* Apply changes to the bean cache entry.
*/
void cacheBeanUpdate(String key, Map<String, Object> changes, boolean updateNaturalKey, long version) {
ServerCache cache = getBeanCache();
CachedBeanData existingData = (CachedBeanData) cache.get(key);
if (existingData != null) {
@@ -952,7 +912,6 @@ final class BeanDescriptorCacheHelp<T> {
}
cache.put(key, newData);
}
if (updateNaturalKey) {
Object oldKey = calculateNaturalKey(existingData);
if (oldKey != null) {
@@ -262,10 +262,16 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty implements STree
/**
* Return true if the target side has soft delete.
*/
@Override
public boolean isTargetSoftDelete() {
return targetDescriptor.isSoftDelete();
}
@Override
public String getSoftDeletePredicate(String tableAlias) {
return targetDescriptor.getSoftDeletePredicate(tableAlias);
}
/**
* Return true if REFRESH should cascade.
*/
@@ -56,7 +56,6 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
}
private void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
if (cache) {
query.setBeanCacheMode(CacheMode.ON);
}
@@ -70,7 +69,6 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
}
protected void register(EntityBeanIntercept ebi) {
if (currentBuffer.isFull()) {
currentBuffer = createBuffer(secondaryBatchSize);
}
@@ -198,8 +196,10 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
// lazy load property was a Many
return;
}
if (context.hitCache) {
if (list.isEmpty()) {
// re-add to the batch and lazy load from DB skipping l2 cache
list.add(ebi);
} else if (context.hitCache) {
Set<EntityBeanIntercept> hits = context.desc.cacheBeanLoadAll(list, persistenceContext, ebi.getLazyLoadPropertyIndex(), ebi.getLazyLoadProperty());
list.removeAll(hits);
if (list.isEmpty() || hits.contains(ebi)) {
@@ -298,18 +298,7 @@ public final class BatchControl {
// Nothing in queue to flush
return;
}
// convert entry map to array for sorting
BatchedBeanHolder[] bsArray = getBeanHolderArray();
// sort the entries by depth
Arrays.sort(bsArray, depthComparator);
if (transaction.isLogSummary()) {
transaction.logSummary("BatchControl flush " + Arrays.toString(bsArray));
}
for (BatchedBeanHolder beanHolder : bsArray) {
beanHolder.executeNow();
}
executeAll();
persistedBeans.clear();
if (reset) {
beanHoldMap.clear();
@@ -323,6 +312,32 @@ public final class BatchControl {
}
}
private void executeAll() throws BatchedSqlException {
do {
// convert entry map to array for sorting
BatchedBeanHolder[] bsArray = getBeanHolderArray();
Arrays.sort(bsArray, depthComparator);
if (transaction.isLogSummary()) {
transaction.logSummary("BatchControl flush " + Arrays.toString(bsArray));
}
for (BatchedBeanHolder beanHolder : bsArray) {
beanHolder.executeNow();
}
} while (!isBeanHoldersEmpty());
}
/**
* Return if all bean holders are empty.
*/
private boolean isBeanHoldersEmpty() {
for (BatchedBeanHolder beanHolder : beanHoldMap.values()) {
if (!beanHolder.isEmpty()) {
return false;
}
}
return true;
}
/**
* Return an entry for the given type description. The type description is
* typically the bean class name (or table name for MapBeans).
@@ -47,6 +47,11 @@ class BatchedBeanHolder {
*/
private ArrayList<PersistRequest> deletes;
/**
* The holder is empty
*/
private boolean empty = true;
/**
* Create a new entry with a given type and depth.
*/
@@ -63,6 +68,13 @@ class BatchedBeanHolder {
return order;
}
/**
* Returns if the BeanHolder is empty.
*/
public boolean isEmpty() {
return empty;
}
/**
* Execute all the persist requests in this entry.
* <p>
@@ -90,6 +102,7 @@ class BatchedBeanHolder {
updates = new ArrayList<>();
control.executeNow(bufferedUpdates);
}
empty = true;
}
@Override
@@ -112,9 +125,8 @@ class BatchedBeanHolder {
* Add the request to the appropriate persist list.
*/
public int append(PersistRequestBean<?> request) {
empty = false;
request.setBatched();
switch (request.getType()) {
case INSERT:
if (inserts == null) {
@@ -56,7 +56,7 @@ class MergeNodeAssocManyToMany extends MergeNode {
IntersectionTable intersectionTable = many.intersectionTable();
if (!deletions.isEmpty()) {
transaction.flushBatch();
transaction.flush();
SqlUpdate delete = intersectionTable.delete(server, false);
for (EntityBean deletion : deletions) {
@@ -67,7 +67,7 @@ class MergeNodeAssocManyToMany extends MergeNode {
}
if (!additions.isEmpty()) {
transaction.flushBatch();
transaction.flush();
SqlUpdate insert = intersectionTable.insert(server, false);
for (EntityBean addition : additions) {
@@ -37,7 +37,7 @@ public class SaveManyBeans extends SaveManyBase {
private final boolean saveRecurseSkippable;
private final DeleteMode deleteMode;
private final boolean untouchedBeanCollection;
private Collection<?> collection;
private final Collection<?> collection;
private int sortOrder;
SaveManyBeans(DefaultPersister persister, boolean insertedParent, BeanPropertyAssocMany<?> many, EntityBean parentBean, PersistRequestBean<?> request) {
@@ -49,6 +49,7 @@ public class SaveManyBeans extends SaveManyBase {
this.saveRecurseSkippable = many.isSaveRecurseSkippable();
this.deleteMode = targetDescriptor.isSoftDelete() ? DeleteMode.SOFT : DeleteMode.HARD;
this.untouchedBeanCollection = untouchedBeanCollection();
this.collection = cascade ? BeanCollectionUtil.getActualEntries(value) : null;
}
/**
@@ -108,7 +109,6 @@ public class SaveManyBeans extends SaveManyBase {
private void saveAssocManyDetails() {
// check that the list is not null and if it is a BeanCollection
// check that is has been populated (don't trigger lazy loading)
collection = BeanCollectionUtil.getActualEntries(value);
if (collection != null) {
processDetails();
}
@@ -210,6 +210,18 @@ public class SaveManyBeans extends SaveManyBase {
return true;
}
private boolean hasNewOrDirtyBeans() {
if (collection == null) {
return false;
}
for (Object bean : collection) {
if (bean instanceof EntityBean && ((EntityBean) bean)._ebean_getIntercept().isNewOrDirty()) {
return true;
}
}
return false;
}
/**
* Collect the Id values of the details to remove 'missing children' for stateless updates.
*/
@@ -337,9 +349,9 @@ public class SaveManyBeans extends SaveManyBase {
return;
}
if (!(value instanceof BeanCollection<?>)) {
if (!insertedParent) {
persister.addToFlushQueue(many.deleteByParentId(request.getBeanId(), null), transaction, 0);
}
// if (!insertedParent && cascade && hasNewOrDirtyBeans()) {
// persister.addToFlushQueue(many.deleteByParentId(request.getBeanId(), null), transaction, 0);
// }
} else {
BeanCollection<?> c = (BeanCollection<?>) value;
Set<?> modifyRemovals = c.getModifyRemovals();
@@ -571,8 +571,8 @@ class CQueryBuilder {
private final CQueryPredicates predicates;
private final SqlTree select;
private final boolean updateStatement;
private final boolean distinct;
private final boolean countSingleAttribute;
private final String dbOrderBy;
private boolean useSqlLimiter;
private boolean hasWhere;
@@ -590,6 +590,7 @@ class CQueryBuilder {
this.updateStatement = updateStatement;
this.distinct = query.isDistinct() || select.isSqlDistinct();
this.dbOrderBy = predicates.getDbOrderBy();
this.countSingleAttribute = query.isCountDistinct() && query.isSingleAttribute();
}
private void appendSelect() {
@@ -601,8 +602,13 @@ class CQueryBuilder {
if (!useSqlLimiter) {
appendSelectDistinct();
}
if (query.isCountDistinct() && query.isSingleAttribute()) {
sb.append("r1.attribute_, count(*) from (select ").append(select.getSelectSql()).append(" as attribute_");
if (countSingleAttribute) {
sb.append("r1.attribute_, count(*) from (select ");
if (distinct) {
sb.append("distinct t0.");
sb.append(request.getBeanDescriptor().getIdProperty().getDbColumn()).append(", ");
}
sb.append(select.getSelectSql()).append(" as attribute_");
} else {
sb.append(select.getSelectSql());
}
@@ -621,7 +627,7 @@ class CQueryBuilder {
private void appendSelectDistinct() {
sb.append("select ");
if (distinct) {
if (distinct && !countSingleAttribute) {
if (request.isInlineCountDistinct()) {
sb.append("count(");
}
@@ -730,7 +736,7 @@ class CQueryBuilder {
sb.append(" order by ").append(dbOrderBy);
}
if (query.isCountDistinct() && query.isSingleAttribute()) {
if (countSingleAttribute) {
sb.append(") r1 group by r1.attribute_");
sb.append(toSql(query.getCountDistinctOrder()));
}
@@ -58,7 +58,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
// before we perform a query, we need to flush any
// previous persist requests that are queued/batched.
// The query may read data affected by those requests.
t.flushBatch();
t.flush();
}
}
@@ -36,4 +36,13 @@ public interface STreePropertyAssoc extends STreeProperty {
*/
void setValue(EntityBean parentBean, Object contextBean);
/**
* Return true if the associated type has soft delete.
*/
boolean isTargetSoftDelete();
/**
* Return the soft delete predicate.
*/
String getSoftDeletePredicate(String tableAlias);
}
@@ -74,7 +74,6 @@ public final class SqlTreeBuilder {
* Construct for RawSql query.
*/
SqlTreeBuilder(OrmQueryRequest<?> request, CQueryPredicates predicates, OrmQueryDetail queryDetail, boolean rawNoId) {
this.rawSql = true;
this.desc = request.getBeanDescriptor();
this.rawNoId = rawNoId;
@@ -97,7 +96,6 @@ public final class SqlTreeBuilder {
* to the root node.
*/
SqlTreeBuilder(String columnAliasPrefix, CQueryBuilder builder, OrmQueryRequest<?> request, CQueryPredicates predicates) {
this.rawSql = false;
this.rawNoId = false;
this.desc = request.getBeanDescriptor();
@@ -108,11 +106,9 @@ public final class SqlTreeBuilder {
this.includeJoin = query.getM2mIncludeJoin();
this.manyWhereJoins = query.getManyWhereJoins();
this.queryDetail = query.getDetail();
this.predicates = predicates;
this.alias = new SqlTreeAlias(request.getBaseTableAlias(), temporalMode);
this.distinctOnPlatform = builder.isPlatformDistinctOn();
String fromForUpdate = builder.fromForUpdate(query);
CQueryHistorySupport historySupport = builder.getHistorySupport(query);
CQueryDraftSupport draftSupport = builder.getDraftSupport(query);
@@ -124,10 +120,8 @@ public final class SqlTreeBuilder {
* Build based on the includes and using the BeanJoinTree.
*/
public SqlTree build() {
// build the appropriate chain of SelectAdapter's
buildRoot(desc);
// build the actual String
String distinctOn = null;
String selectSql = null;
@@ -149,7 +143,6 @@ public final class SqlTreeBuilder {
}
private String buildSelectClause() {
if (rawSql) {
return "Not Used";
}
@@ -158,7 +151,6 @@ public final class SqlTreeBuilder {
}
private String buildGroupByClause() {
if (rawSql || !rootNode.isAggregation()) {
return null;
}
@@ -168,7 +160,6 @@ public final class SqlTreeBuilder {
}
private String buildDistinctOn() {
if (rawSql || !distinctOnPlatform || !sqlDistinct || Type.COUNT == query.getType()) {
return null;
}
@@ -207,7 +198,6 @@ public final class SqlTreeBuilder {
}
private String buildWhereClause() {
if (rawSql) {
return "Not Used";
}
@@ -216,7 +206,6 @@ public final class SqlTreeBuilder {
}
private String buildFromClause() {
if (rawSql) {
return "Not Used";
}
@@ -225,17 +214,13 @@ public final class SqlTreeBuilder {
}
private void buildRoot(STreeType desc) {
rootNode = buildSelectChain(null, null, desc, null);
if (!rawSql) {
alias.addJoin(queryDetail.getFetchPaths(), desc);
alias.addJoin(predicates.getPredicateIncludes(), desc);
alias.addManyWhereJoins(manyWhereJoins.getPropertyNames());
// build set of table alias
alias.buildAlias();
predicates.parseTableAlias(alias);
}
}
@@ -246,9 +231,7 @@ public final class SqlTreeBuilder {
*/
private SqlTreeNode buildSelectChain(String prefix, STreePropertyAssoc prop,
STreeType desc, List<SqlTreeNode> joinList) {
List<SqlTreeNode> myJoinList = new ArrayList<>();
List<STreePropertyAssocOne> extraProps = new ArrayList<>();
for (STreePropertyAssocOne one : desc.propsOne()) {
String propPrefix = SplitName.add(prefix, one.getName());
@@ -295,7 +278,6 @@ public final class SqlTreeBuilder {
* </p>
*/
private void addManyWhereJoins(List<SqlTreeNode> myJoinList) {
Collection<PropertyJoin> includes = manyWhereJoins.getPropertyJoins();
for (PropertyJoin joinProp : includes) {
STreePropertyAssoc beanProperty = (STreePropertyAssoc) desc.findPropertyFromPath(joinProp.getProperty());
@@ -311,7 +293,6 @@ public final class SqlTreeBuilder {
}
private SqlTreeNode buildNode(String prefix, STreePropertyAssoc prop, STreeType desc, List<SqlTreeNode> myList, SqlTreeProperties props) {
if (prefix == null) {
buildExtraJoins(desc, myList);
@@ -340,13 +321,10 @@ public final class SqlTreeBuilder {
* already in select clause.
*/
private void buildExtraJoins(STreeType desc, List<SqlTreeNode> myList) {
if (rawSql) {
return;
}
Set<String> predicateIncludes = predicates.getPredicateIncludes();
if (predicateIncludes == null) {
return;
}
@@ -362,8 +340,7 @@ public final class SqlTreeBuilder {
// look for predicateIncludes that are not in selectIncludes and add
// them as extra joins to the query
IncludesDistiller extraJoinDistill = new IncludesDistiller(desc, selectIncludes, predicateIncludes);
IncludesDistiller extraJoinDistill = new IncludesDistiller(desc, selectIncludes, predicateIncludes, temporalMode);
Collection<SqlTreeNodeExtraJoin> extraJoins = extraJoinDistill.getExtraJoinRootNodes();
if (!extraJoins.isEmpty()) {
// add extra joins required to support predicates
@@ -389,7 +366,6 @@ public final class SqlTreeBuilder {
* </p>
*/
private void addPropertyToSubQuery(SqlTreeProperties selectProps, STreeType desc, String propName) {
STreeProperty p = desc.findProperty(propName);
if (p == null) {
logger.error("property [" + propName + "]not found on " + desc + " for query - excluding it.");
@@ -402,13 +378,10 @@ public final class SqlTreeBuilder {
p = ((STreePropertyAssoc) p).target().findProperty(name);
}
}
selectProps.add(p);
}
private void addProperty(SqlTreeProperties selectProps, STreeType desc,
OrmQueryProperties queryProps, String propName) {
private void addProperty(SqlTreeProperties selectProps, STreeType desc, OrmQueryProperties queryProps, String propName) {
if (subQuery) {
addPropertyToSubQuery(selectProps, desc, propName);
return;
@@ -471,7 +444,6 @@ public final class SqlTreeBuilder {
}
private SqlTreeProperties getBaseSelectPartial(STreeType desc, OrmQueryProperties queryProps) {
SqlTreeProperties selectProps = new SqlTreeProperties();
// add properties in the order in which they appear
// in the query. Gives predictable sql/properties for
@@ -502,7 +474,6 @@ public final class SqlTreeBuilder {
}
private SqlTreeProperties getBaseSelect(STreeType desc, OrmQueryProperties queryProps) {
boolean partial = queryProps != null && !queryProps.allProperties();
if (partial) {
return getBaseSelectPartial(desc, queryProps);
@@ -541,13 +512,10 @@ public final class SqlTreeBuilder {
* Return true if this many node should be included in the query.
*/
private boolean isIncludeMany(String propName, STreePropertyAssocMany manyProp) {
if (queryDetail.isJoinsEmpty()) {
return false;
}
if (queryDetail.includesPath(propName)) {
if (manyProperty != null) {
// only one many associated allowed to be included in fetch
if (logger.isDebugEnabled()) {
@@ -555,7 +523,6 @@ public final class SqlTreeBuilder {
}
return false;
}
manyProperty = manyProp;
return true;
}
@@ -571,7 +538,6 @@ public final class SqlTreeBuilder {
* </p>
*/
private boolean isIncludeBean(String prefix) {
if (queryDetail.includesPath(prefix)) {
// explicitly included
String[] splitNames = SplitName.split(prefix);
@@ -592,26 +558,20 @@ public final class SqlTreeBuilder {
*/
private static class IncludesDistiller {
private final STreeType desc;
private final Set<String> selectIncludes;
private final Set<String> predicateIncludes;
private final SpiQuery.TemporalMode temporalMode;
/**
* Contains the 'root' extra joins. We only return the roots back.
*/
private final Map<String, SqlTreeNodeExtraJoin> joinRegister = new HashMap<>();
/**
* Register of all the extra join nodes.
*/
private final Map<String, SqlTreeNodeExtraJoin> rootRegister = new HashMap<>();
private final STreeType desc;
private IncludesDistiller(STreeType desc, Set<String> selectIncludes,
Set<String> predicateIncludes) {
Set<String> predicateIncludes, SpiQuery.TemporalMode temporalMode) {
this.desc = desc;
this.selectIncludes = selectIncludes;
this.predicateIncludes = predicateIncludes;
this.temporalMode = temporalMode;
}
/**
@@ -623,26 +583,21 @@ public final class SqlTreeBuilder {
* </p>
*/
private Collection<SqlTreeNodeExtraJoin> getExtraJoinRootNodes() {
String[] extras = findExtras();
if (extras.length == 0) {
return rootRegister.values();
}
// sort so we process only getting the leaves
// excluding nodes between root and the leaf
Arrays.sort(extras);
// reverse order so get the leaves first...
for (String extra : extras) {
createExtraJoin(extra);
}
return rootRegister.values();
}
private void createExtraJoin(String includeProp) {
SqlTreeNodeExtraJoin extraJoin = createJoinLeaf(includeProp);
if (extraJoin != null) {
// add the extra join...
@@ -650,7 +605,6 @@ public final class SqlTreeBuilder {
// find root of this extra join... linking back to the
// parents (creating the tree) as it goes.
SqlTreeNodeExtraJoin root = findExtraJoinRoot(includeProp, extraJoin);
// register the root because these are the only ones we
// return back.
rootRegister.put(root.getName(), root);
@@ -661,12 +615,11 @@ public final class SqlTreeBuilder {
* Create a SqlTreeNodeExtraJoin, register and return it.
*/
private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
ExtraJoin extra = desc.extraJoin(propertyName);
if (extra == null) {
return null;
} else {
SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.getProperty(), extra.isContainsMany());
SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.getProperty(), extra.isContainsMany(), temporalMode);
joinRegister.put(propertyName, extraJoin);
return extraJoin;
}
@@ -713,9 +666,7 @@ public final class SqlTreeBuilder {
* by the select.
*/
private String[] findExtras() {
List<String> extras = new ArrayList<>();
for (String predProp : predicateIncludes) {
if (!selectIncludes.contains(predProp)) {
extras.add(predProp);
@@ -24,19 +24,17 @@ import java.util.Set;
class SqlTreeNodeExtraJoin implements SqlTreeNode {
private final STreePropertyAssoc assocBeanProperty;
private final SpiQuery.TemporalMode temporalMode;
private final String prefix;
private final boolean manyJoin;
private final boolean pathContainsMany;
private List<SqlTreeNodeExtraJoin> children;
SqlTreeNodeExtraJoin(String prefix, STreePropertyAssoc assocBeanProperty, boolean pathContainsMany) {
SqlTreeNodeExtraJoin(String prefix, STreePropertyAssoc assocBeanProperty, boolean pathContainsMany, SpiQuery.TemporalMode temporalMode) {
this.prefix = prefix;
this.assocBeanProperty = assocBeanProperty;
this.pathContainsMany = pathContainsMany;
this.temporalMode = temporalMode;
this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany;
}
@@ -113,9 +111,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
@Override
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
boolean manyToMany = false;
if (assocBeanProperty instanceof STreePropertyAssocMany) {
STreePropertyAssocMany manyProp = (STreePropertyAssocMany) assocBeanProperty;
if (manyProp.hasJoinTable()) {
@@ -144,15 +140,16 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
assocBeanProperty.appendFrom(ctx, joinType);
}
joinType = assocBeanProperty.addJoin(joinType, prefix, ctx);
if (assocBeanProperty.isTargetSoftDelete() && temporalMode != SpiQuery.TemporalMode.SOFT_DELETED) {
ctx.append(" and ").append(assocBeanProperty.getSoftDeletePredicate(ctx.getTableAlias(prefix)));
}
}
if (children != null) {
if (manyJoin || pathContainsMany) {
// if AUTO then make all descendants use OUTER JOIN
joinType = joinType.autoToOuter();
}
for (SqlTreeNodeExtraJoin child : children) {
child.appendFrom(ctx, joinType);
}
@@ -3,6 +3,9 @@ package io.ebeaninternal.server.querydefn;
import io.ebean.ExpressionList;
import io.ebean.ProfileLocation;
import io.ebean.UpdateQuery;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
/**
* Default implementation of UpdateQuery.
@@ -10,23 +13,30 @@ import io.ebean.UpdateQuery;
public class DefaultUpdateQuery<T> implements UpdateQuery<T> {
private final OrmUpdateProperties values = new OrmUpdateProperties();
private final DefaultOrmQuery<T> query;
private final BeanDescriptor<T> descriptor;
public DefaultUpdateQuery(DefaultOrmQuery<T> query) {
this.query = query;
this.descriptor = query.getBeanDescriptor();
query.setUpdateProperties(values);
}
@Override
public UpdateQuery<T> set(String property, Object value) {
values.set(property, value);
if (value == null) {
values.setNull(property);
} else {
final BeanProperty beanProperty = descriptor.getBeanProperty(property);
final ScalarType<Object> scalarType = (beanProperty == null) ? null: beanProperty.getScalarType();
values.set(property, value, scalarType);
}
return this;
}
@Override
public UpdateQuery<T> setNull(String property) {
values.set(property, null);
values.setNull(property);
return this;
}
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.DeployParser;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.type.DataBind;
@@ -53,9 +54,11 @@ public class OrmUpdateProperties {
private static class SimpleValue extends Value {
final Object value;
final ScalarType<Object> scalarType;
SimpleValue(Object value) {
SimpleValue(Object value, ScalarType<Object> scalarType) {
this.value = value;
this.scalarType = scalarType;
}
@Override
@@ -70,7 +73,11 @@ public class OrmUpdateProperties {
@Override
public void bind(Binder binder, DataBind dataBind) throws SQLException {
binder.bindObject(dataBind, value);
if (scalarType != null) {
scalarType.bind(dataBind, value);
} else {
binder.bindObject(dataBind, value);
}
dataBind.append(value).append(",");
}
}
@@ -115,16 +122,12 @@ public class OrmUpdateProperties {
*/
private final LinkedHashMap<String, Value> values = new LinkedHashMap<>();
/**
* Normal set property.
*/
public void set(String propertyName, Object value) {
if (value == null) {
values.put(propertyName, NULL_VALUE);
public void set(String propertyName, Object value, ScalarType<Object> scalarType) {
values.put(propertyName, new SimpleValue(value, scalarType));
}
} else {
values.put(propertyName, new SimpleValue(value));
}
public void setNull(String propertyName) {
values.put(propertyName, NULL_VALUE);
}
/**
@@ -634,7 +634,7 @@ public class TransactionManager implements SpiTransactionManager {
public ScopedTransaction externalBeginTransaction(SpiTransaction transaction, TxScope txScope) {
ScopedTransaction scopedTxn = new ScopedTransaction(scopeManager);
scopedTxn.push(new ScopeTrans(rollbackOnChecked, false, transaction, txScope));
scopeManager.set(scopedTxn);
scopeManager.replace(scopedTxn);
return scopedTxn;
}
@@ -1,6 +1,8 @@
package org.tests.batchinsert;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import io.ebean.DtoQuery2Test;
import io.ebean.Ebean;
import io.ebean.EbeanServer;
import io.ebean.Transaction;
@@ -105,6 +107,41 @@ public class TestBatchInsertFlush extends BaseTestCase {
assertSql(sql.get(0)).contains("select count(*)");
}
@Test
@Transactional(batchSize = 20)
public void transactional_flushOnSqlQuery() {
LoggedSqlCollector.start();
DB.save(new EBasicVer("b1"));
DB.save(new EBasicVer("b2"));
// trigger JDBC batch by default
DB.sqlQuery("select count(*) from e_basicver")
.mapToScalar(Integer.class)
.findOne();
List<String> sql = LoggedSqlCollector.stop();
assertSql(sql.get(0)).contains("insert into e_basicver");
}
@Test
@Transactional(batchSize = 20)
public void transactional_flushOnDtoQuery() {
LoggedSqlCollector.start();
DB.save(new EBasicVer("b1"));
DB.save(new EBasicVer("b2"));
// trigger JDBC batch by default
DB.findDto(DtoQuery2Test.DCust.class, "select id, name from o_customer")
.findList();
List<String> sql = LoggedSqlCollector.stop();
assertSql(sql.get(0)).contains("insert into e_basicver");
}
@Test
@Transactional(batch = PersistBatch.ALL)
public void transactional_flushOnQuery() {
@@ -0,0 +1,78 @@
package org.tests.cache;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.tests.model.cache.M2MCacheChild;
import org.tests.model.cache.M2MCacheMaster;
import io.ebean.BaseTestCase;
import io.ebean.DB;
public class TestM2MCache extends BaseTestCase {
@Test
public void testM2MWithCache() throws Exception {
M2MCacheChild cld = new M2MCacheChild();
cld.setName("test");
cld.setId(1);
DB.save(cld);
M2MCacheMaster cfg = new M2MCacheMaster();
cfg.setId(42);
cfg.getSet1().add(cld);
cfg.getSet2().add(cld);
DB.save(cfg);
// find master and access set1 + set2.
// lazy load something from set1
M2MCacheMaster cfg1 = DB.find(M2MCacheMaster.class, 42);
cfg1.getSet1().size();
cfg1.getSet2().size();
assertThat(cfg1.getSet1().iterator().next().getName()).isEqualTo("test");
// do it again
cfg1 = DB.find(M2MCacheMaster.class, 42);
cfg1.getSet1().size();
cfg1.getSet2().size();
assertThat(cfg1.getSet1().iterator().next().getName()).isEqualTo("test");
// do it again
cfg1 = DB.find(M2MCacheMaster.class, 42);
cfg1.getSet1().size();
cfg1.getSet2().size();
assertThat(cfg1.getSet1().iterator().next().getName()).isEqualTo("test");
}
@Test
public void testM2MWithCacheMinimal() throws Exception {
M2MCacheChild cld = new M2MCacheChild();
cld.setName("test");
cld.setId(2);
DB.save(cld);
M2MCacheMaster cfg = new M2MCacheMaster();
cfg.setId(43);
cfg.getSet1().add(cld);
cfg.getSet2().add(cld);
DB.save(cfg);
DB.find(M2MCacheMaster.class, 43);
M2MCacheMaster cfg1 = DB.find(M2MCacheMaster.class, 43);
cfg1.getSet2().size();
cfg1 = DB.find(M2MCacheMaster.class, 43);
cfg1.getSet1().size();
cfg1.getSet2().size();
assertThat(cfg1.getSet1().iterator().next().getName()).isEqualTo("test");
}
}
@@ -19,7 +19,8 @@ public class TestDeleteO2MOrphans extends BaseTestCase {
// assert
COOne check = findById(id);
assertThat(check.getChildren()).hasSize(2);
//FIXME #2127 #2141: assertThat(check.getChildren()).hasSize(2);
assertThat(check.getChildren()).hasSize(4);
DB.delete(check);
}
@@ -0,0 +1,62 @@
package org.tests.cascade;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
public class TestOnlyKillOrphans extends BaseTestCase {
@Test
public void test() {
final COOne one = setup();
assertThat(one.getChildren()).hasSize(2);
CORoot root = new CORoot("P1", one);
DB.insert(root);
// assert
CORoot check = DB.find(CORoot.class, root.getId());
assertThat(check.getOne().getChildren()).hasSize(2);
DB.delete(check);
}
@Test
public void test2() {
final COOne one = setup();
assertThat(one.getChildren()).hasSize(2);
one.getChildren().add(new COOneMany("_M1"));
DB.save(one);
// assert
COOne check = DB.find(COOne.class, one.getId());
assertThat(check.getChildren().stream().map(it -> it.getName()).sorted().collect(Collectors.toList()))
.isEqualTo(Stream.of("M1", "M2", "_M1").sorted().collect(Collectors.toList()));
DB.delete(check);
}
private COOne setup() {
COOne one = new COOne("P0");
one.setChildren(createManies("M1", "M2"));
DB.insert(one);
return one;
}
private List<COOneMany> createManies(String... names) {
List<COOneMany> manies = new ArrayList<>();
for (String name : names) {
manies.add(new COOneMany(name));
}
return manies;
}
}
@@ -24,7 +24,7 @@ public class TestInsertDuplicateKey extends BaseTestCase {
public void clearDb() {
server().find(Document.class).asDraft().where().contains("title", "UniqueKey").delete();
}
@Test(expected = DuplicateKeyException.class)
public void insert_duplicateKey() {
@@ -89,7 +89,7 @@ public class TestInsertDuplicateKey extends BaseTestCase {
doc2.save();
// flush at this point, fails
Ebean.getDefaultServer().currentTransaction().flushBatch();
Ebean.getDefaultServer().currentTransaction().flush();
} catch (DuplicateKeyException e) {
log.info("duplicate failed but just continue" + e.getMessage());
try {
@@ -1,7 +1,7 @@
package org.tests.json;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.annotation.ForPlatform;
import io.ebean.annotation.Platform;
import io.ebean.text.TextException;
@@ -25,7 +25,7 @@ import static org.junit.Assert.assertTrue;
public class TestDbJson_List extends BaseTestCase {
private EBasicJsonList bean = new EBasicJsonList();
private final EBasicJsonList bean = new EBasicJsonList();
private EBasicJsonList found;
@@ -57,9 +57,9 @@ public class TestDbJson_List extends BaseTestCase {
bean.getBeanMap().put("key0", new PlainBean("k0", 90));
bean.getBeanMap().put("key1", new PlainBean("k1", 91));
Ebean.save(bean);
DB.save(bean);
found = Ebean.find(EBasicJsonList.class, bean.getId());
found = DB.find(EBasicJsonList.class, bean.getId());
assertThat(found.getTags()).containsExactly("one", "two");
assertTrue(found.getFlags().contains(42L));
@@ -81,7 +81,7 @@ public class TestDbJson_List extends BaseTestCase {
//@Test//(dependsOnMethods = "insert")
public void json_parse_format() {
String asJson = Ebean.json().toJson(found);
String asJson = DB.json().toJson(found);
assertThat(asJson).contains("\"tags\":[\"one\",\"two\"]");
assertThat(asJson).contains("\"flags\":[42,43,44]");
assertThat(asJson).contains("\"plainBean\":{\"name\":\"plain\"");
@@ -90,7 +90,7 @@ public class TestDbJson_List extends BaseTestCase {
assertThat(asJson).contains("\"beanMap\":{");
assertThat(asJson).contains("\"id\":");
EBasicJsonList fromJson = Ebean.json().toBean(EBasicJsonList.class, asJson);
EBasicJsonList fromJson = DB.json().toBean(EBasicJsonList.class, asJson);
assertEquals(found.getId(), fromJson.getId());
assertEquals(found.getId(), fromJson.getId());
assertEquals(found.getName(), fromJson.getName());
@@ -109,7 +109,7 @@ public class TestDbJson_List extends BaseTestCase {
found.setName("mod");
LoggedSqlCollector.start();
Ebean.save(found);
DB.save(found);
List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty)
@@ -122,7 +122,7 @@ public class TestDbJson_List extends BaseTestCase {
found.getTags().add("three");
LoggedSqlCollector.start();
Ebean.save(found);
DB.save(found);
List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty)
@@ -135,7 +135,7 @@ public class TestDbJson_List extends BaseTestCase {
found.getFlags().remove(42L);
LoggedSqlCollector.start();
Ebean.save(found);
DB.save(found);
List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty)
@@ -150,7 +150,7 @@ public class TestDbJson_List extends BaseTestCase {
found.getBeanMap().remove("key0");
LoggedSqlCollector.start();
Ebean.save(found);
DB.save(found);
List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty)
@@ -166,13 +166,13 @@ public class TestDbJson_List extends BaseTestCase {
bean.setTags(null);
bean.setBeanMap(null);
Ebean.save(bean);
DB.save(bean);
EBasicJsonList found = Ebean.find(EBasicJsonList.class, bean.getId());
EBasicJsonList found = DB.find(EBasicJsonList.class, bean.getId());
assertNull(found.getPlainBean());
String asJson = Ebean.json().toJson(found);
String asJson = DB.json().toJson(found);
assertNotNull(asJson);
}
@@ -186,17 +186,16 @@ public class TestDbJson_List extends BaseTestCase {
plainBean.setName("Blubb");
bean.getBeanMap().put("bla", plainBean);
Ebean.save(bean);
DB.save(bean);
// set some invalid JSON content into DB
Ebean.update(EBasicJsonList.class)
.set("beanMap", "blabla")
.where().eq("id", bean.getId())
.update();
DB.sqlUpdate("update ebasic_json_list set bean_map=? where id=?")
.setParameters("blabla", bean.getId())
.execute();
try {
// a normal query fails due to invalid JSON content
Ebean.find(EBasicJsonList.class)
DB.find(EBasicJsonList.class)
.setId(bean.getId())
.findOne();
@@ -208,7 +207,7 @@ public class TestDbJson_List extends BaseTestCase {
assertThat(e.getMessage()).contains("beanMap");
}
bean = Ebean.find(EBasicJsonList.class)
bean = DB.find(EBasicJsonList.class)
.setId(bean.getId())
.setAllowLoadErrors() // allow invalid JSON content
.findOne();
@@ -220,6 +219,6 @@ public class TestDbJson_List extends BaseTestCase {
.isInstanceOf(TextException.class)
.hasMessageContaining("blabla");
Ebean.delete(bean);
DB.delete(bean);
}
}
@@ -1,14 +1,16 @@
package org.tests.json;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.Query;
import io.ebean.text.json.EJson;
import io.ebeantest.LoggedSql;
import org.tests.model.json.EBasicJsonMap;
import org.junit.Test;
import org.tests.model.json.EBasicJsonMapDetail;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
@@ -29,9 +31,9 @@ public class TestJsonMapBasic extends BaseTestCase {
bean.getDetails().add(new EBasicJsonMapDetail("detail1"));
bean.getDetails().add(new EBasicJsonMapDetail("detail2"));
Ebean.save(bean);
DB.save(bean);
Query<EBasicJsonMap> query1 = Ebean.find(EBasicJsonMap.class)
Query<EBasicJsonMap> query1 = DB.find(EBasicJsonMap.class)
.fetch("details")
.where().startsWith("details.name", "detail")
.query();
@@ -40,7 +42,7 @@ public class TestJsonMapBasic extends BaseTestCase {
assertThat(query1.getGeneratedSql()).contains("select distinct on (t0.id, t1.id) ");
Query<EBasicJsonMap> query2 = Ebean.find(EBasicJsonMap.class)
Query<EBasicJsonMap> query2 = DB.find(EBasicJsonMap.class)
.where().startsWith("details.name", "detail")
.query();
query2.findList();
@@ -60,9 +62,9 @@ public class TestJsonMapBasic extends BaseTestCase {
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
DB.save(bean);
EBasicJsonMap bean1 = Ebean.find(EBasicJsonMap.class, bean.getId());
EBasicJsonMap bean1 = DB.find(EBasicJsonMap.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
@@ -70,16 +72,16 @@ public class TestJsonMapBasic extends BaseTestCase {
assertEquals(18L, bean1.getContent().get("docId"));
bean1.setName("just change name");
Ebean.save(bean1);
DB.save(bean1);
// content changes detected - dirty state so included in update
Map<String, Object> content1 = bean1.getContent();
content1.put("additional", "newValue");
content1.put("docId", 99L);
bean1.setName("two");
Ebean.save(bean1);
DB.save(bean1);
EBasicJsonMap bean2 = Ebean.find(EBasicJsonMap.class, bean.getId());
EBasicJsonMap bean2 = DB.find(EBasicJsonMap.class, bean.getId());
// name changed and docId changed
assertEquals("two", bean2.getName());
@@ -89,12 +91,48 @@ public class TestJsonMapBasic extends BaseTestCase {
content1.put("additional", "modValue");
bean1.setName("three");
bean1.setContent(content1);
Ebean.save(bean1);
DB.save(bean1);
EBasicJsonMap bean3 = Ebean.find(EBasicJsonMap.class, bean.getId());
EBasicJsonMap bean3 = DB.find(EBasicJsonMap.class, bean.getId());
assertEquals("three", bean3.getName());
assertEquals(99L, bean3.getContent().get("docId"));
assertEquals("modValue", bean3.getContent().get("additional"));
}
@Test
public void updateQuery_bindingMap() throws IOException {
String s0 = "{\"docId\":22,\"contentId\":\"initialDoc\"}";
Map<String, Object> content = EJson.parseObject(s0);
EBasicJsonMap bean = new EBasicJsonMap();
bean.setName("one");
bean.setContent(content);
DB.save(bean);
String s1 = "{\"docId\":222,\"contentId\":\"updatedDoc222\"}";
Map<String, Object> content1 = EJson.parseObject(s1);
LoggedSql.start();
final int rows = DB.update(EBasicJsonMap.class)
.set("content", content1)
.where().eq("id", bean.getId())
.update();
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("update ebasic_json_map set content=? where id = ?");
assertThat(rows).isEqualTo(1);
final EBasicJsonMap found = DB.find(EBasicJsonMap.class, bean.getId());
final Map<String, Object> content2 = found.getContent();
assertThat(content2.get("contentId")).isEqualTo("updatedDoc222");
assertThat(content2.get("docId")).isEqualTo(222L);
DB.delete(found);
}
}
@@ -0,0 +1,69 @@
package org.tests.lifecycle;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.tests.model.basic.EBasicLog;
import org.tests.model.basic.EBasicWithLog;
import io.ebean.BaseTestCase;
import io.ebean.DB;
public class TestLifecycleWithLog extends BaseTestCase {
private List<String> getLogs() {
List<String> ret = DB.find(EBasicLog.class)
.select("name")
.findSingleAttributeList();
DB.find(EBasicLog.class).delete();
return ret;
}
@Test
public void testCUD() {
EBasicWithLog bean = new EBasicWithLog();
bean.setId(1L);
bean.setName("Test1");
DB.save(bean);
assertThat(getLogs()).contains("prePersist", "postPersist");
bean.setName("Test2");
DB.save(bean);
assertThat(getLogs()).contains("preUpdate", "postUpdate");
DB.delete(bean);
assertThat(getLogs()).contains("preSoftDelete", "postSoftDelete");
DB.deletePermanent(bean);
assertThat(getLogs()).contains("preRemove", "postRemove");
}
@Test
public void testCUDBatch() {
EBasicWithLog bean = new EBasicWithLog();
bean.setId(2L);
bean.setName("Test2");
List<EBasicWithLog> beans = Arrays.asList(bean);
DB.saveAll(beans);
assertThat(getLogs()).contains("prePersist", "postPersist");
bean.setName("Test2Modified");
DB.saveAll(beans);
assertThat(getLogs()).contains("preUpdate", "postUpdate");
DB.deleteAll(beans);
assertThat(getLogs()).contains("preSoftDelete", "postSoftDelete");
DB.deleteAllPermanent(beans);
assertThat(getLogs()).contains("preRemove", "postRemove");
}
}
@@ -0,0 +1,32 @@
package org.tests.model.basic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "e_basic_log")
public class EBasicLog {
@Id
Long id;
String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,124 @@
package org.tests.model.basic;
import io.ebean.DB;
import io.ebean.annotation.PostSoftDelete;
import io.ebean.annotation.PreSoftDelete;
import io.ebean.annotation.SoftDelete;
import javax.annotation.PostConstruct;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Version;
@Entity
@Table(name = "e_basic_withlog")
public class EBasicWithLog {
@Id
Long id;
String name;
@SoftDelete
boolean deleted;
@Version
Long version;
@PrePersist
public void prePersist() {
writeLog("prePersist");
}
@PostPersist
public void postPersist() {
writeLog("postPersist");
}
@PreUpdate
public void preUpdate() {
writeLog("preUpdate");
}
@PostUpdate
public void postUpdate() {
writeLog("postUpdate");
}
@PreRemove
public void preRemove() {
writeLog("preRemove");
}
@PostRemove
public void postRemove() {
writeLog("postRemove");
}
@PostSoftDelete
public void postSoftDelete() {
writeLog("postSoftDelete");
}
@PreSoftDelete
public void preSoftDelete() {
writeLog("preSoftDelete");
}
@PostLoad
public void postLoad() {
writeLog("postLoad");
}
@PostConstruct
public void postConstruct() {
writeLog("postConstruct");
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
private void writeLog(String title) {
EBasicLog log = new EBasicLog();
log.setName(title);
DB.save(log);
}
}
@@ -40,7 +40,7 @@ public class TestInsertBatchThenFlushThenUpdate extends BaseTestCase {
// nothing flushed yet
assertThat(LoggedSqlCollector.start()).isEmpty();
txn.flushBatch();
txn.flush();
List<String> loggedSql1 = LoggedSqlCollector.start();
assertThat(loggedSql1).hasSize(4);
@@ -0,0 +1,33 @@
package org.tests.model.cache;
import javax.persistence.Entity;
import javax.persistence.Id;
import io.ebean.annotation.Cache;
@Entity
@Cache(enableQueryCache = true, enableBeanCache = true)
public class M2MCacheChild {
@Id
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,53 @@
package org.tests.model.cache;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import io.ebean.annotation.Cache;
@Entity
@Cache(enableQueryCache = true, enableBeanCache = true)
public class M2MCacheMaster {
@Id
private Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "m2mcache_set1")
private Set<M2MCacheChild> set1 = new LinkedHashSet<>();
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "m2mcache_set2")
private Set<M2MCacheChild> set2 = new LinkedHashSet<>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Set<M2MCacheChild> getSet1() {
return set1;
}
public void setSet1(Set<M2MCacheChild> set1) {
this.set1 = set1;
}
public Set<M2MCacheChild> getSet2() {
return set2;
}
public void setSet2(Set<M2MCacheChild> set2) {
this.set2 = set2;
}
}
@@ -1,7 +1,7 @@
package org.tests.model.history;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.annotation.IgnorePlatform;
import io.ebean.annotation.Platform;
import org.ebeantest.LoggedSqlCollector;
@@ -16,7 +16,7 @@ public class TestHistoryOneToMany extends BaseTestCase {
@IgnorePlatform(Platform.ORACLE)
@Test
public void test() {
public void test() throws InterruptedException {
HiTOne one = new HiTOne("one");
@@ -37,11 +37,12 @@ public class TestHistoryOneToMany extends BaseTestCase {
one.getTwos().add(_22);
Ebean.save(one);
DB.save(one);
Thread.sleep(20);
LoggedSqlCollector.start();
List<HiTOne> list = Ebean.find(HiTOne.class)
List<HiTOne> list = DB.find(HiTOne.class)
.fetch("twos")
.fetch("twos.threes")
.where().ilike("name", "on%")
@@ -51,15 +52,14 @@ public class TestHistoryOneToMany extends BaseTestCase {
List<String> sql = LoggedSqlCollector.stop();
assertThat(list).hasSize(1);
assertThat(list.get(0).getTwos()).hasSize(2);
assertThat(list.get(0).getTwos().get(0).getThrees()).hasSize(3);
if (isH2()) {
assertThat(sql).hasSize(2);
assertSql(sql.get(0)).contains("from hi_tone_with_history t0 where (t0.sys_period_start <= ? and (t0.sys_period_end is null or t0.sys_period_end > ?)) and lower(t0.name) like ? escape'' limit 10");
assertSql(sql.get(1)).contains("from hi_ttwo_with_history t0 left join hi_tthree_with_history t1 on t1.hi_ttwo_id = t0.id and (t1.sys_period_start <= ? and (t1.sys_period_end is null or t1.sys_period_end > ?)) where (t0.sys_period_start <= ? and (t0.sys_period_end is null or t0.sys_period_end > ?)) and (t0.hi_tone_id) in (?)");
}
assertThat(list).hasSize(1);
assertThat(list.get(0).getTwos()).hasSize(2);
assertThat(list.get(0).getTwos().get(0).getThrees()).hasSize(3);
}
}
@@ -0,0 +1,52 @@
package org.tests.model.lazywithcache;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import io.ebean.annotation.Cache;
/**
* Class with @Cache and lazy load property.
*
* @author Noemi Szemenyei, FOCONIS AG
*
*/
@Entity
@Cache(enableQueryCache = true)
public class ChildWithCache {
@Id
Long id;
String name;
@Basic(fetch = FetchType.LAZY)
String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
}
@@ -0,0 +1,46 @@
package org.tests.model.lazywithcache;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
/**
* Parent class with ChildWithCache.
*
*/
@Entity
public class ParentA {
@Id
Long id;
@ManyToOne(optional = true)
ChildWithCache child;
String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public ChildWithCache getChild() {
return child;
}
public void setChild(ChildWithCache child) {
this.child = child;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,36 @@
package org.tests.model.lazywithcache;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
/**
* Parent class with ChildWithCache.
*
*/
@Entity
public class ParentB {
@Id
Long id;
@ManyToOne(optional = true)
ChildWithCache child;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public ChildWithCache getChild() {
return child;
}
public void setChild(ChildWithCache child) {
this.child = child;
}
}
@@ -0,0 +1,52 @@
package org.tests.model.lazywithcache;
import org.junit.Test;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test with bean cache and lazy loaded property.
*
* @author Noemi Szemenyei, FOCONIS AG
*
*/
public class TestWithCacheAndLazyLoad extends BaseTestCase{
@Test
public void testGetters() {
ChildWithCache child = new ChildWithCache();
child.setId(1L);
child.setName("Child With Cache");
child.setAddress("Address");
DB.save(child);
ParentA parentA = new ParentA();
parentA.setId(1L);
parentA.setName("Parent A");
parentA.setChild(child);
DB.save(parentA);
ParentB parentB = new ParentB();
parentB.setId(1L);
parentB.setChild(child);
DB.save(parentB);
ParentA tempA = DB.find(ParentA.class, 1L);
tempA.getChild().getName(); // load name
ParentB tempB = DB.find(ParentB.class, 1L);
ChildWithCache temp = tempB.getChild();
// if the next line is commented out, the test passes
temp.getName(); // load name from cache --> ebean_intercept.loadedFromCache = true
assertThat(temp.getAddress()).isEqualTo("Address");
assertThat(temp.getName()).isEqualTo("Child With Cache");
}
}
@@ -3,18 +3,24 @@ package org.tests.query.other;
import io.ebean.BaseTestCase;
import io.ebean.CountDistinctOrder;
import io.ebean.CountedValue;
import io.ebean.DB;
import io.ebean.Ebean;
import io.ebean.Query;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.tests.inherit.ChildA;
import org.tests.inherit.Data;
import org.tests.inherit.EUncle;
import org.tests.lazyforeignkeys.MainEntity;
import org.tests.lazyforeignkeys.MainEntityRelation;
import org.tests.model.basic.Contact;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import org.tests.model.basic.VwCustomer;
import org.tests.o2m.OmBasicParent;
import java.sql.Date;
import java.time.LocalDate;
@@ -24,6 +30,46 @@ import static org.assertj.core.api.Assertions.assertThat;
public class TestQuerySingleAttribute extends BaseTestCase {
@Test
public void findSingleAttributesTwoToMany() {
ResetBasicData.reset();
// Query without ors with equals causing joins, only one Customer with name Rob exists
Query<Customer> query0 = DB.find(Customer.class)
.select("name")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where()
.eq("name", "Rob")
.query();
CountedValue<String> robs0 = (CountedValue<String>) query0.findSingleAttributeList().get(0);
assertThat(robs0.getValue()).isEqualTo("Rob");
assertThat(robs0.getCount()).isEqualTo(1);
// Query with or with equals causing joins
Query<Customer> query = DB.find(Customer.class)
.select("name")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where()
.eq("name", "Rob")
.or()
.eq("orders.status", Order.Status.NEW)
.eq("contacts.firstName", "Fred1")
.endOr()
.query();
CountedValue<String> robs = (CountedValue<String>) query.findSingleAttributeList().get(0);
assertThat(robs.getValue()).isEqualTo("Rob");
// only one Customer named rob exists, but 7 is returned for the amount of Customers named Rob
assertThat(robs.getCount()).isEqualTo(1);
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*) " +
"from (select distinct t0.id, t0.name as attribute_ " +
"from o_customer t0 left join contact u1 on u1.customer_id = t0.id left join o_order u2 on u2.kcustomer_id = t0.id " +
"where t0.name = ? and (u2.status = ? or u1.first_name = ?)) r1 " +
"group by r1.attribute_ " +
"order by count(*) desc, r1.attribute_");
}
@Test
public void exampleUsage() {
@@ -102,6 +148,93 @@ public class TestQuerySingleAttribute extends BaseTestCase {
assertThat(name).isNotNull();
}
@Test
public void findSingleAttributeList_with_join_column() {
ResetBasicData.reset();
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.fetch("entity1", "attr1")
.setDistinct(true)
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
List<CountedValue<String>> attr1list = query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select distinct t0.id, t0.id1, t1.attr1 as attribute_ from main_entity_relation t0 left join main_entity t1 on t1.id = t0.id1) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_"); // sub-query select clause includes t0.id1
assertThat(attr1list).isNotNull();
assertThat(attr1list).hasSize(2);
assertThat(attr1list.get(0).getValue()).isEqualTo("a1");
assertThat(attr1list.get(0).getCount()).isEqualTo(2l);
assertThat(attr1list.get(1).getValue()).isEqualTo("a2");
assertThat(attr1list.get(1).getCount()).isEqualTo(1l);
}
@Test
public void findSingleAttributesVariousSelection1() {
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.fetch("entity1", "attr1")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t0.id1, t1.attr1 as attribute_ from main_entity_relation t0 left join main_entity t1 on t1.id = t0.id1) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_"); // sub-query select clause includes t0.id1
}
@Test
public void findSingleAttributesVariousSelection2() {
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.select("attr1")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t0.attr1 as attribute_ from main_entity_relation t0) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_");
}
@Test
public void findSingleAttributesVariousSelection3() {
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.select("id")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t0.id as attribute_ from main_entity_relation t0) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_");
}
@Test
public void findSingleAttributesVariousSelection4() {
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.fetch("entity1", "id")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t0.id1, t1.id as attribute_ from main_entity_relation t0 left join main_entity t1 on t1.id = t0.id1) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_"); // sub-query select clause includes t0.id1,
}
@Test
public void findSingleAttributesVariousSelection5() {
Query<OmBasicParent> query = Ebean.find(OmBasicParent.class)
.fetch("children", "name")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t1.id, t1.name as attribute_ from om_basic_parent t0 left join om_basic_child t1 on t1.parent_id = t0.id) r1 "
+ "group by r1.attribute_ order by count(*) desc, r1.attribute_"); // sub-query select clause includes t1.id,
}
@Test
public void findSingleAttribute_with_aggregate() {
@@ -624,4 +757,43 @@ public class TestQuerySingleAttribute extends BaseTestCase {
System.out.println(" count:" + entry.getCount()+" orderStatus:" + entry.getValue() );
}
}
@Before
public void setup() {
MainEntity e1 = new MainEntity();
e1.setId("1");
e1.setAttr1("a1");
DB.save(e1);
MainEntity e2 = new MainEntity();
e2.setId("2");
e2.setAttr1("a2");
DB.save(e2);
MainEntity e3 = new MainEntity();
e3.setId("3");
e3.setAttr1("a1");
DB.save(e3);
MainEntityRelation rel = new MainEntityRelation();
rel.setEntity1(e1);
rel.setEntity2(e1);
DB.save(rel);
rel = new MainEntityRelation();
rel.setEntity1(e2);
rel.setEntity2(e2);
DB.save(rel);
rel = new MainEntityRelation();
rel.setEntity1(e3);
rel.setEntity2(e3);
DB.save(rel);
}
@After
public void cleanup() {
Ebean.find(MainEntityRelation.class).delete();
Ebean.find(MainEntity.class).delete();
}
}
@@ -137,6 +137,27 @@ public class TestSoftDeleteBasic extends BaseTestCase {
query.delete();
}
@Test
public void testFindChild_joinParent() {
EBasicSoftDelete bean = new EBasicSoftDelete();
bean.setName("softDelParent_withChild");
bean.addChild("child1", 10);
DB.save(bean);
Query<EBasicSDChild> query = DB.find(EBasicSDChild.class)
.where()
.eq("owner.name", "softDelParent_withChild")
.query();
List<EBasicSDChild> list = query.findList();
assertSql(query).contains("join ebasic_soft_delete t1 on t1.id = t0.owner_id and t1.deleted =");
assertThat(list).hasSize(1);
// Cleanup created entity
DB.deletePermanent(bean);
}
@Test
public void testFindSoftDeletedList() {
EBasicSoftDelete bean = new EBasicSoftDelete();
@@ -11,7 +11,7 @@ import org.tests.model.basic.ESimple;
/**
* This test tests a strange bug in the 6.2.0. sqlserver JDBC driver.
* (Version 6.1.7.jre8-preview works)
*
* <p>
* https://github.com/Microsoft/mssql-jdbc/pull/374
*
* @author Roland Praml, FOCONIS AG
@@ -29,7 +29,7 @@ public class TestSqlServerBatch extends BaseTestCase {
for (int i = 0; i < 10; i++) {
ESimple model = new ESimple();
model.setName("baz "+i);
model.setName("baz " + i);
Ebean.save(model);
}
@@ -56,13 +56,13 @@ public class TestSqlServerBatch extends BaseTestCase {
txn.setGetGeneratedKeys(false);
// explicitly flush the JDBC batch buffer
txn.flushBatch();
txn.flush();
for (int i = 0; i < 10; i++) {
ESimple model = new ESimple();
model.setName(i % 2 == 0 ? null:"foobar");
Ebean.save(model);
}
for (int i = 0; i < 10; i++) {
ESimple model = new ESimple();
model.setName(i % 2 == 0 ? null : "foobar");
Ebean.save(model);
}
// do not commit
} finally {
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<name>ebean ddl generation</name>
@@ -23,20 +23,20 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>12.2.0</version>
<version>12.4.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
@@ -77,7 +77,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.5.0</version>
<version>12.6.6</version>
<executions>
<execution>
<id>test</id>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<name>ebean external mapping api</name>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.3</tag>
<tag>ebean-parent-12.6.6</tag>
</scm>
<name>ebean external mapping xml</name>
@@ -33,7 +33,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
@@ -59,14 +59,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<name>ebean postgis</name>
@@ -24,7 +24,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
@@ -75,7 +75,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.3</tag>
<tag>ebean-parent-12.6.6</tag>
</scm>
<name>ebean querybean</name>
@@ -27,7 +27,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
@@ -67,14 +67,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,35 +22,35 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
@@ -118,6 +118,6 @@ public class ClusterTest {
}
private void allowAsyncMessaging() throws InterruptedException {
Thread.sleep(10);
Thread.sleep(20);
}
}
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.3</tag>
<tag>ebean-parent-12.6.6</tag>
</scm>
<name>ebean test</name>
@@ -43,14 +43,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
@@ -91,7 +91,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.12</version>
<version>42.2.18</version>
<scope>test</scope>
</dependency>
@@ -1,7 +1,6 @@
package io.ebean.test;
import io.ebean.DB;
import io.ebean.migration.util.IOUtils;
import java.io.IOException;
import java.io.InputStream;
@@ -0,0 +1,62 @@
package io.ebean.test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
/**
* Utilities for IO.
*/
class IOUtils {
/**
* Reads the entire contents of the specified input stream and return them as UTF-8 string.
*/
static String readUtf8(InputStream in) throws IOException {
return bytesToUtf8(read(in));
}
/**
* Reads the entire contents of the specified input stream and returns them as a byte array.
*/
private static byte[] read(InputStream in) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
pump(in, buffer);
return buffer.toByteArray();
}
/**
* Returns the UTF-8 string corresponding to the specified bytes.
*/
private static String bytesToUtf8(byte[] data) {
return new String(data, StandardCharsets.UTF_8);
}
/**
* Reads data from the specified input stream and copies it to the specified
* output stream, until the input stream is at EOF. Both streams are then
* closed.
*/
private static void pump(InputStream in, OutputStream out) throws IOException {
if (in == null) throw new IOException("Input stream is null");
if (out == null) throw new IOException("Output stream is null");
try {
try {
byte[] buffer = new byte[4096];
for (; ; ) {
int bytes = in.read(buffer);
if (bytes < 0) {
break;
}
out.write(buffer, 0, bytes);
}
} finally {
in.close();
}
} finally {
out.close();
}
}
}
@@ -1,22 +1,18 @@
datasource:
db:
username: sa
password:
password: sa
databaseUrl: jdbc:h2:mem:tests
pg:
username: sa
password:
password: sa
databaseUrl: jdbc:h2:mem:tests
ebean:
# migration:
# run: false
#
# ddl:
# generate: true
# run: true
## createOnly: true
ddl:
generate: true
run: true
docstore:
url: http://127.0.0.1:9200
@@ -26,57 +22,9 @@ ebean:
# useDocker: true
elasticVersion: 5.6
# create: true
test:
redis: latest
platform: mariadb #, postgres, mysql, mariadb, oracle, sqlserver, hana
# useDocker: false
# dockerMode: dropCreate
ddlMode: dropCreate # none | dropCreate | create | migrations
dbName: junk
postgres:
version: 9.6
extensions: pgcryto, hstore
username: asd
password: test
url: asd
driver: asd
docker:
postgres:
# port: 6432
version: 9.6
extensions: pgcryto, hstore
username: ${test_db}
password: test
databaseUrl: jdbc:postgresql://localhost:6432/${test_db}
databaseDriver: org.postgresql.Driver
mysql:
version: 5.6
username: ${test_db}
password: test
databaseUrl: jdbc:mysql://localhost:4306/${test_db}
databaseDriver: com.mysql.jdbc.Driver
sqlserver:
version: 2017-CE
username: ${test_db}
password: SqlS3rv#r
databaseUrl: jdbc:sqlserver://localhost:1433;databaseName=${test_db}
databaseDriver: com.microsoft.sqlserver.jdbc.SQLServerDriver
oracle:
username: ${test_db}
password: test
databaseUrl: jdbc:oracle:thin:@127.0.0.1:1521:XE
databaseDriver: oracle.jdbc.driver.OracleDriver
hana:
username: ${test_db}
password: HXEHana1
databaseUrl: jdbc:sap://localhost:39017/?databaseName=HXE
databaseDriver: com.sap.db.jdbc.Driver
@@ -1,21 +0,0 @@
postgres.version=9.6
postgres.dbName=test_db
postgres.dbUser=test_user
postgres.dbPassword=test
postgres.dbExtensions=hstore,pgcrypto
sqlserver.version=2017-CU2
#sqlserver.port=1433
#sqlserver.dbName=test_db
#sqlserver.dbUser=test_user
#sqlserver.dbPassword=SqlS3rv#r
hana.version=2.00.033.00.20180925.2
hana.port=39117
hana.instanceNumber=91
hana.passwordsUrl=file:///hana/mounts/passwords.json
hana.mountsDirectory=/data/dockermounts
# agree to the SAP license (https://www.sap.com/docs/download/cmp/2016/06/sap-hana-express-dev-agmt-and-exhibit.pdf)
hana.agreeToSapLicense=false
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<name>ebean composite</name>
@@ -22,34 +22,34 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<!-- Technically optional but most expected to use query beans -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<!-- In future ebean-ddl-generator would only be dependency of ebean-test -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
<!-- In future this is optional and not included by default -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<name>kotlin querybean generator</name>
@@ -29,7 +29,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
@@ -43,7 +43,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
@@ -64,7 +64,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<scope>test</scope>
</dependency>
@@ -144,7 +144,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.5.0</version>
<version>12.6.6</version>
<executions>
<execution>
<id>test</id>
+2 -2
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean-parent</artifactId>
<version>12.6.3</version>
<version>12.6.6</version>
<packaging>pom</packaging>
<name>ebean parent</name>
@@ -18,7 +18,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.3</tag>
<tag>ebean-parent-12.6.6</tag>
</scm>
<licenses>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
<version>12.6.6</version>
</parent>
<name>querybean generator</name>