You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/02/20 14:34:15 UTC
[4/4] olingo-odata4 git commit: [OLINGO-545] OrderBy and Filter
System Query Option evaluation added to TecScenario
[OLINGO-545] OrderBy and Filter System Query Option evaluation added to TecScenario
Signed-off-by: Christian Amend <ch...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/0e6c9a11
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/0e6c9a11
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/0e6c9a11
Branch: refs/heads/master
Commit: 0e6c9a118366a0397594da74087b5812b6f52beb
Parents: cfb72de
Author: Christian Holzer <c....@sap.com>
Authored: Thu Feb 19 17:11:45 2015 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Fri Feb 20 14:23:32 2015 +0100
----------------------------------------------------------------------
.../olingo/fit/AbstractBaseTestITCase.java | 18 +-
.../olingo/fit/CXFOAuth2HttpClientFactory.java | 7 +-
.../tecsvc/client/FilterSystemQueryITCase.java | 976 +++++++++++++++++++
.../tecsvc/client/OrderBySystemQueryITCase.java | 172 ++++
.../client/core/uri/AbstractURIBuilder.java | 1 -
.../processor/TechnicalEntityProcessor.java | 33 +-
.../tecsvc/processor/TechnicalProcessor.java | 2 -
.../expression/ExpressionVisitorImpl.java | 236 +++++
.../expression/FilterRuntimeException.java | 38 +
.../expression/FilterSystemQueryHandler.java | 135 +++
.../expression/operand/TypedOperand.java | 199 ++++
.../expression/operand/UntypedOperand.java | 155 +++
.../expression/operand/VisitorOperand.java | 93 ++
.../expression/operation/BinaryOperator.java | 318 ++++++
.../operation/MethodCallOperator.java | 334 +++++++
.../expression/operation/UnaryOperator.java | 63 ++
.../processor/expression/primitive/EdmNull.java | 58 ++
17 files changed, 2812 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/fit/src/test/java/org/apache/olingo/fit/AbstractBaseTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/AbstractBaseTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/AbstractBaseTestITCase.java
index 21dcce1..54658ae 100644
--- a/fit/src/test/java/org/apache/olingo/fit/AbstractBaseTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/AbstractBaseTestITCase.java
@@ -18,6 +18,15 @@
*/
package org.apache.olingo.fit;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
import org.apache.catalina.LifecycleException;
import org.apache.commons.io.IOUtils;
import org.apache.olingo.client.api.CommonODataClient;
@@ -34,15 +43,6 @@ import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-
public abstract class AbstractBaseTestITCase {
/**
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/fit/src/test/java/org/apache/olingo/fit/CXFOAuth2HttpClientFactory.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/CXFOAuth2HttpClientFactory.java b/fit/src/test/java/org/apache/olingo/fit/CXFOAuth2HttpClientFactory.java
index d35b6b0..3a72508 100644
--- a/fit/src/test/java/org/apache/olingo/fit/CXFOAuth2HttpClientFactory.java
+++ b/fit/src/test/java/org/apache/olingo/fit/CXFOAuth2HttpClientFactory.java
@@ -18,11 +18,11 @@
*/
package org.apache.olingo.fit;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
import java.net.URI;
+
import javax.ws.rs.core.MediaType;
+
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
@@ -50,6 +50,9 @@ import org.apache.olingo.client.core.http.AbstractOAuth2HttpClientFactory;
import org.apache.olingo.client.core.http.OAuth2Exception;
import org.apache.olingo.fit.rest.OAuth2Provider;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+
public class CXFOAuth2HttpClientFactory extends AbstractOAuth2HttpClientFactory {
private static final OAuthClientUtils.Consumer OAUTH2_CONSUMER =
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
new file mode 100644
index 0000000..65da795
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
@@ -0,0 +1,976 @@
+/*
+ * 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.fit.tecsvc.client;
+
+import static org.junit.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.client.api.communication.ODataClientErrorException;
+import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
+import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
+import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
+import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
+import org.apache.olingo.client.core.ODataClientFactory;
+import org.apache.olingo.commons.api.domain.ODataEntity;
+import org.apache.olingo.commons.api.domain.ODataEntitySet;
+import org.apache.olingo.commons.api.domain.ODataObjectFactory;
+import org.apache.olingo.commons.api.domain.ODataValuable;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.fit.AbstractBaseTestITCase;
+import org.apache.olingo.fit.tecsvc.TecSvcConst;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class FilterSystemQueryITCase extends AbstractBaseTestITCase {
+
+ private static final String ES_COMP_ALL_PRIM = "ESCompAllPrim";
+ private static final String SERVICE_URI = TecSvcConst.BASE_URI;
+ private static final String ES_TWO_KEY_NAV = "ESTwoKeyNav";
+ private static final String ES_ALL_PRIM = "ESAllPrim";
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {}
+
+ @Test
+ public void testTimeOfDayLiteral() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "PropertyTimeOfDay eq 03:26:05");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDateLiteral() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "PropertyDate eq 2012-12-03");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDateTimeOffsetLiteral() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-03T07:16:23Z");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testInt64Literal() {
+ long value = Integer.MAX_VALUE + 1L;
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "PropertyInt64 gt " + value);
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDoubleLiteral() {
+ Double value = -17900000000000000000.0;
+
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "PropertyDouble le " + value.toString());
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testSimpleEq() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq 1");
+
+ assertEquals(2, result.getBody().getEntities().size());
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ public void testBinaryIntegerOperations() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 add 1 eq (1 sub 3) div 2 mul 3 add 7");
+
+ assertEquals(1, result.getBody().getEntities().size());
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ public void testClientEscaping() {
+ final ODataClient client = getClient();
+ final String filter = client.getFilterFactory().eq(
+ client.getFilterFactory().getArgFactory().property("PropertyString"),
+ client.getFilterFactory().getArgFactory().literal("First Resource - positive values")).build();
+
+ final URI uri = client.newURIBuilder(SERVICE_URI)
+ .appendEntitySetSegment(ES_ALL_PRIM)
+ .filter(filter)
+ .build();
+
+ final ODataRetrieveResponse<ODataEntitySet> response = client.getRetrieveRequestFactory()
+ .getEntitySetRequest(uri).execute();
+
+ assertEquals(1, response.getBody().getEntities().size());
+ ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testStringProperty() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyString eq '2'");
+
+ assertEquals(1, result.getBody().getEntities().size());
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ public void testBooleanOperator() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_TWO_KEY_NAV, "PropertyString eq '2' and PropertyInt16 eq 1");
+ assertEquals(1, result.getBody().getEntities().size());
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyString eq '2' or PropertyInt16 eq 1");
+ assertEquals(2, result.getBody().getEntities().size());
+ oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testBooleanOperatorWithNull() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq null");
+ assertEquals(0, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "null eq null");
+ assertEquals(4, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "null ne null");
+ assertEquals(0, result.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testUnaryWithNullLiterals() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_TWO_KEY_NAV, "PropertyComp/PropertyComp/PropertyBoolean eq not null");
+ assertEquals(0, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyComp/PropertyComp/PropertyBoolean eq 0 add -(5 add null)");
+ assertEquals(0, result.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testUnaryWithWrongTypes() {
+ fail(ES_ALL_PRIM, "PropertyInt16 eq 6 add - 'test'", HttpStatusCode.BAD_REQUEST);
+ fail(ES_ALL_PRIM, "PropertyBoolean eq not 'test'", HttpStatusCode.BAD_REQUEST);
+ }
+
+ @Test
+ public void testMethodCallsWithNull() {
+ // One representative of "stringFuntion" "residue class"
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "endswith(PropertyString, null) eq null"); // null eq null => true
+ assertEquals(3, result.getBody().getEntities().size());
+
+ // One representative of "stringifiedValueFunction" "residue class"
+ result = sendRequest(ES_ALL_PRIM, "substring(PropertyString, null) eq null"); // null eq null => true
+ assertEquals(3, result.getBody().getEntities().size());
+
+ // Substring
+ result = sendRequest(ES_ALL_PRIM, "hour(null) eq null"); // null eq null => true
+ assertEquals(3, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_ALL_PRIM, "substring(PropertyString, 0, null) eq null"); // null eq null => true
+ assertEquals(3, result.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testUnknownLiteral() {
+ // Check if the error code is equals to 400
+ fail(ES_ALL_PRIM, "PropertyInt16 eq ThisIsNotAValidLiteral", HttpStatusCode.BAD_REQUEST);
+ }
+
+ @Test
+ public void testErrorCodeArithmetic() {
+ fail(ES_ALL_PRIM, "PropertyInt16 eq 'hey' add 5", HttpStatusCode.BAD_REQUEST);
+ fail(ES_ALL_PRIM, "PropertyDate eq 5.0 add 2012-12-03", HttpStatusCode.BAD_REQUEST);
+ fail(ES_ALL_PRIM, "PropertyDouble mod 5 eq 0", HttpStatusCode.BAD_REQUEST);
+ fail(ES_ALL_PRIM, "UnkownProperty eq null", HttpStatusCode.BAD_REQUEST);
+ }
+
+ @Test
+ public void testNumericBinaryOperationWithNullValues() {
+ // Create new Entries
+ final String filterString = "PropertyString eq null";
+
+ ODataClient client = getClient();
+ ODataObjectFactory objectFactory = client.getObjectFactory();
+
+ ODataEntity entity = objectFactory.newEntity(new FullQualifiedName("olingo.odata.test1.ETAllPrim"));
+
+ entity.getProperties().add(
+ objectFactory.newPrimitiveProperty("PropertyInt16", objectFactory.newPrimitiveValueBuilder()
+ .buildInt16((short) 1)));
+
+ final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESAllPrim").build();
+ ODataEntityCreateResponse<ODataEntity> createResponse =
+ client.getCUDRequestFactory().getEntityCreateRequest(uri, entity).execute();
+
+ final URI receiveURI =
+ client.newURIBuilder(SERVICE_URI)
+ .appendEntitySetSegment("ESAllPrim")
+ .filter(filterString)
+ .build();
+
+ ODataEntitySetRequest<ODataEntitySet> filterRequest =
+ client.getRetrieveRequestFactory().getEntitySetRequest(receiveURI);
+ filterRequest.addCustomHeader(HttpHeader.COOKIE, createResponse.getHeader(HttpHeader.SET_COOKIE).iterator().next());
+ ODataRetrieveResponse<ODataEntitySet> filterResponse = filterRequest.execute();
+
+ assertEquals(1, filterResponse.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testNumericComparisionOperators() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 ge 1");
+ assertEquals(4, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt 1");
+ assertEquals(2, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 lt 2");
+ assertEquals(2, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 le 2");
+ assertEquals(3, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_ALL_PRIM, "PropertyDouble ge -179000");
+ assertEquals(2, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_ALL_PRIM, "PropertyDouble gt -179000");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_ALL_PRIM, "PropertyDouble lt -179000");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ result = sendRequest(ES_ALL_PRIM, "PropertyDouble le -179000");
+ assertEquals(2, result.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testBinaryOperationIntegerDecimalWithPromotion() {
+ String filterString = ""
+ + "PropertyInt16 mod 2 eq " // Choose mod 2 == 1 => { 1, 3, .. }
+ + "(((5 sub 1) div 5) " // Integer Division 4 / 5 == 0
+ + "add 1) " // 0 + 1 = 1
+ + "and "
+ + "PropertyComp/PropertyInt16 eq " // Complex Property
+ + "5.5 mul 2"; // Single * Int16 => Single => Int16 eq Single => Single eq Single
+
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, filterString);
+ assertEquals(3, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ assertEquals("11", ((ODataValuable) ((ODataValuable) oDataEntity.getProperty("PropertyComp")).getComplexValue()
+ .get("PropertyInt16")).getValue()
+ .toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ assertEquals("11", ((ODataValuable) ((ODataValuable) oDataEntity.getProperty("PropertyComp")).getComplexValue()
+ .get("PropertyInt16")).getValue()
+ .toString());
+
+ oDataEntity = result.getBody().getEntities().get(2);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ assertEquals("11", ((ODataValuable) ((ODataValuable) oDataEntity.getProperty("PropertyComp")).getComplexValue()
+ .get("PropertyInt16")).getValue()
+ .toString());
+ }
+
+ @Test
+ public void testNotOperator() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "not (PropertyInt16 eq 1)");
+ assertEquals(2, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ public void testUnaryMinusOperator() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt -2 add - -3");
+ assertEquals(2, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ public void testUnaryMinusOperatorDecimal() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt -2.0 add - -3.0");
+ assertEquals(2, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ public void testStringPropertyEqualsNull() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyString eq null");
+ assertEquals(0, result.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testAddNullLiteral() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 add null eq 1");
+ assertEquals(0, result.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testAddNullLiteralEqualsNull() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 add null eq null");
+ assertEquals(4, result.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testSubstringStartAndEndGiven() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "substring(PropertyString, length('First') add 1, 8) eq ('Resource')");
+
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testSubstringStartGiven() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_TWO_KEY_NAV, "substring(PropertyComp/PropertyComp/PropertyString, 6) eq 'Value'");
+
+ assertEquals(4, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(2);
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(3);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ @SuppressWarnings("unused")
+ public void testSubstringDouble() {
+ try {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "substring(PropertyString, length('First')"
+ + "add 1, 2.0 * 4) eq ('Resource')");
+ } catch (ODataClientErrorException e) {
+ assertEquals(400, e.getStatusLine().getStatusCode());
+ }
+ }
+
+ @Test
+ public void testYearFunctionDate() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "year(PropertyDate) eq 2015");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testYearFunctionDateTimeOffset() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "year(PropertyDateTimeOffset) eq 2012");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testMonthFunctionDateTimeOffset() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "month(PropertyDateTimeOffset) eq 12");
+ assertEquals(3, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(2);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testMonthFunctionDate() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "month(PropertyDate) eq 11");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDayFunctionDateTimeOffset() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "day(PropertyDateTimeOffset) eq 3");
+ assertEquals(3, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(2);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDayFunctionDate() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "day(PropertyDate) eq 5");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testHourFunctionDateTimeOffset() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "hour(PropertyDateTimeOffset) eq 7");
+ assertEquals(2, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testHourFuntionTimeOfDay() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "hour(PropertyTimeOfDay) eq 3");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testMinuteFunctionDateTimeOffset() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "minute(PropertyDateTimeOffset) eq 17");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testMinuteFuntionTimeOfDay() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "minute(PropertyTimeOfDay) eq 49");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testSecondFunctionDateTimeOffset() {
+ ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_ALL_PRIM, "second(PropertyDateTimeOffset) eq 8");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testSecondFuntionTimeOfDay() {
+ ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_ALL_PRIM, "second(PropertyTimeOfDay) eq 14");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testFractionalsecondsDateTimeOffset() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_COMP_ALL_PRIM, "fractionalseconds(PropertyComp/PropertyDateTimeOffset) eq 0.1234567");
+ assertEquals(2, response.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(1);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testFractionalsecondsDateOfTime() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "fractionalseconds(PropertyTimeOfDay) eq 0");
+ assertEquals(3, response.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testDateTimeFunctionsNull() {
+ ODataRetrieveResponse<ODataEntitySet> response;
+
+ response = sendRequest(ES_ALL_PRIM, "year(null) eq null");
+ assertEquals(3, response.getBody().getEntities().size());
+
+ response = sendRequest(ES_ALL_PRIM, "month(null) eq null");
+ assertEquals(3, response.getBody().getEntities().size());
+
+ response = sendRequest(ES_ALL_PRIM, "day(null) eq null");
+ assertEquals(3, response.getBody().getEntities().size());
+
+ response = sendRequest(ES_ALL_PRIM, "hour(null) eq null");
+ assertEquals(3, response.getBody().getEntities().size());
+
+ response = sendRequest(ES_ALL_PRIM, "minute(null) eq null");
+ assertEquals(3, response.getBody().getEntities().size());
+
+ response = sendRequest(ES_ALL_PRIM, "second(null) eq null");
+ assertEquals(3, response.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testFloor() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq floor(3.8)");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq floor(3.1)");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ public void testCeiling() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq ceiling(2.1)");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq ceiling(2.6)");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ public void testRound() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq round(2.5)");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq round(2.4)");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq round(2.6)");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+
+ result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq round(3.1)");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
+ }
+
+ @Test
+ public void testEndsWith() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "endswith(PropertyString, 'values')");
+ assertEquals(2, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = result.getBody().getEntities().get(1);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testIndexOf() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "indexof(PropertyString, 'positive') eq 17");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testStartsWith() {
+ ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "startswith(PropertyString, 'First')");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testToLower() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "contains(PropertyString, tolower('POSITIVE'))");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testToUpper() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "contains(PropertyString, concat(toupper('f'), 'irst'))");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testTrim() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "trim(substring(PropertyString, 0, 6)) eq 'First'");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDecimalDiv() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "PropertyDouble eq 0 sub (358000 div 2)");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testNumericPromotionToInt64() {
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "PropertyInt64 eq 0");
+ assertEquals(1, result.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = result.getBody().getEntities().get(0);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void castEdm64ToDouble() {
+ double value = Float.MAX_VALUE + 1;
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest(ES_ALL_PRIM, "PropertyInt64 lt " + value);
+ assertEquals(3, result.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testDateTimeOffsetAddDuraton() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-03T07:16:19Z add duration'PT4S'");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDurrationAddDuration() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "PropertyDuration eq duration'PT2S' add duration'PT4S'");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDurrationLiteral() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "PropertyDuration eq duration'P1DT'");
+ assertEquals(0, response.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testDateAddDuration() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-02 add duration'P1DT7H16M23S'");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDateTimeOffsetSubDuration() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-03T07:16:27Z sub duration'PT4S'");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDurrationSubDuration() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "PropertyDuration sub duration'PT2S' eq duration'PT4S'");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDateSubDuration() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-04 sub duration'P0DT16H43M37S'");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDateSubDate() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "PropertyDuration eq 2012-12-04 sub 2012-12-04");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testDateTimeOffsetSubDateTimeOffset() {
+ ODataRetrieveResponse<ODataEntitySet> response =
+ sendRequest(ES_ALL_PRIM, "PropertyDuration eq 2005-12-03T00:00:00Z sub 2005-12-03T00:00:00Z");
+ assertEquals(1, response.getBody().getEntities().size());
+
+ final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testNumericPromotion() {
+ /*
+ * The idea is use the largest possible number of a specific type and add a another number to force an
+ * implicit conversion to an higher type
+ */
+ ODataRetrieveResponse<ODataEntitySet> response;
+
+ // SByte => Int16
+ byte byteValue = Byte.MAX_VALUE; // 2 ^ 7 -1 = 127
+ response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + byteValue + " add " + 1);
+ assertEquals(0, response.getBody().getEntities().size()); // No error occurs
+
+ // Int16 => Int32
+ short shortValue = Short.MAX_VALUE;
+ response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + shortValue + " add " + 1);
+ assertEquals(0, response.getBody().getEntities().size()); // No error occurs
+
+ // Int32 => Int64
+ int intValue = Integer.MAX_VALUE;
+ response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + intValue + " add " + 1);
+ assertEquals(0, response.getBody().getEntities().size()); // No error occurs
+
+ // Int64 => Double
+ Long longValue = Long.MAX_VALUE;
+ response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + longValue + " add " + 1);
+ assertEquals(0, response.getBody().getEntities().size()); // No error occurs
+
+ // Single => Double
+ Float floatValue = Float.MAX_VALUE;
+ response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + floatValue.toString() + " add " + 1.0);
+ assertEquals(0, response.getBody().getEntities().size()); // No error occurs
+ }
+
+ @Test
+ public void testNullComplexProperty() {
+ // Create a new entry.The complex property PropertyCompComp is set to null. So the structure of the property
+ // is still there, but filled is null value (primitive types)
+ // We define a filter, which returns all entry where PropertyCompComp/PropertyComp/PropertyInt16 is equals to 1
+
+ final ODataClient client = getClient();
+ final ODataObjectFactory factory = client.getObjectFactory();
+ ODataEntity newEntity = factory.newEntity(new FullQualifiedName("olingo.odata.test1", "ETKeyNav"));
+ newEntity.getProperties().add(factory.newComplexProperty("PropertyCompComp", null));
+ newEntity.getProperties().add(factory.newPrimitiveProperty("PropertyInt16",
+ factory.newPrimitiveValueBuilder().buildInt16((short) 4)));
+ newEntity.getProperties().add(factory.newPrimitiveProperty("PropertyString",
+ factory.newPrimitiveValueBuilder().buildString("Test")));
+ newEntity.getProperties().add(
+ factory.newComplexProperty("PropertyCompAllPrim",
+ factory.newComplexValue("CTAllPrim")
+ .add(factory.newPrimitiveProperty(
+ "PropertyString",
+ factory.newPrimitiveValueBuilder().buildString("Test 3")))));
+
+ newEntity.getProperties().add(
+ factory.newComplexProperty("PropertyCompTwoPrim",
+ factory.newComplexValue("CTTwoPrim")
+ .add(factory.newPrimitiveProperty(
+ "PropertyInt16",
+ factory.newPrimitiveValueBuilder().buildInt16((short) 1)))
+ .add(factory.newPrimitiveProperty(
+ "PropertyString",
+ factory.newPrimitiveValueBuilder().buildString("Test2")))));
+
+ final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESKeyNav").build();
+ ODataEntityCreateRequest<ODataEntity> request =
+ client.getCUDRequestFactory().getEntityCreateRequest(uri, newEntity);
+ ODataEntityCreateResponse<ODataEntity> response = request.execute();
+ assertEquals(HttpStatusCode.CREATED.getStatusCode(), response.getStatusCode());
+
+ final String cookie = response.getHeader(HttpHeader.SET_COOKIE).iterator().next();
+
+ // Do the filter request
+ ODataRetrieveResponse<ODataEntitySet> result =
+ sendRequest("ESKeyNav", "PropertyCompComp/PropertyComp/PropertyInt16 eq 1", cookie);
+ assertEquals(3, result.getBody().getEntities().size());
+
+ // Try filter all entries where PropertyCompComp is null
+ result = sendRequest("ESKeyNav", "PropertyCompComp/PropertyComp/PropertyInt16 eq null", cookie);
+ assertEquals(1, result.getBody().getEntities().size());
+ }
+
+ @Test
+ public void testSringFunctionWithoutStringParameters() {
+ fail("ESServerSidePaging", "filter=contains(PropertyInt16, 3) eq 'hallo'", HttpStatusCode.BAD_REQUEST);
+ }
+
+ private ODataRetrieveResponse<ODataEntitySet> sendRequest(String entitySet, String filterString) {
+ return sendRequest(entitySet, filterString, null);
+ }
+
+ private ODataRetrieveResponse<ODataEntitySet> sendRequest(String entitySet, String filterString, String cookie) {
+ final ODataClient client = getClient();
+
+ final URI uri =
+ client.newURIBuilder(SERVICE_URI)
+ .appendEntitySetSegment(entitySet)
+ .filter(filterString)
+ .build();
+
+ ODataEntitySetRequest<ODataEntitySet> request = client.getRetrieveRequestFactory().getEntitySetRequest(uri);
+ if (cookie != null) {
+ request.addCustomHeader(HttpHeader.COOKIE, cookie);
+ }
+
+ return request.execute();
+ }
+
+ private void fail(String entitySet, String filterString, HttpStatusCode errorCode) {
+ try {
+ sendRequest(entitySet, filterString);
+ Assert.fail();
+ } catch (ODataClientErrorException e) {
+ assertEquals(errorCode.getStatusCode(), e.getStatusLine().getStatusCode());
+ }
+ }
+
+ @Override
+ protected ODataClient getClient() {
+ ODataClient odata = ODataClientFactory.getV4();
+ odata.getConfiguration().setDefaultPubFormat(ODataFormat.JSON);
+ return odata;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
new file mode 100644
index 0000000..21d248c
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
@@ -0,0 +1,172 @@
+/*
+ * 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.fit.tecsvc.client;
+
+import static org.junit.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.client.api.communication.ODataClientErrorException;
+import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
+import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
+import org.apache.olingo.client.core.ODataClientFactory;
+import org.apache.olingo.commons.api.domain.ODataEntity;
+import org.apache.olingo.commons.api.domain.ODataEntitySet;
+import org.apache.olingo.commons.api.domain.ODataValuable;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.fit.AbstractBaseTestITCase;
+import org.apache.olingo.fit.tecsvc.TecSvcConst;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class OrderBySystemQueryITCase extends AbstractBaseTestITCase {
+
+ private static final String ES_TWO_PRIM = "ESTwoPrim";
+ private static final String ES_ALL_PRIM = "ESAllPrim";
+
+ private static final String SERVICE_URI = TecSvcConst.BASE_URI;
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {}
+
+ @Test
+ public void testSimpleOrderBy() {
+ ODataRetrieveResponse<ODataEntitySet> response = null;
+
+ response = sendRequest(ES_ALL_PRIM, "PropertyDate");
+ assertEquals(3, response.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(1);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(2);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testSimpleOrderByDecending() {
+ ODataRetrieveResponse<ODataEntitySet> response = null;
+
+ response = sendRequest(ES_ALL_PRIM, "PropertyDate desc");
+ assertEquals(3, response.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(1);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(2);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testMultipleOrderBy() {
+ final ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_ALL_PRIM, "PropertyByte, PropertyInt16");
+ assertEquals(3, response.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(1);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(2);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testMultipleOrderByDecending() {
+ final ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_ALL_PRIM, "PropertyByte, PropertyInt16 desc");
+ assertEquals(3, response.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(1);
+ assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(2);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testOrderByWithNull() {
+ final ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_TWO_PRIM, "PropertyString");
+ assertEquals(4, response.getBody().getEntities().size());
+
+ ODataEntity oDataEntity = response.getBody().getEntities().get(0);
+ assertEquals("-32766", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(1);
+ assertEquals("32766", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(2);
+ assertEquals("-365", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+
+ oDataEntity = response.getBody().getEntities().get(3);
+ assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
+ }
+
+ @Test
+ public void testOrderByInvalidExpression() {
+ fail(ES_TWO_PRIM, "PropertyString add 10", HttpStatusCode.BAD_REQUEST);
+ }
+
+ private ODataRetrieveResponse<ODataEntitySet> sendRequest(String entitySet, String orderByString) {
+ final ODataClient client = getClient();
+ String escapedFilterString = escapeFilterString(orderByString);
+
+ final URI uri =
+ client.newURIBuilder(SERVICE_URI)
+ .appendEntitySetSegment(entitySet)
+ .orderBy(escapedFilterString)
+ .build();
+
+ ODataEntitySetRequest<ODataEntitySet> request = client.getRetrieveRequestFactory().getEntitySetRequest(uri);
+
+ return request.execute();
+ }
+
+ private void fail(String entitySet, String filterString, HttpStatusCode errorCode) {
+ try {
+ sendRequest(entitySet, filterString);
+ Assert.fail();
+ } catch (ODataClientErrorException e) {
+ assertEquals(errorCode.getStatusCode(), e.getStatusLine().getStatusCode());
+ }
+ }
+
+ private String escapeFilterString(String filterString) {
+ return filterString.replace(" ", "%20");
+ }
+
+ @Override
+ protected ODataClient getClient() {
+ ODataClient odata = ODataClientFactory.getV4();
+ odata.getConfiguration().setDefaultPubFormat(ODataFormat.JSON);
+ return odata;
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/AbstractURIBuilder.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/AbstractURIBuilder.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/AbstractURIBuilder.java
index f80e394..5802ff3 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/AbstractURIBuilder.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/AbstractURIBuilder.java
@@ -311,7 +311,6 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
// it will try to call URLEncodedUtils.format(Iterable<>,Charset) method,
// which works in desktop java application, however, throws NoSuchMethodError in android OS,
// so here manually construct the URL by its overload URLEncodedUtils.format(List<>,String).
- //String queryStr = URLEncodedUtils.format(list1, "UTF-8");
final String queryStr = encodeQueryParameter(list1);
sb.append(queryStr);
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
index 9868366..3113028 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
@@ -32,6 +32,7 @@ import org.apache.olingo.commons.api.http.HttpContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.commons.core.data.EntitySetImpl;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
@@ -52,13 +53,14 @@ import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.tecsvc.data.DataProvider;
+import org.apache.olingo.server.tecsvc.processor.expression.FilterSystemQueryHandler;
/**
* Technical Processor for entity-related functionality.
*/
public class TechnicalEntityProcessor extends TechnicalProcessor
implements EntityCollectionProcessor, ActionEntityCollectionProcessor, CountEntityCollectionProcessor,
- EntityProcessor, ActionEntityProcessor, MediaEntityProcessor {
+ EntityProcessor, ActionEntityProcessor, MediaEntityProcessor {
public TechnicalEntityProcessor(final DataProvider dataProvider) {
super(dataProvider);
@@ -68,14 +70,21 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
public void readEntityCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType requestedContentType) throws ODataApplicationException, SerializerException {
validateOptions(uriInfo.asUriInfoResource());
- final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
- EntitySet entitySet = readEntityCollection(uriInfo);
- if (entitySet == null) {
+
+ final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());
+ final EntitySet entitySetInitial = readEntityCollection(uriInfo);
+ if (entitySetInitial == null) {
throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
} else {
- if (uriInfo.getCountOption() != null && uriInfo.getCountOption().getValue()) {
- setCount(entitySet);
- }
+ // Modifying the original entitySet means modifying the "database", so we have to make a shallow
+ // copy of the entity set (new EntitySet, but exactly the same data)
+ EntitySet entitySet = new EntitySetImpl();
+ entitySet.getEntities().addAll(entitySetInitial.getEntities());
+
+ // Apply system query options
+ FilterSystemQueryHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, edmEntitySet);
+ FilterSystemQueryHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, edmEntitySet);
+
final ODataFormat format = ODataFormat.fromContentType(requestedContentType);
ODataSerializer serializer = odata.createSerializer(format);
final ExpandOption expand = uriInfo.getExpandOption();
@@ -95,7 +104,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
@Override
public void processActionEntityCollection(final ODataRequest request, final ODataResponse response,
final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat)
- throws ODataApplicationException, DeserializerException, SerializerException {
+ throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Process entity collection is not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@@ -150,7 +159,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
@Override
public void createMediaEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
- throws ODataApplicationException, DeserializerException, SerializerException {
+ throws ODataApplicationException, DeserializerException, SerializerException {
createEntity(request, response, uriInfo, requestFormat, responseFormat);
}
@@ -168,9 +177,9 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
final EdmEntityType edmEntityType = edmEntitySet.getEntityType();
Entity entity = dataProvider.create(edmEntitySet);
- if (edmEntityType.hasStream()) { // called from createMediaEntity(...), not directly
+ if (edmEntityType.hasStream()) { // called from createMediaEntity(...), not directly
dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()),
- requestFormat.toContentTypeString());
+ requestFormat.toContentTypeString());
} else {
dataProvider.update(edmEntitySet, entity,
odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
@@ -228,7 +237,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
@Override
public void processActionEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
- throws ODataApplicationException, DeserializerException, SerializerException {
+ throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Process entity is not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index 3ecb4ed..31257cb 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -156,9 +156,7 @@ public abstract class TechnicalProcessor implements Processor {
protected void validateOptions(final UriInfoResource uriInfo) throws ODataApplicationException {
if (uriInfo.getCountOption() != null
|| !uriInfo.getCustomQueryOptions().isEmpty()
- || uriInfo.getFilterOption() != null
|| uriInfo.getIdOption() != null
- || uriInfo.getOrderByOption() != null
|| uriInfo.getSearchOption() != null
|| uriInfo.getSkipOption() != null
|| uriInfo.getSkipTokenOption() != null
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/ExpressionVisitorImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/ExpressionVisitorImpl.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/ExpressionVisitorImpl.java
new file mode 100644
index 0000000..12a4940
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/ExpressionVisitorImpl.java
@@ -0,0 +1,236 @@
+/*
+ * 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.tecsvc.processor.expression;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEnumType;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
+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;
+import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.UntypedOperand;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
+import org.apache.olingo.server.tecsvc.processor.expression.operation.BinaryOperator;
+import org.apache.olingo.server.tecsvc.processor.expression.operation.MethodCallOperator;
+import org.apache.olingo.server.tecsvc.processor.expression.operation.UnaryOperator;
+
+public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand> {
+
+ final private Entity entity;
+ final private EdmEntitySet edmEntitySet;
+
+ public ExpressionVisitorImpl(Entity entity, EdmEntitySet edmEntitySet) {
+ this.entity = entity;
+ this.edmEntitySet = edmEntitySet;
+ }
+
+ @Override
+ public VisitorOperand visitBinaryOperator(BinaryOperatorKind operator, VisitorOperand left, VisitorOperand right)
+ throws ExpressionVisitException, ODataApplicationException {
+
+ final BinaryOperator binaryOperator = new BinaryOperator(left, right);
+
+ switch (operator) {
+ case AND:
+ return binaryOperator.andOperator();
+ case OR:
+ return binaryOperator.orOperator();
+ case EQ:
+ return binaryOperator.equalsOperator();
+ case NE:
+ return binaryOperator.notEqualsOperator();
+ case GE:
+ return binaryOperator.greaterEqualsOperator();
+ case GT:
+ return binaryOperator.greaterThanOperator();
+ case LE:
+ return binaryOperator.lessEqualsOperator();
+ case LT:
+ return binaryOperator.lessThanOperator();
+ case ADD:
+ case SUB:
+ case MUL:
+ case DIV:
+ case MOD:
+ return binaryOperator.arithmeticOperator(operator);
+ default:
+ return throwNotImplemented();
+ }
+ }
+
+ @Override
+ public VisitorOperand visitUnaryOperator(UnaryOperatorKind operator, VisitorOperand operand)
+ throws ExpressionVisitException, ODataApplicationException {
+
+ final UnaryOperator unaryOperator = new UnaryOperator(operand);
+
+ switch (operator) {
+ case MINUS:
+ return unaryOperator.minusOperation();
+ case NOT:
+ return unaryOperator.notOperation();
+ default:
+ // Can`t happen
+ return throwNotImplemented();
+ }
+ }
+
+ @Override
+ public VisitorOperand visitMethodCall(MethodKind methodCall, List<VisitorOperand> parameters)
+ throws ExpressionVisitException, ODataApplicationException {
+
+ final MethodCallOperator methodCallOperation = new MethodCallOperator(parameters);
+
+ switch (methodCall) {
+ case ENDSWITH:
+ return methodCallOperation.endsWith();
+ case INDEXOF:
+ return methodCallOperation.indexOf();
+ case STARTSWITH:
+ return methodCallOperation.startsWith();
+ case TOLOWER:
+ return methodCallOperation.toLower();
+ case TOUPPER:
+ return methodCallOperation.toUpper();
+ case TRIM:
+ return methodCallOperation.trim();
+ case SUBSTRING:
+ return methodCallOperation.substring();
+ case CONTAINS:
+ return methodCallOperation.contains();
+ case CONCAT:
+ return methodCallOperation.concat();
+ case LENGTH:
+ return methodCallOperation.length();
+ case YEAR:
+ return methodCallOperation.year();
+ case MONTH:
+ return methodCallOperation.month();
+ case DAY:
+ return methodCallOperation.day();
+ case HOUR:
+ return methodCallOperation.hour();
+ case MINUTE:
+ return methodCallOperation.minute();
+ case SECOND:
+ return methodCallOperation.second();
+ case FRACTIONALSECONDS:
+ return methodCallOperation.fractionalseconds();
+ case ROUND:
+ return methodCallOperation.round();
+ case FLOOR:
+ return methodCallOperation.floor();
+ case CEILING:
+ return methodCallOperation.ceiling();
+
+ default:
+ return throwNotImplemented();
+ }
+ }
+
+ @Override
+ public VisitorOperand visitLambdaExpression(String lambdaFunction, String lambdaVariable, Expression expression)
+ throws ExpressionVisitException, ODataApplicationException {
+
+ return throwNotImplemented();
+ }
+
+ @Override
+ public VisitorOperand visitLiteral(String literal) throws ExpressionVisitException, ODataApplicationException {
+
+ return new UntypedOperand(literal);
+ }
+
+ @Override
+ public VisitorOperand visitMember(UriInfoResource member) throws ExpressionVisitException,
+ ODataApplicationException {
+
+ final List<UriResource> uriResourceParts = member.getUriResourceParts();
+
+ // UriResourceParts contains at least one UriResource
+ Property currentProperty = entity.getProperty(uriResourceParts.get(0).toString());
+ EdmType currentType = ((UriResourcePartTyped) uriResourceParts.get(0)).getType();
+
+ EdmProperty currentEdmProperty = edmEntitySet.getEntityType()
+ .getStructuralProperty(uriResourceParts.get(0).toString());
+
+ for (int i = 1; i < uriResourceParts.size(); i++) {
+ currentType = ((UriResourcePartTyped) uriResourceParts.get(i)).getType();
+
+ if (currentProperty.isComplex() || currentProperty.isLinkedComplex()) {
+ final List<Property> complex = currentProperty.isLinkedComplex() ?
+ currentProperty.asLinkedComplex().getValue() : currentProperty.asComplex();
+
+ for (final Property innerProperty : complex) {
+ if (innerProperty.getName().equals(uriResourceParts.get(i).toString())) {
+ EdmComplexType edmComplexType = (EdmComplexType) currentEdmProperty.getType();
+ currentEdmProperty = edmComplexType.getStructuralProperty(uriResourceParts.get(i).toString());
+ currentProperty = innerProperty;
+ break;
+ }
+ }
+ }
+ }
+
+ return new TypedOperand(((Property) currentProperty).getValue(), currentType, currentEdmProperty);
+ }
+
+ @Override
+ public VisitorOperand visitAlias(String aliasName) throws ExpressionVisitException, ODataApplicationException {
+ return throwNotImplemented();
+ }
+
+ @Override
+ public VisitorOperand visitTypeLiteral(EdmType type) throws ExpressionVisitException, ODataApplicationException {
+ return throwNotImplemented();
+ }
+
+ @Override
+ public VisitorOperand visitLambdaReference(String variableName) throws ExpressionVisitException,
+ ODataApplicationException {
+ return throwNotImplemented();
+ }
+
+ @Override
+ public VisitorOperand visitEnum(EdmEnumType type, List<String> enumValues) throws ExpressionVisitException,
+ ODataApplicationException {
+ return throwNotImplemented();
+ }
+
+ private VisitorOperand throwNotImplemented() throws ODataApplicationException {
+ throw new ODataApplicationException("Not implemented", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),
+ Locale.ROOT);
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/FilterRuntimeException.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/FilterRuntimeException.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/FilterRuntimeException.java
new file mode 100644
index 0000000..21fc110
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/FilterRuntimeException.java
@@ -0,0 +1,38 @@
+/*
+ * 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.tecsvc.processor.expression;
+
+import org.apache.olingo.commons.api.ODataRuntimeException;
+
+public class FilterRuntimeException extends ODataRuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public FilterRuntimeException(Exception cause) {
+ super(cause);
+ }
+
+ public FilterRuntimeException(String msg, Exception cause) {
+ super(msg, cause);
+ }
+
+ public FilterRuntimeException(String msg) {
+ super(msg);
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/FilterSystemQueryHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/FilterSystemQueryHandler.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/FilterSystemQueryHandler.java
new file mode 100644
index 0000000..5b5b506
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/FilterSystemQueryHandler.java
@@ -0,0 +1,135 @@
+/*
+ * 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.tecsvc.processor.expression;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Locale;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.queryoption.FilterOption;
+import org.apache.olingo.server.api.uri.queryoption.OrderByItem;
+import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
+import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
+
+public class FilterSystemQueryHandler {
+
+ public static void applyFilterSystemQuery(FilterOption filterOption, EntitySet entitySet, EdmEntitySet edmEntitySet)
+ throws ODataApplicationException {
+
+ if (filterOption == null) {
+ return;
+ }
+
+ try {
+ final Iterator<Entity> iter = entitySet.getEntities().iterator();
+
+ while (iter.hasNext()) {
+ final VisitorOperand operand = filterOption.getExpression()
+ .accept(new ExpressionVisitorImpl(iter.next(), edmEntitySet));
+ final TypedOperand typedOperand = operand.asTypedOperand();
+
+ if (!(typedOperand.is(EdmBoolean.getInstance())
+ && Boolean.TRUE.equals(typedOperand.getTypedValue(Boolean.class)))) {
+ iter.remove();
+ }
+ }
+
+ } catch (ExpressionVisitException e) {
+ throw new ODataApplicationException("Exception in filter evaluation",
+ HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
+ }
+ }
+
+ public static void applyOrderByOption(final OrderByOption orderByOption, final EntitySet entitySet,
+ final EdmEntitySet edmEntitySet) throws ODataApplicationException {
+
+ if (orderByOption == null) {
+ return;
+ }
+
+ try {
+ applyOrderByOptionInternal(orderByOption, entitySet, edmEntitySet);
+ } catch (FilterRuntimeException e) {
+ if (e.getCause() instanceof ODataApplicationException) {
+ // Throw the nested exception, to send the correct HTTP status code in the HTTP response
+ throw (ODataApplicationException) e.getCause();
+ } else {
+ throw new ODataApplicationException("Exception in orderBy evaluation", HttpStatusCode.INTERNAL_SERVER_ERROR
+ .getStatusCode(), Locale.ROOT);
+ }
+ }
+ }
+
+ private static void applyOrderByOptionInternal(final OrderByOption orderByOption, final EntitySet entitySet,
+ final EdmEntitySet edmEntitySet) throws ODataApplicationException {
+ Collections.sort(entitySet.getEntities(), new Comparator<Entity>() {
+ @Override
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public int compare(final Entity e1, final Entity e2) {
+ // Evaluate the first order option for both entity
+ // If and only if the result of the previous order option is equals to 0
+ // evaluate the next order option until all options are evaluated or they are not equals
+ int result = 0;
+
+ for (int i = 0; i < orderByOption.getOrders().size() && result == 0; i++) {
+ try {
+ final OrderByItem item = orderByOption.getOrders().get(i);
+ final TypedOperand op1 =
+ item.getExpression().accept(new ExpressionVisitorImpl(e1, edmEntitySet)).asTypedOperand();
+ final TypedOperand op2 =
+ item.getExpression().accept(new ExpressionVisitorImpl(e2, edmEntitySet)).asTypedOperand();
+
+ if (op1.isNull() || op2.isNull()) {
+ if (op1.isNull() && op2.isNull()) {
+ result = 0; // null is equals to null
+ } else {
+ result = op1.isNull() ? -1 : 1;
+ }
+ } else {
+ Object o1 = op1.getValue();
+ Object o2 = op2.getValue();
+
+ if (o1.getClass() == o2.getClass() && o1 instanceof Comparable) {
+ result = ((Comparable) o1).compareTo(o2);
+ } else {
+ result = 0;
+ }
+ }
+
+ result = item.isDescending() ? result * -1 : result;
+ } catch (ODataApplicationException e) {
+ throw new FilterRuntimeException(e);
+ } catch (ExpressionVisitException e) {
+ throw new FilterRuntimeException(e);
+ }
+ }
+ return result;
+ }
+ });
+ }
+}