blob: 4286672d22ff3f28af8ccd040548b611091415a8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.uri.parser;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edmx.EdmxReference;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriInfoKind;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceKind;
import org.apache.olingo.server.api.uri.queryoption.ApplyItem;
import org.apache.olingo.server.api.uri.queryoption.ApplyOption;
import org.apache.olingo.server.api.uri.queryoption.apply.Aggregate;
import org.apache.olingo.server.api.uri.queryoption.apply.AggregateExpression;
import org.apache.olingo.server.api.uri.queryoption.apply.AggregateExpression.StandardMethod;
import org.apache.olingo.server.api.uri.queryoption.apply.BottomTop;
import org.apache.olingo.server.api.uri.queryoption.apply.BottomTop.Method;
import org.apache.olingo.server.api.uri.queryoption.apply.Compute;
import org.apache.olingo.server.api.uri.queryoption.apply.ComputeExpression;
import org.apache.olingo.server.api.uri.queryoption.apply.Concat;
import org.apache.olingo.server.api.uri.queryoption.apply.CustomFunction;
import org.apache.olingo.server.api.uri.queryoption.apply.Expand;
import org.apache.olingo.server.api.uri.queryoption.apply.Filter;
import org.apache.olingo.server.api.uri.queryoption.apply.GroupBy;
import org.apache.olingo.server.api.uri.queryoption.apply.GroupByItem;
import org.apache.olingo.server.api.uri.queryoption.apply.Identity;
import org.apache.olingo.server.api.uri.queryoption.apply.Search;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.core.uri.UriInfoImpl;
import org.apache.olingo.server.core.uri.parser.search.SearchParserException;
import org.apache.olingo.server.core.uri.testutil.ExpandValidator;
import org.apache.olingo.server.core.uri.testutil.FilterValidator;
import org.apache.olingo.server.core.uri.testutil.ResourceValidator;
import org.apache.olingo.server.core.uri.testutil.TestUriValidator;
import org.apache.olingo.server.core.uri.testutil.TestValidator;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider;
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
import org.apache.olingo.server.tecsvc.provider.FunctionProvider;
import org.apache.olingo.server.tecsvc.provider.PropertyProvider;
import org.junit.Test;
/** Tests of the $apply parser inspired by the ABNF test cases. */
public class ApplyParserTest {
private static final OData odata = OData.newInstance();
private static final Edm edm = odata.createServiceMetadata(
new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
@Test
public void basic() throws Exception {
parseEx("ESTwoKeyNav", "").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESAllPrim(0)/PropertyInt16", "identity")
.isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
}
@Test
public void aggregate() throws Exception {
parse("ESTwoKeyNav", "aggregate(PropertyInt16 with sum as s)")
.is(Aggregate.class)
.goAggregate(0).isStandardMethod(StandardMethod.SUM).isAlias("s")
.goExpression().goPath().first().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parse("ESTwoKeyNav", "aggregate(PropertyInt16 with min as m)")
.goAggregate(0).isStandardMethod(StandardMethod.MIN).isAlias("m");
parse("ESTwoKeyNav", "aggregate(PropertyInt16 with max as m)")
.goAggregate(0).isStandardMethod(StandardMethod.MAX).isAlias("m");
parse("ESTwoKeyNav", "aggregate(PropertyInt16 with average as a)")
.goAggregate(0).isStandardMethod(StandardMethod.AVERAGE).isAlias("a");
parse("ESTwoKeyNav", "aggregate(PropertyInt16 with countdistinct as c)")
.goAggregate(0).isStandardMethod(StandardMethod.COUNT_DISTINCT).isAlias("c");
parse("ESTwoKeyNav", "aggregate(PropertyInt16 with custom.aggregate as c)")
.is(Aggregate.class)
.goAggregate(0).isCustomMethod(new FullQualifiedName("custom", "aggregate")).isAlias("c");
parse("ESTwoKeyNav", "aggregate(PropertyInt16 with min as min,PropertyInt16 with max as max)")
.goAggregate(0).isStandardMethod(StandardMethod.MIN).isAlias("min").goUp()
.goAggregate(1).isStandardMethod(StandardMethod.MAX).isAlias("max");
parseEx("ESTwoKeyNav", "aggregate()")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESTwoKeyNav", "aggregate(PropertyInt16)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 with sum)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 as s)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 with SUM as s)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESTwoKeyNav", "aggregate(PropertyString with countdistinct as PropertyInt16)")
.isExSemantic(UriParserSemanticException.MessageKeys.IS_PROPERTY);
parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 with min as m,PropertyInt16 with max as m)")
.isExSemantic(UriParserSemanticException.MessageKeys.IS_PROPERTY);
}
@Test
public void aggregateExpression() throws Exception {
parse("ESTwoKeyNav", "aggregate(PropertyInt16 mul PropertyComp/PropertyInt16 with sum as s)")
.is(Aggregate.class)
.goAggregate(0).isStandardMethod(StandardMethod.SUM)
.goExpression().isBinary(BinaryOperatorKind.MUL)
.left().goPath().first().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false)
.goUpFilterValidator().root()
.right().goPath().first().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
.n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parse("ESTwoKeyNav",
"aggregate(NavPropertyETKeyNavMany(PropertyInt16 mul NavPropertyETTwoKeyNavOne/PropertyInt16 with sum as s))")
.goAggregate(0)
.goInlineAggregateExpression().isStandardMethod(StandardMethod.SUM)
.goUpAggregate()
.goPath().first().isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
parseEx("ESTwoKeyNav", "aggregate((PropertyInt16 mul 2 with sum as s))")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void aggregateCount() throws Exception {
parse("ESTwoKeyNav", "aggregate($count as count)")
.is(Aggregate.class)
.goAggregate(0).goPath().first().isCount();
parseEx("ESTwoKeyNav", "aggregate($count)").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESTwoKeyNav", "aggregate($count with sum as count)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void aggregateFrom() throws Exception {
parse("ESTwoKeyNav", "aggregate(PropertyInt16 with sum as s from CollPropertyComp with average)")
.goAggregate(0).isStandardMethod(StandardMethod.SUM)
.goFrom(0).isStandardMethod(StandardMethod.AVERAGE)
.goExpression().goPath().first()
.isComplexProperty("CollPropertyComp", ComplexTypeProvider.nameCTPrimComp, true);
parse("ESTwoKeyNav",
"aggregate(PropertyInt16 with sum as s from CollPropertyComp with average from CollPropertyString with max)")
.goAggregate(0).isStandardMethod(StandardMethod.SUM)
.goFrom(0).isStandardMethod(StandardMethod.AVERAGE)
.goUpAggregate().goFrom(1).isStandardMethod(StandardMethod.MAX);
parse("ESTwoKeyNav", "aggregate(customAggregate as a from CollPropertyComp with average)")
.goAggregate(0).goFrom(0).isStandardMethod(StandardMethod.AVERAGE);
parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 as a from CollPropertyComp with average)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESTwoKeyNav", "aggregate(PropertyInt16 with sum from CollPropertyComp with average)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void identity() throws Exception {
parse("ESTwoKeyNav", "identity").is(Identity.class);
parseEx("ESTwoKeyNav", "identity()")
.isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
}
@Test
public void compute() throws Exception {
parse("ESTwoKeyNav", "compute(PropertyInt16 mul NavPropertyETKeyNavOne/PropertyInt16 as p)")
.is(Compute.class)
.goCompute(0).isAlias("p").goExpression().isBinary(BinaryOperatorKind.MUL)
.left().isMember().goPath().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parse("ESTwoKeyNav", "compute(PropertyInt16 mul 2 as p,day(now()) as d)")
.goCompute(0).isAlias("p")
.goUp().goCompute(1).isAlias("d")
.goExpression().isMethod(MethodKind.DAY, 1).goParameter(0).isMethod(MethodKind.NOW, 0);
parseEx("ESTwoKeyNav", "compute(PropertyInt16)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESTwoKeyNav", "compute(PropertyComp as c)")
.isExSemantic(UriParserSemanticException.MessageKeys.ONLY_FOR_PRIMITIVE_TYPES);
}
@Test
public void concat() throws Exception {
parse("ESTwoKeyNav", "concat(topcount(2,PropertyInt16),bottomcount(2,PropertyInt16))")
.is(Concat.class)
.goConcat(0).goBottomTop().isMethod(Method.TOP_COUNT)
.goUp().goUp()
.goConcat(1).goBottomTop().isMethod(Method.BOTTOM_COUNT).goNumber().isLiteral("2");
parseEx("ESTwoKeyNav", "concat(identity)").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void expand() throws Exception {
parse("ESTwoKeyNav", "expand(NavPropertyETKeyNavMany,filter(PropertyInt16 gt 2))")
.is(Expand.class).goExpand()
.goPath().first().isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
.goUpExpandValidator().goFilter().is("<<PropertyInt16> gt <2>>");
parse("ESTwoKeyNav",
"expand(NavPropertyETKeyNavMany,expand(NavPropertyETTwoKeyNavMany,filter(PropertyInt16 gt 2)))")
.is(Expand.class).goExpand().goExpand().goFilter().is("<<PropertyInt16> gt <2>>");
parse("ESTwoKeyNav",
"expand(NavPropertyETKeyNavMany,expand(NavPropertyETTwoKeyNavMany,filter(PropertyInt16 gt 2)),"
+ "expand(NavPropertyETTwoKeyNavOne,expand(NavPropertyETKeyNavMany)))")
.is(Expand.class).goExpand().goExpand().next().goExpand()
.goPath().first().isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
parseEx("ESTwoKeyNav", "expand()")
.isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
}
@Test
public void search() throws Exception {
parse("ESTwoKeyNav", "search(String)").isSearch("'String'");
parseEx("ESTwoKeyNav", "search()")
.isExceptionMessage(SearchParserException.MessageKeys.EXPECTED_DIFFERENT_TOKEN);
}
@Test
public void filter() throws Exception {
parse("ESTwoKeyNav", "filter(PropertyInt16 gt 3)")
.is(Filter.class)
.goFilter().isBinary(BinaryOperatorKind.GT)
.left().isMember().goPath().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parseEx("ESTwoKeyNav", "filter()").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void bottomTop() throws Exception {
parse("ESTwoKeyNav", "topcount(2,PropertyInt16)")
.goBottomTop().isMethod(Method.TOP_COUNT)
.goNumber().isLiteralType(odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte))
.isLiteral("2");
parse("ESTwoKeyNav", "topsum(2,PropertyInt16)")
.goBottomTop().isMethod(Method.TOP_SUM)
.goValue().isMember().goPath().first().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parse("ESTwoKeyNav", "toppercent(2,PropertyInt16)").goBottomTop().isMethod(Method.TOP_PERCENT);
parse("ESTwoKeyNav", "bottomcount(2,PropertyInt16)").goBottomTop().isMethod(Method.BOTTOM_COUNT);
parse("ESTwoKeyNav", "bottomsum(2,PropertyInt16)").goBottomTop().isMethod(Method.BOTTOM_SUM);
parse("ESTwoKeyNav", "bottompercent(2,PropertyInt16)").goBottomTop().isMethod(Method.BOTTOM_PERCENT);
parseEx("ESTwoKeyNav", "bottompercent(1.2,PropertyInt16)")
.isExSemantic(UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE);
parseEx("ESTwoKeyNav", "bottompercent(2,PropertyString)")
.isExSemantic(UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE);
}
@Test
public void customFunction() throws Exception {
parse("ESBaseTwoKeyNav", "Namespace1_Alias.BFCESBaseTwoKeyNavRTESBaseTwoKey()")
.isCustomFunction(FunctionProvider.nameBFCESBaseTwoKeyNavRTESBaseTwoKey);
parse("ESKeyNav(1)/CollPropertyComp", "Namespace1_Alias.BFCCollCTPrimCompRTESAllPrim()")
.isCustomFunction(FunctionProvider.nameBFCCollCTPrimCompRTESAllPrim);
parseEx("ESBaseTwoKeyNav", "BFCESBaseTwoKeyNavRTESBaseTwoKey()")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESBaseTwoKeyNav", "Namespace1_Alias.BFCETBaseTwoKeyNavRTETTwoKeyNav()")
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
parseEx("ESBaseTwoKeyNav", "Namespace1_Alias.BFCCollStringRTESTwoKeyNav()")
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
parseEx("ESTwoKeyNav", "Namespace1_Alias.BFCESTwoKeyNavRTTwoKeyNav()")
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_MUST_USE_COLLECTIONS);
}
@Test
public void groupBy() throws Exception {
parse("ESTwoKeyNav", "groupby((PropertyString))")
.is(GroupBy.class)
.goGroupBy(0).goPath().first().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
parse("ESTwoKeyNav", "groupby((NavPropertyETKeyNavOne/PropertyInt16))")
.is(GroupBy.class)
.goGroupBy(0).goPath().first().isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
.n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parse("ESTwoKeyNav", "groupby((NavPropertyETKeyNavOne/PropertyInt16,PropertyString))")
.is(GroupBy.class)
.goGroupBy(1).goPath().first().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
parse("ESTwoKeyNav", "groupby((NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString))");
parse("ESTwoKeyNav",
"groupby((NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString,PropertyString))")
.goGroupBy(2).goPath().first().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
parse("ESTwoKeyNav", "groupby((Namespace1_Alias.ETBaseTwoKeyNav/NavPropertyETBaseTwoKeyNavOne/PropertyInt16))")
.is(GroupBy.class)
.goGroupBy(0).goPath().first().isType(EntityTypeProvider.nameETBaseTwoKeyNav)
.n().isNavProperty("NavPropertyETBaseTwoKeyNavOne", EntityTypeProvider.nameETBaseTwoKeyNav, false)
.n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parse("ESTwoKeyNav", "groupby((NavPropertyETTwoKeyNavOne/Namespace1_Alias.ETBaseTwoKeyNav/PropertyInt16))")
.is(GroupBy.class)
.goGroupBy(0).goPath()
.first().isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false)
.isTypeFilterOnCollection(EntityTypeProvider.nameETBaseTwoKeyNav)
.n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parseEx("ESTwoKeyNav", "groupby((wrongProperty))")
.isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
parseEx("ESTwoKeyNav", "groupby((Namespace1_Alias.ETBaseTwoKeyNav))")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
parseEx("ESTwoKeyNav", "groupby((NavPropertyETTwoKeyNavOne/Namespace1_Alias.ETBaseTwoKeyNav))")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void groupByAggregate() throws Exception {
parse("ESTwoKeyNav", "groupby((PropertyInt16),aggregate(PropertyInt16 with sum as s))")
.goGroupByOption().goAggregate(0).isStandardMethod(StandardMethod.SUM)
.goExpression().goPath().first().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parse("ESTwoKeyNav",
"groupby((NavPropertyETKeyNavOne/PropertyInt16),aggregate(PropertyInt16 with average as a))")
.goGroupByOption().goAggregate(0).isStandardMethod(StandardMethod.AVERAGE)
.goUp().goUp().goGroupBy(0).goPath()
.first().isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
.n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
parse("ESTwoKeyNav", "groupby((NavPropertyETKeyNavOne/PropertyInt16),"
+ "aggregate(PropertyInt16 with sum as s,PropertyInt16 with average as a))")
.goGroupByOption().goAggregate(1).isStandardMethod(StandardMethod.AVERAGE);
parse("ESTwoKeyNav", "groupby((PropertyInt16),aggregate(NavPropertyETKeyNavMany/$count as c))")
.goGroupByOption().goAggregate(0).goPath().at(1).isCount();
parse("ESTwoKeyNav", "groupby((PropertyString),aggregate(NavPropertyETKeyNavMany(PropertyInt16 with sum as s)))")
.goGroupByOption().goAggregate(0).goInlineAggregateExpression().isStandardMethod(StandardMethod.SUM)
.goUpAggregate().goPath().first()
.isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
parse("ESTwoKeyNav",
"groupby((NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString),"
+ "aggregate(PropertyInt16 with sum as s))")
.goGroupBy(1).goPath().at(1).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
parse("ESTwoKeyNav",
"groupby((NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString),"
+ "aggregate(PropertyInt16 with sum as s from NavPropertyETKeyNavOne/PropertyInt16 with average))")
.goGroupByOption().goAggregate(0).goFrom(0).isStandardMethod(StandardMethod.AVERAGE);
parse("ESTwoKeyNav", "groupby((NavPropertyETKeyNavOne),aggregate(CollPropertyComp(PropertyInt16 with sum as s)))");
parse("ESTwoKeyNav",
"groupby((NavPropertyETTwoKeyNavOne/PropertyInt16),"
+ "topcount(2,PropertyInt16)/aggregate(PropertyInt16 with sum as s))")
.goGroupByOption()
.at(0).goBottomTop().isMethod(Method.TOP_COUNT)
.goUp().at(1).goAggregate(0).isStandardMethod(StandardMethod.SUM);
parseEx("ESTwoKeyNav", "groupby((PropertyInt16),identity,identity)")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void groupByRollUp() throws Exception {
parse("ESTwoKeyNav",
"groupby((rollup(NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString),"
+ "rollup(NavPropertyETKeyNavOne/NavPropertyETTwoKeyNavOne/PropertyInt16,"
+ "NavPropertyETTwoKeyNavOne/PropertyString),NavPropertyETTwoKeyNavOne/PropertyInt16),"
+ "aggregate(PropertyInt16 with sum as s))")
.goGroupBy(1).goRollup(1).goPath()
.first().isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false)
.n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
parse("ESTwoKeyNav",
"groupby((rollup($all,NavPropertyETKeyNavOne/PropertyInt16,NavPropertyETKeyNavOne/PropertyString),"
+ "NavPropertyETTwoKeyNavOne/PropertyString),"
+ "aggregate(PropertyInt16 with sum as s from NavPropertyETTwoKeyNavOne/PropertyInt16 with average "
+ "from NavPropertyETTwoKeyNavOne/PropertyString with average))")
.goGroupBy(0).isRollupAll().goUp().goGroupByOption().goAggregate(0).goFrom(1)
.isStandardMethod(StandardMethod.AVERAGE).goExpression().goPath().at(1)
.isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
parseEx("ESTwoKeyNav", "groupby((rollup($all)))")
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void groupBySpecial() throws Exception {
parse("ESTwoKeyNav", "groupby((NavPropertyETTwoKeyNavOne/PropertyInt16),aggregate(customAggregate))")
.is(GroupBy.class)
.goGroupByOption().goAggregate(0)
.goPath().first().isUriPathInfoKind(UriResourceKind.primitiveProperty);
parse("ESTwoKeyNav",
"groupby((PropertyString),aggregate(NavPropertyETKeyNavMany/$count as c,"
+ "NavPropertyETKeyNavMany(PropertyInt16 with sum as s)))")
.is(GroupBy.class)
.goGroupByOption().goAggregate(0).isAlias("c").goPath().at(1).isCount();
parse("ESTwoKeyNav",
"groupby((PropertyString),aggregate(NavPropertyETKeyNavMany($count as c),"
+ "NavPropertyETKeyNavMany(PropertyInt16 with sum as s)))")
.is(GroupBy.class)
.goGroupByOption().goAggregate(0).goInlineAggregateExpression()
.isAlias("c").goPath().first().isCount();
parse("ESTwoKeyNav",
"groupby((NavPropertyETKeyNavOne/PropertyString),"
+ "aggregate(PropertyInt16 with sum as s,customAggregate))")
.is(GroupBy.class)
.goGroupByOption().goAggregate(1).isStandardMethod(null).isAlias(null)
.goPath().first().isUriPathInfoKind(UriResourceKind.primitiveProperty);
parse("ESTwoKeyNav",
"groupby((PropertyString),aggregate(NavPropertyETKeyNavMany(PropertyInt16 with sum as s),"
+ "NavPropertyETKeyNavMany/customAggregate))")
.is(GroupBy.class)
.goGroupByOption().goAggregate(1)
.goPath().at(1).isUriPathInfoKind(UriResourceKind.primitiveProperty);
parse("ESTwoKeyNav",
"groupby((PropertyString),aggregate(NavPropertyETKeyNavMany(PropertyInt16 with sum as s),"
+ "NavPropertyETKeyNavMany(PropertyInt16 with average as a)))")
.is(GroupBy.class)
.goGroupByOption().goAggregate(0).goInlineAggregateExpression()
.isStandardMethod(StandardMethod.SUM).isAlias("s")
.goUpAggregate().goUp().goAggregate(1).goInlineAggregateExpression()
.isStandardMethod(StandardMethod.AVERAGE).isAlias("a");
}
@Test
public void sequence() throws Exception {
parse("ESTwoKeyNav", "identity/identity/identity")
.at(0).is(Identity.class).at(1).is(Identity.class).at(2).is(Identity.class);
parse("ESTwoKeyNav", "filter(PropertyInt16 le 1)/aggregate(PropertyInt16 with sum as s)")
.at(0).is(Filter.class)
.at(1).is(Aggregate.class).goAggregate(0).isStandardMethod(StandardMethod.SUM).isAlias("s");
parse("ESTwoKeyNav",
"groupby((NavPropertyETKeyNavOne),aggregate(PropertyInt16 with sum as s))/"
+ "aggregate(s with average as a)")
.at(1).goAggregate(0).isStandardMethod(StandardMethod.AVERAGE).isAlias("a");
parse("ESTwoKeyNav",
"filter(PropertyInt16 ge 1)/"
+ "groupby((NavPropertyETKeyNavOne/PropertyString),aggregate(PropertyInt16 with sum as s))")
.at(0).is(Filter.class)
.at(1).is(GroupBy.class);
parse("ESTwoKeyNav",
"groupby((NavPropertyETKeyNavOne/PropertyString),aggregate(PropertyInt16 with sum as s))/"
+ "filter(s ge 10)/concat(identity,groupby((NavPropertyETKeyNavOne/PropertyString),"
+ "aggregate(s with sum as t)))")
.at(0).is(GroupBy.class)
.at(1).is(Filter.class)
.at(2).is(Concat.class).goConcat(0).is(Identity.class);
parse("ESTwoKeyNav",
"groupby((NavPropertyETKeyNavOne/PropertyString),aggregate(PropertyInt16 with sum as s))/"
+ "filter(s ge 10)/groupby((rollup(NavPropertyETKeyNavOne/PropertyString,"
+ "NavPropertyETKeyNavOne/PropertyCompAllPrim/PropertyDuration)),aggregate(s with sum as t))")
.at(0).is(GroupBy.class)
.at(1).is(Filter.class)
.at(2).is(GroupBy.class).goGroupBy(0).goRollup(1).goPath().at(2)
.isPrimitiveProperty("PropertyDuration", PropertyProvider.nameDuration, false);
parse("ESTwoKeyNav",
"groupby((NavPropertyETKeyNavOne/PropertyString),aggregate(PropertyInt16 with sum as s))/"
+ "concat(filter(s ge 10),groupby((NavPropertyETKeyNavOne/PropertyString),"
+ "aggregate(s with sum as t)))")
.at(0).is(GroupBy.class)
.at(1).is(Concat.class).goConcat(1).is(GroupBy.class);
parse("ESTwoKeyNav",
"filter(PropertyInt16 eq 1)/expand(NavPropertyETKeyNavMany,filter(not PropertyCompAllPrim/PropertyBoolean))/"
+ "groupby((NavPropertyETKeyNavOne/PropertyInt16),"
+ "aggregate(NavPropertyETKeyNavMany(PropertyInt16 with sum as s)))")
.at(0).is(Filter.class)
.at(1).is(Expand.class)
.at(2).is(GroupBy.class);
parseEx("ESTwoKeyNav", "identity/").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
}
@Test
public void otherQueryOptions() throws Exception {
new TestUriValidator().setEdm(edm).run("ESTwoKeyNav",
"$apply=aggregate(PropertyInt16 with sum as s)&$filter=s gt 3&$select=s")
.goSelectItemPath(0).first().isPrimitiveProperty("s", PropertyProvider.nameDecimal, false)
.goUpUriValidator()
.goFilter().left().goPath().first().isPrimitiveProperty("s", PropertyProvider.nameDecimal, false);
new FilterValidator().setEdm(edm).runUriOrderBy("ESTwoKeyNav",
"$apply=aggregate(PropertyInt16 with sum as s)&$orderby=s")
.goOrder(0).goPath().first().isPrimitiveProperty("s", PropertyProvider.nameDecimal, false);
}
@Test
public void onCount() throws Exception {
parse("ESTwoKeyNav/$count", "aggregate(PropertyInt16 with sum as s)")
.goAggregate(0).isStandardMethod(StandardMethod.SUM).isAlias("s")
.goExpression().goPath().first()
.isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
}
private ApplyValidator parse(final String path, final String apply)
throws UriParserException, UriValidationException {
final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, "$apply=" + apply, null);
return new ApplyValidator(uriInfo.getApplyOption());
}
private TestUriValidator parseEx(final String path, final String apply) {
return new TestUriValidator().setEdm(edm).runEx(path, "$apply=" + apply);
}
private final class ApplyValidator implements TestValidator {
private final ApplyOption applyOption;
private final ApplyValidator previous;
private ApplyItem applyItem;
protected ApplyValidator(final ApplyOption applyOption) {
this(applyOption, null);
}
private ApplyValidator(final ApplyOption applyOption, final ApplyValidator previous) {
this.applyOption = applyOption;
this.previous = previous;
at(0);
}
public ApplyValidator at(final int index) {
assertTrue(index < applyOption.getApplyItems().size());
applyItem = applyOption.getApplyItems().get(index);
return this;
}
public ApplyValidator is(final Class<? extends ApplyItem> cls) {
assertNotNull(applyItem);
assertTrue(cls.isAssignableFrom(applyItem.getClass()));
return this;
}
public AggregateValidator goAggregate(final int index) {
is(Aggregate.class);
assertTrue(index < ((Aggregate) applyItem).getExpressions().size());
return new AggregateValidator(((Aggregate) applyItem).getExpressions().get(index), this);
}
public ExpandValidator goExpand() {
is(Expand.class);
return new ExpandValidator().setUpValidator(this).setExpand(((Expand) applyItem).getExpandOption());
}
public FilterValidator goFilter() {
is(Filter.class);
return new FilterValidator().setFilter(((Filter) applyItem).getFilterOption());
}
public BottomTopValidator goBottomTop() {
is(BottomTop.class);
return new BottomTopValidator((BottomTop) applyItem, this);
}
public ApplyValidator isCustomFunction(final FullQualifiedName function) {
is(CustomFunction.class);
assertEquals(function, ((CustomFunction) applyItem).getFunction().getFullQualifiedName());
return this;
}
public ApplyValidator isSearch(final String serializedSearch) {
is(Search.class);
assertEquals(serializedSearch, ((Search) applyItem).getSearchOption().getSearchExpression().toString());
return this;
}
public ApplyValidator goConcat(final int index) {
is(Concat.class);
assertTrue(index < ((Concat) applyItem).getApplyOptions().size());
return new ApplyValidator(((Concat) applyItem).getApplyOptions().get(index), this);
}
public ComputeValidator goCompute(final int index) {
is(Compute.class);
assertTrue(index < ((Compute) applyItem).getExpressions().size());
return new ComputeValidator(((Compute) applyItem).getExpressions().get(index), this);
}
public GroupByValidator goGroupBy(final int index) {
is(GroupBy.class);
assertTrue(index < ((GroupBy) applyItem).getGroupByItems().size());
return new GroupByValidator(((GroupBy) applyItem).getGroupByItems().get(index), this);
}
public ApplyValidator goGroupByOption() {
is(GroupBy.class);
assertNotNull(((GroupBy) applyItem).getApplyOption());
return new ApplyValidator(((GroupBy) applyItem).getApplyOption(), this);
}
public ApplyValidator goUp() {
return previous;
}
}
private final class AggregateValidator implements TestValidator {
private final AggregateExpression aggregateExpression;
private final TestValidator previous;
protected AggregateValidator(final AggregateExpression aggregateExpression, final TestValidator previous) {
this.aggregateExpression = aggregateExpression;
this.previous = previous;
}
public AggregateValidator isStandardMethod(final AggregateExpression.StandardMethod method) {
assertNotNull(aggregateExpression);
assertEquals(method, aggregateExpression.getStandardMethod());
return this;
}
public AggregateValidator isCustomMethod(final FullQualifiedName method) {
assertNotNull(aggregateExpression);
assertEquals(method, aggregateExpression.getCustomMethod());
return this;
}
public AggregateValidator isAlias(final String alias) {
assertNotNull(aggregateExpression);
assertEquals(alias, aggregateExpression.getAlias());
return this;
}
public FilterValidator goExpression() {
assertNotNull(aggregateExpression);
assertNotNull(aggregateExpression.getExpression());
return new FilterValidator().setValidator(this).setEdm(edm)
.setExpression(aggregateExpression.getExpression());
}
public ResourceValidator goPath() {
assertNotNull(aggregateExpression);
assertFalse(aggregateExpression.getPath().isEmpty());
UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
for (final UriResource segment : aggregateExpression.getPath()) {
resource.addResourcePart(segment);
}
return new ResourceValidator().setUpValidator(this).setEdm(edm).setUriInfoPath(resource);
}
public AggregateValidator goInlineAggregateExpression() {
return new AggregateValidator(aggregateExpression.getInlineAggregateExpression(), this);
}
public AggregateValidator goFrom(final int index) {
assertTrue(index < aggregateExpression.getFrom().size());
return new AggregateValidator(aggregateExpression.getFrom().get(index), this);
}
public AggregateValidator goUpAggregate() {
return (AggregateValidator) previous;
}
public ApplyValidator goUp() {
return (ApplyValidator) previous;
}
}
private final class BottomTopValidator implements TestValidator {
private final BottomTop item;
private final ApplyValidator previous;
private BottomTopValidator(final BottomTop item, final ApplyValidator previous) {
this.item = item;
this.previous = previous;
}
public BottomTopValidator isMethod(final BottomTop.Method method) {
assertEquals(method, item.getMethod());
return this;
}
public FilterValidator goNumber() {
assertNotNull(item.getNumber());
return new FilterValidator().setValidator(this).setEdm(edm).setExpression(item.getNumber());
}
public FilterValidator goValue() {
assertNotNull(item.getValue());
return new FilterValidator().setValidator(this).setEdm(edm).setExpression(item.getValue());
}
public ApplyValidator goUp() {
return previous;
}
}
private final class ComputeValidator implements TestValidator {
private final ComputeExpression item;
private final ApplyValidator previous;
private ComputeValidator(final ComputeExpression item, final ApplyValidator previous) {
this.item = item;
this.previous = previous;
}
public ComputeValidator isAlias(final String alias) {
assertEquals(alias, item.getAlias());
return this;
}
public FilterValidator goExpression() {
assertNotNull(item.getExpression());
return new FilterValidator().setValidator(this).setEdm(edm).setExpression(item.getExpression());
}
public ApplyValidator goUp() {
return previous;
}
}
private final class GroupByValidator implements TestValidator {
private final GroupByItem item;
private final TestValidator previous;
private GroupByValidator(final GroupByItem item, final TestValidator previous) {
this.item = item;
this.previous = previous;
}
public ResourceValidator goPath() {
assertFalse(item.getPath().isEmpty());
UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
for (final UriResource segment : item.getPath()) {
resource.addResourcePart(segment);
}
return new ResourceValidator().setUpValidator(this).setEdm(edm).setUriInfoPath(resource);
}
public GroupByValidator isRollupAll() {
assertTrue(item.isRollupAll());
return this;
}
public GroupByValidator goRollup(final int index) {
assertTrue(index < item.getRollup().size());
return new GroupByValidator(item.getRollup().get(index), this);
}
public ApplyValidator goUp() {
return (ApplyValidator) previous;
}
}
}