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;