| /* |
| * 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; |
| } |
| } |
| } |