From 1445056d46c765d71a4ef2275facab06149e2bb5 Mon Sep 17 00:00:00 2001 From: Alexey Kuzin Date: Tue, 13 Sep 2022 16:50:36 -0400 Subject: [PATCH 1/2] Add options for batch CRUD operations --- .../proxy/CRUDAbstractOperationOptions.java | 2 +- .../driver/core/proxy/CRUDBatchOptions.java | 61 +++++++++++++++++++ .../core/proxy/CRUDOperationOptionsTest.java | 12 ++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/tarantool/driver/core/proxy/CRUDBatchOptions.java diff --git a/src/main/java/io/tarantool/driver/core/proxy/CRUDAbstractOperationOptions.java b/src/main/java/io/tarantool/driver/core/proxy/CRUDAbstractOperationOptions.java index 6b419c4d..c6148876 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/CRUDAbstractOperationOptions.java +++ b/src/main/java/io/tarantool/driver/core/proxy/CRUDAbstractOperationOptions.java @@ -16,7 +16,7 @@ abstract class CRUDAbstractOperationOptions { private final Map resultMap = new HashMap<>(); /** - * Inheritable Builder for select cluster proxy operation options. + * Inheritable Builder for cluster proxy operation options. *

* This abstract class is necessary for implementing fluent builder inheritance. * The solution with {@code self()} method allows to avoid weird java diff --git a/src/main/java/io/tarantool/driver/core/proxy/CRUDBatchOptions.java b/src/main/java/io/tarantool/driver/core/proxy/CRUDBatchOptions.java new file mode 100644 index 00000000..3e810469 --- /dev/null +++ b/src/main/java/io/tarantool/driver/core/proxy/CRUDBatchOptions.java @@ -0,0 +1,61 @@ +package io.tarantool.driver.core.proxy; + +import java.util.Map; + +/** + * This class is not part of the public API. + * + * Represent options for proxy cluster batch operations + * + * @author Alexey Kuzin + */ +public final class CRUDBatchOptions extends CRUDBaseOptions { + + public static final String BATCH_STOP_ON_ERROR = "stop_on_error"; + public static final String BATCH_ROLLBACK_ON_ERROR = "rollback_on_error"; + + protected + > + CRUDBatchOptions(AbstractBuilder builder) { + super(builder); + + if (builder.stopOnError != null) { + addOption(BATCH_STOP_ON_ERROR, builder.stopOnError); + } + + if (builder.rollbackOnError != null) { + addOption(BATCH_ROLLBACK_ON_ERROR, builder.rollbackOnError); + } + } + + protected abstract static + class AbstractBuilder> + extends CRUDBaseOptions.AbstractBuilder { + private Boolean stopOnError; + private Boolean rollbackOnError; + + public T withStopOnError(Boolean stopOnError) { + this.stopOnError = stopOnError; + return self(); + } + + public T withRollbackOnError(Boolean rollbackOnError) { + this.rollbackOnError = rollbackOnError; + return self(); + } + } + + protected static final class Builder + extends AbstractBuilder { + + @Override + Builder self() { + return this; + } + + @Override + public CRUDBatchOptions build() { + return new CRUDBatchOptions(this); + } + } +} diff --git a/src/test/java/io/tarantool/driver/core/proxy/CRUDOperationOptionsTest.java b/src/test/java/io/tarantool/driver/core/proxy/CRUDOperationOptionsTest.java index 96a669a9..8c21c5a7 100644 --- a/src/test/java/io/tarantool/driver/core/proxy/CRUDOperationOptionsTest.java +++ b/src/test/java/io/tarantool/driver/core/proxy/CRUDOperationOptionsTest.java @@ -53,4 +53,16 @@ public void baseOperationOptions_createNotEmptyTest() { assertEquals(1, options.asMap().size()); assertEquals(1000, options.asMap().get(CRUDBaseOptions.TIMEOUT)); } + + @Test + public void batchOperationOptions_createNotEmptyTest() { + CRUDBatchOptions options = new CRUDBatchOptions.Builder() + .withStopOnError(false) + .withRollbackOnError(true) + .build(); + + assertEquals(2, options.asMap().size()); + assertEquals(false, options.asMap().get(CRUDBatchOptions.BATCH_STOP_ON_ERROR)); + assertEquals(true, options.asMap().get(CRUDBatchOptions.BATCH_ROLLBACK_ON_ERROR)); + } } From eef114ea57498820d382219aa298218954986a86 Mon Sep 17 00:00:00 2001 From: Alexey Kuzin Date: Wed, 14 Sep 2022 18:36:27 -0400 Subject: [PATCH 2/2] Support insert_many and replace_many CRUD operations --- CHANGELOG.md | 5 +- .../proxy/ProxyOperationsMappingConfig.java | 57 ++++++- .../api/space/TarantoolSpaceOperations.java | 66 +++++++- .../api/space/options/AbstractOptions.java | 23 ++- .../api/space/options/DeleteOptions.java | 4 +- .../api/space/options/InsertManyOptions.java | 26 ++++ .../api/space/options/InsertOptions.java | 4 +- .../options/OperationWithTimeoutOptions.java | 17 +++ .../driver/api/space/options/Options.java | 12 +- .../api/space/options/ReplaceManyOptions.java | 26 ++++ .../api/space/options/ReplaceOptions.java | 4 +- .../api/space/options/SelectOptions.java | 13 +- .../api/space/options/UpdateOptions.java | 4 +- .../api/space/options/UpsertOptions.java | 4 +- .../space/options/proxy/ProxyBaseOptions.java | 21 ++- .../options/proxy/ProxyDeleteOptions.java | 3 + .../options/proxy/ProxyInsertManyOptions.java | 66 ++++++++ .../options/proxy/ProxyInsertOptions.java | 3 + .../proxy/ProxyReplaceManyOptions.java | 66 ++++++++ .../options/proxy/ProxyReplaceOptions.java | 3 + .../options/proxy/ProxySelectOptions.java | 18 ++- .../options/proxy/ProxyTruncateOptions.java | 24 +++ .../options/proxy/ProxyUpdateOptions.java | 3 + .../options/proxy/ProxyUpsertOptions.java | 3 + .../core/proxy/AbstractProxyOperation.java | 19 +-- .../proxy/CRUDAbstractOperationOptions.java | 7 +- .../driver/core/proxy/CRUDBaseOptions.java | 23 +-- .../driver/core/proxy/CRUDBatchOptions.java | 30 ++-- .../driver/core/proxy/CRUDSelectOptions.java | 46 ++---- .../core/proxy/DeleteProxyOperation.java | 7 +- .../core/proxy/InsertManyProxyOperation.java | 69 +++++++++ .../core/proxy/InsertProxyOperation.java | 6 +- .../driver/core/proxy/ProxyOperation.java | 6 +- .../core/proxy/ReplaceManyProxyOperation.java | 69 +++++++++ .../core/proxy/ReplaceProxyOperation.java | 6 +- .../core/proxy/SelectProxyOperation.java | 14 +- .../core/proxy/TruncateProxyOperation.java | 11 +- .../core/proxy/UpdateProxyOperation.java | 7 +- .../core/proxy/UpsertProxyOperation.java | 6 +- .../core/space/ProxyTarantoolSpace.java | 143 ++++++++++++++++-- .../core/space/RetryingTarantoolSpace.java | 25 +++ .../driver/core/space/TarantoolSpace.java | 16 ++ .../core/proxy/CRUDOperationOptionsTest.java | 17 ++- .../proxy/ProxyOperationBuildersTest.java | 121 +++++++++++++-- .../ClusterTarantoolTupleClientIT.java | 18 +++ .../integration/ProxyTarantoolClientIT.java | 73 +++++++++ .../options/ProxySpaceDeleteOptionsIT.java | 10 +- .../ProxySpaceInsertManyOptionsIT.java | 136 +++++++++++++++++ .../ProxySpaceReplaceManyOptionsIT.java | 126 +++++++++++++++ .../options/ProxySpaceReplaceOptionsIT.java | 1 - .../options/ProxySpaceSelectOptionsIT.java | 7 +- .../options/ProxySpaceUpsertOptionsIT.java | 10 +- .../cartridge/app/roles/api_router.lua | 2 + .../cartridge/testapp-scm-1.rockspec | 2 +- 54 files changed, 1308 insertions(+), 200 deletions(-) create mode 100644 src/main/java/io/tarantool/driver/api/space/options/InsertManyOptions.java create mode 100644 src/main/java/io/tarantool/driver/api/space/options/OperationWithTimeoutOptions.java create mode 100644 src/main/java/io/tarantool/driver/api/space/options/ReplaceManyOptions.java create mode 100644 src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyInsertManyOptions.java create mode 100644 src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyReplaceManyOptions.java create mode 100644 src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyTruncateOptions.java create mode 100644 src/main/java/io/tarantool/driver/core/proxy/InsertManyProxyOperation.java create mode 100644 src/main/java/io/tarantool/driver/core/proxy/ReplaceManyProxyOperation.java create mode 100644 src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceInsertManyOptionsIT.java create mode 100644 src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceReplaceManyOptionsIT.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b7eac90..bfcd4cd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,15 @@ ### Features - Added options parameter to Tarantool Space API ([#266](https://github.com/tarantool/cartridge-java/pull/266)) +- Added support for insert_many and replace_many CRUD operations ([#259](https://github.com/tarantool/cartridge-java/issues/259)) ## [0.8.2] - 2022-09-16 ### Features -- Removed code duplication in *ProxyOperations builders ([#256](https://github.com/tarantool/cartridge-java/issues/256)) - Added client EventLoopThreadsNumber property for control netty work threads ([#253](https://github.com/tarantool/cartridge-java/pull/253)) + +### Misc +- Removed code duplication in *ProxyOperations builders ([#256](https://github.com/tarantool/cartridge-java/issues/256)) - Refactor CRUDOperationOptions to a hierarchy of classes ([#258](https://github.com/tarantool/cartridge-java/issues/258)) ## [0.8.1] - 2022-08-18 diff --git a/src/main/java/io/tarantool/driver/api/proxy/ProxyOperationsMappingConfig.java b/src/main/java/io/tarantool/driver/api/proxy/ProxyOperationsMappingConfig.java index 26826b66..2c540bd0 100644 --- a/src/main/java/io/tarantool/driver/api/proxy/ProxyOperationsMappingConfig.java +++ b/src/main/java/io/tarantool/driver/api/proxy/ProxyOperationsMappingConfig.java @@ -12,7 +12,9 @@ public final class ProxyOperationsMappingConfig { public static final String SCHEMA_FUNCTION = "ddl.get_schema"; public static final String DELETE_FUNCTION = CRUD_PREFIX + "delete"; public static final String INSERT_FUNCTION = CRUD_PREFIX + "insert"; + public static final String INSERT_MANY_FUNCTION = CRUD_PREFIX + "insert_many"; public static final String REPLACE_FUNCTION = CRUD_PREFIX + "replace"; + public static final String REPLACE_MANY_FUNCTION = CRUD_PREFIX + "replace_many"; public static final String SELECT_FUNCTION = CRUD_PREFIX + "select"; public static final String UPDATE_FUNCTION = CRUD_PREFIX + "update"; public static final String UPSERT_FUNCTION = CRUD_PREFIX + "upsert"; @@ -21,7 +23,9 @@ public final class ProxyOperationsMappingConfig { private final String schemaFunctionName; private final String deleteFunctionName; private final String insertFunctionName; + private final String insertManyFunctionName; private final String replaceFunctionName; + private final String replaceManyFunctionName; private final String updateFunctionName; private final String upsertFunctionName; private final String selectFunctionName; @@ -58,6 +62,16 @@ public String getInsertFunctionName() { return insertFunctionName; } + /** + * Get API function name for performing the insert_many operation. + * The default value is crud.insert_many. + * + * @return a callable API function name + */ + public String getInsertManyFunctionName() { + return insertManyFunctionName; + } + /** * Get API function name for performing the replace operation. The default value is crud.replace. * @@ -67,6 +81,16 @@ public String getReplaceFunctionName() { return replaceFunctionName; } + /** + * Get API function name for performing the replace_many operation. + * The default value is crud.replace_many. + * + * @return a callable API function name + */ + public String getReplaceManyFunctionName() { + return replaceManyFunctionName; + } + /** * Get API function name for performing the update operation. The default value is crud.update. * @@ -104,13 +128,16 @@ public String getTruncateFunctionName() { } private ProxyOperationsMappingConfig(String schemaFunctionName, String deleteFunctionName, - String insertFunctionName, String replaceFunctionName, + String insertFunctionName, String insertManyFunctionName, + String replaceFunctionName, String replaceManyFunctionName, String updateFunctionName, String upsertFunctionName, String selectFunctionName, String truncateFunctionName) { this.schemaFunctionName = schemaFunctionName; this.deleteFunctionName = deleteFunctionName; this.insertFunctionName = insertFunctionName; + this.insertManyFunctionName = insertManyFunctionName; this.replaceFunctionName = replaceFunctionName; + this.replaceManyFunctionName = replaceManyFunctionName; this.updateFunctionName = updateFunctionName; this.upsertFunctionName = upsertFunctionName; this.selectFunctionName = selectFunctionName; @@ -134,7 +161,9 @@ public static final class Builder { private String schemaFunctionName = SCHEMA_FUNCTION; private String deleteFunctionName = DELETE_FUNCTION; private String insertFunctionName = INSERT_FUNCTION; + private String insertManyFunctionName = INSERT_MANY_FUNCTION; private String replaceFunctionName = REPLACE_FUNCTION; + private String replaceManyFunctionName = REPLACE_MANY_FUNCTION; private String updateFunctionName = UPDATE_FUNCTION; private String upsertFunctionName = UPSERT_FUNCTION; private String selectFunctionName = SELECT_FUNCTION; @@ -176,6 +205,17 @@ public Builder withInsertFunctionName(String insertFunctionName) { return this; } + /** + * Get API function name for performing the insert_many operation + * + * @param insertManyFunctionName name for stored function performing insert_many operation + * @return a callable API function name + */ + public Builder withInsertManyFunctionName(String insertManyFunctionName) { + this.insertManyFunctionName = insertManyFunctionName; + return this; + } + /** * Get API function name for performing the replace operation * @@ -187,6 +227,17 @@ public Builder withReplaceFunctionName(String replaceFunctionName) { return this; } + /** + * Get API function name for performing the replace_many operation + * + * @param replaceManyFunctionName name for stored function performing replace_many operation + * @return a callable API function name + */ + public Builder withReplaceManyFunctionName(String replaceManyFunctionName) { + this.replaceManyFunctionName = replaceManyFunctionName; + return this; + } + /** * Get API function name for performing the update operation * @@ -238,8 +289,8 @@ public Builder withTruncateFunctionName(String truncateFunctionName) { */ public ProxyOperationsMappingConfig build() { return new ProxyOperationsMappingConfig(schemaFunctionName, deleteFunctionName, insertFunctionName, - replaceFunctionName, updateFunctionName, upsertFunctionName, selectFunctionName, - truncateFunctionName); + insertManyFunctionName, replaceFunctionName, replaceManyFunctionName, updateFunctionName, + upsertFunctionName, selectFunctionName, truncateFunctionName); } } } diff --git a/src/main/java/io/tarantool/driver/api/space/TarantoolSpaceOperations.java b/src/main/java/io/tarantool/driver/api/space/TarantoolSpaceOperations.java index 1f09d550..316d5d96 100644 --- a/src/main/java/io/tarantool/driver/api/space/TarantoolSpaceOperations.java +++ b/src/main/java/io/tarantool/driver/api/space/TarantoolSpaceOperations.java @@ -4,7 +4,9 @@ import io.tarantool.driver.api.cursor.TarantoolCursor; import io.tarantool.driver.api.metadata.TarantoolSpaceMetadata; import io.tarantool.driver.api.space.options.DeleteOptions; +import io.tarantool.driver.api.space.options.InsertManyOptions; import io.tarantool.driver.api.space.options.InsertOptions; +import io.tarantool.driver.api.space.options.ReplaceManyOptions; import io.tarantool.driver.api.space.options.ReplaceOptions; import io.tarantool.driver.api.space.options.SelectOptions; import io.tarantool.driver.api.space.options.UpdateOptions; @@ -38,7 +40,7 @@ public interface TarantoolSpaceOperations delete(Conditions conditions, DeleteOptions options * Inserts tuple into the space, if no tuple with same unique keys exists. Otherwise throw duplicate key error. * * @param tuple new data - * @param options specified options + * @param options operation options * @return a future that will contain all corresponding tuples once completed * @throws TarantoolClientException in case if request failed */ @@ -67,6 +69,30 @@ default CompletableFuture insert(T tuple, InsertOptions options) throws Taran return insert(tuple); } + /** + * Inserts several tuples into the space at once. If writing of any tuple fails, + * all tuples will not be saved. + * + * @param tuples new data + * @return a future that will contain all corresponding tuples once completed + * @throws TarantoolClientException in case if request failed + */ + CompletableFuture insertMany(Collection tuples) throws TarantoolClientException; + + /** + * Inserts several tuples into the space at once. If writing of any tuple fails, + * all tuples will not be saved. + * + * @param tuples new data + * @param options operation options + * @return a future that will contain all corresponding tuples once completed + * @throws TarantoolClientException in case if request failed + */ + default CompletableFuture insertMany(Collection tuples, InsertManyOptions options) + throws TarantoolClientException { + return insertMany(tuples); + } + /** * Insert a tuple into the space or replace an existing one. * @@ -80,7 +106,7 @@ default CompletableFuture insert(T tuple, InsertOptions options) throws Taran * Insert a tuple into the space or replace an existing one. * * @param tuple new data - * @param options specified options + * @param options operation options * @return a future that will contain all corresponding tuples once completed * @throws TarantoolClientException in case if request failed */ @@ -89,7 +115,31 @@ default CompletableFuture replace(T tuple, ReplaceOptions options) throws Tar } /** - * Select tuples matching the specified query with specified conditions. + * Insert or replace several tuples into the space at once. If writing of any tuple fails, + * all tuples will not be saved. + * + * @param tuples new data + * @return a future that will contain all corresponding tuples once completed + * @throws TarantoolClientException in case if request failed + */ + CompletableFuture replaceMany(Collection tuples) throws TarantoolClientException; + + /** + * Insert or replace several tuples into the space at once. If writing of any tuple fails, + * all tuples will not be saved, but this behavior can be changed with the options. + * + * @param tuples new data + * @param options operation options + * @return a future that will contain all corresponding tuples once completed + * @throws TarantoolClientException in case if request failed + */ + default CompletableFuture replaceMany(Collection tuples, ReplaceManyOptions options) + throws TarantoolClientException { + return replaceMany(tuples); + } + + /** + * Select tuples matching the specified query with options. * * @param conditions query with options * @return a future that will contain all corresponding tuples once completed @@ -101,7 +151,7 @@ default CompletableFuture replace(T tuple, ReplaceOptions options) throws Tar * Select tuples matching the specified query with specified conditions and options. * * @param conditions specified conditions - * @param options specified options + * @param options operation options * @return a future that will contain all corresponding tuples once completed * @throws TarantoolClientException in case if the request failed */ @@ -124,7 +174,7 @@ default CompletableFuture select(Conditions conditions, SelectOptions options * * @param conditions query with options * @param tuple tuple with new field values - * @param options specified options + * @param options operation options * @return a future that will contain corresponding tuple once completed * @throws TarantoolClientException in case if the request failed */ @@ -147,7 +197,7 @@ default CompletableFuture update(Conditions conditions, T tuple, UpdateOption * * @param conditions query with options * @param operations the list update operations - * @param options specified options + * @param options operation options * @return a future that will contain corresponding tuple once completed * @throws TarantoolClientException in case if the request failed */ @@ -174,7 +224,7 @@ default CompletableFuture update(Conditions conditions, TupleOperations opera * @param conditions query with options * @param tuple new data that will be insert if tuple will be not found * @param operations the list of update operations to be performed if the tuple exists - * @param options specified options + * @param options operation options * @return a future that will empty list * @throws TarantoolClientException in case if the request failed */ diff --git a/src/main/java/io/tarantool/driver/api/space/options/AbstractOptions.java b/src/main/java/io/tarantool/driver/api/space/options/AbstractOptions.java index bed58419..9d13136b 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/AbstractOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/AbstractOptions.java @@ -2,12 +2,10 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; /** - * Public API for space operations. - * - * An abstract class necessary for implementing CRT (curiously recurring template) - * pattern for the cluster proxy operation options. + * An abstract class-container for all operation options. * * @author Alexey Kuzin * @author Artyom Dubinin @@ -18,11 +16,24 @@ public abstract class AbstractOptions> implements O protected abstract B self(); + /** + * Add an option value. + * + * @param option option name + * @param value option value + */ public void addOption(String option, Object value) { resultMap.put(option, value); } - public Map asMap() { - return resultMap; + /** + * Get an option value. + * + * @param option option name + * @param optionClass option value type + */ + @SuppressWarnings("unchecked") + public Optional getOption(String option, Class optionClass) { + return Optional.ofNullable((T) resultMap.get(option)); } } diff --git a/src/main/java/io/tarantool/driver/api/space/options/DeleteOptions.java b/src/main/java/io/tarantool/driver/api/space/options/DeleteOptions.java index 1b5f0720..0c6259f1 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/DeleteOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/DeleteOptions.java @@ -1,10 +1,10 @@ package io.tarantool.driver.api.space.options; /** - * Marker interface for space delete options + * Marker interface for space delete operation options * * @author Artyom Dubinin * @author Alexey Kuzin */ -public interface DeleteOptions extends Options { +public interface DeleteOptions extends OperationWithTimeoutOptions { } diff --git a/src/main/java/io/tarantool/driver/api/space/options/InsertManyOptions.java b/src/main/java/io/tarantool/driver/api/space/options/InsertManyOptions.java new file mode 100644 index 00000000..a73bdab3 --- /dev/null +++ b/src/main/java/io/tarantool/driver/api/space/options/InsertManyOptions.java @@ -0,0 +1,26 @@ +package io.tarantool.driver.api.space.options; + +import java.util.Optional; + +/** + * Marker interface for space insert_many operation options + * + * @author Alexey Kuzin + */ +public interface InsertManyOptions extends OperationWithTimeoutOptions { + /** + * Return whether all changes should not be saved if any tuple insertion + * was unsuccesful. + * + * @return true, if the operation should rollback on error + */ + Optional getRollbackOnError(); + + /** + * Return whether the operation should be interrupted if any tuple insertion + * was unsuccesful. + * + * @return true, if the operation should stop on error + */ + Optional getStopOnError(); +} diff --git a/src/main/java/io/tarantool/driver/api/space/options/InsertOptions.java b/src/main/java/io/tarantool/driver/api/space/options/InsertOptions.java index 8bd5fe63..9fc499bb 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/InsertOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/InsertOptions.java @@ -1,10 +1,10 @@ package io.tarantool.driver.api.space.options; /** - * Marker interface for space insert options + * Marker interface for space insert operation options * * @author Artyom Dubinin * @author Alexey Kuzin */ -public interface InsertOptions extends Options { +public interface InsertOptions extends OperationWithTimeoutOptions { } diff --git a/src/main/java/io/tarantool/driver/api/space/options/OperationWithTimeoutOptions.java b/src/main/java/io/tarantool/driver/api/space/options/OperationWithTimeoutOptions.java new file mode 100644 index 00000000..5f56433f --- /dev/null +++ b/src/main/java/io/tarantool/driver/api/space/options/OperationWithTimeoutOptions.java @@ -0,0 +1,17 @@ +package io.tarantool.driver.api.space.options; + +import java.util.Optional; + +/** + * Base class for all operation options that may have a configurable timeout. + * + * @author Alexey Kuzin + */ +public interface OperationWithTimeoutOptions extends Options { + /** + * Return operation timeout. + * + * @return timeout, in milliseconds. + */ + Optional getTimeout(); +} diff --git a/src/main/java/io/tarantool/driver/api/space/options/Options.java b/src/main/java/io/tarantool/driver/api/space/options/Options.java index a72c771b..fd29e410 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/Options.java +++ b/src/main/java/io/tarantool/driver/api/space/options/Options.java @@ -1,6 +1,6 @@ package io.tarantool.driver.api.space.options; -import java.util.Map; +import java.util.Optional; /** * Marker interface for space operations options @@ -11,7 +11,7 @@ public interface Options { /** - * Add named option + * Add named option. * * @param option name of option * @param value value of option @@ -19,9 +19,11 @@ public interface Options { void addOption(String option, Object value); /** - * Return serializable options representation. + * Return option value by name. * - * @return a map + * @param option option name + * @param optionClass option value type + * @return option value */ - Map asMap(); + Optional getOption(String option, Class optionClass); } diff --git a/src/main/java/io/tarantool/driver/api/space/options/ReplaceManyOptions.java b/src/main/java/io/tarantool/driver/api/space/options/ReplaceManyOptions.java new file mode 100644 index 00000000..185cd519 --- /dev/null +++ b/src/main/java/io/tarantool/driver/api/space/options/ReplaceManyOptions.java @@ -0,0 +1,26 @@ +package io.tarantool.driver.api.space.options; + +import java.util.Optional; + +/** + * Marker interface for space replace_many operation options + * + * @author Alexey Kuzin + */ +public interface ReplaceManyOptions extends OperationWithTimeoutOptions { + /** + * Return whether all changes should not be saved if any tuple replace + * was unsuccesful. + * + * @return true, if the operation should rollback on error + */ + Optional getRollbackOnError(); + + /** + * Return whether the operation should be interrupted if any tuple replace + * was unsuccesful. + * + * @return true, if the operation should stop on error + */ + Optional getStopOnError(); +} diff --git a/src/main/java/io/tarantool/driver/api/space/options/ReplaceOptions.java b/src/main/java/io/tarantool/driver/api/space/options/ReplaceOptions.java index ac94e7ca..b2c931bf 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/ReplaceOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/ReplaceOptions.java @@ -1,10 +1,10 @@ package io.tarantool.driver.api.space.options; /** - * Marker interface for space replace options + * Marker interface for space replace operation options * * @author Artyom Dubinin * @author Alexey Kuzin */ -public interface ReplaceOptions extends Options { +public interface ReplaceOptions extends OperationWithTimeoutOptions { } 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 ad2b9648..fc2cc092 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 @@ -1,10 +1,19 @@ package io.tarantool.driver.api.space.options; +import java.util.Optional; + /** - * Marker interface for space select options + * Marker interface for space select operation options * * @author Artyom Dubinin * @author Alexey Kuzin */ -public interface SelectOptions extends Options { +public interface SelectOptions extends OperationWithTimeoutOptions { + /** + * Return the internal size of batch for transferring data between + * storage and router nodes. + * + * @return batch size + */ + Optional getBatchSize(); } diff --git a/src/main/java/io/tarantool/driver/api/space/options/UpdateOptions.java b/src/main/java/io/tarantool/driver/api/space/options/UpdateOptions.java index f681a884..620c8692 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/UpdateOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/UpdateOptions.java @@ -1,10 +1,10 @@ package io.tarantool.driver.api.space.options; /** - * Marker interface for space update options + * Marker interface for space update operation options * * @author Artyom Dubinin * @author Alexey Kuzin */ -public interface UpdateOptions extends Options { +public interface UpdateOptions extends OperationWithTimeoutOptions { } diff --git a/src/main/java/io/tarantool/driver/api/space/options/UpsertOptions.java b/src/main/java/io/tarantool/driver/api/space/options/UpsertOptions.java index 50fc96c2..d3d997fe 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/UpsertOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/UpsertOptions.java @@ -1,10 +1,10 @@ package io.tarantool.driver.api.space.options; /** - * Marker interface for space upsert options + * Marker interface for space upsert operation options * * @author Artyom Dubinin * @author Alexey Kuzin */ -public interface UpsertOptions extends Options { +public interface UpsertOptions extends OperationWithTimeoutOptions { } diff --git a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyBaseOptions.java b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyBaseOptions.java index 10fcacf2..5da2608a 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyBaseOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyBaseOptions.java @@ -1,6 +1,9 @@ package io.tarantool.driver.api.space.options.proxy; +import java.util.Optional; + import io.tarantool.driver.api.space.options.AbstractOptions; +import io.tarantool.driver.api.space.options.OperationWithTimeoutOptions; /** * Represent options for all proxy functions @@ -8,12 +11,28 @@ * @author Alexey Kuzin * @author Artyom Dubinin */ -abstract class ProxyBaseOptions> extends AbstractOptions { +abstract class ProxyBaseOptions> extends AbstractOptions + implements OperationWithTimeoutOptions { public static final String TIMEOUT = "timeout"; + /** + * Specifies timeout for waiting for a server response for the operation. + * Configured request timeout for that client will be used by default. + * + * @param timeout request timeout, in milliseconds + * @return this options instance + */ public B withTimeout(int timeout) { + if (timeout <= 0) { + throw new IllegalArgumentException("Timeout should be greater than 0"); + } addOption(TIMEOUT, timeout); return self(); } + + @Override + public Optional getTimeout() { + return getOption(TIMEOUT, Integer.class); + } } diff --git a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyDeleteOptions.java b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyDeleteOptions.java index 5317e764..d4a00b95 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyDeleteOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyDeleteOptions.java @@ -13,6 +13,9 @@ public final class ProxyDeleteOptions extends ProxyBaseOptions + implements InsertManyOptions { + + public static final String ROLLBACK_ON_ERROR = "rollback_on_error"; + public static final String STOP_ON_ERROR = "stop_on_error"; + + private ProxyInsertManyOptions() { + } + + /** + * Create new instance. + */ + public static ProxyInsertManyOptions create() { + return new ProxyInsertManyOptions(); + } + + /** + * Specifies whether to not save any changes in the space if any tuple insert operation + * is unsuccesful. Default value is true. + * + * @param rollbackOnError should rollback batch on error + * @return this options instance + */ + public ProxyInsertManyOptions withRollbackOnError(boolean rollbackOnError) { + addOption(ROLLBACK_ON_ERROR, rollbackOnError); + return self(); + } + + /** + * Specifies whether to not try to insert more tuples into the space if any tuple insert + * operation is unsuccesful. Default value is true. + * + * @param stopOnError should stop batch on error + * @return this options instance + */ + public ProxyInsertManyOptions withStopOnError(boolean stopOnError) { + addOption(STOP_ON_ERROR, stopOnError); + return self(); + } + + @Override + protected ProxyInsertManyOptions self() { + return this; + } + + @Override + public Optional getRollbackOnError() { + return getOption(ROLLBACK_ON_ERROR, Boolean.class); + } + + @Override + public Optional getStopOnError() { + return getOption(STOP_ON_ERROR, Boolean.class); + } +} diff --git a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyInsertOptions.java b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyInsertOptions.java index f0008d9e..4d50249c 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyInsertOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyInsertOptions.java @@ -13,6 +13,9 @@ public final class ProxyInsertOptions extends ProxyBaseOptions + implements ReplaceManyOptions { + + public static final String ROLLBACK_ON_ERROR = "rollback_on_error"; + public static final String STOP_ON_ERROR = "stop_on_error"; + + private ProxyReplaceManyOptions() { + } + + /** + * Create new instance. + */ + public static ProxyReplaceManyOptions create() { + return new ProxyReplaceManyOptions(); + } + + /** + * Specifies whether to not save any changes in the space if any tuple replace operation + * is unsuccesful. Default value is true. + * + * @param rollbackOnError should rollback batch on error + * @return this options instance + */ + public ProxyReplaceManyOptions withRollbackOnError(boolean rollbackOnError) { + addOption(ROLLBACK_ON_ERROR, rollbackOnError); + return self(); + } + + /** + * Specifies whether to not try to replace more tuples into the space if any tuple replace + * operation is unsuccesful. Default value is true. + * + * @param stopOnError should stop batch on error + * @return this options instance + */ + public ProxyReplaceManyOptions withStopOnError(boolean stopOnError) { + addOption(STOP_ON_ERROR, stopOnError); + return self(); + } + + @Override + protected ProxyReplaceManyOptions self() { + return this; + } + + @Override + public Optional getRollbackOnError() { + return getOption(ROLLBACK_ON_ERROR, Boolean.class); + } + + @Override + public Optional getStopOnError() { + return getOption(STOP_ON_ERROR, Boolean.class); + } +} diff --git a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyReplaceOptions.java b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyReplaceOptions.java index 1d71a696..d42558b5 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyReplaceOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyReplaceOptions.java @@ -13,6 +13,9 @@ public final class ProxyReplaceOptions extends ProxyBaseOptions getBatchSize() { + return getOption(BATCH_SIZE, Integer.class); + } } diff --git a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyTruncateOptions.java b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyTruncateOptions.java new file mode 100644 index 00000000..fb018456 --- /dev/null +++ b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyTruncateOptions.java @@ -0,0 +1,24 @@ +package io.tarantool.driver.api.space.options.proxy; + +/** + * Represent options for truncate cluster proxy operation + * + * @author Alexey Kuzin + */ +public final class ProxyTruncateOptions extends ProxyBaseOptions { + + private ProxyTruncateOptions() { + } + + /** + * Create new instance. + */ + public static ProxyTruncateOptions create() { + return new ProxyTruncateOptions(); + } + + @Override + protected ProxyTruncateOptions self() { + return this; + } +} diff --git a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyUpdateOptions.java b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyUpdateOptions.java index 54711b34..61ed8049 100644 --- a/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyUpdateOptions.java +++ b/src/main/java/io/tarantool/driver/api/space/options/proxy/ProxyUpdateOptions.java @@ -13,6 +13,9 @@ public final class ProxyUpdateOptions extends ProxyBaseOptions execute() { return client.callForSingleResult(functionName, arguments, argumentsMapper, resultMapper); } - abstract static class GenericOperationsBuilder> { + abstract static + class GenericOperationsBuilder> { protected TarantoolCallOperations client; protected String spaceName; protected String functionName; protected MessagePackObjectMapper argumentsMapper; protected CallResultMapper> resultMapper; - protected int requestTimeout; - protected Options options; + protected O options; GenericOperationsBuilder() { } @@ -127,24 +127,13 @@ public B withResultMapper(CallResultMapper> resultMa return self(); } - /** - * Specify response reading timeout - * - * @param requestTimeout the timeout for reading the responses from Tarantool server, in milliseconds - * @return builder - */ - public B withRequestTimeout(int requestTimeout) { - this.requestTimeout = requestTimeout; - return self(); - } - /** * Specify custom options * * @param options cluster proxy operation options * @return builder */ - public B withOptions(Options options) { + public B withOptions(O options) { this.options = options; return self(); } diff --git a/src/main/java/io/tarantool/driver/core/proxy/CRUDAbstractOperationOptions.java b/src/main/java/io/tarantool/driver/core/proxy/CRUDAbstractOperationOptions.java index c6148876..af3f0103 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/CRUDAbstractOperationOptions.java +++ b/src/main/java/io/tarantool/driver/core/proxy/CRUDAbstractOperationOptions.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; /** * This class is not part of the public API. @@ -38,8 +39,10 @@ class AbstractBuilder value) { + if (value.isPresent()) { + resultMap.put(option, value.get()); + } } /** diff --git a/src/main/java/io/tarantool/driver/core/proxy/CRUDBaseOptions.java b/src/main/java/io/tarantool/driver/core/proxy/CRUDBaseOptions.java index fa79855f..2c1497fb 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/CRUDBaseOptions.java +++ b/src/main/java/io/tarantool/driver/core/proxy/CRUDBaseOptions.java @@ -1,6 +1,6 @@ package io.tarantool.driver.core.proxy; -import io.tarantool.driver.api.space.options.Options; +import java.util.Optional; /** * This class is not part of the public API. @@ -17,16 +17,7 @@ class CRUDBaseOptions extends CRUDAbstractOperationOptions { protected > CRUDBaseOptions(AbstractBuilder builder) { - if (builder.timeout != null) { - addOption(TIMEOUT, builder.timeout); - } - - if (builder.options != null) { - Object batchSize = builder.options.asMap().get(TIMEOUT); - if (batchSize != null) { - addOption(TIMEOUT, batchSize); - } - } + addOption(TIMEOUT, builder.timeout); } /** @@ -37,18 +28,12 @@ class CRUDBaseOptions extends CRUDAbstractOperationOptions { protected abstract static class AbstractBuilder> extends CRUDAbstractOperationOptions.AbstractBuilder { - protected Integer timeout; - protected Options options; + protected Optional timeout = Optional.empty(); - public T withTimeout(int timeout) { + public T withTimeout(Optional timeout) { this.timeout = timeout; return self(); } - - public T withOptions(Options options) { - this.options = options; - return self(); - } } /** diff --git a/src/main/java/io/tarantool/driver/core/proxy/CRUDBatchOptions.java b/src/main/java/io/tarantool/driver/core/proxy/CRUDBatchOptions.java index 3e810469..643aaf2c 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/CRUDBatchOptions.java +++ b/src/main/java/io/tarantool/driver/core/proxy/CRUDBatchOptions.java @@ -1,6 +1,6 @@ package io.tarantool.driver.core.proxy; -import java.util.Map; +import java.util.Optional; /** * This class is not part of the public API. @@ -15,38 +15,32 @@ public final class CRUDBatchOptions extends CRUDBaseOptions { public static final String BATCH_ROLLBACK_ON_ERROR = "rollback_on_error"; protected - > - CRUDBatchOptions(AbstractBuilder builder) { + > + CRUDBatchOptions(AbstractBuilder builder) { super(builder); - if (builder.stopOnError != null) { - addOption(BATCH_STOP_ON_ERROR, builder.stopOnError); - } - - if (builder.rollbackOnError != null) { - addOption(BATCH_ROLLBACK_ON_ERROR, builder.rollbackOnError); - } + addOption(BATCH_STOP_ON_ERROR, builder.stopOnError); + addOption(BATCH_ROLLBACK_ON_ERROR, builder.rollbackOnError); } protected abstract static - class AbstractBuilder> - extends CRUDBaseOptions.AbstractBuilder { - private Boolean stopOnError; - private Boolean rollbackOnError; + class AbstractBuilder> + extends CRUDBaseOptions.AbstractBuilder { + private Optional stopOnError = Optional.empty(); + private Optional rollbackOnError = Optional.empty(); - public T withStopOnError(Boolean stopOnError) { + public T withStopOnError(Optional stopOnError) { this.stopOnError = stopOnError; return self(); } - public T withRollbackOnError(Boolean rollbackOnError) { + public T withRollbackOnError(Optional rollbackOnError) { this.rollbackOnError = rollbackOnError; return self(); } } - protected static final class Builder - extends AbstractBuilder { + protected static final class Builder extends AbstractBuilder { @Override Builder self() { 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 eac4fbd4..a79feef0 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/CRUDSelectOptions.java +++ b/src/main/java/io/tarantool/driver/core/proxy/CRUDSelectOptions.java @@ -1,5 +1,7 @@ package io.tarantool.driver.core.proxy; +import java.util.Optional; + import io.tarantool.driver.protocol.Packable; /** @@ -17,28 +19,13 @@ final class CRUDSelectOptions extends CRUDBaseOptions { public static final String SELECT_AFTER = "after"; public static final String SELECT_BATCH_SIZE = "batch_size"; - private > - CRUDSelectOptions(AbstractBuilder builder) { + private > + CRUDSelectOptions(AbstractBuilder builder) { super(builder); - if (builder.selectLimit != null) { - addOption(SELECT_LIMIT, builder.selectLimit); - } - - if (builder.after != null) { - addOption(SELECT_AFTER, builder.after); - } - - if (builder.selectBatchSize != null) { - addOption(SELECT_BATCH_SIZE, builder.selectBatchSize); - } - - if (builder.options != null) { - Object batchSize = builder.options.asMap().get(SELECT_BATCH_SIZE); - if (batchSize != null) { - addOption(SELECT_BATCH_SIZE, batchSize); - } - } + addOption(SELECT_LIMIT, builder.selectLimit); + addOption(SELECT_AFTER, builder.after); + addOption(SELECT_BATCH_SIZE, builder.selectBatchSize); } /** @@ -47,23 +34,23 @@ final class CRUDSelectOptions extends CRUDBaseOptions { * @see CRUDAbstractOperationOptions.AbstractBuilder */ protected abstract static - class AbstractBuilder> - extends CRUDBaseOptions.AbstractBuilder { - private Long selectLimit; - private Packable after; - private Long selectBatchSize; + class AbstractBuilder> + extends CRUDBaseOptions.AbstractBuilder { + private Optional selectLimit = Optional.empty(); + private Optional after = Optional.empty(); + private Optional selectBatchSize = Optional.empty(); - public T withSelectLimit(long selectLimit) { + public T withSelectLimit(Optional selectLimit) { this.selectLimit = selectLimit; return self(); } - public T withSelectBatchSize(long selectBatchSize) { + public T withSelectBatchSize(Optional selectBatchSize) { this.selectBatchSize = selectBatchSize; return self(); } - public T withSelectAfter(Packable startTuple) { + public T withSelectAfter(Optional startTuple) { this.after = startTuple; return self(); } @@ -72,8 +59,7 @@ public T withSelectAfter(Packable startTuple) { /** * Concrete Builder implementation for select cluster proxy operation options. */ - protected static final class Builder - extends AbstractBuilder { + protected static final class Builder extends AbstractBuilder { @Override Builder self() { diff --git a/src/main/java/io/tarantool/driver/core/proxy/DeleteProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/DeleteProxyOperation.java index d82f4daa..b8a8fa3c 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/DeleteProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/DeleteProxyOperation.java @@ -2,6 +2,7 @@ import io.tarantool.driver.api.SingleValueCallResult; import io.tarantool.driver.api.TarantoolCallOperations; +import io.tarantool.driver.api.space.options.DeleteOptions; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.protocol.TarantoolIndexQuery; @@ -29,7 +30,8 @@ private DeleteProxyOperation(TarantoolCallOperations client, /** * The builder for this class. */ - public static final class Builder extends GenericOperationsBuilder> { + public static final class Builder + extends GenericOperationsBuilder> { private TarantoolIndexQuery indexQuery; public Builder() { @@ -47,8 +49,7 @@ public Builder withIndexQuery(TarantoolIndexQuery indexQuery) { public DeleteProxyOperation build() { CRUDBaseOptions requestOptions = new CRUDBaseOptions.Builder() - .withTimeout(requestTimeout) - .withOptions(options) + .withTimeout(options.getTimeout()) .build(); List arguments = Arrays.asList(spaceName, indexQuery.getKeyValues(), requestOptions.asMap()); diff --git a/src/main/java/io/tarantool/driver/core/proxy/InsertManyProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/InsertManyProxyOperation.java new file mode 100644 index 00000000..4e608e07 --- /dev/null +++ b/src/main/java/io/tarantool/driver/core/proxy/InsertManyProxyOperation.java @@ -0,0 +1,69 @@ +package io.tarantool.driver.core.proxy; + +import io.tarantool.driver.api.SingleValueCallResult; +import io.tarantool.driver.api.TarantoolCallOperations; +import io.tarantool.driver.api.space.options.InsertManyOptions; +import io.tarantool.driver.mappers.CallResultMapper; +import io.tarantool.driver.mappers.MessagePackObjectMapper; +import io.tarantool.driver.protocol.Packable; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * Proxy operation for inserting many records at once + * + * @param result type + * @param result collection type + * @author Alexey Kuzin + */ +public final class InsertManyProxyOperation> + extends AbstractProxyOperation { + + InsertManyProxyOperation(TarantoolCallOperations client, + String functionName, + List arguments, + MessagePackObjectMapper argumentsMapper, + CallResultMapper> resultMapper) { + super(client, functionName, arguments, argumentsMapper, resultMapper); + } + + /** + * The builder for this class. + */ + public static final class Builder> + extends GenericOperationsBuilder> { + private Collection tuples; + + public Builder() { + } + + @Override + Builder self() { + return this; + } + + public Builder withTuples(Collection tuples) { + this.tuples = tuples; + return this; + } + + public InsertManyProxyOperation build() { + if (tuples == null) { + throw new IllegalArgumentException("Tuples must be specified for batch insert operation"); + } + + CRUDBatchOptions requestOptions = new CRUDBatchOptions.Builder() + .withTimeout(options.getTimeout()) + .withStopOnError(options.getStopOnError()) + .withRollbackOnError(options.getRollbackOnError()) + .build(); + + List arguments = Arrays.asList(spaceName, tuples, requestOptions.asMap()); + + return new InsertManyProxyOperation<>( + this.client, this.functionName, arguments, this.argumentsMapper, this.resultMapper); + } + } +} diff --git a/src/main/java/io/tarantool/driver/core/proxy/InsertProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/InsertProxyOperation.java index 955bda6a..36a0c171 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/InsertProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/InsertProxyOperation.java @@ -2,6 +2,7 @@ import io.tarantool.driver.api.SingleValueCallResult; import io.tarantool.driver.api.TarantoolCallOperations; +import io.tarantool.driver.api.space.options.InsertOptions; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.protocol.Packable; @@ -32,7 +33,7 @@ private InsertProxyOperation(TarantoolCallOperations client, * The builder for this class. */ public static final class Builder> - extends GenericOperationsBuilder> { + extends GenericOperationsBuilder> { private T tuple; public Builder() { @@ -50,8 +51,7 @@ public Builder withTuple(T tuple) { public InsertProxyOperation build() { CRUDBaseOptions requestOptions = new CRUDBaseOptions.Builder() - .withTimeout(requestTimeout) - .withOptions(options) + .withTimeout(options.getTimeout()) .build(); List arguments = Arrays.asList(spaceName, tuple, requestOptions.asMap()); diff --git a/src/main/java/io/tarantool/driver/core/proxy/ProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/ProxyOperation.java index f790a520..7b6f02d4 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/ProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/ProxyOperation.java @@ -9,6 +9,10 @@ * @author Sergey Volgin */ public interface ProxyOperation { - + /** + * Perform operation. + * + * @return a future with operation result + */ CompletableFuture execute(); } diff --git a/src/main/java/io/tarantool/driver/core/proxy/ReplaceManyProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/ReplaceManyProxyOperation.java new file mode 100644 index 00000000..0f58696a --- /dev/null +++ b/src/main/java/io/tarantool/driver/core/proxy/ReplaceManyProxyOperation.java @@ -0,0 +1,69 @@ +package io.tarantool.driver.core.proxy; + +import io.tarantool.driver.api.SingleValueCallResult; +import io.tarantool.driver.api.TarantoolCallOperations; +import io.tarantool.driver.api.space.options.ReplaceManyOptions; +import io.tarantool.driver.mappers.CallResultMapper; +import io.tarantool.driver.mappers.MessagePackObjectMapper; +import io.tarantool.driver.protocol.Packable; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * Proxy operation for replacing many records at once + * + * @param result type + * @param result collection type + * @author Alexey Kuzin + */ +public final class ReplaceManyProxyOperation> + extends AbstractProxyOperation { + + ReplaceManyProxyOperation(TarantoolCallOperations client, + String functionName, + List arguments, + MessagePackObjectMapper argumentsMapper, + CallResultMapper> resultMapper) { + super(client, functionName, arguments, argumentsMapper, resultMapper); + } + + /** + * The builder for this class. + */ + public static final class Builder> + extends GenericOperationsBuilder> { + private Collection tuples; + + public Builder() { + } + + @Override + Builder self() { + return this; + } + + public Builder withTuples(Collection tuples) { + this.tuples = tuples; + return this; + } + + public ReplaceManyProxyOperation build() { + if (tuples == null) { + throw new IllegalArgumentException("Tuples must be specified for batch replace operation"); + } + + CRUDBatchOptions requestOptions = new CRUDBatchOptions.Builder() + .withTimeout(options.getTimeout()) + .withStopOnError(options.getStopOnError()) + .withRollbackOnError(options.getRollbackOnError()) + .build(); + + List arguments = Arrays.asList(spaceName, tuples, requestOptions.asMap()); + + return new ReplaceManyProxyOperation<>( + this.client, this.functionName, arguments, this.argumentsMapper, this.resultMapper); + } + } +} diff --git a/src/main/java/io/tarantool/driver/core/proxy/ReplaceProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/ReplaceProxyOperation.java index 84b5deee..bb063e16 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/ReplaceProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/ReplaceProxyOperation.java @@ -2,6 +2,7 @@ import io.tarantool.driver.api.SingleValueCallResult; import io.tarantool.driver.api.TarantoolCallOperations; +import io.tarantool.driver.api.space.options.ReplaceOptions; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.MessagePackObjectMapper; import io.tarantool.driver.protocol.Packable; @@ -33,7 +34,7 @@ public final class ReplaceProxyOperation> - extends GenericOperationsBuilder> { + extends GenericOperationsBuilder> { private T tuple; public Builder() { @@ -51,8 +52,7 @@ public Builder withTuple(T tuple) { public ReplaceProxyOperation build() { CRUDBaseOptions requestOptions = new CRUDBaseOptions.Builder() - .withTimeout(requestTimeout) - .withOptions(options) + .withTimeout(options.getTimeout()) .build(); List arguments = Arrays.asList(spaceName, tuple, requestOptions.asMap()); 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 4436571b..5bcf4218 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/SelectProxyOperation.java @@ -5,11 +5,13 @@ import io.tarantool.driver.api.conditions.Conditions; import io.tarantool.driver.api.metadata.TarantoolMetadataOperations; import io.tarantool.driver.api.metadata.TarantoolSpaceMetadata; +import io.tarantool.driver.api.space.options.SelectOptions; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.MessagePackObjectMapper; import java.util.Arrays; import java.util.List; +import java.util.Optional; /** * Proxy operation for select @@ -31,7 +33,8 @@ private SelectProxyOperation(TarantoolCallOperations client, /** * The builder for this class. */ - public static final class Builder extends GenericOperationsBuilder> { + public static final class Builder + extends GenericOperationsBuilder> { private final TarantoolMetadataOperations operations; private final TarantoolSpaceMetadata metadata; private Conditions conditions; @@ -53,11 +56,10 @@ public Builder withConditions(Conditions conditions) { public SelectProxyOperation build() { CRUDSelectOptions.Builder requestOptions = new CRUDSelectOptions.Builder() - .withTimeout(requestTimeout) - .withSelectBatchSize(conditions.getLimit()) - .withSelectLimit(conditions.getLimit()) - .withSelectAfter(conditions.getStartTuple()) - .withOptions(options); + .withTimeout(options.getTimeout()) + .withSelectBatchSize(options.getBatchSize()) + .withSelectLimit(Optional.of(conditions.getLimit())) + .withSelectAfter(Optional.ofNullable(conditions.getStartTuple())); List arguments = Arrays.asList( spaceName, diff --git a/src/main/java/io/tarantool/driver/core/proxy/TruncateProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/TruncateProxyOperation.java index 4998d39d..9f7dc50e 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/TruncateProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/TruncateProxyOperation.java @@ -2,6 +2,7 @@ import io.tarantool.driver.api.TarantoolCallOperations; import io.tarantool.driver.api.TarantoolVoidResult; +import io.tarantool.driver.api.space.options.OperationWithTimeoutOptions; import java.util.Arrays; import java.util.List; @@ -54,7 +55,9 @@ public static Builder builder() { return new Builder(); } - public static final class Builder extends AbstractProxyOperation.GenericOperationsBuilder { + public static final class Builder + extends AbstractProxyOperation.GenericOperationsBuilder { + public Builder() { } @@ -68,11 +71,11 @@ Builder self() { * @return TruncateProxyOperation instance */ public TruncateProxyOperation build() { - CRUDBaseOptions options = new CRUDBaseOptions.Builder() - .withTimeout(requestTimeout) + CRUDBaseOptions requestOptions = new CRUDBaseOptions.Builder() + .withTimeout(options.getTimeout()) .build(); - List arguments = Arrays.asList(spaceName, options.asMap()); + List arguments = Arrays.asList(spaceName, requestOptions.asMap()); return new TruncateProxyOperation(this.client, this.functionName, arguments); } diff --git a/src/main/java/io/tarantool/driver/core/proxy/UpdateProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/UpdateProxyOperation.java index b8b417c0..63e4e051 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/UpdateProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/UpdateProxyOperation.java @@ -2,6 +2,7 @@ import io.tarantool.driver.api.SingleValueCallResult; import io.tarantool.driver.api.TarantoolCallOperations; +import io.tarantool.driver.api.space.options.UpdateOptions; import io.tarantool.driver.api.tuple.operations.TupleOperations; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.MessagePackObjectMapper; @@ -30,7 +31,8 @@ public final class UpdateProxyOperation extends AbstractProxyOperation { /** * The builder for this class. */ - public static final class Builder extends GenericOperationsBuilder> { + public static final class Builder + extends GenericOperationsBuilder> { private TarantoolIndexQuery indexQuery; private TupleOperations operations; @@ -54,8 +56,7 @@ public Builder withTupleOperation(TupleOperations operations) { public UpdateProxyOperation build() { CRUDBaseOptions requestOptions = new CRUDBaseOptions.Builder() - .withTimeout(requestTimeout) - .withOptions(options) + .withTimeout(options.getTimeout()) .build(); List arguments = Arrays.asList(spaceName, diff --git a/src/main/java/io/tarantool/driver/core/proxy/UpsertProxyOperation.java b/src/main/java/io/tarantool/driver/core/proxy/UpsertProxyOperation.java index bc9d6f9b..8ffa6292 100644 --- a/src/main/java/io/tarantool/driver/core/proxy/UpsertProxyOperation.java +++ b/src/main/java/io/tarantool/driver/core/proxy/UpsertProxyOperation.java @@ -2,6 +2,7 @@ import io.tarantool.driver.api.SingleValueCallResult; import io.tarantool.driver.api.TarantoolCallOperations; +import io.tarantool.driver.api.space.options.UpsertOptions; import io.tarantool.driver.api.tuple.operations.TupleOperations; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.MessagePackObjectMapper; @@ -33,7 +34,7 @@ public final class UpsertProxyOperation> - extends GenericOperationsBuilder> { + extends GenericOperationsBuilder> { private T tuple; private TupleOperations operations; @@ -57,8 +58,7 @@ public Builder withTupleOperation(TupleOperations operations) { public UpsertProxyOperation build() { CRUDBaseOptions requestOptions = new CRUDBaseOptions.Builder() - .withTimeout(requestTimeout) - .withOptions(options) + .withTimeout(options.getTimeout()) .build(); List arguments = Arrays.asList( diff --git a/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolSpace.java b/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolSpace.java index 87066d07..89c8837d 100644 --- a/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolSpace.java +++ b/src/main/java/io/tarantool/driver/core/space/ProxyTarantoolSpace.java @@ -9,16 +9,29 @@ import io.tarantool.driver.api.proxy.ProxyOperationsMappingConfig; import io.tarantool.driver.api.space.TarantoolSpaceOperations; import io.tarantool.driver.api.space.options.DeleteOptions; +import io.tarantool.driver.api.space.options.InsertManyOptions; import io.tarantool.driver.api.space.options.InsertOptions; +import io.tarantool.driver.api.space.options.ReplaceManyOptions; import io.tarantool.driver.api.space.options.ReplaceOptions; import io.tarantool.driver.api.space.options.SelectOptions; import io.tarantool.driver.api.space.options.UpdateOptions; import io.tarantool.driver.api.space.options.UpsertOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyDeleteOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyInsertManyOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyInsertOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyReplaceManyOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyReplaceOptions; +import io.tarantool.driver.api.space.options.proxy.ProxySelectOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyTruncateOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyUpdateOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyUpsertOptions; import io.tarantool.driver.api.tuple.operations.TupleOperations; import io.tarantool.driver.core.proxy.DeleteProxyOperation; import io.tarantool.driver.core.proxy.InsertProxyOperation; +import io.tarantool.driver.core.proxy.InsertManyProxyOperation; import io.tarantool.driver.core.proxy.ProxyOperation; import io.tarantool.driver.core.proxy.ReplaceProxyOperation; +import io.tarantool.driver.core.proxy.ReplaceManyProxyOperation; import io.tarantool.driver.core.proxy.SelectProxyOperation; import io.tarantool.driver.core.proxy.TruncateProxyOperation; import io.tarantool.driver.core.proxy.UpdateProxyOperation; @@ -64,11 +77,16 @@ public ProxyTarantoolSpace(TarantoolClientConfig config, @Override public CompletableFuture delete(Conditions conditions) throws TarantoolClientException { - return delete(conditions, tupleResultMapper(), null); + return delete(conditions, tupleResultMapper(), ProxyDeleteOptions.create() + .withTimeout(config.getRequestTimeout()) + ); } @Override public CompletableFuture delete(Conditions conditions, DeleteOptions options) throws TarantoolClientException { + if (options == null) { + throw new IllegalArgumentException("Options should not be null"); + } return delete(conditions, tupleResultMapper(), options); } @@ -85,7 +103,6 @@ private CompletableFuture delete(Conditions conditions, .withIndexQuery(indexQuery) .withArgumentsMapper(config.getMessagePackMapper()) .withResultMapper(resultMapper) - .withRequestTimeout(config.getRequestTimeout()) .withOptions(options) .build(); @@ -94,11 +111,16 @@ private CompletableFuture delete(Conditions conditions, @Override public CompletableFuture insert(T tuple) throws TarantoolClientException { - return insert(tuple, tupleResultMapper(), null); + return insert(tuple, tupleResultMapper(), ProxyInsertOptions.create() + .withTimeout(config.getRequestTimeout()) + ); } @Override public CompletableFuture insert(T tuple, InsertOptions options) throws TarantoolClientException { + if (options == null) { + throw new IllegalArgumentException("Options should not be null"); + } return insert(tuple, tupleResultMapper(), options); } @@ -113,7 +135,41 @@ private CompletableFuture insert(T tuple, .withTuple(tuple) .withArgumentsMapper(config.getMessagePackMapper()) .withResultMapper(resultMapper) - .withRequestTimeout(config.getRequestTimeout()) + .withOptions(options) + .build(); + + return executeOperation(operation); + } + + @Override + public CompletableFuture insertMany(Collection tuples) { + return insertMany(tuples, tupleResultMapper(), ProxyInsertManyOptions.create() + .withTimeout(config.getRequestTimeout()) + .withStopOnError(true) + .withRollbackOnError(true) + ); + } + + @Override + public CompletableFuture insertMany(Collection tuples, InsertManyOptions options) + throws TarantoolClientException { + if (options == null) { + throw new IllegalArgumentException("Options should not be null"); + } + return insertMany(tuples, tupleResultMapper(), options); + } + + private CompletableFuture insertMany(Collection tuples, + CallResultMapper> resultMapper, + InsertManyOptions options) + throws TarantoolClientException { + InsertManyProxyOperation operation = new InsertManyProxyOperation.Builder() + .withClient(client) + .withSpaceName(spaceName) + .withFunctionName(operationsMapping.getInsertManyFunctionName()) + .withTuples(tuples) + .withArgumentsMapper(config.getMessagePackMapper()) + .withResultMapper(resultMapper) .withOptions(options) .build(); @@ -122,11 +178,16 @@ private CompletableFuture insert(T tuple, @Override public CompletableFuture replace(T tuple) throws TarantoolClientException { - return replace(tuple, tupleResultMapper(), null); + return replace(tuple, tupleResultMapper(), ProxyReplaceOptions.create() + .withTimeout(config.getRequestTimeout()) + ); } @Override public CompletableFuture replace(T tuple, ReplaceOptions options) throws TarantoolClientException { + if (options == null) { + throw new IllegalArgumentException("Options should not be null"); + } return replace(tuple, tupleResultMapper(), options); } @@ -141,7 +202,40 @@ private CompletableFuture replace(T tuple, .withTuple(tuple) .withArgumentsMapper(config.getMessagePackMapper()) .withResultMapper(resultMapper) - .withRequestTimeout(config.getRequestTimeout()) + .withOptions(options) + .build(); + + return executeOperation(operation); + } + + @Override + public CompletableFuture replaceMany(Collection tuples) throws TarantoolClientException { + return replaceMany(tuples, tupleResultMapper(), ProxyReplaceManyOptions.create() + .withTimeout(config.getRequestTimeout()) + .withStopOnError(true) + .withRollbackOnError(true) + ); + } + + @Override + public CompletableFuture replaceMany(Collection tuples, ReplaceManyOptions options) { + if (options == null) { + throw new IllegalArgumentException("Options should not be null"); + } + return replaceMany(tuples, tupleResultMapper(), options); + } + + private CompletableFuture replaceMany(Collection tuples, + CallResultMapper> resultMapper, + ReplaceManyOptions options) + throws TarantoolClientException { + ReplaceManyProxyOperation operation = new ReplaceManyProxyOperation.Builder() + .withClient(client) + .withSpaceName(spaceName) + .withFunctionName(operationsMapping.getReplaceManyFunctionName()) + .withTuples(tuples) + .withArgumentsMapper(config.getMessagePackMapper()) + .withResultMapper(resultMapper) .withOptions(options) .build(); @@ -150,12 +244,17 @@ private CompletableFuture replace(T tuple, @Override public CompletableFuture select(Conditions conditions) throws TarantoolClientException { - return select(conditions, tupleResultMapper(), null); + return select(conditions, tupleResultMapper(), ProxySelectOptions.create() + .withTimeout(config.getRequestTimeout()) + ); } @Override public CompletableFuture select(Conditions conditions, SelectOptions options) throws TarantoolClientException { + if (options == null) { + throw new IllegalArgumentException("Options should not be null"); + } return select(conditions, tupleResultMapper(), options); } @@ -163,7 +262,6 @@ private CompletableFuture select(Conditions conditions, CallResultMapper> resultMapper, SelectOptions options) throws TarantoolClientException { - SelectProxyOperation operation = new SelectProxyOperation.Builder(metadataOperations, spaceMetadata) .withClient(client) .withSpaceName(spaceName) @@ -172,7 +270,7 @@ private CompletableFuture select(Conditions conditions, .withOptions(options) .withArgumentsMapper(config.getMessagePackMapper()) .withResultMapper(resultMapper) - .withRequestTimeout(config.getRequestTimeout()) + .withOptions(options) .build(); return executeOperation(operation); @@ -180,11 +278,16 @@ private CompletableFuture select(Conditions conditions, @Override public CompletableFuture update(Conditions conditions, T tuple) { - return update(conditions, makeOperationsFromTuple(tuple), tupleResultMapper(), null); + return update(conditions, makeOperationsFromTuple(tuple), tupleResultMapper(), ProxyUpdateOptions.create() + .withTimeout(config.getRequestTimeout()) + ); } @Override public CompletableFuture update(Conditions conditions, T tuple, UpdateOptions options) { + if (options == null) { + throw new IllegalArgumentException("Options should not be null"); + } return update(conditions, makeOperationsFromTuple(tuple), tupleResultMapper(), options); } @@ -198,11 +301,16 @@ public CompletableFuture update(Conditions conditions, T tuple, UpdateOptions @Override public CompletableFuture update(Conditions conditions, TupleOperations operations) { - return update(conditions, operations, tupleResultMapper(), null); + return update(conditions, operations, tupleResultMapper(), ProxyUpdateOptions.create() + .withTimeout(config.getRequestTimeout()) + ); } @Override public CompletableFuture update(Conditions conditions, TupleOperations operations, UpdateOptions options) { + if (options == null) { + throw new IllegalArgumentException("Options should not be null"); + } return update(conditions, operations, tupleResultMapper(), options); } @@ -220,7 +328,6 @@ private CompletableFuture update(Conditions conditions, .withTupleOperation(operations) .withArgumentsMapper(config.getMessagePackMapper()) .withResultMapper(resultMapper) - .withRequestTimeout(config.getRequestTimeout()) .withOptions(options) .build(); @@ -229,12 +336,17 @@ private CompletableFuture update(Conditions conditions, @Override public CompletableFuture upsert(Conditions conditions, T tuple, TupleOperations operations) { - return upsert(conditions, tuple, operations, tupleResultMapper(), null); + return upsert(conditions, tuple, operations, tupleResultMapper(), ProxyUpsertOptions.create() + .withTimeout(config.getRequestTimeout()) + ); } @Override public CompletableFuture upsert(Conditions conditions, T tuple, TupleOperations operations, UpsertOptions options) { + if (options == null) { + throw new IllegalArgumentException("Options should not be null"); + } return upsert(conditions, tuple, operations, tupleResultMapper(), options); } @@ -252,7 +364,6 @@ private CompletableFuture upsert(Conditions conditions, .withTupleOperation(operations) .withArgumentsMapper(config.getMessagePackMapper()) .withResultMapper(resultMapper) - .withRequestTimeout(config.getRequestTimeout()) .withOptions(options) .build(); @@ -266,7 +377,9 @@ public CompletableFuture truncate() throws TarantoolClientException { .withClient(client) .withSpaceName(spaceName) .withFunctionName(operationsMapping.getTruncateFunctionName()) - .withRequestTimeout(config.getRequestTimeout()) + .withOptions(ProxyTruncateOptions.create() + .withTimeout(config.getRequestTimeout()) + ) .build() ); } catch (TarantoolClientException e) { diff --git a/src/main/java/io/tarantool/driver/core/space/RetryingTarantoolSpace.java b/src/main/java/io/tarantool/driver/core/space/RetryingTarantoolSpace.java index 7527834b..4a7bacb9 100644 --- a/src/main/java/io/tarantool/driver/core/space/RetryingTarantoolSpace.java +++ b/src/main/java/io/tarantool/driver/core/space/RetryingTarantoolSpace.java @@ -7,7 +7,9 @@ import io.tarantool.driver.api.retry.RequestRetryPolicyFactory; import io.tarantool.driver.api.space.TarantoolSpaceOperations; import io.tarantool.driver.api.space.options.DeleteOptions; +import io.tarantool.driver.api.space.options.InsertManyOptions; import io.tarantool.driver.api.space.options.InsertOptions; +import io.tarantool.driver.api.space.options.ReplaceManyOptions; import io.tarantool.driver.api.space.options.ReplaceOptions; import io.tarantool.driver.api.space.options.SelectOptions; import io.tarantool.driver.api.space.options.UpdateOptions; @@ -72,6 +74,17 @@ public CompletableFuture insert(T tuple, InsertOptions options) throws Tarant return wrapOperation(() -> spaceOperations.insert(tuple, options)); } + @Override + public CompletableFuture insertMany(Collection tuples) throws TarantoolClientException { + return wrapOperation(() -> spaceOperations.insertMany(tuples)); + } + + @Override + public CompletableFuture insertMany(Collection tuples, InsertManyOptions options) + throws TarantoolClientException { + return wrapOperation(() -> spaceOperations.insertMany(tuples, options)); + } + @Override public CompletableFuture replace(T tuple) throws TarantoolClientException { @@ -84,6 +97,18 @@ public CompletableFuture replace(T tuple, ReplaceOptions options) return wrapOperation(() -> spaceOperations.replace(tuple, options)); } + @Override + public CompletableFuture replaceMany(Collection tuples) + throws TarantoolClientException { + return wrapOperation(() -> spaceOperations.replaceMany(tuples)); + } + + @Override + public CompletableFuture replaceMany(Collection tuples, ReplaceManyOptions options) + throws TarantoolClientException { + return wrapOperation(() -> spaceOperations.replaceMany(tuples, options)); + } + @Override public CompletableFuture select(Conditions conditions) throws TarantoolClientException { diff --git a/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java b/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java index 43f0eba2..c532db40 100644 --- a/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java +++ b/src/main/java/io/tarantool/driver/core/space/TarantoolSpace.java @@ -85,6 +85,14 @@ public CompletableFuture insert(T tuple) throws TarantoolClientException { return insert(tuple, tupleResultMapper()); } + @Override + public CompletableFuture insertMany(Collection tuples) throws TarantoolClientException { + // TODO: add support with interactive transactions if the node has the MVCC mode enabled + // TODO: add support in all other cases if https://github.com/tarantool/tarantool/issues/7691 is implemented + throw new UnsupportedOperationException( + "Standalone node API does not support inserting several tuples at once yet"); + } + private CompletableFuture insert(T tuple, MessagePackValueMapper resultMapper) throws TarantoolClientException { try { @@ -104,6 +112,14 @@ public CompletableFuture replace(T tuple) throws TarantoolClientException { return replace(tuple, tupleResultMapper()); } + @Override + public CompletableFuture replaceMany(Collection tuples) throws TarantoolClientException { + // TODO: add support with interactive transactions if the node has the MVCC mode enabled + // TODO: add support in all other cases if https://github.com/tarantool/tarantool/issues/7691 is implemented + throw new UnsupportedOperationException( + "Standalone node API does not support replacing several tuples at once yet"); + } + private CompletableFuture replace(T tuple, MessagePackValueMapper resultMapper) throws TarantoolClientException { try { diff --git a/src/test/java/io/tarantool/driver/core/proxy/CRUDOperationOptionsTest.java b/src/test/java/io/tarantool/driver/core/proxy/CRUDOperationOptionsTest.java index 8c21c5a7..41e0b265 100644 --- a/src/test/java/io/tarantool/driver/core/proxy/CRUDOperationOptionsTest.java +++ b/src/test/java/io/tarantool/driver/core/proxy/CRUDOperationOptionsTest.java @@ -9,6 +9,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -30,24 +31,24 @@ public void selectOperationOptions_createNotEmptyTest() { TarantoolTuple tuple = new TarantoolTupleImpl(values, defaultMapper); CRUDSelectOptions options = new CRUDSelectOptions.Builder() - .withTimeout(1000) - .withSelectLimit(50) - .withSelectBatchSize(10) - .withSelectAfter(tuple) + .withTimeout(Optional.of(1000)) + .withSelectLimit(Optional.of(50L)) + .withSelectBatchSize(Optional.of(10)) + .withSelectAfter(Optional.of(tuple)) .build(); assertEquals(4, options.asMap().size()); assertEquals(1000, options.asMap().get(CRUDBaseOptions.TIMEOUT)); assertEquals(50L, options.asMap().get(CRUDSelectOptions.SELECT_LIMIT)); - assertEquals(10L, options.asMap().get(CRUDSelectOptions.SELECT_BATCH_SIZE)); + assertEquals(10, options.asMap().get(CRUDSelectOptions.SELECT_BATCH_SIZE)); assertEquals(tuple, options.asMap().get(CRUDSelectOptions.SELECT_AFTER)); } @Test public void baseOperationOptions_createNotEmptyTest() { CRUDBaseOptions options = new CRUDBaseOptions.Builder() - .withTimeout(1000) + .withTimeout(Optional.of(1000)) .build(); assertEquals(1, options.asMap().size()); @@ -57,8 +58,8 @@ public void baseOperationOptions_createNotEmptyTest() { @Test public void batchOperationOptions_createNotEmptyTest() { CRUDBatchOptions options = new CRUDBatchOptions.Builder() - .withStopOnError(false) - .withRollbackOnError(true) + .withStopOnError(Optional.of(false)) + .withRollbackOnError(Optional.of(true)) .build(); assertEquals(2, options.asMap().size()); 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 d85957b3..3c7af26d 100644 --- a/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java +++ b/src/test/java/io/tarantool/driver/core/proxy/ProxyOperationBuildersTest.java @@ -3,11 +3,21 @@ import io.tarantool.driver.api.SingleValueCallResult; import io.tarantool.driver.api.TarantoolResult; import io.tarantool.driver.api.conditions.Conditions; +import io.tarantool.driver.api.space.options.proxy.ProxyDeleteOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyInsertManyOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyInsertOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyReplaceManyOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyReplaceOptions; +import io.tarantool.driver.api.space.options.proxy.ProxySelectOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyTruncateOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyUpdateOptions; +import io.tarantool.driver.api.space.options.proxy.ProxyUpsertOptions; +import io.tarantool.driver.api.tuple.DefaultTarantoolTupleFactory; import io.tarantool.driver.api.tuple.TarantoolTuple; +import io.tarantool.driver.api.tuple.TarantoolTupleFactory; import io.tarantool.driver.api.tuple.operations.TupleOperations; import io.tarantool.driver.core.ClusterTarantoolTupleClient; import io.tarantool.driver.core.metadata.TarantoolMetadata; -import io.tarantool.driver.core.tuple.TarantoolTupleImpl; import io.tarantool.driver.mappers.CallResultMapper; import io.tarantool.driver.mappers.DefaultMessagePackMapperFactory; import io.tarantool.driver.mappers.DefaultResultMapperFactoryFactory; @@ -23,6 +33,7 @@ import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ProxyOperationBuildersTest { @@ -36,6 +47,7 @@ public class ProxyOperationBuildersTest { CallResultMapper, SingleValueCallResult>> defaultResultMapper = mapperFactoryFactory.defaultTupleSingleResultMapperFactory() .withDefaultTupleValueConverter(defaultMapper, null); + private final TarantoolTupleFactory factory = new DefaultTarantoolTupleFactory(defaultMapper); @Test public void deleteOperationBuilderTest() { @@ -50,7 +62,9 @@ public void deleteOperationBuilderTest() { .withIndexQuery(indexQuery) .withResultMapper(defaultResultMapper) .withArgumentsMapper(defaultMapper) - .withRequestTimeout(client.getConfig().getRequestTimeout()) + .withOptions(ProxyDeleteOptions.create() + .withTimeout(client.getConfig().getRequestTimeout()) + ) .build(); Map options = new HashMap<>(); @@ -66,7 +80,7 @@ public void deleteOperationBuilderTest() { @Test public void insertOperationBuilderTest() { List values = Arrays.asList(4, "a4", "Nineteen Eighty-Four", "George Orwell", 1984); - TarantoolTuple tarantoolTuple = new TarantoolTupleImpl(values, defaultMapper); + TarantoolTuple tarantoolTuple = factory.create(values); InsertProxyOperation> insertOperation = new InsertProxyOperation.Builder>() @@ -76,7 +90,9 @@ public void insertOperationBuilderTest() { .withTuple(tarantoolTuple) .withArgumentsMapper(defaultMapper) .withResultMapper(defaultResultMapper) - .withRequestTimeout(client.getConfig().getRequestTimeout()) + .withOptions(ProxyInsertOptions.create() + .withTimeout(client.getConfig().getRequestTimeout()) + ) .build(); Map options = new HashMap<>(); @@ -88,10 +104,43 @@ public void insertOperationBuilderTest() { assertEquals(defaultResultMapper, insertOperation.getResultMapper()); } + @Test + public void insertManyOperationBuilderTest() { + List tarantoolTuples = Arrays.asList( + factory.create(Arrays.asList(4, "a4", "Nineteen Eighty-Four", "George Orwell", 1984)), + factory.create(Arrays.asList(44, "a44", "Silmarillion", "J. R. R. Tolkien", 1977)) + ); + + InsertManyProxyOperation> operation = + new InsertManyProxyOperation.Builder>() + .withClient(client) + .withSpaceName("space1") + .withFunctionName("function1") + .withTuples(tarantoolTuples) + .withResultMapper(defaultResultMapper) + .withArgumentsMapper(defaultMapper) + .withOptions(ProxyInsertManyOptions.create() + .withTimeout(client.getConfig().getRequestTimeout()) + .withRollbackOnError(true) + .withStopOnError(false) + ) + .build(); + + Map options = new HashMap<>(); + options.put(CRUDBaseOptions.TIMEOUT, client.getConfig().getRequestTimeout()); + options.put(CRUDBatchOptions.BATCH_ROLLBACK_ON_ERROR, true); + options.put(CRUDBatchOptions.BATCH_STOP_ON_ERROR, false); + + assertEquals(client, operation.getClient()); + assertEquals("function1", operation.getFunctionName()); + assertEquals(Arrays.asList("space1", tarantoolTuples, options), operation.getArguments()); + assertEquals(defaultResultMapper, operation.getResultMapper()); + } + @Test public void replaceOperationBuilderTest() { List values = Arrays.asList(4, "a4", "Nineteen Eighty-Four", "George Orwell", 1984); - TarantoolTuple tarantoolTuple = new TarantoolTupleImpl(values, defaultMapper); + TarantoolTuple tarantoolTuple = factory.create(values); ReplaceProxyOperation> operation = new ReplaceProxyOperation.Builder>() @@ -101,7 +150,9 @@ public void replaceOperationBuilderTest() { .withTuple(tarantoolTuple) .withResultMapper(defaultResultMapper) .withArgumentsMapper(defaultMapper) - .withRequestTimeout(client.getConfig().getRequestTimeout()) + .withOptions(ProxyReplaceOptions.create() + .withTimeout(client.getConfig().getRequestTimeout()) + ) .build(); Map options = new HashMap<>(); @@ -114,6 +165,40 @@ public void replaceOperationBuilderTest() { } @Test + public void replaceManyOperationBuilderTest() { + List tarantoolTuples = Arrays.asList( + factory.create(Arrays.asList(4, "a4", "Nineteen Eighty-Four", "George Orwell", 1984)), + factory.create(Arrays.asList(44, "a44", "Silmarillion", "J. R. R. Tolkien", 1977)) + ); + + ReplaceManyProxyOperation> operation = + new ReplaceManyProxyOperation.Builder>() + .withClient(client) + .withSpaceName("space1") + .withFunctionName("function1") + .withTuples(tarantoolTuples) + .withResultMapper(defaultResultMapper) + .withArgumentsMapper(defaultMapper) + .withOptions(ProxyReplaceManyOptions.create() + .withTimeout(client.getConfig().getRequestTimeout()) + .withRollbackOnError(true) + .withStopOnError(false) + ) + .build(); + + Map options = new HashMap<>(); + options.put(CRUDBaseOptions.TIMEOUT, client.getConfig().getRequestTimeout()); + options.put(CRUDBatchOptions.BATCH_ROLLBACK_ON_ERROR, true); + options.put(CRUDBatchOptions.BATCH_STOP_ON_ERROR, false); + + assertEquals(client, operation.getClient()); + assertEquals("function1", operation.getFunctionName()); + assertEquals(Arrays.asList("space1", tarantoolTuples, options), operation.getArguments()); + assertEquals(defaultResultMapper, operation.getResultMapper()); + } + + @Test + @SuppressWarnings("unchecked") public void selectOperationBuilderTest() { TarantoolMetadata testOperations = new TarantoolMetadata(new TestMetadataProvider()); @@ -132,12 +217,15 @@ public void selectOperationBuilderTest() { .withConditions(conditions) .withResultMapper(defaultResultMapper) .withArgumentsMapper(defaultMapper) - .withRequestTimeout(client.getConfig().getRequestTimeout()) + .withOptions(ProxySelectOptions.create() + .withTimeout(client.getConfig().getRequestTimeout()) + .withBatchSize(123456) + ) .build(); Map options = new HashMap<>(); options.put(CRUDBaseOptions.TIMEOUT, client.getConfig().getRequestTimeout()); - options.put(CRUDSelectOptions.SELECT_BATCH_SIZE, 100L); + options.put(CRUDSelectOptions.SELECT_BATCH_SIZE, 123456); options.put(CRUDSelectOptions.SELECT_LIMIT, 100L); assertEquals(client, op.getClient()); @@ -145,7 +233,8 @@ public void selectOperationBuilderTest() { assertEquals(3, op.getArguments().size()); assertEquals("space1", op.getArguments().get(0)); assertEquals(selectArguments, op.getArguments().get(1)); - assertEquals(options, op.getArguments().get(2)); + Map actualOptions = (Map) op.getArguments().get(2); + assertEquals(options.toString(), actualOptions.toString()); assertEquals(defaultResultMapper, op.getResultMapper()); } @@ -163,7 +252,9 @@ public void updateOperationBuilderTest() { .withTupleOperation(TupleOperations.add(3, 90).andAdd(4, 5)) .withResultMapper(defaultResultMapper) .withArgumentsMapper(defaultMapper) - .withRequestTimeout(client.getConfig().getRequestTimeout()) + .withOptions(ProxyUpdateOptions.create() + .withTimeout(client.getConfig().getRequestTimeout()) + ) .build(); Map options = new HashMap<>(); @@ -187,7 +278,7 @@ public void upsertOperationBuilderTest() { indexQuery.withKeyValues(Collections.singletonList(10)); List values = Arrays.asList(4, "a4", "Nineteen Eighty-Four", "George Orwell", 1984); - TarantoolTuple tarantoolTuple = new TarantoolTupleImpl(values, defaultMapper); + TarantoolTuple tarantoolTuple = factory.create(values); UpsertProxyOperation> operation = new UpsertProxyOperation.Builder>() @@ -198,7 +289,9 @@ public void upsertOperationBuilderTest() { .withTupleOperation(TupleOperations.add(3, 90).andAdd(4, 5)) .withResultMapper(defaultResultMapper) .withArgumentsMapper(defaultMapper) - .withRequestTimeout(client.getConfig().getRequestTimeout()) + .withOptions(ProxyUpsertOptions.create() + .withTimeout(client.getConfig().getRequestTimeout()) + ) .build(); Map options = new HashMap<>(); @@ -220,7 +313,9 @@ public void test_truncateOperationBuilder_shouldReturnTruncateOperationObjectsWi .withClient(client) .withSpaceName("space1") .withFunctionName("function1") - .withRequestTimeout(client.getConfig().getRequestTimeout()) + .withOptions(ProxyTruncateOptions.create() + .withTimeout(client.getConfig().getRequestTimeout()) + ) .build(); // when prepare HashMap with options diff --git a/src/test/java/io/tarantool/driver/integration/ClusterTarantoolTupleClientIT.java b/src/test/java/io/tarantool/driver/integration/ClusterTarantoolTupleClientIT.java index 7dd4d959..8c5cf239 100644 --- a/src/test/java/io/tarantool/driver/integration/ClusterTarantoolTupleClientIT.java +++ b/src/test/java/io/tarantool/driver/integration/ClusterTarantoolTupleClientIT.java @@ -178,6 +178,24 @@ public void replaceRequest() throws Exception { assertEquals(1847, value.get().getInteger(4)); } + @Test + public void test_insertMany_shouldThrowException() throws Exception { + TarantoolSpaceOperations> testSpace = + client.space(TEST_SPACE_NAME); + + assertThrows(UnsupportedOperationException.class, + () -> testSpace.insertMany(Collections.emptyList())); + } + + @Test + public void test_replaceMany_shouldThrowException() throws Exception { + TarantoolSpaceOperations> testSpace = + client.space(TEST_SPACE_NAME); + + assertThrows(UnsupportedOperationException.class, + () -> testSpace.replaceMany(Collections.emptyList())); + } + @Test public void deleteRequest() throws Exception { TarantoolSpaceOperations> testSpace = diff --git a/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientIT.java b/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientIT.java index aa24d44c..d62ed72a 100644 --- a/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientIT.java +++ b/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientIT.java @@ -51,6 +51,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -264,6 +265,78 @@ public void replaceTest() throws ExecutionException, InterruptedException { assertEquals(tuple.getInteger(4), 100); } + @Test + public void test_insertMany_replaceMany() throws ExecutionException, InterruptedException { + truncateSpace(TEST_SPACE_NAME); + TarantoolSpaceOperations> profileSpace = + client.space(TEST_SPACE_NAME); + + List tarantoolTuples = new ArrayList<>(3); + tarantoolTuples.addAll(Arrays.asList( + tupleFactory.create(Arrays.asList(123, null, "Jane Doe", 18, 999)), + tupleFactory.create(Arrays.asList(456, null, "Jack the Ripper", 33, 111)) + )); + + TarantoolResult insertTuples = profileSpace.insertMany(tarantoolTuples).get(); + assertEquals(insertTuples.size(), 2); + TarantoolTuple tuple = insertTuples.get(0); + assertEquals(tuple.size(), 5); + assertEquals(tuple.getInteger(0), 123); + assertNotNull(tuple.getInteger(1)); //bucket_id + assertEquals(tuple.getString(2), "Jane Doe"); + assertEquals(tuple.getInteger(3), 18); + assertEquals(tuple.getInteger(4), 999); + tuple = insertTuples.get(1); + assertEquals(tuple.size(), 5); + assertEquals(tuple.getInteger(0), 456); + assertEquals(tuple.getString(2), "Jack the Ripper"); + assertEquals(tuple.getInteger(3), 33); + assertEquals(tuple.getInteger(4), 111); + + tarantoolTuples.set(0, tupleFactory.create(Arrays.asList(123, null, "Jane Doe", 18, 990))); + tarantoolTuples.add(tupleFactory.create(Arrays.asList(777, null, "Ostap Bender", 99, 777))); + + List duplicateTuples = Collections.unmodifiableList(tarantoolTuples); + + // Repeat the insert with the same IDs + assertThrows(ExecutionException.class, + () -> profileSpace.insertMany(duplicateTuples).get(), + "Duplicate key exists in unique index 'primary' in space 'test_space'"); + + // The data wasn't changed + TarantoolResult selectResult = profileSpace.select(Conditions.any()).get(); + assertEquals(2, selectResult.size()); + assertEquals(selectResult.get(0).getInteger(4), 999); + + // Replace + tarantoolTuples = Arrays.asList( + tupleFactory.create(Arrays.asList(123, null, "John Doe", 21, 100)), + tupleFactory.create(Arrays.asList(456, null, "Jack the Ripper", 44, 333)), + tupleFactory.create(Arrays.asList(777, null, "Ostap Bender", 99, 777)) + ); + TarantoolResult replaceResult = profileSpace.replaceMany(tarantoolTuples).get(); + assertEquals(replaceResult.size(), 3); + tuple = replaceResult.get(0); + assertEquals(tuple.size(), 5); + assertEquals(tuple.getInteger(0), 123); + assertNotNull(tuple.getInteger(1)); //bucket_id + assertEquals(tuple.getString(2), "John Doe"); + assertEquals(tuple.getInteger(3), 21); + assertEquals(tuple.getInteger(4), 100); + tuple = replaceResult.get(1); + assertEquals(tuple.size(), 5); + assertEquals(tuple.getInteger(0), 456); + assertEquals(tuple.getString(2), "Jack the Ripper"); + assertEquals(tuple.getInteger(3), 44); + assertEquals(tuple.getInteger(4), 333); + tuple = replaceResult.get(2); + assertEquals(tuple.size(), 5); + assertEquals(tuple.getInteger(0), 777); + assertEquals(tuple.getString(2), "Ostap Bender"); + assertEquals(tuple.getInteger(3), 99); + assertEquals(tuple.getInteger(4), 777); + } + @Test public void clusterUpdateTest() throws ExecutionException, InterruptedException { TarantoolSpaceOperations> profileSpace = diff --git a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceDeleteOptionsIT.java b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceDeleteOptionsIT.java index d136bcce..6be5dd00 100644 --- a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceDeleteOptionsIT.java +++ b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceDeleteOptionsIT.java @@ -5,15 +5,12 @@ 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.tuple.DefaultTarantoolTupleFactory; import io.tarantool.driver.api.tuple.TarantoolTuple; -import io.tarantool.driver.api.tuple.TarantoolTupleFactory; import io.tarantool.driver.auth.SimpleTarantoolCredentials; import io.tarantool.driver.core.ClusterTarantoolTupleClient; import io.tarantool.driver.core.ProxyTarantoolTupleClient; import io.tarantool.driver.api.space.options.proxy.ProxyDeleteOptions; import io.tarantool.driver.integration.SharedCartridgeContainer; -import io.tarantool.driver.mappers.DefaultMessagePackMapperFactory; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -30,9 +27,6 @@ public class ProxySpaceDeleteOptionsIT 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; @@ -85,8 +79,8 @@ public void withTimeout() throws ExecutionException, InterruptedException { // with option timeout profileSpace.delete( - conditions, - ProxyDeleteOptions.create().withTimeout(customRequestTimeout) + conditions, + ProxyDeleteOptions.create().withTimeout(customRequestTimeout) ).get(); crudDeleteOpts = client.eval("return crud_delete_opts").get(); assertEquals(customRequestTimeout, ((HashMap) crudDeleteOpts.get(0)).get("timeout")); diff --git a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceInsertManyOptionsIT.java b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceInsertManyOptionsIT.java new file mode 100644 index 00000000..d7d6773e --- /dev/null +++ b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceInsertManyOptionsIT.java @@ -0,0 +1,136 @@ +package io.tarantool.driver.integration.proxy.options; + +import io.tarantool.driver.api.TarantoolClient; +import io.tarantool.driver.api.TarantoolClientConfig; +import io.tarantool.driver.api.TarantoolResult; +import io.tarantool.driver.api.space.TarantoolSpaceOperations; +import io.tarantool.driver.api.tuple.DefaultTarantoolTupleFactory; +import io.tarantool.driver.api.tuple.TarantoolTuple; +import io.tarantool.driver.api.tuple.TarantoolTupleFactory; +import io.tarantool.driver.auth.SimpleTarantoolCredentials; +import io.tarantool.driver.core.ClusterTarantoolTupleClient; +import io.tarantool.driver.core.ProxyTarantoolTupleClient; +import io.tarantool.driver.api.space.options.proxy.ProxyInsertManyOptions; +import io.tarantool.driver.integration.SharedCartridgeContainer; +import io.tarantool.driver.mappers.DefaultMessagePackMapperFactory; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Alexey Kuzin + */ +public class ProxySpaceInsertManyOptionsIT 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"; + + @BeforeAll + public static void setUp() throws Exception { + startCluster(); + USER_NAME = container.getUsername(); + PASSWORD = container.getPassword(); + initClient(); + } + + 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()); + client = new ProxyTarantoolTupleClient(clusterClient); + } + + @BeforeEach + public void truncateSpace() { + truncateSpace(TEST_SPACE_NAME); + } + + private static void truncateSpace(String spaceName) { + client.space(spaceName).truncate().join(); + } + + @Test + public void withStopOnError_withRollbackOnError() throws ExecutionException, InterruptedException { + TarantoolSpaceOperations> profileSpace = + client.space(TEST_SPACE_NAME); + + List tarantoolTuples = Arrays.asList( + tupleFactory.create(1, null, "FIO", 50, 100), + tupleFactory.create(2, null, "KEK", 75, 125) + ); + + // with default values + profileSpace.insertMany(tarantoolTuples).get(); + List crudInsertManyOpts = client.eval("return crud_insert_many_opts").get(); + assertEquals(true, ((HashMap) crudInsertManyOpts.get(0)).get("rollback_on_error")); + assertEquals(true, ((HashMap) crudInsertManyOpts.get(0)).get("stop_on_error")); + + // with custom values + tarantoolTuples = Arrays.asList( + tupleFactory.create(3, null, "FIO", 50, 100), + tupleFactory.create(4, null, "KEK", 75, 125) + ); + + profileSpace.insertMany( + tarantoolTuples, + ProxyInsertManyOptions.create() + .withRollbackOnError(false) + .withStopOnError(false) + ).get(); + crudInsertManyOpts = client.eval("return crud_insert_many_opts").get(); + assertEquals(false, ((HashMap) crudInsertManyOpts.get(0)).get("rollback_on_error")); + assertEquals(false, ((HashMap) crudInsertManyOpts.get(0)).get("stop_on_error")); + } + + @Test + public void withTimeout() throws ExecutionException, InterruptedException { + TarantoolSpaceOperations> profileSpace = + client.space(TEST_SPACE_NAME); + + int requestConfigTimeout = client.getConfig().getRequestTimeout(); + int customRequestTimeout = requestConfigTimeout * 2; + + List tarantoolTuples = Arrays.asList( + tupleFactory.create(1, null, "FIO", 50, 100), + tupleFactory.create(2, null, "KEK", 75, 125) + ); + + // with config timeout + profileSpace.insertMany(tarantoolTuples).get(); + List crudInsertManyOpts = client.eval("return crud_insert_many_opts").get(); + assertEquals(requestConfigTimeout, ((HashMap) crudInsertManyOpts.get(0)).get("timeout")); + + // with option timeout + tarantoolTuples = Arrays.asList( + tupleFactory.create(3, null, "FIO", 50, 100), + tupleFactory.create(4, null, "KEK", 75, 125) + ); + + profileSpace.insertMany( + tarantoolTuples, + ProxyInsertManyOptions.create().withTimeout(customRequestTimeout) + ).get(); + crudInsertManyOpts = client.eval("return crud_insert_many_opts").get(); + assertEquals(customRequestTimeout, ((HashMap) crudInsertManyOpts.get(0)).get("timeout")); + } +} diff --git a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceReplaceManyOptionsIT.java b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceReplaceManyOptionsIT.java new file mode 100644 index 00000000..deb03d11 --- /dev/null +++ b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceReplaceManyOptionsIT.java @@ -0,0 +1,126 @@ +package io.tarantool.driver.integration.proxy.options; + +import io.tarantool.driver.api.TarantoolClient; +import io.tarantool.driver.api.TarantoolClientConfig; +import io.tarantool.driver.api.TarantoolResult; +import io.tarantool.driver.api.space.TarantoolSpaceOperations; +import io.tarantool.driver.api.tuple.DefaultTarantoolTupleFactory; +import io.tarantool.driver.api.tuple.TarantoolTuple; +import io.tarantool.driver.api.tuple.TarantoolTupleFactory; +import io.tarantool.driver.auth.SimpleTarantoolCredentials; +import io.tarantool.driver.core.ClusterTarantoolTupleClient; +import io.tarantool.driver.core.ProxyTarantoolTupleClient; +import io.tarantool.driver.api.space.options.proxy.ProxyReplaceManyOptions; +import io.tarantool.driver.integration.SharedCartridgeContainer; +import io.tarantool.driver.mappers.DefaultMessagePackMapperFactory; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Alexey Kuzin + */ +public class ProxySpaceReplaceManyOptionsIT 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"; + + @BeforeAll + public static void setUp() throws Exception { + startCluster(); + USER_NAME = container.getUsername(); + PASSWORD = container.getPassword(); + initClient(); + } + + 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()); + client = new ProxyTarantoolTupleClient(clusterClient); + } + + @BeforeEach + public void truncateSpace() { + truncateSpace(TEST_SPACE_NAME); + } + + private static void truncateSpace(String spaceName) { + client.space(spaceName).truncate().join(); + } + + @Test + public void withStopOnError_withRollbackOnError() throws ExecutionException, InterruptedException { + TarantoolSpaceOperations> profileSpace = + client.space(TEST_SPACE_NAME); + + List tarantoolTuples = Arrays.asList( + tupleFactory.create(1, null, "FIO", 50, 100), + tupleFactory.create(2, null, "KEK", 75, 125) + ); + + // with default values + profileSpace.replaceMany(tarantoolTuples).get(); + List crudReplaceManyOpts = client.eval("return crud_replace_many_opts").get(); + assertEquals(true, ((HashMap) crudReplaceManyOpts.get(0)).get("rollback_on_error")); + assertEquals(true, ((HashMap) crudReplaceManyOpts.get(0)).get("stop_on_error")); + + // with custom values + profileSpace.replaceMany( + tarantoolTuples, + ProxyReplaceManyOptions.create() + .withRollbackOnError(false) + .withStopOnError(false) + ).get(); + crudReplaceManyOpts = client.eval("return crud_replace_many_opts").get(); + assertEquals(false, ((HashMap) crudReplaceManyOpts.get(0)).get("rollback_on_error")); + assertEquals(false, ((HashMap) crudReplaceManyOpts.get(0)).get("stop_on_error")); + } + + @Test + public void withTimeout() throws ExecutionException, InterruptedException { + TarantoolSpaceOperations> profileSpace = + client.space(TEST_SPACE_NAME); + + int requestConfigTimeout = client.getConfig().getRequestTimeout(); + int customRequestTimeout = requestConfigTimeout * 2; + + List tarantoolTuples = Arrays.asList( + tupleFactory.create(1, null, "FIO", 50, 100), + tupleFactory.create(2, null, "KEK", 75, 125) + ); + + // with config timeout + profileSpace.replaceMany(tarantoolTuples).get(); + List crudReplaceManyOpts = client.eval("return crud_replace_many_opts").get(); + assertEquals(requestConfigTimeout, ((HashMap) crudReplaceManyOpts.get(0)).get("timeout")); + + // with option timeout + profileSpace.replaceMany( + tarantoolTuples, + ProxyReplaceManyOptions.create().withTimeout(customRequestTimeout) + ).get(); + crudReplaceManyOpts = client.eval("return crud_replace_many_opts").get(); + assertEquals(customRequestTimeout, ((HashMap) crudReplaceManyOpts.get(0)).get("timeout")); + } +} diff --git a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceReplaceOptionsIT.java b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceReplaceOptionsIT.java index 9ab2f8e9..7352a02b 100644 --- a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceReplaceOptionsIT.java +++ b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceReplaceOptionsIT.java @@ -37,7 +37,6 @@ public class ProxySpaceReplaceOptionsIT extends SharedCartridgeContainer { public static String PASSWORD; private static final String TEST_SPACE_NAME = "test__profile"; - private static final String PK_FIELD_NAME = "profile_id"; @BeforeAll public static void setUp() throws Exception { 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 a2bdd275..8a1e5710 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 @@ -87,10 +87,13 @@ public void withBatchSizeTest() throws ExecutionException, InterruptedException TarantoolResult selectResult = profileSpace.select(conditions).get(); assertEquals(10, selectResult.size()); List crudSelectOpts = client.eval("return crud_select_opts").get(); - assertEquals(10, ((HashMap) crudSelectOpts.get(0)).get("batch_size")); + assertEquals(null, ((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")); diff --git a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceUpsertOptionsIT.java b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceUpsertOptionsIT.java index 55550273..e3c4e24a 100644 --- a/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceUpsertOptionsIT.java +++ b/src/test/java/io/tarantool/driver/integration/proxy/options/ProxySpaceUpsertOptionsIT.java @@ -88,11 +88,11 @@ public void withTimeout() throws ExecutionException, InterruptedException { // with option timeout profileSpace.upsert( - conditions, - tarantoolTuple, - TupleOperations.set("age", 50), - ProxyUpsertOptions.create().withTimeout(customRequestTimeout) - ).get(); + conditions, + tarantoolTuple, + TupleOperations.set("age", 50), + ProxyUpsertOptions.create().withTimeout(customRequestTimeout) + ).get(); crudUpsertOpts = client.eval("return crud_upsert_opts").get(); assertEquals(customRequestTimeout, ((HashMap) crudUpsertOpts.get(0)).get("timeout")); } diff --git a/src/test/resources/cartridge/app/roles/api_router.lua b/src/test/resources/cartridge/app/roles/api_router.lua index dca20a78..c2668496 100644 --- a/src/test/resources/cartridge/app/roles/api_router.lua +++ b/src/test/resources/cartridge/app/roles/api_router.lua @@ -19,7 +19,9 @@ local crud_methods_to_patch = { 'select', 'delete', 'insert', + 'insert_many', 'replace', + 'replace_many', 'update', 'upsert', } diff --git a/src/test/resources/cartridge/testapp-scm-1.rockspec b/src/test/resources/cartridge/testapp-scm-1.rockspec index 355acf73..9bb80743 100644 --- a/src/test/resources/cartridge/testapp-scm-1.rockspec +++ b/src/test/resources/cartridge/testapp-scm-1.rockspec @@ -8,7 +8,7 @@ dependencies = { 'tarantool', 'lua >= 5.1', 'cartridge == 2.7.3-1', - 'crud == 0.10.0-1', + 'crud == 0.14.0-1', } build = { type = 'none';