Merge branch 'master' into wip/h2database-v2

This commit is contained in:
Rob Bygrave committed 2022-01-26 22:07:20 +13:00
commit 17df5a2c16
36 files changed
+647 -548

No files matched your search

+5 -1
View File
@@ -31,6 +31,10 @@ jobs:
path: path:
~/.m2 ~/.m2
key: build-${{ env.cache-name }} key: build-${{ env.cache-name }}
- name: Maven version
run: mvn --version
# - name: Maven single test
# run: mvn --batch-mode clean verify -Dtest="io.ebeaninternal.server.core.DefaultServer_getReferenceTest" -DfailIfNoTests=false
- name: Build with Maven - name: Build with Maven
run: mvn package run: mvn clean package
-3
View File
@@ -49,6 +49,3 @@ Goto [https://ebean.io/docs/](https://ebean.io/docs/)
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects") [Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
## Other versions
* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent) - ebean-agent
* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin) - ebean-maven-plugin
+1 -1
View File
@@ -63,7 +63,7 @@
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<tiles> <tiles>
<tile>io.ebean.tile:enhancement:12.11.3</tile> <tile>io.ebean.tile:enhancement:12.14.1</tile>
<tile>io.avaje.tile:moditech-module:1.0</tile> <tile>io.avaje.tile:moditech-module:1.0</tile>
</tiles> </tiles>
</configuration> </configuration>
@@ -193,7 +193,7 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
// set the generated sql back to the query // set the generated sql back to the query
// so its available to the user... // so its available to the user...
query.setGeneratedSql(queryPlan.getSql()); query.setGeneratedSql(queryPlan.getSql());
SqlTree sqlTree = queryPlan.getSqlTree(); SqlTreePlan sqlTree = queryPlan.getSqlTree();
this.rootNode = sqlTree.getRootNode(); this.rootNode = sqlTree.getRootNode();
this.manyProperty = sqlTree.getManyProperty(); this.manyProperty = sqlTree.getManyProperty();
this.sql = queryPlan.getSql(); this.sql = queryPlan.getSql();
@@ -110,7 +110,7 @@ final class CQueryBuilder {
sql = buildUpdateSql(request, rootTableAlias, predicates, sqlTree); sql = buildUpdateSql(request, rootTableAlias, predicates, sqlTree);
} }
// cache the query plan // cache the query plan
queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql()); queryPlan = new CQueryPlan(request, sql, sqlTree.plan(), predicates.getLogWhereSql());
request.putQueryPlan(queryPlan); request.putQueryPlan(queryPlan);
return new CQueryUpdate(request, predicates, queryPlan); return new CQueryUpdate(request, predicates, queryPlan);
} }
@@ -197,7 +197,7 @@ final class CQueryBuilder {
SqlTree sqlTree = createSqlTree(request, predicates); SqlTree sqlTree = createSqlTree(request, predicates);
SqlLimitResponse s = buildSql(null, request, predicates, sqlTree); SqlLimitResponse s = buildSql(null, request, predicates, sqlTree);
queryPlan = new CQueryPlan(request, s.getSql(), sqlTree, predicates.getLogWhereSql()); queryPlan = new CQueryPlan(request, s.getSql(), sqlTree.plan(), predicates.getLogWhereSql());
request.putQueryPlan(queryPlan); request.putQueryPlan(queryPlan);
return new CQueryFetchSingleAttribute(request, predicates, queryPlan, query.isCountDistinct()); return new CQueryFetchSingleAttribute(request, predicates, queryPlan, query.isCountDistinct());
} }
@@ -288,7 +288,7 @@ final class CQueryBuilder {
} }
} }
// cache the query plan // cache the query plan
queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql()); queryPlan = new CQueryPlan(request, sql, sqlTree.plan(), predicates.getLogWhereSql());
request.putQueryPlan(queryPlan); request.putQueryPlan(queryPlan);
return new CQueryRowCount(queryPlan, request, predicates); return new CQueryRowCount(queryPlan, request, predicates);
} }
@@ -343,7 +343,7 @@ final class CQueryBuilder {
if (rawSql) { if (rawSql) {
queryPlan = new CQueryPlanRawSql(request, res, sqlTree, predicates.getLogWhereSql()); queryPlan = new CQueryPlanRawSql(request, res, sqlTree, predicates.getLogWhereSql());
} else { } else {
queryPlan = new CQueryPlan(request, res, sqlTree, false, predicates.getLogWhereSql()); queryPlan = new CQueryPlan(request, res, sqlTree.plan(), false, predicates.getLogWhereSql());
} }
BeanDescriptor<T> desc = request.descriptor(); BeanDescriptor<T> desc = request.descriptor();
if (desc.isReadAuditing()) { if (desc.isReadAuditing()) {
@@ -55,7 +55,7 @@ public class CQueryPlan implements SpiQueryPlan {
private final String sql; private final String sql;
private final String hash; private final String hash;
private final String logWhereSql; private final String logWhereSql;
private final SqlTree sqlTree; private final SqlTreePlan sqlTree;
/** /**
* Encrypted properties required additional binding. * Encrypted properties required additional binding.
@@ -76,7 +76,7 @@ public class CQueryPlan implements SpiQueryPlan {
/** /**
* Create a query plan based on a OrmQueryRequest. * Create a query plan based on a OrmQueryRequest.
*/ */
CQueryPlan(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTree sqlTree, boolean rawSql, String logWhereSql) { CQueryPlan(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTreePlan sqlTree, boolean rawSql, String logWhereSql) {
this.server = request.server(); this.server = request.server();
this.dataTimeZone = server.dataTimeZone(); this.dataTimeZone = server.dataTimeZone();
this.beanType = request.descriptor().type(); this.beanType = request.descriptor().type();
@@ -101,7 +101,7 @@ public class CQueryPlan implements SpiQueryPlan {
/** /**
* Create a query plan for a raw sql query. * Create a query plan for a raw sql query.
*/ */
CQueryPlan(OrmQueryRequest<?> request, String sql, SqlTree sqlTree, String logWhereSql) { CQueryPlan(OrmQueryRequest<?> request, String sql, SqlTreePlan sqlTree, String logWhereSql) {
this.server = request.server(); this.server = request.server();
this.dataTimeZone = server.dataTimeZone(); this.dataTimeZone = server.dataTimeZone();
this.beanType = request.descriptor().type(); this.beanType = request.descriptor().type();
@@ -249,7 +249,7 @@ public class CQueryPlan implements SpiQueryPlan {
return rawSql ? planKey.getPartialKey() + "_" + hash : planKey.getPartialKey(); return rawSql ? planKey.getPartialKey() + "_" + hash : planKey.getPartialKey();
} }
final SqlTree getSqlTree() { final SqlTreePlan getSqlTree() {
return sqlTree; return sqlTree;
} }
@@ -17,7 +17,7 @@ final class CQueryPlanRawSql extends CQueryPlan {
private final int[] rsetIndexPositions; private final int[] rsetIndexPositions;
CQueryPlanRawSql(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTree sqlTree, String logWhereSql) { CQueryPlanRawSql(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTree sqlTree, String logWhereSql) {
super(request, sqlRes, sqlTree, true, logWhereSql); super(request, sqlRes, sqlTree.plan(), true, logWhereSql);
this.rsetIndexPositions = createIndexPositions(request, sqlTree); this.rsetIndexPositions = createIndexPositions(request, sqlTree);
} }
@@ -56,6 +56,10 @@ final class SqlTree {
this.noJoins = !includeJoins; this.noJoins = !includeJoins;
} }
SqlTreePlan plan() {
return new SqlTreePlan(rootNode.createLoad(), manyProperty, encryptedProps, dependentTables());
}
/** /**
* Return true if the query mandates SQL Distinct due to ToMany inclusion. * Return true if the query mandates SQL Distinct due to ToMany inclusion.
*/ */
@@ -123,10 +127,6 @@ final class SqlTree {
return inheritanceWhereSql; return inheritanceWhereSql;
} }
SqlTreeRoot getRootNode() {
return (SqlTreeRoot)rootNode;
}
/** /**
* Return the property that is associated with the many. There can only be one * Return the property that is associated with the many. There can only be one
* per SqlSelect. This can be null. * per SqlSelect. This can be null.
@@ -135,10 +135,6 @@ final class SqlTree {
return manyProperty; return manyProperty;
} }
STreeProperty[] getEncryptedProps() {
return encryptedProps;
}
/** /**
* Return true if the query has a many join. * Return true if the query has a many join.
*/ */
@@ -153,7 +149,7 @@ final class SqlTree {
/** /**
* Return the tables that are joined in this query. * Return the tables that are joined in this query.
*/ */
Set<String> dependentTables() { private Set<String> dependentTables() {
Set<String> tables = new LinkedHashSet<>(); Set<String> tables = new LinkedHashSet<>();
rootNode.dependentTables(tables); rootNode.dependentTables(tables);
return tables; return tables;
@@ -0,0 +1,28 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarDataReader;
import io.ebeaninternal.server.deploy.DbReadContext;
import java.sql.SQLException;
/**
* Tree node that loads an entity bean type.
*/
interface SqlTreeLoad {
/**
* Load the appropriate information from the SqlSelectReader.
* <p>
* At a high level this actually controls the reading of the data from the
* jdbc resultSet and putting it into the bean etc.
* </p>
*/
EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException;
/**
* Return the reader for the single attribute query.
*/
ScalarDataReader<?> getSingleAttributeReader();
}
@@ -0,0 +1,373 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.ScalarDataReader;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.id.IdBinder;
import java.sql.SQLException;
import java.util.Map;
/**
* Normal bean included in the query.
*/
class SqlTreeLoadBean implements SqlTreeLoad {
final STreeType desc;
final IdBinder idBinder;
final SqlTreeLoad[] children;
private final boolean partialObject;
private final STreeProperty[] properties;
private final STreePropertyAssoc nodeBeanProp;
final boolean readId;
private final boolean readIdNormal;
private final boolean disableLazyLoad;
private final InheritInfo inheritInfo;
final String prefix;
private final Map<String, String> pathMap;
final STreePropertyAssocMany lazyLoadParent;
private final SpiQuery.TemporalMode temporalMode;
private final boolean temporalVersions;
final IdBinder lazyLoadParentIdBinder;
SqlTreeLoadBean(SqlTreeNodeBean node) {
this.lazyLoadParent = node.lazyLoadParent;
this.lazyLoadParentIdBinder = node.lazyLoadParentIdBinder;
this.prefix = node.prefix;
this.desc = node.desc;
this.inheritInfo = desc.inheritInfo();
this.idBinder = desc.idBinder();
this.temporalMode = node.temporalMode;
this.temporalVersions = node.temporalVersions;
this.nodeBeanProp = node.nodeBeanProp;
this.readId = node.readId;//!aggregationRoot && withId && desc.hasId();
this.readIdNormal = readId && !temporalVersions;
this.disableLazyLoad = node.disableLazyLoad;// disableLazyLoad || !readIdNormal || desc.isRawSqlBased();
this.partialObject = node.partialObject;//props.isPartialObject();
this.properties = node.properties;//props.getProps();
this.pathMap = node.pathMap;//createPathMap(prefix, desc);
this.children = node.createLoadChildren();
}
boolean isRoot() {
return false;
}
@Override
public final ScalarDataReader<?> getSingleAttributeReader() {
if (properties == null || properties.length == 0) {
// if we have no property ask first children (in a distinct select with join)
if (children.length == 0) {
// expected to be a findIds query
return desc.idBinder().getBeanProperty();
}
return children[0].getSingleAttributeReader();
}
if (properties[0] instanceof STreePropertyAssocOne) {
STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0];
if (assocOne.isAssocId()) {
return assocOne.idReader();
}
}
return properties[0];
}
/**
* Load that takes into account inheritance.
*/
private final class LoadInherit extends Load {
private LoadInherit(DbReadContext ctx, EntityBean parentBean) {
super(ctx, parentBean);
}
@Override
void initBeanType() throws SQLException {
InheritInfo localInfo = readId ? inheritInfo.readType(ctx) : desc.inheritInfo();
if (localInfo == null) {
// the bean must be null
localIdBinder = idBinder;
localDesc = desc;
} else {
localBean = localInfo.createEntityBean();
localType = localInfo.getType();
localIdBinder = localInfo.getIdBinder();
localDesc = localInfo.desc();
}
}
@Override
void loadProperties() {
// take account of inheritance
for (STreeProperty property : properties) {
localDesc.inheritanceLoad(sqlBeanLoad, property, ctx);
}
}
}
/**
* Load a bean instance.
*/
class Load {
final DbReadContext ctx;
final EntityBean parentBean;
Object lazyLoadParentId;
Class<?> localType;
STreeType localDesc;
IdBinder localIdBinder;
EntityBean localBean;
Mode queryMode;
PersistenceContext persistenceContext;
Object id;
EntityBean contextBean;
SqlBeanLoad sqlBeanLoad;
boolean lazyLoadMany;
private Load(DbReadContext ctx, EntityBean parentBean) {
this.ctx = ctx;
this.parentBean = parentBean;
}
private void initLazyParent() throws SQLException {
if (lazyLoadParentIdBinder != null) {
lazyLoadParentId = lazyLoadParentIdBinder.read(ctx);
}
}
void initBeanType() throws SQLException {
localDesc = desc;
localBean = desc.createEntityBean();
localIdBinder = idBinder;
}
private void initPersistenceContext() {
queryMode = ctx.getQueryMode();
persistenceContext = (!readIdNormal) ? null : ctx.getPersistenceContext();
}
private void readId() throws SQLException {
if (readId) {
id = localIdBinder.readSet(ctx, localBean);
if (id == null) {
readIdNullBean();
} else if (!temporalVersions) {
readIdBean();
}
}
}
private void readIdBean() {
// check the PersistenceContext to see if the bean already exists
contextBean = (EntityBean) localDesc.contextPutIfAbsent(persistenceContext, id, localBean);
if (contextBean == null) {
// bean just added to the persistenceContext
contextBean = localBean;
} else {
// bean already exists in persistenceContext
if (queryMode.isLoadContextBean()) {
// if explicitly set loadContextBean to true, then reload
localBean = contextBean;
} else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) {
// reload if contextBean is partial object
localBean = contextBean;
// and switch to lazyLoad query mode in order not to overwrite
// existing properties in SqlBeanLoad::load
queryMode = Mode.LAZYLOAD_BEAN;
} else {
// ignore the DB data...
localBean = null;
}
}
}
private void readIdNullBean() {
// bean must be null...
localBean = null;
// ... but there may exist as reference bean in parent which has to be marked as deleted.
if (parentBean != null && nodeBeanProp instanceof STreePropertyAssocOne) {
contextBean = ((STreePropertyAssocOne)nodeBeanProp).getValueAsEntityBean(parentBean);
if (contextBean != null) {
desc.markAsDeleted(contextBean);
}
}
}
private void initSqlLoadBean() {
ctx.setCurrentPrefix(prefix, pathMap);
ctx.propagateState(localBean);
sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode);
}
void loadProperties() {
for (STreeProperty property : properties) {
property.load(sqlBeanLoad);
}
}
private void loadChildren() throws SQLException {
if (localBean == null && queryMode == Mode.LAZYLOAD_MANY) {
// batch lazy load many into existing contextBean
localBean = contextBean;
lazyLoadMany = true;
}
for (SqlTreeLoad child : children) {
child.load(ctx, localBean, contextBean);
}
}
private boolean isLazyLoadManyRoot() {
return queryMode == Mode.LAZYLOAD_MANY && isRoot();
}
private EntityBean getContextBean() {
return contextBean;
}
private void postLoad() {
if (!lazyLoadMany && localBean != null) {
ctx.setCurrentPrefix(prefix, pathMap);
if (readIdNormal) {
createListProxies();
}
if (temporalMode == SpiQuery.TemporalMode.DRAFT) {
localDesc.setDraft(localBean);
}
localDesc.postLoad(localBean);
EntityBeanIntercept ebi = localBean._ebean_getIntercept();
ebi.setPersistenceContext(persistenceContext);
if (Mode.LAZYLOAD_BEAN == queryMode) {
// Lazy Load does not reset the dirty state
ebi.setLoadedLazy();
} else if (readId) {
// normal bean loading
ebi.setLoaded();
}
if (disableLazyLoad) {
// bean does not have an Id or is SqlSelect based
ebi.setDisableLazyLoad(true);
} else if (partialObject) {
if (readId) {
// register for lazy loading
ctx.register(null, ebi);
}
} else {
ebi.setFullyLoadedBean(true);
}
if (ctx.isAutoTuneProfiling() && !disableLazyLoad) {
// collect autoTune profiling for this bean...
ctx.profileBean(ebi, prefix);
}
}
}
/**
* Create lazy loading proxies for the Many's except for the one that is
* included in the actual query.
*/
private void createListProxies() {
STreePropertyAssocMany fetchedMany = ctx.getManyProperty();
boolean forceNewReference = queryMode == Mode.REFRESH_BEAN;
for (STreePropertyAssocMany many : localDesc.propsMany()) {
if (many != fetchedMany) {
// create a proxy for the many (deferred fetching)
BeanCollection<?> ref = many.createReference(localBean, forceNewReference);
if (ref != null) {
if (disableLazyLoad) {
ref.setDisableLazyLoad(true);
}
if (!ref.isRegisteredWithLoadContext()) {
ctx.register(many.asMany(), ref);
}
}
}
}
}
private void setBeanToParent() {
if (parentBean != null) {
// set this back to the parentBean
nodeBeanProp.setValue(parentBean, contextBean);
}
}
private EntityBean complete() {
if (!readIdNormal) {
// a bean with no Id (never found in context)
if (lazyLoadParentId != null) {
ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId);
}
return localBean;
} else {
if (lazyLoadParentId != null) {
ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId);
}
return contextBean;
}
}
private void initialise() throws SQLException {
initLazyParent();
initBeanType();
initPersistenceContext();
readId();
initSqlLoadBean();
loadProperties();
loadChildren();
}
/**
* Perform the load returning the loaded bean.
*/
final EntityBean perform() throws SQLException {
initialise();
if (isLazyLoadManyRoot()) {
return getContextBean();
}
postLoad();
setBeanToParent();
return complete();
}
/**
* Return true if this bean was already in the context. If already in the
* context we need to check if it is already contained in the collection.
*/
final boolean isContextBean() {
return localBean == null;
}
}
/**
* read the properties from the resultSet.
*/
@Override
public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException {
return createLoad(ctx, parentBean).perform();
}
/**
* Create the loader with or without inheritance.
*/
final Load createLoad(DbReadContext ctx, EntityBean parentBean) {
return (inheritInfo != null) ? new LoadInherit(ctx, parentBean) : new Load(ctx, parentBean);
}
@Override
public String toString() {
return "SqlTreeLoadBean: " + desc;
}
}
@@ -0,0 +1,30 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.DbReadContext;
import java.sql.SQLException;
final class SqlTreeLoadManyRoot extends SqlTreeLoadBean {
private final STreePropertyAssocMany manyProp;
SqlTreeLoadManyRoot(SqlTreeNodeManyRoot node) {
super(node);
this.manyProp = node.manyProp;
}
@Override
public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException {
// pass in null for parentBean because added to a collection rather than set to the parentBean
Load load = createLoad(cquery, null);
EntityBean detailBean = load.perform();
if (contextParent != null) {
// Add to the collection and initialise collection if needed
// A null detailBean may initialise an empty collection
// Check for bean existing in collection based on load.isContextBean()
manyProp.addBeanToCollectionWithCreate(contextParent, detailBean, load.isContextBean());
}
return detailBean;
}
}
@@ -0,0 +1,43 @@
package io.ebeaninternal.server.query;
import io.ebean.Version;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.DbReadContext;
import java.sql.SQLException;
import java.sql.Timestamp;
/**
* Represents the root node of the Sql Tree.
*/
final class SqlTreeLoadRoot extends SqlTreeLoadBean implements SqlTreeRoot {
SqlTreeLoadRoot(SqlTreeNodeBean node) {
super(node);
}
@Override
protected boolean isRoot() {
return true;
}
@Override
public EntityBean load(DbReadContext ctx) throws SQLException {
return load(ctx, null, null);
}
/**
* Read the version bean.
*/
@Override
@SuppressWarnings("unchecked")
public <T> Version<T> loadVersion(DbReadContext ctx) throws SQLException {
// read the sys period lower and upper bounds
// these are always the first 2 columns in the resultSet
Timestamp start = ctx.getDataReader().getTimestamp();
Timestamp end = ctx.getDataReader().getTimestamp();
T bean = (T) load(ctx, null, null);
return new Version<>(bean, start, end);
}
}
@@ -1,13 +1,8 @@
package io.ebeaninternal.server.query; package io.ebeaninternal.server.query;
import io.ebean.Version;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarDataReader;
import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.DbSqlContext;
import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -64,25 +59,11 @@ interface SqlTreeNode {
*/ */
void addSoftDeletePredicate(SpiQuery<?> query); void addSoftDeletePredicate(SpiQuery<?> query);
/**
* Load the appropriate information from the SqlSelectReader.
* <p>
* At a high level this actually controls the reading of the data from the
* jdbc resultSet and putting it into the bean etc.
* </p>
*/
EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException;
/** /**
* Return true if the query has a many join. * Return true if the query has a many join.
*/ */
boolean hasMany(); boolean hasMany();
/**
* Return the reader for the single attribute query.
*/
ScalarDataReader<?> getSingleAttributeReader();
/** /**
* Return true if the query is known to only have a single property selected. * Return true if the query is known to only have a single property selected.
*/ */
@@ -92,4 +73,9 @@ interface SqlTreeNode {
* Add dependent tables to the given set. * Add dependent tables to the given set.
*/ */
void dependentTables(Set<String> tables); void dependentTables(Set<String> tables);
/**
* Create the loader for this node.
*/
SqlTreeLoad createLoad();
} }
@@ -1,30 +1,20 @@
package io.ebeaninternal.server.query; package io.ebeaninternal.server.query;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.ScalarDataReader;
import io.ebean.util.SplitName; import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.deploy.id.IdBinder; import io.ebeaninternal.server.deploy.id.IdBinder;
import java.sql.SQLException; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* Normal bean included in the query. * Normal bean included in the query.
*/ */
class SqlTreeNodeBean implements SqlTreeNode { class SqlTreeNodeBean implements SqlTreeNode {
private static final SqlTreeLoad[] NO_LOAD_CHILDREN = new SqlTreeLoad[0];
private static final SqlTreeNode[] NO_CHILDREN = new SqlTreeNode[0]; private static final SqlTreeNode[] NO_CHILDREN = new SqlTreeNode[0];
final STreeType desc; final STreeType desc;
@@ -36,33 +26,33 @@ class SqlTreeNodeBean implements SqlTreeNode {
/** /**
* Set to true if this is a partial object fetch. * Set to true if this is a partial object fetch.
*/ */
private final boolean partialObject; final boolean partialObject;
private final STreeProperty[] properties; final STreeProperty[] properties;
/** /**
* Extra where clause added by Where annotation on associated many. * Extra where clause added by Where annotation on associated many.
*/ */
private final String extraWhere; final String extraWhere;
private final STreePropertyAssoc nodeBeanProp; final STreePropertyAssoc nodeBeanProp;
/** /**
* False if report bean and has no id property. * False if report bean and has no id property.
*/ */
final boolean readId; final boolean readId;
private final boolean readIdNormal; final boolean readIdNormal;
private final boolean disableLazyLoad; final boolean disableLazyLoad;
private final InheritInfo inheritInfo; final InheritInfo inheritInfo;
final String prefix; final String prefix;
private final Map<String, String> pathMap; final Map<String, String> pathMap;
final STreePropertyAssocMany lazyLoadParent; final STreePropertyAssocMany lazyLoadParent;
private final SpiQuery.TemporalMode temporalMode; final SpiQuery.TemporalMode temporalMode;
private final boolean temporalVersions; final boolean temporalVersions;
private final IdBinder lazyLoadParentIdBinder; final IdBinder lazyLoadParentIdBinder;
String baseTableAlias; String baseTableAlias;
/** /**
* Table alias set if this bean node includes a join to a intersection * Table alias set if this bean node includes a join to a intersection
* table and that table has history support. * table and that table has history support.
*/ */
private boolean intersectionAsOfTableAlias; boolean intersectionAsOfTableAlias;
private final boolean aggregation; final boolean aggregation;
/** /**
* Construct for leaf node. * Construct for leaf node.
@@ -108,8 +98,23 @@ class SqlTreeNodeBean implements SqlTreeNode {
pathMap = createPathMap(prefix, desc); pathMap = createPathMap(prefix, desc);
} }
boolean isRoot() { @Override
return false; public SqlTreeLoad createLoad() {
return new SqlTreeLoadBean(this);
}
protected SqlTreeLoad[] createLoadChildren() {
if (children.length == 0) {
return NO_LOAD_CHILDREN;
}
List<SqlTreeLoad> loadChildren = new ArrayList<>(children.length);
for (SqlTreeNode child : children) {
SqlTreeLoad load = child.createLoad();
if (load != null) {
loadChildren.add(load);
}
}
return loadChildren.toArray(new SqlTreeLoad[0]);
} }
@Override @Override
@@ -117,25 +122,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
return properties != null && properties.length == 1 && children.length == 0; return properties != null && properties.length == 1 && children.length == 0;
} }
@Override
public final ScalarDataReader<?> getSingleAttributeReader() {
if (properties == null || properties.length == 0) {
// if we have no property ask first children (in a distinct select with join)
if (children.length == 0) {
// expected to be a findIds query
return desc.idBinder().getBeanProperty();
}
return children[0].getSingleAttributeReader();
}
if (properties[0] instanceof STreePropertyAssocOne) {
STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0];
if (assocOne.isAssocId()) {
return assocOne.idReader();
}
}
return properties[0];
}
private Map<String, String> createPathMap(String prefix, STreeType desc) { private Map<String, String> createPathMap(String prefix, STreeType desc) {
HashMap<String, String> m = new HashMap<>(); HashMap<String, String> m = new HashMap<>();
for (STreePropertyAssocMany many : desc.propsMany()) { for (STreePropertyAssocMany many : desc.propsMany()) {
@@ -173,293 +159,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
} }
} }
/**
* Load that takes into account inheritance.
*/
private final class LoadInherit extends Load {
private LoadInherit(DbReadContext ctx, EntityBean parentBean) {
super(ctx, parentBean);
}
@Override
void initBeanType() throws SQLException {
InheritInfo localInfo = readId ? inheritInfo.readType(ctx) : desc.inheritInfo();
if (localInfo == null) {
// the bean must be null
localIdBinder = idBinder;
localDesc = desc;
} else {
localBean = localInfo.createEntityBean();
localType = localInfo.getType();
localIdBinder = localInfo.getIdBinder();
localDesc = localInfo.desc();
}
}
@Override
void loadProperties() {
// take account of inheritance
for (STreeProperty property : properties) {
localDesc.inheritanceLoad(sqlBeanLoad, property, ctx);
}
}
}
/**
* Load a bean instance.
*/
class Load {
final DbReadContext ctx;
final EntityBean parentBean;
Object lazyLoadParentId;
Class<?> localType;
STreeType localDesc;
IdBinder localIdBinder;
EntityBean localBean;
Mode queryMode;
PersistenceContext persistenceContext;
Object id;
EntityBean contextBean;
SqlBeanLoad sqlBeanLoad;
boolean lazyLoadMany;
private Load(DbReadContext ctx, EntityBean parentBean) {
this.ctx = ctx;
this.parentBean = parentBean;
}
private void initLazyParent() throws SQLException {
if (lazyLoadParentIdBinder != null) {
lazyLoadParentId = lazyLoadParentIdBinder.read(ctx);
}
}
void initBeanType() throws SQLException {
localDesc = desc;
localBean = desc.createEntityBean();
localIdBinder = idBinder;
}
private void initPersistenceContext() {
queryMode = ctx.getQueryMode();
persistenceContext = (!readIdNormal) ? null : ctx.getPersistenceContext();
}
private void readId() throws SQLException {
if (readId) {
id = localIdBinder.readSet(ctx, localBean);
if (id == null) {
readIdNullBean();
} else if (!temporalVersions) {
readIdBean();
}
}
}
private void readIdBean() {
// check the PersistenceContext to see if the bean already exists
contextBean = (EntityBean) localDesc.contextPutIfAbsent(persistenceContext, id, localBean);
if (contextBean == null) {
// bean just added to the persistenceContext
contextBean = localBean;
} else {
// bean already exists in persistenceContext
if (queryMode.isLoadContextBean()) {
// if explicitly set loadContextBean to true, then reload
localBean = contextBean;
} else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) {
// reload if contextBean is partial object
localBean = contextBean;
// and switch to lazyLoad query mode in order not to overwrite
// existing properties in SqlBeanLoad::load
queryMode = Mode.LAZYLOAD_BEAN;
} else {
// ignore the DB data...
localBean = null;
}
}
}
private void readIdNullBean() {
// bean must be null...
localBean = null;
// ... but there may exist as reference bean in parent which has to be marked as deleted.
if (parentBean != null && nodeBeanProp instanceof STreePropertyAssocOne) {
contextBean = ((STreePropertyAssocOne)nodeBeanProp).getValueAsEntityBean(parentBean);
if (contextBean != null) {
desc.markAsDeleted(contextBean);
}
}
}
private void initSqlLoadBean() {
ctx.setCurrentPrefix(prefix, pathMap);
ctx.propagateState(localBean);
sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode);
}
void loadProperties() {
for (STreeProperty property : properties) {
property.load(sqlBeanLoad);
}
}
private void loadChildren() throws SQLException {
if (localBean == null && queryMode == Mode.LAZYLOAD_MANY) {
// batch lazy load many into existing contextBean
localBean = contextBean;
lazyLoadMany = true;
}
for (SqlTreeNode child : children) {
child.load(ctx, localBean, contextBean);
}
}
private boolean isLazyLoadManyRoot() {
return queryMode == Mode.LAZYLOAD_MANY && isRoot();
}
private EntityBean getContextBean() {
return contextBean;
}
private void postLoad() {
if (!lazyLoadMany && localBean != null) {
ctx.setCurrentPrefix(prefix, pathMap);
if (readIdNormal) {
createListProxies();
}
if (temporalMode == SpiQuery.TemporalMode.DRAFT) {
localDesc.setDraft(localBean);
}
localDesc.postLoad(localBean);
EntityBeanIntercept ebi = localBean._ebean_getIntercept();
ebi.setPersistenceContext(persistenceContext);
if (Mode.LAZYLOAD_BEAN == queryMode) {
// Lazy Load does not reset the dirty state
ebi.setLoadedLazy();
} else if (readId) {
// normal bean loading
ebi.setLoaded();
}
if (disableLazyLoad) {
// bean does not have an Id or is SqlSelect based
ebi.setDisableLazyLoad(true);
} else if (partialObject) {
if (readId) {
// register for lazy loading
ctx.register(null, ebi);
}
} else {
ebi.setFullyLoadedBean(true);
}
if (ctx.isAutoTuneProfiling() && !disableLazyLoad) {
// collect autoTune profiling for this bean...
ctx.profileBean(ebi, prefix);
}
}
}
/**
* Create lazy loading proxies for the Many's except for the one that is
* included in the actual query.
*/
private void createListProxies() {
STreePropertyAssocMany fetchedMany = ctx.getManyProperty();
boolean forceNewReference = queryMode == Mode.REFRESH_BEAN;
for (STreePropertyAssocMany many : localDesc.propsMany()) {
if (many != fetchedMany) {
// create a proxy for the many (deferred fetching)
BeanCollection<?> ref = many.createReference(localBean, forceNewReference);
if (ref != null) {
if (disableLazyLoad) {
ref.setDisableLazyLoad(true);
}
if (!ref.isRegisteredWithLoadContext()) {
ctx.register(many.asMany(), ref);
}
}
}
}
}
private void setBeanToParent() {
if (parentBean != null) {
// set this back to the parentBean
nodeBeanProp.setValue(parentBean, contextBean);
}
}
private EntityBean complete() {
if (!readIdNormal) {
// a bean with no Id (never found in context)
if (lazyLoadParentId != null) {
ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId);
}
return localBean;
} else {
if (lazyLoadParentId != null) {
ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId);
}
return contextBean;
}
}
private void initialise() throws SQLException {
initLazyParent();
initBeanType();
initPersistenceContext();
readId();
initSqlLoadBean();
loadProperties();
loadChildren();
}
/**
* Perform the load returning the loaded bean.
*/
final EntityBean perform() throws SQLException {
initialise();
if (isLazyLoadManyRoot()) {
return getContextBean();
}
postLoad();
setBeanToParent();
return complete();
}
/**
* Return true if this bean was already in the context. If already in the
* context we need to check if it is already contained in the collection.
*/
final boolean isContextBean() {
return localBean == null;
}
}
/**
* read the properties from the resultSet.
*/
@Override
public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException {
return createLoad(ctx, parentBean).perform();
}
/**
* Create the loader with or without inheritance.
*/
final Load createLoad(DbReadContext ctx, EntityBean parentBean) {
return (inheritInfo != null) ? new LoadInherit(ctx, parentBean) : new Load(ctx, parentBean);
}
@Override @Override
public final void appendGroupBy(DbSqlContext ctx, boolean subQuery) { public final void appendGroupBy(DbSqlContext ctx, boolean subQuery) {
ctx.pushJoin(prefix); ctx.pushJoin(prefix);
@@ -38,6 +38,11 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode {
this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany; this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany;
} }
@Override
public SqlTreeLoad createLoad() {
return null;
}
@Override @Override
public boolean isSingleProperty() { public boolean isSingleProperty() {
return false; return false;
@@ -73,11 +78,6 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode {
// nothing to do here // nothing to do here
} }
@Override
public ScalarType<?> getSingleAttributeReader() {
throw new IllegalStateException("No expected");
}
/** /**
* Return true if the extra join is a many join. * Return true if the extra join is a many join.
* <p> * <p>
@@ -184,14 +184,6 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode {
public void appendWhere(DbSqlContext ctx) { public void appendWhere(DbSqlContext ctx) {
} }
/**
* Does nothing.
*/
@Override
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
return null;
}
@Override @Override
public boolean hasMany() { public boolean hasMany() {
return manyJoin; return manyJoin;
@@ -33,13 +33,13 @@ final class SqlTreeNodeFormulaWhereJoin implements SqlTreeNode {
} }
@Override @Override
public boolean isSingleProperty() { public SqlTreeLoad createLoad() {
return true; return null;
} }
@Override @Override
public ScalarType<?> getSingleAttributeReader() { public boolean isSingleProperty() {
throw new IllegalStateException("No expected"); return true;
} }
@Override @Override
@@ -98,12 +98,6 @@ final class SqlTreeNodeFormulaWhereJoin implements SqlTreeNode {
// nothing to do here // nothing to do here
} }
@Override
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
// nothing to do here
return null;
}
@Override @Override
public boolean hasMany() { public boolean hasMany() {
return true; return true;
@@ -1,16 +1,13 @@
package io.ebeaninternal.server.query; package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.DbSqlContext;
import java.sql.SQLException;
import java.util.List; import java.util.List;
final class SqlTreeNodeManyRoot extends SqlTreeNodeBean { final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
private final STreePropertyAssocMany manyProp; final STreePropertyAssocMany manyProp;
SqlTreeNodeManyRoot(String prefix, STreePropertyAssocMany prop, SqlTreeProperties props, List<SqlTreeNode> myList, SqlTreeNodeManyRoot(String prefix, STreePropertyAssocMany prop, SqlTreeProperties props, List<SqlTreeNode> myList,
boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
@@ -19,22 +16,13 @@ final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
} }
@Override @Override
public boolean hasMany() { public SqlTreeLoad createLoad() {
return true; return new SqlTreeLoadManyRoot(this);
} }
@Override @Override
public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException { public boolean hasMany() {
// pass in null for parentBean because added to a collection rather than set to the parentBean return true;
SqlTreeNodeBean.Load load = createLoad(cquery, null);
EntityBean detailBean = load.perform();
if (contextParent != null) {
// Add to the collection and initialise collection if needed
// A null detailBean may initialise an empty collection
// Check for bean existing in collection based on load.isContextBean()
manyProp.addBeanToCollectionWithCreate(contextParent, detailBean, load.isContextBean());
}
return detailBean;
} }
/** /**
@@ -1,10 +1,7 @@
package io.ebeaninternal.server.query; package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebean.util.SplitName; import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.TableJoin;
@@ -37,13 +34,13 @@ final class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
} }
@Override @Override
public boolean isSingleProperty() { public SqlTreeLoad createLoad() {
return false; return null;
} }
@Override @Override
public ScalarType<?> getSingleAttributeReader() { public boolean isSingleProperty() {
throw new IllegalStateException("No expected"); return false;
} }
@Override @Override
@@ -132,12 +129,6 @@ final class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
// nothing to do here // nothing to do here
} }
@Override
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
// nothing to do here
return null;
}
@Override @Override
public boolean hasMany() { public boolean hasMany() {
return true; return true;
@@ -1,21 +1,16 @@
package io.ebeaninternal.server.query; package io.ebeaninternal.server.query;
import io.ebean.Version;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.TableJoin;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
/** /**
* Represents the root node of the Sql Tree. * Represents the root node of the Sql Tree.
*/ */
final class SqlTreeNodeRoot extends SqlTreeNodeBean implements SqlTreeRoot { final class SqlTreeNodeRoot extends SqlTreeNodeBean {
private final TableJoin includeJoin; private final TableJoin includeJoin;
private final boolean sqlDistinct; private final boolean sqlDistinct;
@@ -34,27 +29,8 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean implements SqlTreeRoot {
} }
@Override @Override
protected boolean isRoot() { public SqlTreeLoad createLoad() {
return true; return new SqlTreeLoadRoot(this);
}
@Override
public EntityBean load(DbReadContext ctx) throws SQLException {
return load(ctx, null, null);
}
/**
* Read the version bean.
*/
@Override
@SuppressWarnings("unchecked")
public <T> Version<T> loadVersion(DbReadContext ctx) throws SQLException {
// read the sys period lower and upper bounds
// these are always the first 2 columns in the resultSet
Timestamp start = ctx.getDataReader().getTimestamp();
Timestamp end = ctx.getDataReader().getTimestamp();
T bean = (T) load(ctx, null, null);
return new Version<>(bean, start, end);
} }
@Override @Override
@@ -0,0 +1,41 @@
package io.ebeaninternal.server.query;
import java.util.Set;
final class SqlTreePlan {
private final SqlTreeLoad rootNode;
private final STreePropertyAssocMany manyProperty;
private final STreeProperty[] encryptedProps;
private final Set<String> dependentTables;
SqlTreePlan(SqlTreeLoad rootNode, STreePropertyAssocMany manyProperty, STreeProperty[] encryptedProps, Set<String> dependentTables) {
this.rootNode = rootNode;
this.manyProperty = manyProperty;
this.encryptedProps = encryptedProps;
this.dependentTables = dependentTables;
}
SqlTreeRoot getRootNode() {
return (SqlTreeRoot)rootNode;
}
/**
* Return the property that is associated with the many. There can only be one
* per SqlSelect. This can be null.
*/
STreePropertyAssocMany getManyProperty() {
return manyProperty;
}
STreeProperty[] getEncryptedProps() {
return encryptedProps;
}
/**
* Return the tables that are joined in this query.
*/
Set<String> dependentTables() {
return dependentTables;
}
}
+1 -1
View File
@@ -89,7 +89,7 @@
<configuration> <configuration>
<tiles> <tiles>
<!-- other tiles ... --> <!-- other tiles ... -->
<tile>io.ebean.tile:enhancement:12.11.3</tile> <tile>io.ebean.tile:enhancement:12.14.1</tile>
<tile>io.avaje.tile:moditech-module:1.0</tile> <tile>io.avaje.tile:moditech-module:1.0</tile>
</tiles> </tiles>
</configuration> </configuration>
+1 -1
View File
@@ -14,7 +14,7 @@
<properties> <properties>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<ebean-maven-plugin.version>12.13.0</ebean-maven-plugin.version> <ebean-maven-plugin.version>12.14.1</ebean-maven-plugin.version>
<kotlin.version>1.6.0</kotlin.version> <kotlin.version>1.6.0</kotlin.version>
</properties> </properties>
+1 -1
View File
@@ -105,7 +105,7 @@
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<tiles> <tiles>
<tile>io.ebean.tile:enhancement:12.11.3</tile> <tile>io.ebean.tile:enhancement:12.14.1</tile>
<tile>io.avaje.tile:moditech-module:1.0</tile> <tile>io.avaje.tile:moditech-module:1.0</tile>
</tiles> </tiles>
</configuration> </configuration>
+1 -1
View File
@@ -100,7 +100,7 @@
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<tiles> <tiles>
<tile>io.ebean.tile:enhancement:12.11.3</tile> <tile>io.ebean.tile:enhancement:12.14.1</tile>
<tile>io.avaje.tile:moditech-module:1.0</tile> <tile>io.avaje.tile:moditech-module:1.0</tile>
</tiles> </tiles>
</configuration> </configuration>
+1 -1
View File
@@ -80,7 +80,7 @@
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<tiles> <tiles>
<tile>io.ebean.tile:enhancement:12.11.3</tile> <tile>io.ebean.tile:enhancement:12.14.1</tile>
<tile>io.avaje.tile:moditech-module:1.0</tile> <tile>io.avaje.tile:moditech-module:1.0</tile>
</tiles> </tiles>
</configuration> </configuration>
+1 -1
View File
@@ -249,7 +249,7 @@
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<tiles> <tiles>
<tile>io.ebean.tile:enhancement:12.11.3</tile> <tile>io.ebean.tile:enhancement:12.14.1</tile>
<tile>io.avaje.tile:moditech-module:1.0</tile> <tile>io.avaje.tile:moditech-module:1.0</tile>
</tiles> </tiles>
</configuration> </configuration>
@@ -24,8 +24,8 @@ public class DefaultServer_getReferenceTest extends BaseTestCase {
ResetBasicData.reset(); ResetBasicData.reset();
DB.execute(() -> { DB.execute(() -> {
Customer loaded = DB.find(Customer.class, 1); Customer loaded = DB.find(Customer.class).where().eq("name", "Rob").findOne();
Customer reference = DB.reference(Customer.class, 1); Customer reference = DB.reference(Customer.class, loaded.getId());
assertThat(loaded).isSameAs(reference); assertThat(loaded).isSameAs(reference);
}); });
} }
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.deploy; package io.ebeaninternal.server.deploy;
import io.ebean.BaseTestCase; import io.ebean.BaseTestCase;
import io.ebean.DB;
import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean; import io.ebean.bean.EntityBean;
import io.ebean.common.BeanList; import io.ebean.common.BeanList;
@@ -66,11 +67,13 @@ public class BeanPropertyAssocManyTest extends BaseTestCase {
ResetBasicData.reset(); ResetBasicData.reset();
List<Object> customerIds = new ArrayList<>(); List<Long> ids = DB.find(Customer.class).orderBy("id").setMaxRows(2).findIds();
customerIds.add(1L);
customerIds.add(2L);
List<Object> contactIdsForOne = contacts().findIdsByParentId(1L, null, null, null, true); List<Object> customerIds = new ArrayList<>();
customerIds.add(ids.get(0));
customerIds.add(ids.get(1));
List<Object> contactIdsForOne = contacts().findIdsByParentId(ids.get(0), null, null, null, true);
List<Object> contactIdsForMultiple = contacts().findIdsByParentId(null, customerIds, null, null, true); List<Object> contactIdsForMultiple = contacts().findIdsByParentId(null, customerIds, null, null, true);
@@ -6,13 +6,20 @@ import io.ebean.Database;
import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.IgnorePlatform;
import io.ebean.annotation.Platform; import io.ebean.annotation.Platform;
import io.ebean.annotation.Transactional; import io.ebean.annotation.Transactional;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer; import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
public class TestBatchSaveWithGetBeanId extends BaseTestCase { public class TestBatchSaveWithGetBeanId extends BaseTestCase {
@BeforeAll
static void before() {
ResetBasicData.reset();
}
/** /**
* Making this transaction with batchSize means that the insert * Making this transaction with batchSize means that the insert
* below does not occur immediately ... and the getBeanId() * below does not occur immediately ... and the getBeanId()
@@ -22,7 +29,6 @@ public class TestBatchSaveWithGetBeanId extends BaseTestCase {
@Test @Test
@IgnorePlatform(Platform.HANA) // HANA doesn't support insert batching @IgnorePlatform(Platform.HANA) // HANA doesn't support insert batching
public void test() { public void test() {
Database server = DB.getDefault(); Database server = DB.getDefault();
Customer model = new Customer(); Customer model = new Customer();
model.setName("foo"); model.setName("foo");
@@ -2,8 +2,10 @@ package org.tests.insert;
import io.ebean.BaseTestCase; import io.ebean.BaseTestCase;
import io.ebean.DB; import io.ebean.DB;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer; import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -12,9 +14,13 @@ import static org.junit.jupiter.api.Assertions.*;
public class TestInsertCollection extends BaseTestCase { public class TestInsertCollection extends BaseTestCase {
@BeforeAll
static void before() {
ResetBasicData.reset();
}
@Test @Test
public void test() { public void test() {
Customer cust1 = new Customer(); Customer cust1 = new Customer();
cust1.setName("jim"); cust1.setName("jim");
@@ -2,6 +2,7 @@ package org.tests.model.basic;
import io.ebean.DB; import io.ebean.DB;
import io.ebean.Database; import io.ebean.Database;
import io.ebean.Transaction;
import org.tests.model.basic.Order.Status; import org.tests.model.basic.Order.Status;
import java.sql.Date; import java.sql.Date;
@@ -47,6 +48,7 @@ public class ResetBasicData {
// the test rely on the products being in there // the test rely on the products being in there
return; return;
} }
Transaction.current().setBatchMode(false);
//me.deleteAll(); //me.deleteAll();
me.insertCountries(); me.insertCountries();
me.insertProducts(); me.insertProducts();
@@ -56,41 +58,7 @@ public class ResetBasicData {
} }
public void deleteAll() { private void insertCountries() {
DB.execute(() -> {
// orm update use bean name and bean properties
server.sqlUpdate("delete from o_cached_bean_child").execute();
server.sqlUpdate("delete from o_cached_bean_country").execute();
server.sqlUpdate("delete from o_cached_bean").execute();
server.createUpdate(OrderShipment.class, "delete from orderShipment").execute();
server.createUpdate(OrderDetail.class, "delete from orderDetail").execute();
server.createUpdate(Order.class, "delete from order").execute();
server.createUpdate(Contact.class, "delete from contact").execute();
server.createUpdate(Customer.class, "delete from Customer").execute();
server.createUpdate(Address.class, "delete from address").execute();
// sql update uses table and column names
server.sqlUpdate("delete from o_country").execute();
server.sqlUpdate("delete from o_product").execute();
});
}
public void insertCountries() {
if (server.find(Country.class).findCount() > 0) {
return;
}
server.execute(() -> {
Country c = new Country(); Country c = new Country();
c.setCode("NZ"); c.setCode("NZ");
c.setName("New Zealand"); c.setName("New Zealand");
@@ -100,16 +68,10 @@ public class ResetBasicData {
au.setCode("AU"); au.setCode("AU");
au.setName("Australia"); au.setName("Australia");
server.save(au); server.save(au);
});
} }
public void insertProducts() { private void insertProducts() {
if (server.find(Product.class).findCount() > 0) {
return;
}
server.execute(() -> {
Product p = new Product(); Product p = new Product();
p.setName("Chair"); p.setName("Chair");
p.setSku("C001"); p.setSku("C001");
@@ -129,12 +91,9 @@ public class ResetBasicData {
p.setName("Printer"); p.setName("Printer");
p.setSku("C003"); p.setSku("C003");
server.save(p); server.save(p);
});
} }
public void insertTestCustAndOrders() { private void insertTestCustAndOrders() {
DB.execute(() -> {
Customer cust1 = insertCustomer("Rob"); Customer cust1 = insertCustomer("Rob");
Customer cust2 = insertCustomerNoAddress(); Customer cust2 = insertCustomerNoAddress();
insertCustomerFiona(); insertCustomerFiona();
@@ -145,11 +104,9 @@ public class ResetBasicData {
createOrder3(cust1); createOrder3(cust1);
createOrder4(cust1); createOrder4(cust1);
createOrder5(cust2); createOrder5(cust2);
});
} }
public static Customer createCustAndOrder(String custName) { public static Customer createCustAndOrder(String custName) {
ResetBasicData me = new ResetBasicData(); ResetBasicData me = new ResetBasicData();
Customer cust1 = insertCustomer(custName); Customer cust1 = insertCustomer(custName);
me.createOrder1(cust1); me.createOrder1(cust1);
@@ -157,7 +114,6 @@ public class ResetBasicData {
} }
public static Order createOrderCustAndOrder(String custName) { public static Order createOrderCustAndOrder(String custName) {
ResetBasicData me = new ResetBasicData(); ResetBasicData me = new ResetBasicData();
Customer cust1 = insertCustomer(custName); Customer cust1 = insertCustomer(custName);
return me.createOrder1(cust1); return me.createOrder1(cust1);
@@ -166,10 +122,8 @@ public class ResetBasicData {
private static int contactEmailNum = 1; private static int contactEmailNum = 1;
private Customer insertCustomerFiona() { private Customer insertCustomerFiona() {
Customer c = createCustomer("Fiona", "12 Apple St", "West Coast Rd", 1, "2009-08-31"); Customer c = createCustomer("Fiona", "12 Apple St", "West Coast Rd", 1, "2009-08-31");
c.setStatus(Customer.Status.ACTIVE); c.setStatus(Customer.Status.ACTIVE);
c.addContact(createContact("Fiona", "Black")); c.addContact(createContact("Fiona", "Black"));
c.addContact(createContact("Tracy", "Red")); c.addContact(createContact("Tracy", "Red"));
@@ -185,22 +139,18 @@ public class ResetBasicData {
} }
private Customer insertCustomerNoContacts(String name) { private Customer insertCustomerNoContacts(String name) {
Customer c = createCustomer("Roger", "15 Kumera Way", "Bos town", 1, "2010-04-10"); Customer c = createCustomer("Roger", "15 Kumera Way", "Bos town", 1, "2010-04-10");
c.setName(name); c.setName(name);
c.setStatus(Customer.Status.ACTIVE); c.setStatus(Customer.Status.ACTIVE);
DB.save(c); DB.save(c);
return c; return c;
} }
private Customer insertCustomerNoAddress() { private Customer insertCustomerNoAddress() {
Customer c = new Customer(); Customer c = new Customer();
c.setName("Cust NoAddress"); c.setName("Cust NoAddress");
c.setStatus(Customer.Status.NEW); c.setStatus(Customer.Status.NEW);
c.addContact(createContact("Jack", "Black")); c.addContact(createContact("Jack", "Black"));
DB.save(c); DB.save(c);
return c; return c;
} }
@@ -216,7 +166,6 @@ public class ResetBasicData {
} }
public static Customer createCustomer(String name, String shippingStreet, String billingStreet, int contactSuffix, String annDate) { public static Customer createCustomer(String name, String shippingStreet, String billingStreet, int contactSuffix, String annDate) {
Customer c = new Customer(); Customer c = new Customer();
c.setName(name); c.setName(name);
c.setStatus(Customer.Status.NEW); c.setStatus(Customer.Status.NEW);
@@ -251,17 +200,14 @@ public class ResetBasicData {
c.setBillingAddress(billingAddr); c.setBillingAddress(billingAddr);
} }
return c; return c;
} }
private Order createOrder1(Customer customer) { private Order createOrder1(Customer customer) {
Product product1 = DB.reference(Product.class, 1); Product product1 = DB.reference(Product.class, 1);
Product product2 = DB.reference(Product.class, 2); Product product2 = DB.reference(Product.class, 2);
Product product3 = DB.reference(Product.class, 3); Product product3 = DB.reference(Product.class, 3);
Order order = new Order(); Order order = new Order();
order.setCustomer(customer); order.setCustomer(customer);
order.setOrderDate(Date.valueOf("2018-07-01")); order.setOrderDate(Date.valueOf("2018-07-01"));
@@ -271,16 +217,12 @@ public class ResetBasicData {
details.add(new OrderDetail(product2, 3, 1.10)); details.add(new OrderDetail(product2, 3, 1.10));
details.add(new OrderDetail(product3, 1, 2.00)); details.add(new OrderDetail(product3, 1, 2.00));
order.setDetails(details); order.setDetails(details);
order.addShipment(new OrderShipment()); order.addShipment(new OrderShipment());
DB.save(order); DB.save(order);
return order; return order;
} }
private void createOrder2(Customer customer) { private void createOrder2(Customer customer) {
Product product1 = DB.reference(Product.class, 1); Product product1 = DB.reference(Product.class, 1);
Order order = new Order(); Order order = new Order();
@@ -291,14 +233,11 @@ public class ResetBasicData {
List<OrderDetail> details = new ArrayList<>(); List<OrderDetail> details = new ArrayList<>();
details.add(new OrderDetail(product1, 4, 10.50)); details.add(new OrderDetail(product1, 4, 10.50));
order.setDetails(details); order.setDetails(details);
order.addShipment(new OrderShipment()); order.addShipment(new OrderShipment());
DB.save(order); DB.save(order);
} }
private void createOrder3(Customer customer) { private void createOrder3(Customer customer) {
Product product1 = DB.reference(Product.class, 1); Product product1 = DB.reference(Product.class, 1);
Product product3 = DB.reference(Product.class, 3); Product product3 = DB.reference(Product.class, 3);
@@ -312,30 +251,23 @@ public class ResetBasicData {
details.add(new OrderDetail(product3, 40, 2.10)); details.add(new OrderDetail(product3, 40, 2.10));
details.add(new OrderDetail(product1, 5, 10.00)); details.add(new OrderDetail(product1, 5, 10.00));
order.setDetails(details); order.setDetails(details);
order.addShipment(new OrderShipment()); order.addShipment(new OrderShipment());
DB.save(order); DB.save(order);
} }
private void createOrder4(Customer customer) { private void createOrder4(Customer customer) {
Order order = new Order(); Order order = new Order();
order.setCustomer(customer); order.setCustomer(customer);
order.setOrderDate(Date.valueOf("2018-07-04")); order.setOrderDate(Date.valueOf("2018-07-04"));
order.addShipment(new OrderShipment()); order.addShipment(new OrderShipment());
DB.save(order); DB.save(order);
} }
private void createOrder5(Customer customer) { private void createOrder5(Customer customer) {
Order order = new Order(); Order order = new Order();
order.setCustomer(customer); order.setCustomer(customer);
order.setOrderDate(Date.valueOf("2018-06-28")); order.setOrderDate(Date.valueOf("2018-06-28"));
order.addShipment(new OrderShipment()); order.addShipment(new OrderShipment());
DB.save(order); DB.save(order);
} }
} }
@@ -131,7 +131,7 @@ public class TestQuerySingleAttribute extends BaseTestCase {
Query<Customer> query = DB.find(Customer.class) Query<Customer> query = DB.find(Customer.class)
.select("name") .select("name")
.where().eq("id", 1).query(); .where().eq("name", "Rob").query();
String name = query.findSingleAttribute(); String name = query.findSingleAttribute();
@@ -248,7 +248,7 @@ public class TestQuerySingleAttribute extends BaseTestCase {
String name = DB.find(Customer.class) String name = DB.find(Customer.class)
.select("name") .select("name")
.where().eq("id", 1) .where().eq("name", "Rob")
.findSingleAttribute(); .findSingleAttribute();
assertThat(name).isNotNull(); assertThat(name).isNotNull();
@@ -3,11 +3,13 @@ package org.tests.update;
import io.ebean.DB; import io.ebean.DB;
import io.ebean.TransactionalTestCase; import io.ebean.TransactionalTestCase;
import io.ebean.test.LoggedSql; import io.ebean.test.LoggedSql;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.tests.model.basic.Contact; import org.tests.model.basic.Contact;
import org.tests.model.basic.Customer; import org.tests.model.basic.Customer;
import org.tests.model.basic.EBasic; import org.tests.model.basic.EBasic;
import org.tests.model.basic.EBasic.Status; import org.tests.model.basic.EBasic.Status;
import org.tests.model.basic.ResetBasicData;
import javax.persistence.EntityNotFoundException; import javax.persistence.EntityNotFoundException;
import java.util.*; import java.util.*;
@@ -17,6 +19,11 @@ import static org.junit.jupiter.api.Assertions.*;
public class TestStatelessUpdate extends TransactionalTestCase { public class TestStatelessUpdate extends TransactionalTestCase {
@BeforeAll
static void before() {
ResetBasicData.reset();
}
@Test @Test
public void test() { public void test() {
@@ -3,14 +3,21 @@ package org.tests.update;
import io.ebean.BaseTestCase; import io.ebean.BaseTestCase;
import io.ebean.DB; import io.ebean.DB;
import io.ebean.SqlRow; import io.ebean.SqlRow;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer; import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestUpdatePartial extends BaseTestCase { public class TestUpdatePartial extends BaseTestCase {
@BeforeAll
static void before() {
ResetBasicData.reset();
}
@Test @Test
public void test() { public void test() {
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.avaje</groupId> <groupId>org.avaje</groupId>
<artifactId>java8-oss</artifactId> <artifactId>java8-oss</artifactId>
<version>2.3</version> <version>3.3</version>
<relativePath/> <relativePath/>
</parent> </parent>
+2 -2
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.avaje</groupId> <groupId>org.avaje</groupId>
<artifactId>java11-oss</artifactId> <artifactId>java11-oss</artifactId>
<version>2.3</version> <version>3.4</version>
<relativePath/> <relativePath/>
</parent> </parent>
@@ -19,7 +19,7 @@
<maven.compiler.source>11</maven.compiler.source> <maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target> <maven.compiler.target>11</maven.compiler.target>
<ebean-maven-plugin.version>12.13.0</ebean-maven-plugin.version> <ebean-maven-plugin.version>12.14.1</ebean-maven-plugin.version>
<kotlin.version>1.6.0</kotlin.version> <kotlin.version>1.6.0</kotlin.version>
<jackson.version>2.12.1</jackson.version> <jackson.version>2.12.1</jackson.version>
<maven.deploy.skip>true</maven.deploy.skip> <maven.deploy.skip>true</maven.deploy.skip>