This is an automated email from the ASF dual-hosted git repository.
upthewaterspout pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new b730a43 GEODE-3126: Adding a query message to the protobuf protocol
b730a43 is described below
commit b730a430b50b5d847ae8c029a5c7ac12cbc315b7
Author: Dan Smith <[email protected]>
AuthorDate: Wed Feb 21 17:16:00 2018 -0800
GEODE-3126: Adding a query message to the protobuf protocol
Adding an oql query request and response to the new protocol.
---
.../src/main/proto/v1/basicTypes.proto | 12 ++
.../src/main/proto/v1/clientProtocol.proto | 3 +
.../src/main/proto/v1/region_API.proto | 16 ++
.../OqlQueryRequestOperationHandler.java | 126 ++++++++++++++++
.../registry/ProtobufOperationContextRegistry.java | 9 ++
.../serialization/exception/DecodingException.java | 2 +-
.../serialization/exception/EncodingException.java | 2 +-
...ueryRequestOperationHandlerIntegrationTest.java | 164 +++++++++++++++++++++
.../OqlQueryRequestOperationHandlerJUnitTest.java | 138 +++++++++++++++++
9 files changed, 470 insertions(+), 2 deletions(-)
diff --git a/geode-protobuf-messages/src/main/proto/v1/basicTypes.proto
b/geode-protobuf-messages/src/main/proto/v1/basicTypes.proto
index a0ca4aa..2b306dd 100644
--- a/geode-protobuf-messages/src/main/proto/v1/basicTypes.proto
+++ b/geode-protobuf-messages/src/main/proto/v1/basicTypes.proto
@@ -29,6 +29,18 @@ message Entry {
EncodedValue value = 2;
}
+message EncodedValueList {
+ repeated EncodedValue element = 1;
+}
+
+//Represents a table, such as the results of
+//an OQL query. The field names and all rows
+//should have the same number of elements.
+message Table {
+ repeated string fieldName = 1;
+ repeated EncodedValueList row = 2;
+}
+
message EncodedValue {
oneof value{
int32 intResult = 1;
diff --git a/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
b/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
index e4181c7..d049aec 100644
--- a/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
+++ b/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
@@ -66,6 +66,9 @@ message Message {
ExecuteFunctionOnGroupRequest executeFunctionOnGroupRequest = 24;
ExecuteFunctionOnGroupResponse executeFunctionOnGroupResponse= 25;
+
+ OQLQueryRequest oqlQueryRequest = 26;
+ OQLQueryResponse oqlQueryResponse = 27;
}
}
diff --git a/geode-protobuf-messages/src/main/proto/v1/region_API.proto
b/geode-protobuf-messages/src/main/proto/v1/region_API.proto
index b68eb5d..c3465db 100644
--- a/geode-protobuf-messages/src/main/proto/v1/region_API.proto
+++ b/geode-protobuf-messages/src/main/proto/v1/region_API.proto
@@ -84,3 +84,19 @@ message GetRegionRequest {
message GetRegionResponse {
Region region = 1;
}
+
+message OQLQueryRequest {
+ string query = 1;
+ repeated EncodedValue bindParameter = 2;
+}
+
+//Response to an OQL query. Depending on the query,
+//it may return a single value, a list of values, or a table
+//of values.
+message OQLQueryResponse {
+ oneof result {
+ EncodedValue singleResult = 1;
+ EncodedValueList listResult = 2;
+ Table tableResult = 3;
+ }
+}
diff --git
a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OqlQueryRequestOperationHandler.java
b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OqlQueryRequestOperationHandler.java
new file mode 100644
index 0000000..448fcea
--- /dev/null
+++
b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OqlQueryRequestOperationHandler.java
@@ -0,0 +1,126 @@
+/*
+ * 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.geode.internal.protocol.protobuf.v1.operations;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.cache.query.Query;
+import org.apache.geode.cache.query.QueryException;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.cache.query.Struct;
+import org.apache.geode.cache.query.internal.InternalQueryService;
+import org.apache.geode.cache.query.types.StructType;
+import org.apache.geode.internal.exception.InvalidExecutionContextException;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.protocol.operations.ProtobufOperationHandler;
+import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
+import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes.EncodedValue;
+import org.apache.geode.internal.protocol.protobuf.v1.Failure;
+import org.apache.geode.internal.protocol.protobuf.v1.MessageExecutionContext;
+import
org.apache.geode.internal.protocol.protobuf.v1.ProtobufSerializationService;
+import
org.apache.geode.internal.protocol.protobuf.v1.RegionAPI.OQLQueryRequest;
+import
org.apache.geode.internal.protocol.protobuf.v1.RegionAPI.OQLQueryResponse;
+import
org.apache.geode.internal.protocol.protobuf.v1.RegionAPI.OQLQueryResponse.Builder;
+import org.apache.geode.internal.protocol.protobuf.v1.Result;
+import org.apache.geode.internal.protocol.protobuf.v1.Success;
+import
org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.DecodingException;
+import
org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.EncodingException;
+import
org.apache.geode.internal.protocol.protobuf.v1.state.exception.ConnectionStateException;
+
+public class OqlQueryRequestOperationHandler
+ implements ProtobufOperationHandler<OQLQueryRequest, OQLQueryResponse> {
+ Logger logger = LogService.getLogger();
+
+ @Override
+ public Result<OQLQueryResponse> process(final ProtobufSerializationService
serializationService,
+ final OQLQueryRequest request, final MessageExecutionContext
messageExecutionContext)
+ throws InvalidExecutionContextException, ConnectionStateException,
EncodingException,
+ DecodingException {
+ String queryString = request.getQuery();
+ List<EncodedValue> encodedParameters = request.getBindParameterList();
+
+ InternalQueryService queryService =
messageExecutionContext.getCache().getQueryService();
+
+ Query query = queryService.newQuery(queryString);
+
+ Object[] bindParameters = decodeBindParameters(serializationService,
encodedParameters);
+ try {
+ Object results = query.execute(bindParameters);
+ return Success.of(encodeResults(serializationService, results));
+ } catch (QueryException e) {
+ logger.info("Query failed: " + query, e);
+ return Failure.of(e);
+ }
+
+ }
+
+ private Object[] decodeBindParameters(final ProtobufSerializationService
serializationService,
+ final List<EncodedValue> encodedParameters) {
+ Object[] bindParameters = new Object[encodedParameters.size()];
+ for (int i = 0; i < encodedParameters.size(); i++) {
+ bindParameters[i] =
serializationService.decode(encodedParameters.get(i));
+ }
+ return bindParameters;
+ }
+
+ private OQLQueryResponse encodeResults(final ProtobufSerializationService
serializationService,
+ final Object value) throws EncodingException {
+ final Builder builder = OQLQueryResponse.newBuilder();
+
+ // The result is a single value
+ if (!(value instanceof SelectResults)) {
+ builder.setSingleResult(serializationService.encode(value));
+ return builder.build();
+ }
+
+ SelectResults<?> selectResults = (SelectResults<?>) value;
+
+ // The result is a list of objects
+ if (!selectResults.getCollectionType().getElementType().isStructType()) {
+ BasicTypes.EncodedValueList.Builder listResult =
BasicTypes.EncodedValueList.newBuilder();
+
selectResults.stream().map(serializationService::encode).forEach(listResult::addElement);
+ builder.setListResult(listResult);
+ return builder.build();
+ }
+
+ // The result is a list of structs
+ SelectResults<Struct> structResults = (SelectResults<Struct>)
selectResults;
+
+ StructType elementType = (StructType)
structResults.getCollectionType().getElementType();
+ BasicTypes.Table.Builder tableResult = BasicTypes.Table.newBuilder();
+ tableResult.addAllFieldName(Arrays.asList(elementType.getFieldNames()));
+
+ for (Struct row : structResults) {
+ tableResult.addRow(encodeStruct(serializationService, row));
+ }
+ builder.setTableResult(tableResult);
+
+ return builder.build();
+ }
+
+ private BasicTypes.EncodedValueList.Builder encodeStruct(
+ final ProtobufSerializationService serializationService, final Struct
row)
+ throws EncodingException {
+ BasicTypes.EncodedValueList.Builder structBuilder =
BasicTypes.EncodedValueList.newBuilder();
+ for (Object element : row.getFieldValues()) {
+ structBuilder.addElement(serializationService.encode(element));
+ }
+ return structBuilder;
+ }
+
+}
diff --git
a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
index 8043d10..4811bac 100644
---
a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
+++
b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
@@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.geode.annotations.Experimental;
import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
+import
org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol.Message.MessageTypeCase;
import org.apache.geode.internal.protocol.protobuf.v1.ProtobufOperationContext;
import
org.apache.geode.internal.protocol.protobuf.v1.ProtobufSerializationService;
import org.apache.geode.internal.protocol.protobuf.v1.RegionAPI;
@@ -31,12 +32,15 @@ import
org.apache.geode.internal.protocol.protobuf.v1.operations.GetRegionNamesR
import
org.apache.geode.internal.protocol.protobuf.v1.operations.GetRegionRequestOperationHandler;
import
org.apache.geode.internal.protocol.protobuf.v1.operations.GetRequestOperationHandler;
import
org.apache.geode.internal.protocol.protobuf.v1.operations.GetServerOperationHandler;
+import
org.apache.geode.internal.protocol.protobuf.v1.operations.OqlQueryRequestOperationHandler;
import
org.apache.geode.internal.protocol.protobuf.v1.operations.PutAllRequestOperationHandler;
import
org.apache.geode.internal.protocol.protobuf.v1.operations.PutRequestOperationHandler;
import
org.apache.geode.internal.protocol.protobuf.v1.operations.RemoveRequestOperationHandler;
import
org.apache.geode.internal.protocol.protobuf.v1.operations.security.AuthenticationRequestOperationHandler;
import org.apache.geode.management.internal.security.ResourcePermissions;
import org.apache.geode.security.ResourcePermission;
+import org.apache.geode.security.ResourcePermission.Operation;
+import org.apache.geode.security.ResourcePermission.Resource;
@Experimental
public class ProtobufOperationContextRegistry {
@@ -143,5 +147,10 @@ public class ProtobufOperationContextRegistry {
// Resource permissions get handled per-function, since they have
varying permission
// requirements.
this::skipAuthorizationCheck));
+ operationContexts.put(MessageTypeCase.OQLQUERYREQUEST,
+ new
ProtobufOperationContext<>(ClientProtocol.Message::getOqlQueryRequest,
+ new OqlQueryRequestOperationHandler(),
+ opsResp ->
ClientProtocol.Message.newBuilder().setOqlQueryResponse(opsResp),
+ new ResourcePermission(Resource.DATA, Operation.READ)));
}
}
diff --git
a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/serialization/exception/DecodingException.java
b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/serialization/exception/DecodingException.java
index 93cedff..47be69a 100644
---
a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/serialization/exception/DecodingException.java
+++
b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/serialization/exception/DecodingException.java
@@ -20,7 +20,7 @@ import org.apache.geode.annotations.Experimental;
* This indicates an encoding type that we don't know how to handle.
*/
@Experimental
-public class DecodingException extends Exception {
+public class DecodingException extends RuntimeException {
public DecodingException(String message) {
super(message);
}
diff --git
a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/serialization/exception/EncodingException.java
b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/serialization/exception/EncodingException.java
index 1c2c615..1f5091e 100644
---
a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/serialization/exception/EncodingException.java
+++
b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/serialization/exception/EncodingException.java
@@ -20,7 +20,7 @@ import org.apache.geode.annotations.Experimental;
* This indicates a Java object that we don't know how to handle.
*/
@Experimental
-public class EncodingException extends Exception {
+public class EncodingException extends RuntimeException {
public EncodingException(String message) {
super(message);
}
diff --git
a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OqlQueryRequestOperationHandlerIntegrationTest.java
b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OqlQueryRequestOperationHandlerIntegrationTest.java
new file mode 100644
index 0000000..85f04c2
--- /dev/null
+++
b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OqlQueryRequestOperationHandlerIntegrationTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.geode.internal.protocol.protobuf.v1.operations;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.cache.query.FunctionDomainException;
+import org.apache.geode.cache.query.NameResolutionException;
+import org.apache.geode.cache.query.QueryInvocationTargetException;
+import org.apache.geode.cache.query.TypeMismatchException;
+import org.apache.geode.cache.query.data.PortfolioPdx;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.exception.InvalidExecutionContextException;
+import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
+import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes.EncodedValue;
+import org.apache.geode.internal.protocol.protobuf.v1.MessageExecutionContext;
+import
org.apache.geode.internal.protocol.protobuf.v1.ProtobufSerializationService;
+import
org.apache.geode.internal.protocol.protobuf.v1.RegionAPI.OQLQueryRequest;
+import
org.apache.geode.internal.protocol.protobuf.v1.RegionAPI.OQLQueryResponse;
+import org.apache.geode.internal.protocol.protobuf.v1.Result;
+import
org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.DecodingException;
+import
org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.EncodingException;
+import
org.apache.geode.internal.protocol.protobuf.v1.state.exception.ConnectionStateException;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class OqlQueryRequestOperationHandlerIntegrationTest {
+ private Cache cache;
+
+ @Before
+ public void setUp() throws Exception {
+ cache = new CacheFactory().set(ConfigurationProperties.LOCATORS,
"").create();
+ Region region =
cache.createRegionFactory(RegionShortcut.LOCAL).create("region");
+
+ IntStream.range(0, 2).forEach(i -> region.put("key" + i, new
PortfolioPdx(i)));
+ }
+
+ @After
+ public void tearDown() {
+ cache.close();
+ }
+
+ @Test
+ public void queryForSingleObject() throws ConnectionStateException,
DecodingException,
+ InvalidExecutionContextException, EncodingException,
NameResolutionException,
+ TypeMismatchException, QueryInvocationTargetException,
FunctionDomainException {
+ checkResults("(select * from /region).size", 2);
+ }
+
+ @Test
+ public void queryForMultipleWholeObjects() throws ConnectionStateException,
DecodingException,
+ InvalidExecutionContextException, EncodingException,
NameResolutionException,
+ TypeMismatchException, QueryInvocationTargetException,
FunctionDomainException {
+ checkResults("select ID from /region order by ID", 0, 1);
+ }
+
+ @Test
+ public void queryForMultipleProjectionFields() throws
ConnectionStateException, DecodingException,
+ InvalidExecutionContextException, EncodingException,
NameResolutionException,
+ TypeMismatchException, QueryInvocationTargetException,
FunctionDomainException {
+ checkResults("select ID,status from /region order by ID", new
EncodedValue[] {},
+ new String[] {"ID", "status"}, new Object[] {0, "active"}, new
Object[] {1, "inactive"});
+ }
+
+ @Test
+ public void queryForSingleStruct() throws ConnectionStateException,
DecodingException,
+ InvalidExecutionContextException, EncodingException,
NameResolutionException,
+ TypeMismatchException, QueryInvocationTargetException,
FunctionDomainException {
+ checkResults("select count(*),min(ID) from /region", new EncodedValue[] {},
+ new String[] {"0", "ID"}, new Object[] {2, 0});
+ }
+
+ @Test
+ public void queryWithBindParameters() throws ConnectionStateException,
DecodingException,
+ InvalidExecutionContextException, EncodingException,
NameResolutionException,
+ TypeMismatchException, QueryInvocationTargetException,
FunctionDomainException {
+ checkResults("select ID,status from /region where ID=$1",
+ new EncodedValue[] {new ProtobufSerializationService().encode(0)},
+ new String[] {"ID", "status"}, new Object[] {0, "active"});
+ }
+
+ private void checkResults(final String query, final Object value)
+ throws InvalidExecutionContextException, ConnectionStateException,
EncodingException,
+ DecodingException {
+ ProtobufSerializationService serializer = new
ProtobufSerializationService();
+ final Result<OQLQueryResponse> results =
+ invokeHandler(query, new EncodedValue[] {}, serializer);
+
+ assertEquals(serializer.encode(value),
results.getMessage().getSingleResult());
+ }
+
+ private void checkResults(final String query, final Object... values)
+ throws InvalidExecutionContextException, ConnectionStateException,
EncodingException,
+ DecodingException {
+ ProtobufSerializationService serializer = new
ProtobufSerializationService();
+ final Result<OQLQueryResponse> results =
+ invokeHandler(query, new EncodedValue[] {}, serializer);
+
+ List<EncodedValue> expected =
+
Arrays.asList(values).stream().map(serializer::encode).collect(Collectors.toList());
+ assertEquals(expected,
results.getMessage().getListResult().getElementList());
+ }
+
+ private void checkResults(final String query, EncodedValue[] bindParameters,
String[] fieldnames,
+ final Object[]... rows) throws InvalidExecutionContextException,
ConnectionStateException,
+ EncodingException, DecodingException {
+ ProtobufSerializationService serializer = new
ProtobufSerializationService();
+ final Result<OQLQueryResponse> results = invokeHandler(query,
bindParameters, serializer);
+
+ List<BasicTypes.EncodedValueList> expected = new ArrayList<>();
+ for (Object[] row : rows) {
+ List<EncodedValue> encodedRow =
+
Arrays.asList(row).stream().map(serializer::encode).collect(Collectors.toList());
+
expected.add(BasicTypes.EncodedValueList.newBuilder().addAllElement(encodedRow).build());
+ }
+
+ assertEquals(expected, results.getMessage().getTableResult().getRowList());
+ assertEquals(Arrays.asList(fieldnames),
+ results.getMessage().getTableResult().getFieldNameList());
+ }
+
+ private Result<OQLQueryResponse> invokeHandler(String query, EncodedValue[]
bindParameters,
+ ProtobufSerializationService serializer) throws
InvalidExecutionContextException,
+ ConnectionStateException, EncodingException, DecodingException {
+ final MessageExecutionContext context =
mock(MessageExecutionContext.class);
+ when(context.getCache()).thenReturn((InternalCache) cache);
+ final OQLQueryRequest request =
OQLQueryRequest.newBuilder().setQuery(query)
+ .addAllBindParameter(Arrays.asList(bindParameters)).build();
+ Result<OQLQueryResponse> result =
+ new OqlQueryRequestOperationHandler().process(serializer, request,
context);
+
+ return result;
+ }
+}
diff --git
a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OqlQueryRequestOperationHandlerJUnitTest.java
b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OqlQueryRequestOperationHandlerJUnitTest.java
new file mode 100644
index 0000000..d0b4aaf
--- /dev/null
+++
b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OqlQueryRequestOperationHandlerJUnitTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.geode.internal.protocol.protobuf.v1.operations;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.query.FunctionDomainException;
+import org.apache.geode.cache.query.NameResolutionException;
+import org.apache.geode.cache.query.Query;
+import org.apache.geode.cache.query.QueryInvocationTargetException;
+import org.apache.geode.cache.query.SelectResults;
+import org.apache.geode.cache.query.TypeMismatchException;
+import org.apache.geode.cache.query.internal.InternalQueryService;
+import org.apache.geode.cache.query.internal.LinkedStructSet;
+import org.apache.geode.cache.query.internal.ResultsBag;
+import org.apache.geode.cache.query.internal.StructImpl;
+import org.apache.geode.cache.query.internal.types.ObjectTypeImpl;
+import org.apache.geode.cache.query.internal.types.StructTypeImpl;
+import org.apache.geode.internal.exception.InvalidExecutionContextException;
+import org.apache.geode.internal.protocol.TestExecutionContext;
+import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
+import
org.apache.geode.internal.protocol.protobuf.v1.ProtobufSerializationService;
+import
org.apache.geode.internal.protocol.protobuf.v1.RegionAPI.OQLQueryRequest;
+import
org.apache.geode.internal.protocol.protobuf.v1.RegionAPI.OQLQueryResponse;
+import org.apache.geode.internal.protocol.protobuf.v1.Result;
+import
org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.DecodingException;
+import
org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.EncodingException;
+import
org.apache.geode.internal.protocol.protobuf.v1.state.exception.ConnectionStateException;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class OqlQueryRequestOperationHandlerJUnitTest extends
OperationHandlerJUnitTest {
+
+ public static final String SELECT_STAR_QUERY = "select * from /region";
+ public static final String STRING_RESULT_1 = "result1";
+ public static final String STRING_RESULT_2 = "result2";
+ private InternalQueryService queryService;
+
+ @Before
+ public void setUp() throws Exception {
+ queryService = mock(InternalQueryService.class);
+ when(cacheStub.getQueryService()).thenReturn(queryService);
+ operationHandler = new OqlQueryRequestOperationHandler();
+ }
+
+ @Test
+ public void queryForSingleObject() throws ConnectionStateException,
DecodingException,
+ InvalidExecutionContextException, EncodingException,
NameResolutionException,
+ TypeMismatchException, QueryInvocationTargetException,
FunctionDomainException {
+ Query query = mock(Query.class);
+ when(queryService.newQuery(eq(SELECT_STAR_QUERY))).thenReturn(query);
+ when(query.execute((Object[]) any())).thenReturn(STRING_RESULT_1);
+ final OQLQueryRequest request =
+ OQLQueryRequest.newBuilder().setQuery(SELECT_STAR_QUERY).build();
+ final Result<OQLQueryResponse> result =
operationHandler.process(serializationService, request,
+ TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertEquals(serializationService.encode(STRING_RESULT_1),
+ result.getMessage().getSingleResult());
+ }
+
+ @Test
+ public void queryForMultipleObjects() throws ConnectionStateException,
DecodingException,
+ InvalidExecutionContextException, EncodingException,
NameResolutionException,
+ TypeMismatchException, QueryInvocationTargetException,
FunctionDomainException {
+ Query query = mock(Query.class);
+ when(queryService.newQuery(eq(SELECT_STAR_QUERY))).thenReturn(query);
+ SelectResults results = new ResultsBag();
+ results.setElementType(new ObjectTypeImpl());
+ results.add(STRING_RESULT_1);
+ results.add(STRING_RESULT_2);
+
+ when(query.execute((Object[]) any())).thenReturn(results);
+ final OQLQueryRequest request =
+ OQLQueryRequest.newBuilder().setQuery(SELECT_STAR_QUERY).build();
+ final Result<OQLQueryResponse> result =
operationHandler.process(serializationService, request,
+ TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertEquals(Arrays.asList(STRING_RESULT_1, STRING_RESULT_2),
+ result.getMessage().getListResult().getElementList().stream()
+ .map(serializationService::decode).collect(Collectors.toList()));
+ }
+
+ @Test
+ public void queryForMultipleStructs() throws ConnectionStateException,
DecodingException,
+ InvalidExecutionContextException, EncodingException,
NameResolutionException,
+ TypeMismatchException, QueryInvocationTargetException,
FunctionDomainException {
+ Query query = mock(Query.class);
+ when(queryService.newQuery(eq(SELECT_STAR_QUERY))).thenReturn(query);
+
+
+ SelectResults results = new LinkedStructSet();
+ StructTypeImpl elementType = new StructTypeImpl(new String[] {"field1"});
+ results.setElementType(elementType);
+ results.add(new StructImpl(elementType, new Object[] {STRING_RESULT_1}));
+ results.add(new StructImpl(elementType, new Object[] {STRING_RESULT_2}));
+
+ when(query.execute((Object[]) any())).thenReturn(results);
+
+ final OQLQueryRequest request =
+ OQLQueryRequest.newBuilder().setQuery(SELECT_STAR_QUERY).build();
+
+ final Result<OQLQueryResponse> result =
operationHandler.process(serializationService, request,
+ TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
+
+ assertEquals(
+ Arrays.asList(
+ BasicTypes.EncodedValueList.newBuilder()
+
.addElement(serializationService.encode(STRING_RESULT_1)).build(),
+ BasicTypes.EncodedValueList.newBuilder()
+
.addElement(serializationService.encode(STRING_RESULT_2)).build()),
+ result.getMessage().getTableResult().getRowList());
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
[email protected].