You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/01/09 14:21:53 UTC
cayenne git commit: CAY-2190: Aggregate functions and GROUP BY
support - function expressions for: COUNT(*), COUNT(field), MIN, MAX, AVG,
SUM - new methods in FunctionExpressionFactory
Repository: cayenne
Updated Branches:
refs/heads/master 80d0287af -> 50fe31c93
CAY-2190: Aggregate functions and GROUP BY support
- function expressions for: COUNT(*),COUNT(field),MIN,MAX,AVG,SUM
- new methods in FunctionExpressionFactory
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/50fe31c9
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/50fe31c9
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/50fe31c9
Branch: refs/heads/master
Commit: 50fe31c934d3fb2e50ab0ca5ae29676ce949b368
Parents: 80d0287
Author: Nikita Timofeev <st...@gmail.com>
Authored: Mon Jan 9 16:51:44 2017 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Mon Jan 9 16:51:44 2017 +0300
----------------------------------------------------------------------
.../org/apache/cayenne/test/jdbc/DBHelper.java | 6 +-
.../select/DefaultSelectTranslator.java | 67 ++++++-
.../translator/select/QualifierTranslator.java | 6 +-
.../SQLServerTrimmingQualifierTranslator.java | 6 +
.../java/org/apache/cayenne/exp/Expression.java | 6 +-
.../cayenne/exp/FunctionExpressionFactory.java | 47 +++++
.../exp/parser/ASTAggregateFunctionCall.java | 36 ++++
.../apache/cayenne/exp/parser/ASTAsterisk.java | 80 ++++++++
.../org/apache/cayenne/exp/parser/ASTAvg.java | 47 +++++
.../org/apache/cayenne/exp/parser/ASTCount.java | 50 +++++
.../org/apache/cayenne/exp/parser/ASTMax.java | 47 +++++
.../org/apache/cayenne/exp/parser/ASTMin.java | 47 +++++
.../org/apache/cayenne/exp/parser/ASTSum.java | 47 +++++
...ectActionWithUnsupportedDistinctTypesIT.java | 4 +-
.../exp/FunctionExpressionFactoryTest.java | 53 +++++-
.../cayenne/exp/parser/ASTAggregateTest.java | 61 +++++++
.../cayenne/query/ObjectSelect_AggregateIT.java | 181 +++++++++++++++++++
.../query/ObjectSelect_PrimitiveColumnsIT.java | 24 +++
.../cayenne/testdo/testmap/auto/_Artist.java | 10 +-
19 files changed, 811 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/build-tools/cayenne-test-utilities/src/main/java/org/apache/cayenne/test/jdbc/DBHelper.java
----------------------------------------------------------------------
diff --git a/build-tools/cayenne-test-utilities/src/main/java/org/apache/cayenne/test/jdbc/DBHelper.java b/build-tools/cayenne-test-utilities/src/main/java/org/apache/cayenne/test/jdbc/DBHelper.java
index 0d6ce00..ec080c0 100644
--- a/build-tools/cayenne-test-utilities/src/main/java/org/apache/cayenne/test/jdbc/DBHelper.java
+++ b/build-tools/cayenne-test-utilities/src/main/java/org/apache/cayenne/test/jdbc/DBHelper.java
@@ -168,7 +168,11 @@ public class DBHelper {
st.setNull(i + 1, type);
} else {
- st.setObject(i + 1, values[i]);
+ if(columnTypes != null) {
+ st.setObject(i + 1, values[i], columnTypes[i]);
+ } else {
+ st.setObject(i + 1, values[i]);
+ }
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
index 34cf746..1ea302d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslator.java
@@ -26,6 +26,8 @@ import org.apache.cayenne.dba.TypesMapping;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.TraversalHelper;
+import org.apache.cayenne.exp.parser.ASTAggregateFunctionCall;
import org.apache.cayenne.exp.parser.ASTDbPath;
import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.map.DbAttribute;
@@ -94,6 +96,13 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
*/
boolean forcingDistinct;
+ /**
+ * Does this SQL have any aggregate function
+ */
+ boolean haveAggregate;
+ List<ColumnDescriptor> groupByColumns;
+
+
public DefaultSelectTranslator(Query query, DbAdapter adapter, EntityResolver entityResolver) {
super(query, adapter, entityResolver);
}
@@ -186,6 +195,11 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
queryBuf.append(qualifierBuffer);
}
+ if(haveAggregate && !groupByColumns.isEmpty()) {
+ queryBuf.append(" GROUP BY ");
+ appendGroupByColumns(queryBuf, groupByColumns);
+ }
+
// append prebuilt ordering
if (orderingBuffer.length() > 0) {
queryBuf.append(" ORDER BY ").append(orderingBuffer);
@@ -226,6 +240,23 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
}
/**
+ * Append columns to GROUP BY clause
+ * use distinct from appendSelectColumns() method
+ * as it has some incompatible overridden versions (i.e. in Oracle translator)
+ *
+ * @since 4.0
+ */
+ protected void appendGroupByColumns(StringBuilder buffer, List<ColumnDescriptor> groupByColumns) {
+ int columnCount = groupByColumns.size();
+ buffer.append(groupByColumns.get(0).getName());
+
+ for (int i = 1; i < columnCount; i++) {
+ buffer.append(", ");
+ buffer.append(groupByColumns.get(i).getName());
+ }
+ }
+
+ /**
* Handles appending optional limit and offset clauses. This implementation
* does nothing, deferring to subclasses to define the LIMIT/OFFSET clause
* syntax.
@@ -305,8 +336,12 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
return columns;
}
+ /**
+ * If query contains explicit column list, use only them
+ */
<T> List<ColumnDescriptor> appendOverridedColumns(List<ColumnDescriptor> columns, SelectQuery<T> query) {
QualifierTranslator qualifierTranslator = adapter.getQualifierTranslator(this);
+ groupByColumns = new ArrayList<>();
for(Property<?> property : query.getColumns()) {
StringBuilder builder = new StringBuilder();
qualifierTranslator.setOut(builder);
@@ -316,11 +351,37 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
ColumnDescriptor descriptor = new ColumnDescriptor(builder.toString(), type);
descriptor.setDataRowKey(property.getName());
columns.add(descriptor);
+
+ if(isAggregate(property)) {
+ haveAggregate = true;
+ } else {
+ groupByColumns.add(descriptor);
+ }
+ }
+
+ if(!haveAggregate) {
+ // if no expression with aggregation function found, we don't need this information
+ groupByColumns.clear();
}
return columns;
}
+ private boolean isAggregate(Property<?> property) {
+ final boolean[] isAggregate = new boolean[1];
+ Expression exp = property.getExpression();
+ exp.traverse(new TraversalHelper() {
+ @Override
+ public void startNode(Expression node, Expression parentNode) {
+ if(node instanceof ASTAggregateFunctionCall) {
+ isAggregate[0] = true;
+ }
+ }
+ });
+
+ return isAggregate[0];
+ }
+
<T> List<ColumnDescriptor> appendDbEntityColumns(List<ColumnDescriptor> columns, SelectQuery<T> query) {
Set<ColumnTracker> attributes = new HashSet<>();
@@ -450,7 +511,7 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
if (relationship != null) {
String labelPrefix = pathExp.getPath();
- DbEntity targetEntity = (DbEntity) relationship.getTargetEntity();
+ DbEntity targetEntity = relationship.getTargetEntity();
for (DbAttribute pk : targetEntity.getPrimaryKeys()) {
@@ -496,7 +557,7 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
// go via target OE to make sure that Java types are mapped
// correctly...
ObjRelationship targetRel = (ObjRelationship) prefetchExp.evaluate(oe);
- ObjEntity targetEntity = (ObjEntity) targetRel.getTargetEntity();
+ ObjEntity targetEntity = targetRel.getTargetEntity();
String labelPrefix = dbPrefetch.getPath();
for (ObjAttribute oa : targetEntity.getAttributes()) {
@@ -518,7 +579,7 @@ public class DefaultSelectTranslator extends QueryAssembler implements SelectTra
}
// append remaining target attributes such as keys
- DbEntity targetDbEntity = (DbEntity) r.getTargetEntity();
+ DbEntity targetDbEntity = r.getTargetEntity();
for (DbAttribute attribute : targetDbEntity.getAttributes()) {
appendColumn(columns, null, attribute, attributes, labelPrefix + '.' + attribute.getName());
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
index ad4b74a..3998c00 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
@@ -383,6 +383,8 @@ public class QualifierTranslator extends QueryAssemblerHelper implements Travers
out.append("1 = 1");
} else if (node.getType() == Expression.FALSE) {
out.append("1 = 0");
+ } else if (node.getType() == Expression.ASTERISK) {
+ out.append("*");
}
}
@@ -484,7 +486,9 @@ public class QualifierTranslator extends QueryAssemblerHelper implements Travers
return true;
}
- if (node.getType() == Expression.OBJ_PATH || node.getType() == Expression.DB_PATH) {
+ if (node.getType() == Expression.OBJ_PATH
+ || node.getType() == Expression.DB_PATH
+ || node.getType() == Expression.ASTERISK) {
return false;
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java
index 9a4e9be..2f03bd7 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java
@@ -129,6 +129,9 @@ class SQLServerTrimmingQualifierTranslator extends TrimmingQualifierTranslator {
case "MOD":
// noop
break;
+ case "TRIM":
+ out.append("LTRIM(RTRIM");
+ break;
default:
super.appendFunction(functionExpression);
}
@@ -155,6 +158,9 @@ class SQLServerTrimmingQualifierTranslator extends TrimmingQualifierTranslator {
out.delete(out.length() - " % ".length(), out.length());
} else {
super.clearLastFunctionArgDivider(functionExpression);
+ if("TRIM".equals(functionExpression.getFunctionName())) {
+ out.append(")");
+ }
}
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java
index a4534e2..a422f7e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/Expression.java
@@ -25,7 +25,6 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -156,6 +155,11 @@ public abstract class Expression implements Serializable, XMLSerializable {
*/
public static final int FUNCTION_CALL = 45;
+ /**
+ * @since 4.0
+ */
+ public static final int ASTERISK = 46;
+
protected int type;
/**
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java
index cfecdc7..0d17829 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java
@@ -20,15 +20,20 @@
package org.apache.cayenne.exp;
import org.apache.cayenne.exp.parser.ASTAbs;
+import org.apache.cayenne.exp.parser.ASTAvg;
import org.apache.cayenne.exp.parser.ASTConcat;
+import org.apache.cayenne.exp.parser.ASTCount;
import org.apache.cayenne.exp.parser.ASTLength;
import org.apache.cayenne.exp.parser.ASTLocate;
import org.apache.cayenne.exp.parser.ASTLower;
+import org.apache.cayenne.exp.parser.ASTMax;
+import org.apache.cayenne.exp.parser.ASTMin;
import org.apache.cayenne.exp.parser.ASTMod;
import org.apache.cayenne.exp.parser.ASTObjPath;
import org.apache.cayenne.exp.parser.ASTScalar;
import org.apache.cayenne.exp.parser.ASTSqrt;
import org.apache.cayenne.exp.parser.ASTSubstring;
+import org.apache.cayenne.exp.parser.ASTSum;
import org.apache.cayenne.exp.parser.ASTTrim;
import org.apache.cayenne.exp.parser.ASTUpper;
@@ -285,4 +290,46 @@ public class FunctionExpressionFactory {
}
return new ASTConcat(expressions);
}
+
+ /**
+ * @return Expression COUNT(*)
+ */
+ public static Expression countExp() {
+ return new ASTCount();
+ }
+
+ /**
+ * @return Expression COUNT(exp)
+ */
+ public static Expression countExp(Expression exp) {
+ return new ASTCount(exp);
+ }
+
+ /**
+ * @return Expression MIN(exp)
+ */
+ public static Expression minExp(Expression exp) {
+ return new ASTMin(exp);
+ }
+
+ /**
+ * @return Expression MAX(exp)
+ */
+ public static Expression maxExp(Expression exp) {
+ return new ASTMax(exp);
+ }
+
+ /**
+ * @return Expression AVG(exp)
+ */
+ public static Expression avgExp(Expression exp) {
+ return new ASTAvg(exp);
+ }
+
+ /**
+ * @return SUM(exp) expression
+ */
+ public static Expression sumExp(Expression exp) {
+ return new ASTSum(exp);
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAggregateFunctionCall.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAggregateFunctionCall.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAggregateFunctionCall.java
new file mode 100644
index 0000000..d4dec9e
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAggregateFunctionCall.java
@@ -0,0 +1,36 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+/**
+ * Base class for all aggregation functions expressions
+ * It's more like marker interface for now.
+ * @since 4.0
+ */
+public abstract class ASTAggregateFunctionCall extends ASTFunctionCall {
+
+ ASTAggregateFunctionCall(int id, String functionName) {
+ super(id, functionName);
+ }
+
+ ASTAggregateFunctionCall(String functionName, Object... nodes) {
+ super(functionName, nodes);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAsterisk.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAsterisk.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAsterisk.java
new file mode 100644
index 0000000..33b81cc
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAsterisk.java
@@ -0,0 +1,80 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * Asterisk operator for COUNT(*) expression.
+ * @since 4.0
+ */
+public class ASTAsterisk extends SimpleNode {
+
+ /**
+ * Constructor used by expression parser. Do not invoke directly.
+ */
+ ASTAsterisk(int id) {
+ super(id);
+ }
+
+ public ASTAsterisk() {
+ super(ExpressionParserTreeConstants.JJTMULTIPLY);
+ }
+
+ @Override
+ protected Object evaluateNode(Object o) throws Exception {
+ return o;
+ }
+
+ @Override
+ protected String getExpressionOperator(int index) {
+ throw new UnsupportedOperationException("No operator for '" + ExpressionParserTreeConstants.jjtNodeName[id]
+ + "'");
+ }
+
+ @Override
+ public Expression shallowCopy() {
+ return new ASTAsterisk(id);
+ }
+
+ @Override
+ public int getType() {
+ return Expression.ASTERISK;
+ }
+
+ /**
+ * @since 4.0
+ */
+ @Override
+ public void appendAsString(Appendable out) throws IOException {
+ out.append("*");
+ }
+
+ /**
+ * @since 4.0
+ */
+ @Override
+ public void appendAsEJBQL(List<Object> parameterAccumulator, Appendable out, String rootId) throws IOException {
+ out.append("*");
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAvg.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAvg.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAvg.java
new file mode 100644
index 0000000..16146cf
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTAvg.java
@@ -0,0 +1,47 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * @since 4.0
+ */
+public class ASTAvg extends ASTAggregateFunctionCall {
+
+ ASTAvg(int id) {
+ super(id, "AVG");
+ }
+
+ public ASTAvg(Expression expression) {
+ super("AVG", expression);
+ }
+
+
+ @Override
+ protected Object evaluateNode(Object o) throws Exception {
+ return o; // TODO: how to evaluate aggregation function?
+ }
+
+ @Override
+ public Expression shallowCopy() {
+ return new ASTAvg(id);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCount.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCount.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCount.java
new file mode 100644
index 0000000..72172f7
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCount.java
@@ -0,0 +1,50 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * @since 4.0
+ */
+public class ASTCount extends ASTAggregateFunctionCall {
+
+ ASTCount(int id) {
+ super(id, "COUNT");
+ }
+
+ public ASTCount(Expression expression) {
+ super("COUNT", expression);
+ }
+
+ public ASTCount() {
+ super("COUNT", new ASTAsterisk());
+ }
+
+ @Override
+ protected Object evaluateNode(Object o) throws Exception {
+ return o; // TODO: how to evaluate aggregation function?
+ }
+
+ @Override
+ public Expression shallowCopy() {
+ return new ASTCount(id);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMax.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMax.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMax.java
new file mode 100644
index 0000000..b0356eb
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMax.java
@@ -0,0 +1,47 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * @since 4.0
+ */
+public class ASTMax extends ASTAggregateFunctionCall {
+
+ ASTMax(int id) {
+ super(id, "MAX");
+ }
+
+ public ASTMax(Expression expression) {
+ super("MAX", expression);
+ }
+
+
+ @Override
+ protected Object evaluateNode(Object o) throws Exception {
+ return o; // TODO: how to evaluate aggregation function?
+ }
+
+ @Override
+ public Expression shallowCopy() {
+ return new ASTMax(id);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMin.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMin.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMin.java
new file mode 100644
index 0000000..c55b5df
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTMin.java
@@ -0,0 +1,47 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * @since 4.0
+ */
+public class ASTMin extends ASTAggregateFunctionCall {
+
+ ASTMin(int id) {
+ super(id, "MIN");
+ }
+
+ public ASTMin(Expression expression) {
+ super("MIN", expression);
+ }
+
+
+ @Override
+ protected Object evaluateNode(Object o) throws Exception {
+ return o; // TODO: how to evaluate aggregation function?
+ }
+
+ @Override
+ public Expression shallowCopy() {
+ return new ASTMin(id);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSum.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSum.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSum.java
new file mode 100644
index 0000000..bcc5e12
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTSum.java
@@ -0,0 +1,47 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * @since 4.0
+ */
+public class ASTSum extends ASTAggregateFunctionCall {
+
+ ASTSum(int id) {
+ super(id, "SUM");
+ }
+
+ public ASTSum(Expression expression) {
+ super("SUM", expression);
+ }
+
+
+ @Override
+ protected Object evaluateNode(Object o) throws Exception {
+ return o; // TODO: how to evaluate aggregation function?
+ }
+
+ @Override
+ public Expression shallowCopy() {
+ return new ASTSum(id);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionWithUnsupportedDistinctTypesIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionWithUnsupportedDistinctTypesIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionWithUnsupportedDistinctTypesIT.java
index b2f590bb..fca9bd0 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionWithUnsupportedDistinctTypesIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionWithUnsupportedDistinctTypesIT.java
@@ -59,9 +59,9 @@ public class SelectActionWithUnsupportedDistinctTypesIT extends ServerCase {
@Before
public void setUp() throws Exception {
tProduct = new TableHelper(dbHelper, "PRODUCT");
- tProduct.setColumns("ID", "LONGVARCHAR_COL").setColumnTypes(Types.INTEGER, Types.LONGNVARCHAR);
+ tProduct.setColumns("ID", "LONGVARCHAR_COL");
- tCustomer = new TableHelper(dbHelper, "CUSTOMER").setColumnTypes(Types.INTEGER, Types.LONGNVARCHAR);
+ tCustomer = new TableHelper(dbHelper, "CUSTOMER");
tCustomer.setColumns("ID", "LONGVARCHAR_COL");
tComposition = new TableHelper(dbHelper, "COMPOSITION");
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/test/java/org/apache/cayenne/exp/FunctionExpressionFactoryTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/FunctionExpressionFactoryTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/FunctionExpressionFactoryTest.java
index ab3443e..fd24836 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/FunctionExpressionFactoryTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/FunctionExpressionFactoryTest.java
@@ -20,20 +20,28 @@
package org.apache.cayenne.exp;
import org.apache.cayenne.exp.parser.ASTAbs;
+import org.apache.cayenne.exp.parser.ASTAsterisk;
+import org.apache.cayenne.exp.parser.ASTAvg;
import org.apache.cayenne.exp.parser.ASTConcat;
+import org.apache.cayenne.exp.parser.ASTCount;
import org.apache.cayenne.exp.parser.ASTLength;
import org.apache.cayenne.exp.parser.ASTLocate;
import org.apache.cayenne.exp.parser.ASTLower;
+import org.apache.cayenne.exp.parser.ASTMax;
+import org.apache.cayenne.exp.parser.ASTMin;
import org.apache.cayenne.exp.parser.ASTMod;
import org.apache.cayenne.exp.parser.ASTScalar;
import org.apache.cayenne.exp.parser.ASTSqrt;
import org.apache.cayenne.exp.parser.ASTSubstring;
+import org.apache.cayenne.exp.parser.ASTSum;
import org.apache.cayenne.exp.parser.ASTTrim;
import org.apache.cayenne.exp.parser.ASTUpper;
import org.apache.cayenne.testdo.testmap.Artist;
import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
/**
* @since 4.0
@@ -191,5 +199,48 @@ public class FunctionExpressionFactoryTest {
assertEquals(Artist.PAINTING_ARRAY.path(), exp2.getOperand(2));
}
+ @Test
+ public void countTest() throws Exception {
+ Expression exp1 = FunctionExpressionFactory.countExp();
+ assertTrue(exp1 instanceof ASTCount);
+ assertEquals(1, exp1.getOperandCount());
+ assertEquals(new ASTAsterisk(), exp1.getOperand(0));
+ Expression exp2 = FunctionExpressionFactory.countExp(Artist.ARTIST_NAME.path());
+ assertTrue(exp2 instanceof ASTCount);
+ assertEquals(1, exp2.getOperandCount());
+ assertEquals(Artist.ARTIST_NAME.path(), exp2.getOperand(0));
+ }
+
+ @Test
+ public void minTest() throws Exception {
+ Expression exp1 = FunctionExpressionFactory.minExp(Artist.ARTIST_NAME.path());
+ assertTrue(exp1 instanceof ASTMin);
+ assertEquals(1, exp1.getOperandCount());
+ assertEquals(Artist.ARTIST_NAME.path(), exp1.getOperand(0));
+ }
+
+ @Test
+ public void maxTest() throws Exception {
+ Expression exp1 = FunctionExpressionFactory.maxExp(Artist.ARTIST_NAME.path());
+ assertTrue(exp1 instanceof ASTMax);
+ assertEquals(1, exp1.getOperandCount());
+ assertEquals(Artist.ARTIST_NAME.path(), exp1.getOperand(0));
+ }
+
+ @Test
+ public void avgTest() throws Exception {
+ Expression exp1 = FunctionExpressionFactory.avgExp(Artist.ARTIST_NAME.path());
+ assertTrue(exp1 instanceof ASTAvg);
+ assertEquals(1, exp1.getOperandCount());
+ assertEquals(Artist.ARTIST_NAME.path(), exp1.getOperand(0));
+ }
+
+ @Test
+ public void sumTest() throws Exception {
+ Expression exp1 = FunctionExpressionFactory.sumExp(Artist.ARTIST_NAME.path());
+ assertTrue(exp1 instanceof ASTSum);
+ assertEquals(1, exp1.getOperandCount());
+ assertEquals(Artist.ARTIST_NAME.path(), exp1.getOperand(0));
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTAggregateTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTAggregateTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTAggregateTest.java
new file mode 100644
index 0000000..87ec3bf
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTAggregateTest.java
@@ -0,0 +1,61 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @since 4.0
+ */
+public class ASTAggregateTest {
+
+ @Test
+ public void testAvgConstruct() throws Exception {
+ ASTAvg avg = new ASTAvg(null);
+ assertEquals("AVG", avg.getFunctionName());
+ }
+
+ @Test
+ public void testCountConstruct() throws Exception {
+ ASTCount count = new ASTCount(null);
+ assertEquals("COUNT", count.getFunctionName());
+ }
+
+ @Test
+ public void testMinConstruct() throws Exception {
+ ASTMin min = new ASTMin(null);
+ assertEquals("MIN", min.getFunctionName());
+ }
+
+ @Test
+ public void testMaxConstruct() throws Exception {
+ ASTMax max = new ASTMax(null);
+ assertEquals("MAX", max.getFunctionName());
+ }
+
+ @Test
+ public void testSumConstruct() throws Exception {
+ ASTSum sum = new ASTSum(null);
+ assertEquals("SUM", sum.getFunctionName());
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_AggregateIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_AggregateIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_AggregateIT.java
new file mode 100644
index 0000000..6034d6b
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_AggregateIT.java
@@ -0,0 +1,181 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.query;
+
+import java.sql.Types;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.cayenne.access.DataContext;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.cayenne.exp.FunctionExpressionFactory.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @since 4.0
+ */
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class ObjectSelect_AggregateIT extends ServerCase {
+
+ @Inject
+ private DataContext context;
+
+ @Inject
+ private DBHelper dbHelper;
+
+
+ @Before
+ public void createArtistsDataSet() throws Exception {
+ TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
+ tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH");
+ tArtist.setColumnTypes(Types.INTEGER, Types.VARCHAR, Types.DATE);
+
+ java.sql.Date[] dates = new java.sql.Date[5];
+ // Format: d/m/YY
+ DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
+ for(int i=1; i<=5; i++) {
+ dates[i-1] = new java.sql.Date(dateFormat.parse("1/" + i + "/17").getTime());
+ }
+ for (int i = 1; i <= 20; i++) {
+ tArtist.insert(i, "artist" + i, dates[i % 5]);
+ }
+
+ TableHelper tGallery = new TableHelper(dbHelper, "GALLERY");
+ tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
+ tGallery.insert(1, "tate modern");
+
+ TableHelper tPaintings = new TableHelper(dbHelper, "PAINTING");
+ tPaintings.setColumns("PAINTING_ID", "PAINTING_TITLE", "ARTIST_ID", "GALLERY_ID");
+ for (int i = 1; i <= 20; i++) {
+ tPaintings.insert(i, "painting" + i, i % 5 + 1, 1);
+ }
+ }
+
+ @After
+ public void clearArtistsDataSet() throws Exception {
+ TableHelper tPaintings = new TableHelper(dbHelper, "PAINTING");
+ tPaintings.deleteAll();
+
+ TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
+ tArtist.deleteAll();
+
+ TableHelper tGallery = new TableHelper(dbHelper, "GALLERY");
+ tGallery.deleteAll();
+ }
+
+ @Test
+ public void testCount() throws Exception {
+ Property<Long> countProp = Property.create(countExp(), Long.class);
+
+ long count = ObjectSelect.query(Artist.class)
+ .column(countProp)
+ .selectOne(context);
+ assertEquals(20L, count);
+ }
+
+ @Test
+ @Ignore("Not all databases support AVG(DATE) aggregation")
+ public void testAvg() throws Exception {
+ Property<Date> avgProp = Property.create(avgExp(Artist.DATE_OF_BIRTH.path()), Date.class);
+
+ Date avg = ObjectSelect.query(Artist.class)
+ .column(avgProp)
+ .selectOne(context);
+ DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
+ Date date = dateFormat.parse("1/3/17");
+ assertEquals(date, avg);
+ }
+
+ @Test
+ public void testMin() throws Exception {
+ Property<Date> minProp = Property.create(minExp(Artist.DATE_OF_BIRTH.path()), Date.class);
+
+ Date avg = ObjectSelect.query(Artist.class)
+ .column(minProp)
+ .selectOne(context);
+ DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
+ Date date = dateFormat.parse("1/1/17");
+ assertEquals(date, avg);
+ }
+
+ @Test
+ public void testMax() throws Exception {
+ Property<Date> maxProp = Property.create(maxExp(Artist.DATE_OF_BIRTH.path()), Date.class);
+
+ Date avg = ObjectSelect.query(Artist.class)
+ .column(maxProp)
+ .selectOne(context);
+ DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
+ Date date = dateFormat.parse("1/5/17");
+ assertEquals(date, avg);
+ }
+
+ @Test
+ public void testCountGroupBy() throws Exception {
+ Property<Long> countProp = Property.create(countExp(Artist.ARTIST_NAME.path()), Long.class);
+
+ List<Object[]> count = ObjectSelect.query(Artist.class)
+ .columns(countProp, Artist.DATE_OF_BIRTH)
+ .orderBy(Artist.DATE_OF_BIRTH.asc())
+ .select(context);
+ DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
+ Date date = dateFormat.parse("1/2/17");
+ assertEquals(5L, count.size());
+ assertEquals(4L, count.get(1)[0]);
+ assertEquals(date, count.get(1)[1]);
+ }
+
+ @Test
+ public void testSelectRelationshipCount() throws Exception {
+ Property<Long> paintingCount = Property.create(countExp(Artist.PAINTING_ARRAY.path()), Long.class);
+
+ long count = ObjectSelect.query(Artist.class)
+ .column(paintingCount)
+ .where(Artist.ARTIST_NAME.eq("artist1"))
+ .selectOne(context);
+ assertEquals(4L, count);
+ }
+
+ @Test
+ public void testSelectRelationshipCountWithAnotherField() throws Exception {
+ Property<Long> paintingCount = Property.create(countExp(Artist.PAINTING_ARRAY.path()), Long.class);
+
+ Object[] result = ObjectSelect.query(Artist.class)
+ .columns(Artist.ARTIST_NAME, paintingCount)
+ .where(Artist.ARTIST_NAME.eq("artist1"))
+ .selectOne(context);
+ assertEquals("artist1", result[0]);
+ assertEquals(4L, result[1]);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_PrimitiveColumnsIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_PrimitiveColumnsIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_PrimitiveColumnsIT.java
index 9dccf5b..9906375 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_PrimitiveColumnsIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_PrimitiveColumnsIT.java
@@ -35,6 +35,8 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import static org.apache.cayenne.exp.FunctionExpressionFactory.avgExp;
+import static org.apache.cayenne.exp.FunctionExpressionFactory.sumExp;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -156,4 +158,26 @@ public class ObjectSelect_PrimitiveColumnsIT extends ServerCase {
Object[] result = {11, true};
assertArrayEquals(result, columns.get(0));
}
+
+ @Test
+ public void testSum() throws Exception {
+ Property<Long> sumProp = Property.create(sumExp(PrimitivesTestEntity.INT_COLUMN.path()), Long.class);
+
+ long sum = ObjectSelect.query(PrimitivesTestEntity.class)
+ .column(sumProp)
+ .selectOne(context);
+ assertEquals(2100, sum);
+ }
+
+ @Test
+ public void testAvg() throws Exception {
+ Property<Double> avgProp = Property.create(avgExp(PrimitivesTestEntity.INT_COLUMN.path()), Double.class);
+
+ double avg = ObjectSelect.query(PrimitivesTestEntity.class)
+ .column(avgProp)
+ .selectOne(context);
+ assertEquals(105.0, avg, 0.00001);
+ }
+
+
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/50fe31c9/cayenne-server/src/test/java/org/apache/cayenne/testdo/testmap/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/testmap/auto/_Artist.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/testmap/auto/_Artist.java
index 7d42fab..854e6fd 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/testmap/auto/_Artist.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/testmap/auto/_Artist.java
@@ -21,11 +21,11 @@ public abstract class _Artist extends CayenneDataObject {
public static final String ARTIST_ID_PK_COLUMN = "ARTIST_ID";
- public static final Property<String> ARTIST_NAME = new Property<>("artistName");
- public static final Property<Date> DATE_OF_BIRTH = new Property<>("dateOfBirth");
- public static final Property<List<ArtistExhibit>> ARTIST_EXHIBIT_ARRAY = new Property<>("artistExhibitArray");
- public static final Property<List<ArtGroup>> GROUP_ARRAY = new Property<>("groupArray");
- public static final Property<List<Painting>> PAINTING_ARRAY = new Property<>("paintingArray");
+ public static final Property<String> ARTIST_NAME = Property.create("artistName", String.class);
+ public static final Property<Date> DATE_OF_BIRTH = Property.create("dateOfBirth", Date.class);
+ public static final Property<List<ArtistExhibit>> ARTIST_EXHIBIT_ARRAY = Property.create("artistExhibitArray", List.class);
+ public static final Property<List<ArtGroup>> GROUP_ARRAY = Property.create("groupArray", List.class);
+ public static final Property<List<Painting>> PAINTING_ARRAY = Property.create("paintingArray", List.class);
public void setArtistName(String artistName) {
writeProperty("artistName", artistName);