From 4063fc78abbd6f0de7988a61b885dc064fccc358 Mon Sep 17 00:00:00 2001 From: Belonogov Nikolay Date: Tue, 5 Sep 2023 15:18:07 +0300 Subject: [PATCH] Added "mode" option for crud select operation Needed for #107 --- CHANGELOG.md | 3 + .../options/OperationWithModeOptions.java | 38 ++++++++++ .../api/space/options/SelectOptions.java | 3 +- .../driver/core/proxy/CRUDSelectOptions.java | 8 +++ .../core/proxy/SelectProxyOperation.java | 3 +- .../proxy/ProxyOperationBuildersTest.java | 5 +- .../options/ProxySpaceSelectOptionsIT.java | 72 ++++++++++--------- 7 files changed, 94 insertions(+), 38 deletions(-) create mode 100644 src/main/java/io/tarantool/driver/api/space/options/OperationWithModeOptions.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 89c0ffa7f..ae32068d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [Unreleased] +### API changes +- Add "mode" option for crud select operation ([#107](https://github.com/tarantool/cartridge-java/issues/107)) + ### Bugfixes - Fix Instant converter to parse 8 bytes datetime ([#408](https://github.com/tarantool/cartridge-java/issues/408)) diff --git a/src/main/java/io/tarantool/driver/api/space/options/OperationWithModeOptions.java b/src/main/java/io/tarantool/driver/api/space/options/OperationWithModeOptions.java new file mode 100644 index 000000000..70255474a --- /dev/null +++ b/src/main/java/io/tarantool/driver/api/space/options/OperationWithModeOptions.java @@ -0,0 +1,38 @@ +package io.tarantool.driver.api.space.options; + +import java.util.Optional; + +/** + * Base interface for all operation options that may have a configurable mode. + * + * @author Belonogov Nikolay + */ +public interface OperationWithModeOptions> extends Options, Self { + String MODE = "mode"; + + /** + * Specifies the mode for operations (select, count, get) on a specific node type (mode == "write" - master, mode + * == "read" - replica). By default, mode is "read". + * + * @param mode mode for operations (select, get, count). + * @return this options instance. + */ + default T withMode(String mode) { + if (!mode.equals("read") && !mode.equals("write")) { + throw new IllegalArgumentException("Mode should be \"read\" or \"write\""); + } + + addOption(MODE, mode); + return self(); + } + + /** + * Return operation mode. + * + * @return mode. + */ + default Optional getMode() { + return getOption(MODE, String.class); + } + +} diff --git a/src/main/java/io/tarantool/driver/api/space/options/SelectOptions.java b/src/main/java/io/tarantool/driver/api/space/options/SelectOptions.java index 90efd9f1a..ddcf6adc6 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/SelectOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/SelectOptions.java @@ -9,7 +9,8 @@ * @author Alexey Kuzin */ public interface SelectOptions> - extends OperationWithBucketIdOptions, OperationWithTimeoutOptions, OperationWithFieldsOptions { + extends OperationWithBucketIdOptions, OperationWithTimeoutOptions, OperationWithFieldsOptions, + OperationWithModeOptions { /** * Return the internal size of batch for transferring data between * storage and router nodes. diff --git a/src/main/java/io/tarantool/driver/core/proxy/CRUDSelectOptions.java b/src/main/java/io/tarantool/driver/core/proxy/CRUDSelectOptions.java index 4f57407ba..677c39ed6 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/CRUDSelectOptions.java +++ b/src/main/java/io/tarantool/driver/core/proxy/CRUDSelectOptions.java @@ -20,6 +20,7 @@ final class CRUDSelectOptions extends CRUDBucketIdOptions { public static final String SELECT_AFTER = "after"; public static final String SELECT_BATCH_SIZE = "batch_size"; public static final String FIELDS = "fields"; + public static final String MODE = "mode"; private > CRUDSelectOptions(AbstractBuilder builder) { super(builder); @@ -28,6 +29,7 @@ private > CRUDSelectOptions(AbstractBuilder buil addOption(SELECT_AFTER, builder.after); addOption(SELECT_BATCH_SIZE, builder.selectBatchSize); addOption(FIELDS, builder.fields); + addOption(MODE, builder.mode); } /** @@ -41,6 +43,7 @@ protected abstract static class AbstractBuilder> private Optional after = Optional.empty(); private Optional selectBatchSize = Optional.empty(); private Optional fields = Optional.empty(); + private Optional mode = Optional.empty(); public B withSelectLimit(Optional selectLimit) { this.selectLimit = selectLimit; @@ -61,6 +64,11 @@ public B withFields(Optional fields) { this.fields = fields; return self(); } + + public B withMode(Optional mode) { + this.mode = mode; + return self(); + } } /** diff --git a/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java index d201afd98..a3991f7ac 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java @@ -62,7 +62,8 @@ public SelectProxyOperation build() { .withSelectLimit(Optional.of(conditions.getLimit())) .withSelectAfter(Optional.ofNullable(conditions.getStartTuple())) .withBucketId(options.getBucketId()) - .withFields(options.getFields()); + .withFields(options.getFields()) + .withMode(options.getMode()); List arguments = Arrays.asList( spaceName, diff --git a/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java b/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java index 3f8cbb456..b26395e35 100644 --- a/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java +++ b/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java @@ -24,7 +24,6 @@ import io.tarantool.driver.mappers.TarantoolTupleResultMapperFactory; import io.tarantool.driver.mappers.TarantoolTupleResultMapperFactoryImpl; import io.tarantool.driver.mappers.factories.DefaultMessagePackMapperFactory; -import io.tarantool.driver.mappers.factories.ResultMapperFactoryFactoryImpl; import io.tarantool.driver.protocol.TarantoolIndexQuery; import org.junit.jupiter.api.Test; @@ -42,13 +41,13 @@ public class ProxyOperationBuildersTest { private static final ClusterTarantoolTupleClient client = new ClusterTarantoolTupleClient(); private final MessagePackMapper defaultMapper = DefaultMessagePackMapperFactory.getInstance().defaultComplexTypesMapper(); + private final TarantoolTupleFactory factory = new DefaultTarantoolTupleFactory(defaultMapper); TarantoolTupleResultMapperFactory tarantoolTupleResultMapperFactory = TarantoolTupleResultMapperFactoryImpl.getInstance(); private final CallResultMapper, SingleValueCallResult>> defaultResultMapper = tarantoolTupleResultMapperFactory .withSingleValueArrayToTarantoolTupleResultMapper(defaultMapper, null); - private final TarantoolTupleFactory factory = new DefaultTarantoolTupleFactory(defaultMapper); @Test public void deleteOperationBuilderTest() { @@ -221,6 +220,7 @@ public void selectOperationBuilderTest() { .withOptions(ProxySelectOptions.create() .withTimeout(client.getConfig().getRequestTimeout()) .withBatchSize(123456) + .withMode("write") ) .build(); @@ -228,6 +228,7 @@ public void selectOperationBuilderTest() { options.put(CRUDBaseOptions.TIMEOUT, client.getConfig().getRequestTimeout()); options.put(CRUDSelectOptions.SELECT_BATCH_SIZE, 123456); options.put(CRUDSelectOptions.SELECT_LIMIT, 100L); + options.put(CRUDSelectOptions.MODE, "write"); assertEquals(client, op.getClient()); assertEquals("function1", op.getFunctionName()); diff --git a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceSelectOptionsIT.java b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceSelectOptionsIT.java index 7b5a03392..56431c78e 100644 --- a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceSelectOptionsIT.java +++ b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceSelectOptionsIT.java @@ -5,8 +5,8 @@ import io.tarantool.driver.api.TarantoolResult; import io.tarantool.driver.api.conditions.Conditions; import io.tarantool.driver.api.space.TarantoolSpaceOperations; -import io.tarantool.driver.api.space.options.proxy.ProxySelectOptions; import io.tarantool.driver.api.space.options.SelectOptions; +import io.tarantool.driver.api.space.options.proxy.ProxySelectOptions; import io.tarantool.driver.api.tuple.DefaultTarantoolTupleFactory; import io.tarantool.driver.api.tuple.TarantoolTuple; import io.tarantool.driver.api.tuple.TarantoolTupleFactory; @@ -24,25 +24,21 @@ import java.util.List; import java.util.concurrent.ExecutionException; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.*; /** * @author Artyom Dubinin */ public class ProxySpaceSelectOptionsIT extends SharedCartridgeContainer { - private static TarantoolClient> client; private static final DefaultMessagePackMapperFactory mapperFactory = DefaultMessagePackMapperFactory.getInstance(); private static final TarantoolTupleFactory tupleFactory = new DefaultTarantoolTupleFactory(mapperFactory.defaultComplexTypesMapper()); - - public static String USER_NAME; - public static String PASSWORD; - private static final String TEST_SPACE_NAME = "test__profile"; private static final String PK_FIELD_NAME = "profile_id"; + public static String USER_NAME; + public static String PASSWORD; + private static TarantoolClient> client; @BeforeAll public static void setUp() throws Exception { @@ -53,26 +49,24 @@ public static void setUp() throws Exception { } private static void initClient() { - TarantoolClientConfig config = TarantoolClientConfig.builder() - .withCredentials(new SimpleTarantoolCredentials(USER_NAME, PASSWORD)) - .withConnectTimeout(1000) - .withReadTimeout(1000) - .build(); - - ClusterTarantoolTupleClient clusterClient = new ClusterTarantoolTupleClient( - config, container.getRouterHost(), container.getRouterPort()); + TarantoolClientConfig config = + TarantoolClientConfig.builder().withCredentials(new SimpleTarantoolCredentials(USER_NAME, PASSWORD)) + .withConnectTimeout(1000).withReadTimeout(1000).build(); + + ClusterTarantoolTupleClient clusterClient = + new ClusterTarantoolTupleClient(config, container.getRouterHost(), container.getRouterPort()); client = new ProxyTarantoolTupleClient(clusterClient); } + private static void truncateSpace(String spaceName) { + client.space(spaceName).truncate().join(); + } + @BeforeEach public void truncateSpace() { truncateSpace(TEST_SPACE_NAME); } - private static void truncateSpace(String spaceName) { - client.space(spaceName).truncate().join(); - } - @Test public void withBatchSizeTest() throws ExecutionException, InterruptedException { TarantoolSpaceOperations> profileSpace = @@ -94,10 +88,7 @@ public void withBatchSizeTest() throws ExecutionException, InterruptedException assertNull(((HashMap) crudSelectOpts.get(0)).get("batch_size")); // with batchSize - selectResult = profileSpace.select( - conditions, - ProxySelectOptions.create().withBatchSize(5) - ).get(); + selectResult = profileSpace.select(conditions, ProxySelectOptions.create().withBatchSize(5)).get(); assertEquals(10, selectResult.size()); crudSelectOpts = client.eval("return crud_select_opts").get(); assertEquals(5, ((HashMap) crudSelectOpts.get(0)).get("batch_size")); @@ -116,18 +107,12 @@ public void withTimeout() throws ExecutionException, InterruptedException { List crudSelectOpts = client.eval("return crud_select_opts").get(); assertNull(((HashMap) crudSelectOpts.get(0)).get("timeout")); - profileSpace.select( - Conditions.any(), - ProxySelectOptions.create() - ).get(); + profileSpace.select(Conditions.any(), ProxySelectOptions.create()).get(); crudSelectOpts = client.eval("return crud_select_opts").get(); assertNull(((HashMap) crudSelectOpts.get(0)).get("timeout")); // with option timeout - profileSpace.select( - Conditions.any(), - ProxySelectOptions.create().withTimeout(customRequestTimeout) - ).get(); + profileSpace.select(Conditions.any(), ProxySelectOptions.create().withTimeout(customRequestTimeout)).get(); crudSelectOpts = client.eval("return crud_select_opts").get(); assertEquals(customRequestTimeout, ((HashMap) crudSelectOpts.get(0)).get("timeout")); } @@ -135,7 +120,7 @@ public void withTimeout() throws ExecutionException, InterruptedException { @Test public void withFieldsTest() throws ExecutionException, InterruptedException { TarantoolSpaceOperations> profileSpace = - client.space(TEST_SPACE_NAME); + client.space(TEST_SPACE_NAME); TarantoolTuple tarantoolTuple; @@ -167,4 +152,23 @@ public void withFieldsTest() throws ExecutionException, InterruptedException { assertEquals(1, tuple.getInteger("profile_id")); assertEquals(50, tuple.getInteger("age")); } + + @Test + public void withMode() throws ExecutionException, InterruptedException { + TarantoolSpaceOperations> operations = + client.space(TEST_SPACE_NAME); + + operations.select(Conditions.any()).get(); + List crudSelectOpts = client.eval("return crud_select_opts").get(); + assertNull(((HashMap) crudSelectOpts.get(0)).get("mode")); + + int customTimeout = 2000; + operations.select(Conditions.any(), ProxySelectOptions.create().withTimeout(customTimeout)).get(); + crudSelectOpts = client.eval("return crud_select_opts").get(); + assertNull(((HashMap) crudSelectOpts.get(0)).get("mode")); + + operations.select(Conditions.any(), ProxySelectOptions.create().withMode("write")).get(); + crudSelectOpts = client.eval("return crud_select_opts").get(); + assertEquals("write", ((HashMap) crudSelectOpts.get(0)).get("mode")); + } }