mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#1331 - ENH: Support Aggregation formula with findSingleAttribute() ... max, min, avg, count and count(distinct ..)
This commit is contained in:
@@ -273,13 +273,19 @@ class DefaultDbSqlContext implements DbSqlContext {
|
||||
sb.append(" ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendParseSelect(String parseSelect) {
|
||||
String converted = alias.parse(parseSelect);
|
||||
sb.append(COMMA);
|
||||
sb.append(converted);
|
||||
appendColumnAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendFormulaSelect(String sqlFormulaSelect) {
|
||||
|
||||
String tableAlias = tableAliasStack.peek();
|
||||
String converted = StringHelper.replaceString(sqlFormulaSelect, tableAliasPlaceHolder,
|
||||
tableAlias);
|
||||
|
||||
String converted = StringHelper.replaceString(sqlFormulaSelect, tableAliasPlaceHolder, tableAlias);
|
||||
sb.append(COMMA);
|
||||
sb.append(converted);
|
||||
|
||||
|
||||
@@ -44,6 +44,13 @@ public class SqlBeanLoad {
|
||||
return lazyLoading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB read context.
|
||||
*/
|
||||
public DbReadContext ctx() {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the resultSet index 1.
|
||||
*/
|
||||
@@ -86,4 +93,14 @@ public class SqlBeanLoad {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the given value into the property.
|
||||
*/
|
||||
public void load(BeanProperty target, Object dbVal) {
|
||||
if (!refreshLoading) {
|
||||
target.setValue(bean, dbVal);
|
||||
} else {
|
||||
target.setValueIntercept(bean, dbVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ public final class SqlTreeBuilder {
|
||||
|
||||
// make sure we only included the base/embedded bean once
|
||||
if (!selectProps.containsProperty(baseName)) {
|
||||
BeanProperty p = desc.findBeanProperty(baseName);
|
||||
SqlTreeProperty p = desc.findSqlTreeProperty(baseName);
|
||||
if (p == null) {
|
||||
logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it.");
|
||||
|
||||
@@ -436,7 +436,7 @@ public final class SqlTreeBuilder {
|
||||
} else {
|
||||
// find the property including searching the
|
||||
// sub class hierarchy if required
|
||||
BeanProperty p = desc.findBeanProperty(propName);
|
||||
SqlTreeProperty p = desc.findSqlTreeProperty(propName);
|
||||
if (p == null) {
|
||||
logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it.");
|
||||
p = desc.findBeanProperty("id");
|
||||
|
||||
@@ -48,7 +48,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
*/
|
||||
private final boolean partialObject;
|
||||
|
||||
protected final BeanProperty[] properties;
|
||||
protected final SqlTreeProperty[] properties;
|
||||
|
||||
/**
|
||||
* Extra where clause added by Where annotation on associated many.
|
||||
@@ -87,6 +87,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
private boolean intersectionAsOfTableAlias;
|
||||
|
||||
private final boolean aggregation;
|
||||
private final boolean aggregationRoot;
|
||||
|
||||
/**
|
||||
* Construct for leaf node.
|
||||
@@ -124,13 +125,15 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
this.nodeBeanProp = beanProp;
|
||||
this.extraWhere = (beanProp == null) ? null : beanProp.getExtraWhere();
|
||||
|
||||
this.aggregation = props.isAggregation();
|
||||
this.aggregationRoot = props.isAggregationRoot();
|
||||
|
||||
// the bean has an Id property and we want to use it
|
||||
this.readId = withId && (desc.getIdProperty() != null);
|
||||
this.readId = !aggregationRoot && withId && (desc.getIdProperty() != null);
|
||||
this.disableLazyLoad = disableLazyLoad || !readId || desc.isRawSqlBased() || temporalVersions;
|
||||
|
||||
this.partialObject = props.isPartialObject();
|
||||
this.properties = props.getProps();
|
||||
this.aggregation = props.isAggregation();
|
||||
this.children = myChildren == null ? NO_CHILDREN : myChildren.toArray(new SqlTreeNode[myChildren.size()]);
|
||||
|
||||
pathMap = createPathMap(prefix, desc);
|
||||
@@ -186,7 +189,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
}
|
||||
idBinder.buildRawSqlSelectChain(prefix, selectChain);
|
||||
}
|
||||
for (BeanProperty property : properties) {
|
||||
for (SqlTreeProperty property : properties) {
|
||||
property.buildRawSqlSelectChain(prefix, selectChain);
|
||||
}
|
||||
// recursively continue reading...
|
||||
@@ -289,14 +292,14 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
|
||||
if (inheritInfo == null) {
|
||||
// normal behavior with no inheritance
|
||||
for (BeanProperty property : properties) {
|
||||
for (SqlTreeProperty property : properties) {
|
||||
property.load(sqlBeanLoad);
|
||||
}
|
||||
|
||||
} else {
|
||||
// take account of inheritance and due to subclassing approach
|
||||
// need to get a 'local' version of the property
|
||||
for (BeanProperty property : properties) {
|
||||
for (SqlTreeProperty property : properties) {
|
||||
// get a local version of the BeanProperty
|
||||
BeanProperty p = localDesc.getBeanProperty(property.getName());
|
||||
if (p != null) {
|
||||
@@ -416,7 +419,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
if (readId) {
|
||||
appendSelectId(ctx, idBinder.getBeanProperty());
|
||||
}
|
||||
for (BeanProperty property : properties) {
|
||||
for (SqlTreeProperty property : properties) {
|
||||
if (!property.isAggregation()) {
|
||||
property.appendSelect(ctx, subQuery);
|
||||
}
|
||||
@@ -483,9 +486,9 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
/**
|
||||
* Append the properties to the buffer.
|
||||
*/
|
||||
private void appendSelect(DbSqlContext ctx, boolean subQuery, BeanProperty[] props) {
|
||||
private void appendSelect(DbSqlContext ctx, boolean subQuery, SqlTreeProperty[] props) {
|
||||
|
||||
for (BeanProperty prop : props) {
|
||||
for (SqlTreeProperty prop : props) {
|
||||
prop.appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
@@ -543,7 +546,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
// join and return SqlJoinType to use for child joins
|
||||
joinType = appendFromBaseTable(ctx, joinType);
|
||||
|
||||
for (BeanProperty property : properties) {
|
||||
for (SqlTreeProperty property : properties) {
|
||||
// usually nothing... except for 1-1 Exported
|
||||
property.appendFrom(ctx, joinType);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebeaninternal.api.ManyWhereJoins;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -21,7 +20,7 @@ public class SqlTreeProperties {
|
||||
/**
|
||||
* The bean properties in order.
|
||||
*/
|
||||
private final List<BeanProperty> propsList = new ArrayList<>();
|
||||
private final List<SqlTreeProperty> propsList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Maintain a list of property names to detect embedded bean additions.
|
||||
@@ -32,6 +31,8 @@ public class SqlTreeProperties {
|
||||
|
||||
private boolean aggregation;
|
||||
|
||||
private String aggregationPath;
|
||||
|
||||
SqlTreeProperties() {
|
||||
}
|
||||
|
||||
@@ -39,17 +40,17 @@ public class SqlTreeProperties {
|
||||
return propNames.contains(propName);
|
||||
}
|
||||
|
||||
public void add(BeanProperty[] props) {
|
||||
public void add(SqlTreeProperty[] props) {
|
||||
propsList.addAll(Arrays.asList(props));
|
||||
}
|
||||
|
||||
public void add(BeanProperty prop) {
|
||||
public void add(SqlTreeProperty prop) {
|
||||
propsList.add(prop);
|
||||
propNames.add(prop.getName());
|
||||
}
|
||||
|
||||
public BeanProperty[] getProps() {
|
||||
return propsList.toArray(new BeanProperty[propsList.size()]);
|
||||
public SqlTreeProperty[] getProps() {
|
||||
return propsList.toArray(new SqlTreeProperty[propsList.size()]);
|
||||
}
|
||||
|
||||
boolean isPartialObject() {
|
||||
@@ -77,7 +78,6 @@ public class SqlTreeProperties {
|
||||
boolean requireSqlDistinct(ManyWhereJoins manyWhereJoins) {
|
||||
String joinProperty = aggregationJoin();
|
||||
if (joinProperty != null) {
|
||||
aggregation = true;
|
||||
manyWhereJoins.addAggregationJoin(joinProperty);
|
||||
return false;
|
||||
} else {
|
||||
@@ -97,12 +97,21 @@ public class SqlTreeProperties {
|
||||
*/
|
||||
private String aggregationJoin() {
|
||||
if (!allProperties) {
|
||||
for (BeanProperty beanProperty : propsList) {
|
||||
for (SqlTreeProperty beanProperty : propsList) {
|
||||
if (beanProperty.isAggregation()) {
|
||||
return beanProperty.getElPrefix();
|
||||
aggregation = true;
|
||||
aggregationPath = beanProperty.getElPrefix();
|
||||
return aggregationPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a top level aggregation which means the Id property must be excluded.
|
||||
*/
|
||||
public boolean isAggregationRoot() {
|
||||
return aggregation && (aggregationPath == null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebeaninternal.server.deploy.DbReadContext;
|
||||
import io.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A property in the SQL Tree.
|
||||
*
|
||||
* A BeanProperty or a dynamically created property based on formula.
|
||||
*/
|
||||
public interface SqlTreeProperty {
|
||||
|
||||
/**
|
||||
* Return the property name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the full property name (for error messages).
|
||||
*/
|
||||
String getFullBeanName();
|
||||
|
||||
/**
|
||||
* Return true if the property is the Id.
|
||||
*/
|
||||
boolean isId();
|
||||
|
||||
/**
|
||||
* Return true if the property is an embedded type.
|
||||
*/
|
||||
boolean isEmbedded();
|
||||
|
||||
/**
|
||||
* Return true if the property is an aggregation.
|
||||
*/
|
||||
boolean isAggregation();
|
||||
|
||||
/**
|
||||
* Return the Expression language prefix (join path).
|
||||
*/
|
||||
String getElPrefix();
|
||||
|
||||
/**
|
||||
* Return the underlying scalar type for the property (for findSingleAttribute).
|
||||
*/
|
||||
ScalarType<?> getScalarType();
|
||||
|
||||
/**
|
||||
* For RawSql build the select chain.
|
||||
*/
|
||||
void buildRawSqlSelectChain(String prefix, List<String> selectChain);
|
||||
|
||||
/**
|
||||
* Load into the bean (from the DataReader/ResultSet).
|
||||
*/
|
||||
void load(SqlBeanLoad sqlBeanLoad);
|
||||
|
||||
/**
|
||||
* Ignore the property (moving the column index position without reading).
|
||||
*/
|
||||
void loadIgnore(DbReadContext ctx);
|
||||
|
||||
/**
|
||||
* Append to the select clause.
|
||||
*/
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery);
|
||||
|
||||
/**
|
||||
* Append to the from clause.
|
||||
*/
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user