You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ra...@apache.org on 2021/05/11 05:44:11 UTC
[olingo-odata4] branch master updated: [OLINGO-1526]Support for
Compute aggregate method
This is an automated email from the ASF dual-hosted git repository.
ramyav pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/olingo-odata4.git
The following commit(s) were added to refs/heads/master by this push:
new a3d679a [OLINGO-1526]Support for Compute aggregate method
a3d679a is described below
commit a3d679aacdace04d2860d4b3c07bb92275b4de46
Author: ramya vasanth <ra...@sap.com>
AuthorDate: Tue May 11 11:13:57 2021 +0530
[OLINGO-1526]Support for Compute aggregate method
---
.../uri/queryoption/apply/AggregateExpression.java | 2 +-
.../queryoption/expression/ExpressionVisitor.java | 33 ++--
.../api/uri/queryoption/expression/MethodKind.java | 1 +
.../olingo/server/core/uri/parser/ApplyParser.java | 180 +++++++++++----------
.../server/core/uri/parser/ExpressionParser.java | 10 ++
.../queryoption/apply/AggregateExpressionImpl.java | 9 ++
.../uri/queryoption/expression/MethodImpl.java | 5 +-
.../server/core/uri/parser/ApplyParserTest.java | 65 ++++++--
.../server/core/uri/testutil/FilterValidator.java | 6 +-
9 files changed, 202 insertions(+), 109 deletions(-)
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/apply/AggregateExpression.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/apply/AggregateExpression.java
index e297a22..9947596 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/apply/AggregateExpression.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/apply/AggregateExpression.java
@@ -28,7 +28,7 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
* Represents an aggregate expression.
* @see Aggregate
*/
-public interface AggregateExpression {
+public interface AggregateExpression extends Expression {
/** Standard aggregation method. */
public enum StandardMethod { SUM, MIN, MAX, AVERAGE, COUNT_DISTINCT }
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/ExpressionVisitor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/ExpressionVisitor.java
index f67a495..0bbef26 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/ExpressionVisitor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/ExpressionVisitor.java
@@ -23,6 +23,7 @@ import java.util.List;
import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.queryoption.apply.AggregateExpression;
/**
* Generic interface to define expression visitors with arbitrary return types.
@@ -37,7 +38,7 @@ public interface ExpressionVisitor<T> {
* @param left Application return value of left sub tree
* @param right Application return value of right sub tree
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitBinaryOperator(BinaryOperatorKind operator, T left, T right)
@@ -48,7 +49,7 @@ public interface ExpressionVisitor<T> {
* @param operator Operator kind
* @param operand return value of sub tree
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitUnaryOperator(UnaryOperatorKind operator, T operand)
@@ -71,7 +72,7 @@ public interface ExpressionVisitor<T> {
* @param lambdaVariable Variable name used lambda variable
* @param expression Lambda expression
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitLambdaExpression(String lambdaFunction, String lambdaVariable, Expression expression)
@@ -81,7 +82,7 @@ public interface ExpressionVisitor<T> {
* Called for each traversed {@link Literal} expression
* @param literal Literal
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitLiteral(Literal literal) throws ExpressionVisitException, ODataApplicationException;
@@ -91,7 +92,7 @@ public interface ExpressionVisitor<T> {
* @param member UriInfoResource object describing the whole path used to access an data value
* (this includes for example the usage of $root and $it inside the URI)
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitMember(Member member) throws ExpressionVisitException, ODataApplicationException;
@@ -100,7 +101,7 @@ public interface ExpressionVisitor<T> {
* Called for each traversed {@link Alias} expression
* @param aliasName Name of the alias
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitAlias(String aliasName) throws ExpressionVisitException, ODataApplicationException;
@@ -109,7 +110,7 @@ public interface ExpressionVisitor<T> {
* Called for each traversed {@link TypeLiteral} expression
* @param type EdmType
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitTypeLiteral(EdmType type) throws ExpressionVisitException, ODataApplicationException;
@@ -118,7 +119,7 @@ public interface ExpressionVisitor<T> {
* Called for each traversed {@link LambdaRef}
* @param variableName Name of the used lambda variable
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitLambdaReference(String variableName) throws ExpressionVisitException, ODataApplicationException;
@@ -128,7 +129,7 @@ public interface ExpressionVisitor<T> {
* @param type Type used in the URI before the enumeration values
* @param enumValues List of enumeration values
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitEnum(EdmEnumType type, List<String> enumValues) throws ExpressionVisitException, ODataApplicationException;
@@ -139,10 +140,22 @@ public interface ExpressionVisitor<T> {
* @param left Application return value of left sub tree
* @param right Application return value of right sub tree
* @return Application return value of type T
- * @throws ExpressionVisitException Thrown if an exception while traversing occured
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
* @throws ODataApplicationException Thrown by the application
*/
T visitBinaryOperator(BinaryOperatorKind operator, T left, List<T> right)
throws ExpressionVisitException, ODataApplicationException;
+ /**
+ * Called for each traversed {@link AggregateExpression}
+ * @param aggregateExpr the aggregate expression
+ * @return Application return value of type T
+ * @throws ExpressionVisitException Thrown if an exception while traversing occurred
+ * @throws ODataApplicationException Thrown by the application
+ */
+ default T visitComputeAggregate(AggregateExpression aggregateExpr)
+ throws ExpressionVisitException, ODataApplicationException {
+ throw new UnsupportedOperationException();
+ }
+
}
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/MethodKind.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/MethodKind.java
index 527fddc..0b88da9 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/MethodKind.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/expression/MethodKind.java
@@ -23,6 +23,7 @@ package org.apache.olingo.server.api.uri.queryoption.expression;
* For the semantic of these methods please see the ODATA specification for URL conventions
*/
public enum MethodKind {
+ COMPUTE_AGGREGATE("aggregate"),
CONTAINS("contains"),
STARTSWITH("startswith"),
ENDSWITH("endswith"),
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ApplyParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ApplyParser.java
index 7cc0f3b..6cfe85d 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ApplyParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ApplyParser.java
@@ -222,79 +222,84 @@ public class ApplyParser {
throws UriParserException, UriValidationException {
AggregateImpl aggregate = new AggregateImpl();
do {
- aggregate.addExpression(parseAggregateExpr(referencedType));
+ aggregate.addExpression(parseAggregateExpr(referencedType, Requirement.REQUIRED));
} while (tokenizer.next(TokenKind.COMMA));
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return aggregate;
}
+
+ public AggregateExpression parseAggregateMethodCallExpr(UriTokenizer tokenizer, EdmStructuredType referringType)
+ throws UriParserException, UriValidationException {
+ this.tokenizer = tokenizer;
- private AggregateExpression parseAggregateExpr(EdmStructuredType referencedType)
- throws UriParserException, UriValidationException {
- AggregateExpressionImpl aggregateExpression = new AggregateExpressionImpl();
- tokenizer.saveState();
-
- // First try is checking for a (potentially empty) path prefix and the things that could follow it.
- UriInfoImpl uriInfo = new UriInfoImpl();
- final String identifierLeft = parsePathPrefix(uriInfo, referencedType);
- if (identifierLeft != null) {
- customAggregate(referencedType, aggregateExpression, uriInfo);
- } else if (tokenizer.next(TokenKind.OPEN)) {
- final UriResource lastResourcePart = uriInfo.getLastResourcePart();
- if (lastResourcePart == null) {
- throw new UriParserSyntaxException("Invalid 'aggregateExpr' syntax.",
- UriParserSyntaxException.MessageKeys.SYNTAX);
- }
- aggregateExpression.setPath(uriInfo);
- DynamicStructuredType inlineType = new DynamicStructuredType((EdmStructuredType)
- ParserHelper.getTypeInformation((UriResourcePartTyped) lastResourcePart));
- aggregateExpression.setInlineAggregateExpression(parseAggregateExpr(inlineType));
- ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
- } else if (tokenizer.next(TokenKind.COUNT)) {
- uriInfo.addResourcePart(new UriResourceCountImpl());
- aggregateExpression.setPath(uriInfo);
- final String alias = parseAsAlias(referencedType, true);
- aggregateExpression.setAlias(alias);
- ((DynamicStructuredType) referencedType).addProperty(
- createDynamicProperty(alias,
- // The OData standard mandates Edm.Decimal (with no decimals), although counts are always integer.
- odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal)));
- } else {
- // No legitimate continuation of a path prefix has been found.
-
- // Second try is checking for a common expression.
- tokenizer.returnToSavedState();
- final Expression expression = new ExpressionParser(edm, odata)
- .parse(tokenizer, referencedType, crossjoinEntitySetNames, aliases);
- aggregateExpression.setExpression(expression);
- parseAggregateWith(aggregateExpression);
- if (aggregateExpression.getStandardMethod() == null && aggregateExpression.getCustomMethod() == null) {
- if (tokenizer.next(TokenKind.AsOperator)) {
- throw new UriParserSyntaxException("Invalid 'aggregateExpr' syntax.",
- UriParserSyntaxException.MessageKeys.SYNTAX);
- }
- customAggregateNamedAsProperty(referencedType, aggregateExpression, uriInfo);
-
- return aggregateExpression;
- }
- final String alias = parseAsAlias(referencedType, true);
- aggregateExpression.setAlias(alias);
- DynamicProperty dynamicProperty = createDynamicProperty(alias,
- // Determine the type for standard methods; there is no way to do this for custom methods.
- getTypeForAggregateMethod(aggregateExpression.getStandardMethod(),
- ExpressionParser.getType(expression)));
- if (aggregateExpression.getStandardMethod() == StandardMethod.SUM
- || aggregateExpression.getStandardMethod() == StandardMethod.AVERAGE) {
- //by default a property with no precision/scale defaults to a 0 scale
- //this does not work for sum/average in general
- dynamicProperty.setScale(Integer.MAX_VALUE);
- }
- ((DynamicStructuredType) referencedType).addProperty(
- dynamicProperty);
- parseAggregateFrom(aggregateExpression, referencedType);
- }
+ return parseAggregateExpr(referringType, Requirement.FORBIDDEN);
+ }
- return aggregateExpression;
- }
+ private AggregateExpression parseAggregateExpr(EdmStructuredType referencedType, Requirement aliasRequired)
+ throws UriParserException, UriValidationException {
+ AggregateExpressionImpl aggregateExpression = new AggregateExpressionImpl();
+ tokenizer.saveState();
+
+ // First try is checking for a (potentially empty) path prefix and the things that could follow it.
+ UriInfoImpl uriInfo = new UriInfoImpl();
+ final String identifierLeft = parsePathPrefix(uriInfo, referencedType);
+ if (identifierLeft != null) {
+ customAggregate(referencedType, aggregateExpression, uriInfo);
+ } else if (tokenizer.next(TokenKind.OPEN)) {
+ final UriResource lastResourcePart = uriInfo.getLastResourcePart();
+ if (lastResourcePart == null) {
+ throw new UriParserSyntaxException("Invalid 'aggregateExpr' syntax.",
+ UriParserSyntaxException.MessageKeys.SYNTAX);
+ }
+ aggregateExpression.setPath(uriInfo);
+ DynamicStructuredType inlineType = new DynamicStructuredType((EdmStructuredType)
+ ParserHelper.getTypeInformation((UriResourcePartTyped) lastResourcePart));
+ aggregateExpression.setInlineAggregateExpression(parseAggregateExpr(inlineType, aliasRequired));
+ ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+ } else if (tokenizer.next(TokenKind.COUNT)) {
+ uriInfo.addResourcePart(new UriResourceCountImpl());
+ aggregateExpression.setPath(uriInfo);
+ final String alias = parseAsAlias(referencedType, aliasRequired);
+ if (alias != null) {
+ aggregateExpression.setAlias(alias);
+ ((DynamicStructuredType) referencedType).addProperty(
+ createDynamicProperty(alias,
+ // The OData standard mandates Edm.Decimal (with no decimals),
+ // although counts are always integer.
+ odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal)));
+ }
+ } else {
+ // No legitimate continuation of a path prefix has been found.
+
+ // Second try is checking for a common expression.
+ tokenizer.returnToSavedState();
+ final Expression expression = new ExpressionParser(edm, odata)
+ .parse(tokenizer, referencedType, crossjoinEntitySetNames, aliases);
+ aggregateExpression.setExpression(expression);
+ parseAggregateWith(aggregateExpression);
+ if (aggregateExpression.getStandardMethod() == null && aggregateExpression.getCustomMethod() == null) {
+ if (tokenizer.next(TokenKind.AsOperator)) {
+ throw new UriParserSyntaxException("Invalid 'aggregateExpr' syntax.",
+ UriParserSyntaxException.MessageKeys.SYNTAX);
+ }
+ customAggregateNamedAsProperty(referencedType, aggregateExpression, uriInfo);
+
+ return aggregateExpression;
+ }
+ final String alias = parseAsAlias(referencedType, aliasRequired);
+ if(alias != null) {
+ aggregateExpression.setAlias(alias);
+ ((DynamicStructuredType) referencedType).addProperty(
+ createDynamicProperty(alias,
+ // Determine the type for standard methods; there is no way to do this for custom methods.
+ getTypeForAggregateMethod(aggregateExpression.getStandardMethod(),
+ ExpressionParser.getType(expression))));
+ }
+ parseAggregateFrom(aggregateExpression, referencedType);
+ }
+
+ return aggregateExpression;
+ }
private void customAggregate(EdmStructuredType referencedType, AggregateExpressionImpl aggregateExpression,
UriInfoImpl uriInfo) throws UriParserException {
@@ -306,7 +311,7 @@ public class ApplyParser {
// allowed and have no type.
uriInfo.addResourcePart(new UriResourcePrimitivePropertyImpl(createDynamicProperty(customAggregate, null)));
aggregateExpression.setPath(uriInfo);
- final String alias = parseAsAlias(referencedType, false);
+ final String alias = parseAsAlias(referencedType, Requirement.OPTIONAL);
if (alias != null) {
aggregateExpression.setAlias(alias);
((DynamicStructuredType) referencedType).addProperty(createDynamicProperty(alias, null));
@@ -361,22 +366,31 @@ public class ApplyParser {
return null;
}
}
+
+ enum Requirement {
+ REQUIRED, OPTIONAL, FORBIDDEN
+ }
- private String parseAsAlias(final EdmStructuredType referencedType, final boolean isRequired)
+ private String parseAsAlias(final EdmStructuredType referencedType, final Requirement requirement)
throws UriParserException {
- if (tokenizer.next(TokenKind.AsOperator)) {
- ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
- final String name = tokenizer.getText();
- if (referencedType.getProperty(name) != null) {
- throw new UriParserSemanticException("Alias '" + name + "' is already a property.",
- UriParserSemanticException.MessageKeys.IS_PROPERTY, name);
- }
- return name;
- } else if (isRequired) {
- throw new UriParserSyntaxException("Expected asAlias not found.", UriParserSyntaxException.MessageKeys.SYNTAX);
- }
- return null;
- }
+ if (tokenizer.next(TokenKind.AsOperator)) {
+ if(requirement == Requirement.FORBIDDEN) {
+ throw new UriParserSyntaxException("Unexpected as alias found.",
+ UriParserSyntaxException.MessageKeys.SYNTAX);
+ }
+ ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
+ final String name = tokenizer.getText();
+ if (referencedType.getProperty(name) != null) {
+ throw new UriParserSemanticException("Alias '" + name + "' is already a property.",
+ UriParserSemanticException.MessageKeys.IS_PROPERTY, name);
+ }
+ return name;
+ } else if (requirement == Requirement.REQUIRED) {
+ throw new UriParserSyntaxException("Expected as alias not found.",
+ UriParserSyntaxException.MessageKeys.SYNTAX);
+ }
+ return null;
+ }
private void parseAggregateFrom(AggregateExpressionImpl aggregateExpression,
final EdmStructuredType referencedType) throws UriParserException {
@@ -403,7 +417,7 @@ public class ApplyParser {
throw new UriParserSemanticException("Compute expressions must return primitive values.",
UriParserSemanticException.MessageKeys.ONLY_FOR_PRIMITIVE_TYPES, "compute");
}
- final String alias = parseAsAlias(referencedType, true);
+ final String alias = parseAsAlias(referencedType, Requirement.REQUIRED);
((DynamicStructuredType) referencedType).addProperty(createDynamicProperty(alias, expressionType));
compute.addExpression(new ComputeExpressionImpl()
.setExpression(expression)
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
index 8f69f81..40a97f5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -54,6 +54,7 @@ import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
+import org.apache.olingo.server.api.uri.queryoption.apply.AggregateExpression;
import org.apache.olingo.server.api.uri.queryoption.expression.Alias;
import org.apache.olingo.server.api.uri.queryoption.expression.Binary;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
@@ -123,6 +124,7 @@ public class ExpressionParser {
private static final Map<TokenKind, MethodKind> tokenToMethod;
static {
Map<TokenKind, MethodKind> temp = new EnumMap<>(TokenKind.class);
+ temp.put(TokenKind.AggregateTrafo, MethodKind.COMPUTE_AGGREGATE);
temp.put(TokenKind.CeilingMethod, MethodKind.CEILING);
temp.put(TokenKind.ConcatMethod, MethodKind.CONCAT);
temp.put(TokenKind.ContainsMethod, MethodKind.CONTAINS);
@@ -660,8 +662,16 @@ public class ExpressionParser {
case CAST:
case ISOF:
break;
+
+ case COMPUTE_AGGREGATE:
+ ApplyParser ap = new ApplyParser(edm, odata);
+ AggregateExpression aggrExpr = ap.parseAggregateMethodCallExpr(tokenizer,
+ (EdmStructuredType) referringType);
+ parameters.add(aggrExpr);
+
}
ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+
return parameters;
}
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/apply/AggregateExpressionImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/apply/AggregateExpressionImpl.java
index ed14a33..f7f6fd9 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/apply/AggregateExpressionImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/apply/AggregateExpressionImpl.java
@@ -23,10 +23,13 @@ import java.util.Collections;
import java.util.List;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.queryoption.apply.AggregateExpression;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
+import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
/**
* Represents an aggregate expression.
@@ -110,4 +113,10 @@ public class AggregateExpressionImpl implements AggregateExpression {
this.alias = alias;
return this;
}
+
+ @Override
+ public <T> T accept(ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
index b6e7f2c..aace98c 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
@@ -112,8 +112,11 @@ public class MethodImpl implements Method {
case ISOF:
kind = EdmPrimitiveTypeKind.Boolean;
break;
+ case COMPUTE_AGGREGATE:
+ kind = null;
}
- return new ODataImpl().createPrimitiveTypeInstance(kind);
+
+ return kind == null ? null : new ODataImpl().createPrimitiveTypeInstance(kind);
}
@Override
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
index 25babe2..8307c47 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
@@ -127,22 +127,53 @@ public class ApplyParserTest {
@Test
public void customAggregate() throws Exception {
- parse("ESTwoKeyNav", "aggregate(customAggregate)")
- .is(Aggregate.class)
- .goAggregate(0)
- .noExpression()
- .noInlineAggregateExpression()
- .goPath().first().isUriPathInfoKind(UriResourceKind.primitiveProperty);
+ parse("ESTwoKeyNav", "aggregate(customAggregate)").is(Aggregate.class).goAggregate(0).noExpression()
+ .noInlineAggregateExpression().goPath().first().isUriPathInfoKind(UriResourceKind.primitiveProperty);
}
@Test
public void customAggregateNamedAsProperty() throws Exception {
- parse("ESTwoKeyNav", "aggregate(PropertyInt16)")
- .is(Aggregate.class)
- .goAggregate(0)
- .noExpression()
- .noInlineAggregateExpression()
- .goPath().first().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+ parse("ESTwoKeyNav", "aggregate(PropertyInt16)").is(Aggregate.class).goAggregate(0).noExpression()
+ .noInlineAggregateExpression().goPath().first()
+ .isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+ }
+
+ @Test
+ public void filterByCustomAggregate() throws Exception {
+ ApplyValidator validator = parse("ESTwoKeyNav", "filter(aggregate(customAggregate) gt 5)");
+ FilterValidator filter = validator.is(Filter.class).goFilter().isBinary(BinaryOperatorKind.GT);
+ AggregateValidator aggregate = aggregate(filter.root().left());
+ aggregate.goPath().first().isUriPathInfoKind(UriResourceKind.primitiveProperty);
+ filter.root().right().isLiteral("5");
+ }
+
+ @Test
+ public void filterByCountAggregate() throws Exception {
+ ApplyValidator validator = parse("ESTwoKeyNav", "filter(aggregate($count) ge 9)");
+ FilterValidator filter = validator.is(Filter.class).goFilter().isBinary(BinaryOperatorKind.GE);
+ AggregateValidator aggregate = aggregate(filter.root().left());
+ aggregate.goPath().first().isCount();
+ filter.root().right().isLiteral("9");
+ }
+
+ @Test
+ public void filterByTransformationAggregate() throws Exception {
+ ApplyValidator validator = parse("ESTwoKeyNav", "filter(aggregate(PropertyInt16 with min) ne 3)");
+ FilterValidator filter = validator.is(Filter.class).goFilter().isBinary(BinaryOperatorKind.NE);
+ AggregateValidator aggregate = aggregate(filter.root().left());
+ aggregate.isStandardMethod(StandardMethod.MIN)
+ .goExpression().goPath().first().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+ filter.root().right().isLiteral("3");
+ }
+
+ @Test
+ public void filterByCustomAggregateNamedAsProperty() throws Exception {
+ ApplyValidator validator = parse("ESTwoKeyNav", "filter(aggregate(PropertyString) eq 'Evgeny')");
+ FilterValidator filter = validator.is(Filter.class).goFilter().isBinary(BinaryOperatorKind.EQ);
+ AggregateValidator aggregate = aggregate(filter.root().left());
+ aggregate.goPath().first()
+ .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+ filter.root().right().isLiteral("'Evgeny'");
}
@Test
@@ -660,6 +691,14 @@ public class ApplyParserTest {
return previous;
}
}
+
+ private AggregateValidator aggregate(FilterValidator filter) {
+ filter.isMethod(MethodKind.COMPUTE_AGGREGATE, 1);
+ filter.goParameter(0);
+
+ return new AggregateValidator((AggregateExpression) filter.getExpression(), filter);
+ }
+
private final class AggregateValidator implements TestValidator {
@@ -670,7 +709,7 @@ public class ApplyParserTest {
this.aggregateExpression = aggregateExpression;
this.previous = previous;
}
-
+
public AggregateValidator isStandardMethod(final AggregateExpression.StandardMethod method) {
assertNotNull(aggregateExpression);
assertEquals(method, aggregateExpression.getStandardMethod());
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
index c68ecde..c4cacf7 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
@@ -91,6 +91,10 @@ public class FilterValidator implements TestValidator {
rootExpression = curExpression = expression;
return this;
}
+
+ public Expression getExpression() {
+ return curExpression;
+ }
// --- Execution ---
@@ -375,7 +379,7 @@ public class FilterValidator implements TestValidator {
assertTrue("Current expression not a member", curExpression instanceof Member);
return this;
}
-
+
public FilterValidator isMemberStartType(final FullQualifiedName fullName) {
isMember();
Member member = (Member) curExpression;