From 141f0a8b164e3188e42db0fb390e919bc9da189a Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 22 Jan 2019 15:56:20 +1300 Subject: [PATCH] Testing out concept - aggregation formula on fetch clause --- .../server/deploy/BeanDescriptor.java | 9 +++++---- .../server/deploy/FormulaPropertyPath.java | 11 +++++++++-- .../io/ebeaninternal/server/query/STreeType.java | 2 +- .../server/query/SqlTreeBuilder.java | 10 ++++++---- .../server/query/SqlTreeNodeBean.java | 15 +++++++++++++-- .../server/query/SqlTreeProperties.java | 4 ++++ .../server/deploy/FormulaPropertyPathTest.java | 2 +- 7 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index b94b16bc9..0bc14bdf4 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -2586,9 +2586,10 @@ public class BeanDescriptor implements BeanType, STreeType { /** * Return a 'dynamic property' used to read a formula. */ - private STreeProperty findSqlTreeFormula(String formulaExpression) { + private STreeProperty findSqlTreeFormula(String formula, String path) { - return dynamicProperty.computeIfAbsent(formulaExpression, (formula) -> new FormulaPropertyPath(this, formula).build()); + String key = formula + "-" + path; + return dynamicProperty.computeIfAbsent(key, (fullKey) -> new FormulaPropertyPath(this, formula, path).build()); } /** @@ -2597,9 +2598,9 @@ public class BeanDescriptor implements BeanType, STreeType { * The property can be a dynamic formula or a well known bean property. */ @Override - public STreeProperty findPropertyWithDynamic(String propName) { + public STreeProperty findPropertyWithDynamic(String propName, String path) { if (propName.indexOf('(') > -1) { - return findSqlTreeFormula(propName); + return findSqlTreeFormula(propName, path); } return _findBeanProperty(propName); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java index df7333c01..20926ceb0 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java +++ b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java @@ -20,15 +20,17 @@ class FormulaPropertyPath { private final String internalExpression; + private final String path; + private boolean countDistinct; private String cast; private String alias; - FormulaPropertyPath(BeanDescriptor descriptor, String formula) { - + FormulaPropertyPath(BeanDescriptor descriptor, String formula, String path) { this.descriptor = descriptor; this.formula = formula; + this.path = path; int openBracket = formula.indexOf('('); int closeBracket = formula.lastIndexOf(')'); @@ -94,6 +96,11 @@ class FormulaPropertyPath { DeployPropertyParser parser = descriptor.parser().setCatchFirst(true); String parsed = parser.parse(internalExpression); + if (path != null) { + // fetch("machineStats", "sum(hours), sum(totalKms)") + parsed = parsed.replace("${}", "${" + path + "}"); + } + ElPropertyDeploy firstProp = parser.getFirstProp(); ScalarType scalarType; diff --git a/src/main/java/io/ebeaninternal/server/query/STreeType.java b/src/main/java/io/ebeaninternal/server/query/STreeType.java index 1e4d40e9c..ee47e45f8 100644 --- a/src/main/java/io/ebeaninternal/server/query/STreeType.java +++ b/src/main/java/io/ebeaninternal/server/query/STreeType.java @@ -120,7 +120,7 @@ public interface STreeType { /** * Find and return property allowing for dynamic formula properties. */ - STreeProperty findPropertyWithDynamic(String baseName); + STreeProperty findPropertyWithDynamic(String baseName, String path); /** * Return an extra join if the property path requires it. diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index 1c21b2e6f..2ecfb8d7b 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -273,7 +273,9 @@ public final class SqlTreeBuilder { OrmQueryProperties queryProps = queryDetail.getChunk(prefix, false); SqlTreeProperties props = getBaseSelect(desc, queryProps); - if (prefix == null && !rawSql) { + if (prefix != null) { + props.checkAggregation(); + } else if (!rawSql) { if (props.requireSqlDistinct(manyWhereJoins)) { sqlDistinct = true; } @@ -417,10 +419,10 @@ public final class SqlTreeBuilder { // make sure we only included the base/embedded bean once if (!selectProps.containsProperty(baseName)) { - STreeProperty p = desc.findPropertyWithDynamic(baseName); + STreeProperty p = desc.findPropertyWithDynamic(baseName, null); if (p == null) { // maybe dynamic formula with schema prefix - p = desc.findPropertyWithDynamic(propName); + p = desc.findPropertyWithDynamic(propName, null); if (p != null) { selectProps.add(p); } else { @@ -437,7 +439,7 @@ public final class SqlTreeBuilder { } else { // find the property including searching the // sub class hierarchy if required - STreeProperty p = desc.findPropertyWithDynamic(propName); + STreeProperty p = desc.findPropertyWithDynamic(propName, queryProps.getPath()); if (p == null) { logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it."); p = desc.findProperty("id"); diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index a62106a52..10fcca6c0 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -378,7 +378,7 @@ class SqlTreeNodeBean implements SqlTreeNode { if (!readId || temporalVersions) { // a bean with no Id (never found in context) - if (lazyLoadParentId != null && desc.isElementType()) { + if (lazyLoadParentId != null) { ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId); } return localBean; @@ -422,6 +422,9 @@ class SqlTreeNodeBean implements SqlTreeNode { ctx.pushJoin(prefix); ctx.pushTableAlias(prefix); + if (lazyLoadParent != null) { + lazyLoadParent.addSelectExported(ctx, prefix); + } if (readId) { appendSelectId(ctx, idBinder.getBeanProperty()); } @@ -486,7 +489,15 @@ class SqlTreeNodeBean implements SqlTreeNode { @Override public boolean isAggregation() { - return aggregation; + if (aggregation) { + return true; + } + for (SqlTreeNode child : children) { + if (child.isAggregation()) { + return true; + } + } + return false; } /** diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java index 5ec9b286d..340cb1e04 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java @@ -92,6 +92,10 @@ public class SqlTreeProperties { return aggregation; } + public void checkAggregation() { + aggregationJoin(); + } + /** * Return the property to join for aggregation. */ diff --git a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java index d20581c0b..92b839fbb 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java @@ -61,7 +61,7 @@ public class FormulaPropertyPathTest extends BaseTestCase { private void assertFormula(String input, String funcName, String expression, String cast, String alias) { - FormulaPropertyPath propertyPath = new FormulaPropertyPath(customerDesc, input); + FormulaPropertyPath propertyPath = new FormulaPropertyPath(customerDesc, input, null); assertThat(propertyPath.internalExpression()).isEqualTo(expression); assertThat(propertyPath.outerFunction()).isEqualTo(funcName);