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 <[email protected]>
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;

Reply via email to