This is an automated email from the ASF dual-hosted git repository.
isapego pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new cafb8d3a10 IGNITE-18255 Add key_value_view in C++ (#1949)
cafb8d3a10 is described below
commit cafb8d3a102f82a0a74eb7adca198ae4234224df
Author: Igor Sapego <[email protected]>
AuthorDate: Tue Apr 18 12:08:00 2023 +0400
IGNITE-18255 Add key_value_view in C++ (#1949)
---
modules/platforms/cpp/ignite/client/CMakeLists.txt | 1 +
.../cpp/ignite/client/detail/type_mapping_utils.h | 130 ++++
.../cpp/ignite/client/table/key_value_view.h | 524 ++++++++++++-
.../cpp/ignite/client/table/record_view.h | 112 +--
modules/platforms/cpp/ignite/client/table/table.h | 15 +-
.../platforms/cpp/tests/client-test/CMakeLists.txt | 1 +
.../cpp/tests/client-test/all_fields_type.h | 123 +++
.../client-test/key_value_binary_view_test.cpp | 4 +-
.../cpp/tests/client-test/key_value_view_test.cpp | 825 +++++++++++++++++++++
.../cpp/tests/client-test/record_view_test.cpp | 91 +--
10 files changed, 1612 insertions(+), 214 deletions(-)
diff --git a/modules/platforms/cpp/ignite/client/CMakeLists.txt
b/modules/platforms/cpp/ignite/client/CMakeLists.txt
index fc28d4a98c..614708bd0f 100644
--- a/modules/platforms/cpp/ignite/client/CMakeLists.txt
+++ b/modules/platforms/cpp/ignite/client/CMakeLists.txt
@@ -47,6 +47,7 @@ set(PUBLIC_HEADERS
primitive.h
type_mapping.h
compute/compute.h
+ detail/type_mapping_utils.h
network/cluster_node.h
sql/sql.h
table/ignite_tuple.h
diff --git a/modules/platforms/cpp/ignite/client/detail/type_mapping_utils.h
b/modules/platforms/cpp/ignite/client/detail/type_mapping_utils.h
new file mode 100644
index 0000000000..1f1286683b
--- /dev/null
+++ b/modules/platforms/cpp/ignite/client/detail/type_mapping_utils.h
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ignite/client/table/ignite_tuple.h>
+#include <ignite/client/type_mapping.h>
+
+#include <ignite/common/ignite_result.h>
+
+namespace ignite {
+/**
+ * Convert values to tuples.
+ * @param vals Values.
+ * @return Tuples.
+ */
+template<typename T>
+std::vector<ignite_tuple> values_to_tuples(std::vector<T> values) {
+ //TODO: Optimize memory usage (IGNITE-19198)
+ std::vector<ignite_tuple> tuples;
+ tuples.reserve(values.size());
+ for (auto &&value : std::move(values)) {
+ tuples.push_back(convert_to_tuple(std::move(value)));
+ }
+ return tuples;
+}
+
+/**
+ * Convert key-value pairs to tuples.
+ * @param vals Values.
+ * @return Tuples.
+ */
+template<typename K, typename V>
+std::vector<std::pair<ignite_tuple, ignite_tuple>>
values_to_tuples(std::vector<std::pair<K, V>> values) {
+ //TODO: Optimize memory usage (IGNITE-19198)
+ std::vector<std::pair<ignite_tuple, ignite_tuple>> tuples;
+ tuples.reserve(values.size());
+ for (auto &&pair : std::move(values)) {
+ tuples.emplace_back(convert_to_tuple(std::move(pair.first)),
convert_to_tuple(std::move(pair.second)));
+ }
+ return tuples;
+}
+
+/**
+ * Tuples to values.
+ * @param tuples Tuples.
+ * @return Values.
+ */
+template<typename T>
+std::vector<T> tuples_to_values(std::vector<ignite_tuple> tuples) {
+ //TODO: Optimize memory usage (IGNITE-19198)
+ std::vector<T> values;
+ values.reserve(tuples.size());
+ for (auto &&tuple : std::move(tuples)) {
+ values.emplace_back(convert_from_tuple<T>(std::move(tuple)));
+ }
+ return values;
+}
+
+/**
+ * Optional tuples to optional values.
+ * @param tuples Tuples.
+ * @return Values.
+ */
+template<typename T>
+std::vector<std::optional<T>>
tuples_to_values(std::vector<std::optional<ignite_tuple>> tuples) {
+ //TODO: Optimize memory usage (IGNITE-19198)
+ std::vector<std::optional<T>> values;
+ values.reserve(tuples.size());
+ for (auto &&tuple : std::move(tuples)) {
+ values.emplace_back(convert_from_tuple<T>(std::move(tuple)));
+ }
+ return values;
+}
+
+/**
+ * Convert result from tuple-based type to user type.
+ * @param res Result to convert.
+ * @return Converted result.
+ */
+template<typename T>
+ignite_result<std::optional<T>>
convert_result(ignite_result<std::optional<ignite_tuple>> &&res) {
+ if (res.has_error())
+ return {std::move(res).error()};
+
+ return {convert_from_tuple<T>(std::move(res).value())};
+}
+
+/**
+ * Convert result from tuple-based type to user type.
+ * @param res Result to convert.
+ * @return Converted result.
+ */
+template<typename T>
+ignite_result<std::vector<std::optional<T>>> convert_result(
+ ignite_result<std::vector<std::optional<ignite_tuple>>> &&res) {
+ if (res.has_error())
+ return {std::move(res).error()};
+
+ return {tuples_to_values<T>(std::move(res).value())};
+}
+
+/**
+ * Convert result from tuple-based type to user type.
+ * @param res Result to convert.
+ * @return Converted result.
+ */
+template<typename T>
+ignite_result<std::vector<T>>
convert_result(ignite_result<std::vector<ignite_tuple>> &&res) {
+ if (res.has_error())
+ return {std::move(res).error()};
+
+ return {tuples_to_values<T>(std::move(res).value())};
+}
+
+} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/client/table/key_value_view.h
b/modules/platforms/cpp/ignite/client/table/key_value_view.h
index 26fbafc0a7..04daa2b37e 100644
--- a/modules/platforms/cpp/ignite/client/table/key_value_view.h
+++ b/modules/platforms/cpp/ignite/client/table/key_value_view.h
@@ -19,6 +19,8 @@
#include "ignite/client/table/ignite_tuple.h"
#include "ignite/client/transaction/transaction.h"
+#include "ignite/client/type_mapping.h"
+#include "ignite/client/detail/type_mapping_utils.h"
#include "ignite/common/config.h"
#include "ignite/common/ignite_result.h"
@@ -36,24 +38,8 @@ namespace detail {
class table_impl;
}
-/**
- * Key-Value view interface provides methods to access table records in form
of separate key and value parts.
- */
template<typename K, typename V>
-class key_value_view {
-public:
- typedef typename std::decay<K>::type key_type;
- typedef typename std::decay<V>::type value_type;
-
- // Deleted
- key_value_view(const key_value_view &) = delete;
- key_value_view &operator=(const key_value_view &) = delete;
-
- // Default
- key_value_view() = default;
- key_value_view(key_value_view &&) noexcept = default;
- key_value_view &operator=(key_value_view &&) noexcept = default;
-};
+class key_value_view;
/**
* Key-Value view interface provides methods to access table records in form
of separate key and value parts.
@@ -76,7 +62,7 @@ public:
key_value_view &operator=(key_value_view &&) noexcept = default;
/**
- * Gets a record by key asynchronously.
+ * Gets a value by key asynchronously.
*
* @param tx Optional transaction. If nullptr implicit transaction for this
* single operation is used.
@@ -88,7 +74,7 @@ public:
transaction *tx, const key_type &key,
ignite_callback<std::optional<value_type>> callback);
/**
- * Gets a record by key.
+ * Gets a value by key.
*
* @param tx Optional transaction. If nullptr implicit transaction for this
* single operation is used.
@@ -276,7 +262,7 @@ public:
* @param key Key.
* @return A value indicating whether a record with the specified key was
deleted.
*/
- IGNITE_API bool remove(transaction *tx, const value_type &key) {
+ IGNITE_API bool remove(transaction *tx, const key_type &key) {
return sync<bool>([this, tx, &key](auto callback) { remove_async(tx,
key, std::move(callback)); });
}
@@ -319,7 +305,7 @@ public:
* records from @c keys that did not exist.
*/
IGNITE_API void remove_all_async(
- transaction *tx, std::vector<key_type> keys,
ignite_callback<std::vector<value_type>> callback);
+ transaction *tx, std::vector<key_type> keys,
ignite_callback<std::vector<key_type>> callback);
/**
* Removes values with given keys from the table. If one or more keys
@@ -330,8 +316,8 @@ public:
* @param keys Keys.
* @return Records from @c keys that did not exist.
*/
- IGNITE_API std::vector<value_type> remove_all(transaction *tx,
std::vector<key_type> keys) {
- return sync<std::vector<value_type>>([this, tx, keys =
std::move(keys)](auto callback) mutable {
+ IGNITE_API std::vector<key_type> remove_all(transaction *tx,
std::vector<key_type> keys) {
+ return sync<std::vector<key_type>>([this, tx, keys =
std::move(keys)](auto callback) mutable {
remove_all_async(tx, std::move(keys), std::move(callback));
});
}
@@ -347,7 +333,7 @@ public:
* records from @c records that did not exist.
*/
IGNITE_API void remove_all_async(transaction *tx, const
std::vector<std::pair<key_type, value_type>> &pairs,
- ignite_callback<std::vector<value_type>> callback);
+ ignite_callback<std::vector<key_type>> callback);
/**
* Removes records with given keys and values from the table. If one or
more
@@ -358,8 +344,8 @@ public:
* @param pairs Pairs to remove.
* @return Records from @c records that did not exist.
*/
- IGNITE_API std::vector<value_type> remove_all(transaction *tx,
std::vector<std::pair<key_type, value_type>> pairs) {
- return sync<std::vector<value_type>>([this, tx, pairs =
std::move(pairs)](auto callback) mutable {
+ IGNITE_API std::vector<key_type> remove_all(transaction *tx,
std::vector<std::pair<key_type, value_type>> pairs) {
+ return sync<std::vector<key_type>>([this, tx, pairs =
std::move(pairs)](auto callback) mutable {
remove_all_async(tx, std::move(pairs), std::move(callback));
});
}
@@ -495,4 +481,490 @@ private:
std::shared_ptr<detail::table_impl> m_impl;
};
+/**
+ * Key-Value view interface provides methods to access table records in form
of separate key and value parts.
+ */
+template<typename K, typename V>
+class key_value_view {
+ friend class table;
+
+public:
+ typedef typename std::decay<K>::type key_type;
+ typedef typename std::decay<V>::type value_type;
+
+ // Deleted
+ key_value_view(const key_value_view &) = delete;
+ key_value_view &operator=(const key_value_view &) = delete;
+
+ // Default
+ key_value_view() = default;
+ key_value_view(key_value_view &&) noexcept = default;
+ key_value_view &operator=(key_value_view &&) noexcept = default;
+
+ /**
+ * Gets a value by key asynchronously.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param callback Callback which is called on success with value if it
+ * exists and @c std::nullopt otherwise
+ */
+ void get_async(transaction *tx, const key_type &key,
ignite_callback<std::optional<value_type>> callback) {
+ m_delegate.get_async(tx, convert_to_tuple(key), [callback =
std::move(callback)] (auto res) {
+ callback(convert_result<value_type>(std::move(res)));
+ });
+ }
+
+ /**
+ * Gets a value by key.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @return Value if exists and @c std::nullopt otherwise.
+ */
+ [[nodiscard]] std::optional<value_type> get(transaction *tx, const
key_type &key) {
+ return sync<std::optional<value_type>>(
+ [this, tx, &key](auto callback) { get_async(tx, key,
std::move(callback)); });
+ }
+
+ /**
+ * Gets multiple values by keys asynchronously.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param keys Keys.
+ * @param callback Callback that is called on operation completion. Called
with
+ * resulting records with all columns filled from the table. The order of
+ * elements is guaranteed to be the same as the order of keys. If a
record
+ * does not exist, the resulting element of the corresponding order is
+ * @c std::nullopt.
+ */
+ void get_all_async(
+ transaction *tx, std::vector<key_type> keys,
ignite_callback<std::vector<std::optional<value_type>>> callback) {
+ m_delegate.get_all_async(tx,
values_to_tuples<key_type>(std::move(keys)),
+ [callback = std::move(callback)] (auto res) {
+ callback(convert_result<value_type>(std::move(res)));
+ });
+ }
+
+ /**
+ * Gets multiple values by keys.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param keys Keys.
+ * @return Resulting records with all columns filled from the table.
+ * The order of elements is guaranteed to be the same as the order of
+ * keys. If a record does not exist, the resulting element of the
+ * corresponding order is @c std::nullopt.
+ */
+ [[nodiscard]] std::vector<std::optional<value_type>> get_all(
+ transaction *tx, std::vector<key_type> keys) {
+ return sync<std::vector<std::optional<value_type>>>([this, tx, keys =
std::move(keys)](auto callback) mutable {
+ get_all_async(tx, std::move(keys), std::move(callback));
+ });
+ }
+
+ /**
+ * Asynchronously determines if the table contains a value for the
specified key.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param callback Callback which is called on success with value
+ * indicating whether value exists or not.
+ */
+ void contains_async(transaction *tx, const key_type &key,
ignite_callback<bool> callback) {
+ m_delegate.contains_async(tx, convert_to_tuple(key),
std::move(callback));
+ }
+
+ /**
+ * Determines if the table contains an entry for the specified key.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @return Value indicating whether value exists or not.
+ */
+ [[nodiscard]] bool contains(transaction *tx, const key_type &key) {
+ return sync<bool>([this, tx, &key](auto callback) { contains_async(tx,
key, std::move(callback)); });
+ }
+
+ /**
+ * Puts a value with a given key asynchronously.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @param callback Callback.
+ */
+ void put_async(transaction *tx, const key_type &key, const value_type
&value, ignite_callback<void> callback) {
+ m_delegate.put_async(tx, convert_to_tuple(key),
convert_to_tuple(value), std::move(callback));
+ }
+
+ /**
+ * Puts a value with a given key.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ */
+ void put(transaction *tx, const key_type &key, const value_type &value) {
+ sync<void>([this, tx, &key, &value](auto callback) { put_async(tx,
key, value, std::move(callback)); });
+ }
+
+ /**
+ * Puts multiple key-value pairs asynchronously.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param pairs Pairs to put.
+ * @param callback Callback that is called on operation completion.
+ */
+ void put_all_async(
+ transaction *tx, const std::vector<std::pair<key_type, value_type>>
&pairs, ignite_callback<void> callback) {
+ m_delegate.put_all_async(tx, values_to_tuples<key_type,
value_type>(std::move(pairs)), std::move(callback));
+ }
+
+ /**
+ * Puts multiple key-value pairs.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param pairs Pairs to put.
+ */
+ void put_all(transaction *tx, const std::vector<std::pair<key_type,
value_type>> &pairs) {
+ sync<void>([this, tx, pairs](auto callback) mutable {
put_all_async(tx, pairs, std::move(callback)); });
+ }
+
+ /**
+ * Puts a value with a given key and returns previous value for the key
asynchronously.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @param callback Callback. Called with a value which contains replaced
+ * value or @c std::nullopt if it did not exist.
+ */
+ void get_and_put_async(transaction *tx, const key_type &key, const
value_type &value,
+ ignite_callback<std::optional<value_type>> callback) {
+ m_delegate.get_and_put_async(tx, convert_to_tuple(key),
convert_to_tuple(value),
+ [callback = std::move(callback)] (auto res) {
+ callback(convert_result<value_type>(std::move(res)));
+ });
+ }
+
+ /**
+ * Puts a value with a given key and returns previous value for the key.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @return A replaced value or @c std::nullopt if it did not exist.
+ */
+ [[nodiscard]] std::optional<value_type> get_and_put(
+ transaction *tx, const key_type &key, const value_type &value) {
+ return sync<std::optional<value_type>>(
+ [this, tx, &key, &value](auto callback) { get_and_put_async(tx,
key, value, std::move(callback)); });
+ }
+
+ /**
+ * Asynchronously puts a value with a given key if the specified key is
not present in the table.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @param callback Callback. Called with a value indicating whether the
+ * record was inserted. Equals @c false if a record with the same key
+ * already exists.
+ */
+ void put_if_absent_async(
+ transaction *tx, const key_type &key, const value_type &value,
ignite_callback<bool> callback) {
+ m_delegate.put_if_absent_async(tx, convert_to_tuple(key),
convert_to_tuple(value), std::move(callback));
+ }
+
+ /**
+ * Puts a value with a given key if the specified key is not present in
the table.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ */
+ bool put_if_absent(transaction *tx, const key_type &key, const value_type
&value) {
+ return sync<bool>(
+ [this, tx, &key, &value](auto callback) { put_if_absent_async(tx,
key, value, std::move(callback)); });
+ }
+
+ /**
+ * Removes a value with the specified key asynchronously.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param callback Callback that is called on operation completion. Called
with
+ * a value indicating whether a record with the specified key was
deleted.
+ */
+ void remove_async(transaction *tx, const key_type &key,
ignite_callback<bool> callback) {
+ m_delegate.remove_async(tx, convert_to_tuple(key),
std::move(callback));
+ }
+
+ /**
+ * Removes a value with the specified key.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @return A value indicating whether a record with the specified key was
deleted.
+ */
+ bool remove(transaction *tx, const key_type &key) {
+ return sync<bool>([this, tx, &key](auto callback) { remove_async(tx,
key, std::move(callback)); });
+ }
+
+ /**
+ * Asynchronously removes a value with a given key from the table only if
it is equal to the specified value.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @param callback Callback that is called on operation completion. Called
with
+ * a value indicating whether a record with the specified key was
deleted.
+ */
+ void remove_async(
+ transaction *tx, const key_type &key, const value_type &value,
ignite_callback<bool> callback) {
+ m_delegate.remove_async(tx, convert_to_tuple(key),
convert_to_tuple(value), std::move(callback));
+ }
+
+ /**
+ * Removes a value with a given key from the table only if it is equal to
the specified value.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @return A value indicating whether a record with the specified key was
+ * deleted.
+ */
+ bool remove(transaction *tx, const key_type &key, const value_type &value)
{
+ return sync<bool>(
+ [this, tx, &key, &value](auto callback) { remove_async(tx, key,
value, std::move(callback)); });
+ }
+
+ /**
+ * Removes values with given keys from the table asynchronously. If one or
+ * more keys do not exist, other values are still removed
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param keys Keys.
+ * @param callback Callback that is called on operation completion. Called
with
+ * records from @c keys that did not exist.
+ */
+ void remove_all_async(
+ transaction *tx, std::vector<key_type> keys,
ignite_callback<std::vector<key_type>> callback) {
+ m_delegate.remove_all_async(tx,
values_to_tuples<key_type>(std::move(keys)),
+ [callback = std::move(callback)] (auto res) {
+ callback(convert_result<key_type>(std::move(res)));
+ });
+ }
+
+ /**
+ * Removes values with given keys from the table. If one or more keys
+ * do not exist, other values are still removed
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param keys Keys.
+ * @return Records from @c keys that did not exist.
+ */
+ std::vector<key_type> remove_all(transaction *tx, std::vector<key_type>
keys) {
+ return sync<std::vector<key_type>>([this, tx, keys =
std::move(keys)](auto callback) mutable {
+ remove_all_async(tx, std::move(keys), std::move(callback));
+ });
+ }
+
+ /**
+ * Removes records with given keys and values from the table
asynchronously.
+ * If one or more records do not exist, other records are still removed.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param pairs Pairs to remove.
+ * @param callback Callback that is called on operation completion. Called
with
+ * records from @c records that did not exist.
+ */
+ void remove_all_async(transaction *tx, const
std::vector<std::pair<key_type, value_type>> &pairs,
+ ignite_callback<std::vector<key_type>> callback) {
+ m_delegate.remove_all_async(tx, values_to_tuples<key_type,
value_type>(std::move(pairs)),
+ [callback = std::move(callback)] (auto res) {
+ callback(convert_result<key_type>(std::move(res)));
+ });
+ }
+
+ /**
+ * Removes records with given keys and values from the table. If one or
more
+ * records do not exist, other records are still removed.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param pairs Pairs to remove.
+ * @return Records from @c records that did not exist.
+ */
+ std::vector<key_type> remove_all(transaction *tx,
std::vector<std::pair<key_type, value_type>> pairs) {
+ return sync<std::vector<key_type>>([this, tx, pairs =
std::move(pairs)](auto callback) mutable {
+ remove_all_async(tx, std::move(pairs), std::move(callback));
+ });
+ }
+
+ /**
+ * Gets and removes a value associated with the given key asynchronously.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param callback Callback that is called on operation completion. Called
with
+ * a removed record or @c std::nullopt if it did not exist.
+ */
+ void get_and_remove_async(
+ transaction *tx, const key_type &key,
ignite_callback<std::optional<value_type>> callback) {
+ m_delegate.get_and_remove_async(tx, convert_to_tuple(key),
+ [callback = std::move(callback)] (auto res) {
+ callback(convert_result<value_type>(std::move(res)));
+ });
+ }
+
+ /**
+ * Gets and removes a value associated with the given key.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key key.
+ * @return A removed record or @c std::nullopt if it did not exist.
+ */
+ std::optional<value_type> get_and_remove(transaction *tx, const key_type
&key) {
+ return sync<std::optional<value_type>>(
+ [this, tx, &key](auto callback) { get_and_remove_async(tx, key,
std::move(callback)); });
+ }
+
+ /**
+ * Asynchronously replaces a record with the specified key if it exists,
otherwise does nothing.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @param callback Callback. Called with a value indicating whether a
record
+ * with the specified key was replaced.
+ */
+ void replace_async(transaction *tx, const key_type &key, const value_type
&value, ignite_callback<bool> callback) {
+ m_delegate.replace_async(tx, convert_to_tuple(key),
convert_to_tuple(value), std::move(callback));
+ }
+
+ /**
+ * Replaces a record with the same key columns if it exists, otherwise does
+ * nothing.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @return A value indicating whether a record with the specified key was
+ * replaced.
+ */
+ bool replace(transaction *tx, const key_type &key, const value_type
&value) {
+ return sync<bool>(
+ [this, tx, &key, &value](auto callback) { replace_async(tx, key,
value, std::move(callback)); });
+ }
+
+ /**
+ * Asynchronously replaces a value with a @c new_value one only if
existing value equals to the specified
+ * @c old_value.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param old_value Value to be replaced.
+ * @param new_value New value.
+ * @param callback Callback. Called with a value indicating whether a
+ * specified record was replaced.
+ */
+ void replace_async(transaction *tx, const key_type &key, const value_type
&old_value,
+ const value_type &new_value, ignite_callback<bool> callback) {
+ m_delegate.replace_async(tx, convert_to_tuple(key),
convert_to_tuple(old_value), convert_to_tuple(new_value),
+ std::move(callback));
+ }
+
+ /**
+ * Replaces a value with a @c new_value one only if existing value equals
+ * to the specified @c old_value.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param old_value Value to be replaced.
+ * @param new_value New value.
+ * @return A value indicating whether a specified record was replaced.
+ */
+ bool replace(
+ transaction *tx, const key_type &key, const value_type &old_value,
const value_type &new_value) {
+ return sync<bool>([this, tx, &key, &old_value, &new_value](
+ auto callback) { replace_async(tx, key,
old_value, new_value, std::move(callback)); });
+ }
+
+ /**
+ * Asynchronously replaces a record with the given key if it exists
+ * returning previous value.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @param callback Callback. Called with a previous value for the given
key,
+ * or @c std::nullopt if it did not exist.
+ */
+ void get_and_replace_async(transaction *tx, const key_type &key, const
value_type &value,
+ ignite_callback<std::optional<value_type>> callback) {
+ m_delegate.get_and_replace_async(tx, convert_to_tuple(key),
convert_to_tuple(value),
+ [callback = std::move(callback)] (auto res) {
+ callback(convert_result<value_type>(std::move(res)));
+ });
+ }
+
+ /**
+ * Replaces a record with the given key if it exists returning previous
+ * value.
+ *
+ * @param tx Optional transaction. If nullptr implicit transaction for this
+ * single operation is used.
+ * @param key Key.
+ * @param value Value.
+ * @param callback A previous value for the given key, or @c std::nullopt
if
+ * it did not exist.
+ */
+ [[nodiscard]] std::optional<value_type> get_and_replace(
+ transaction *tx, const key_type &key, const value_type &value) {
+ return sync<std::optional<value_type>>(
+ [this, tx, &key, &value](auto callback) {
get_and_replace_async(tx, key, value, std::move(callback)); });
+ }
+private:
+ /**
+ * Constructor
+ *
+ * @param impl Implementation
+ */
+ explicit key_value_view(key_value_view<ignite_tuple, ignite_tuple>
delegate)
+ : m_delegate(std::move(delegate)) {}
+
+ /** Delegate. */
+ key_value_view<ignite_tuple, ignite_tuple> m_delegate;
+};
+
} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/client/table/record_view.h
b/modules/platforms/cpp/ignite/client/table/record_view.h
index 8c7b3c5db5..57eb7c65ed 100644
--- a/modules/platforms/cpp/ignite/client/table/record_view.h
+++ b/modules/platforms/cpp/ignite/client/table/record_view.h
@@ -20,6 +20,7 @@
#include <ignite/client/table/ignite_tuple.h>
#include <ignite/client/transaction/transaction.h>
#include <ignite/client/type_mapping.h>
+#include <ignite/client/detail/type_mapping_utils.h>
#include <ignite/common/config.h>
#include <ignite/common/ignite_result.h>
@@ -492,7 +493,7 @@ public:
*/
void get_async(transaction *tx, const value_type &key,
ignite_callback<std::optional<value_type>> callback) {
m_delegate.get_async(tx, convert_to_tuple(key), [callback =
std::move(callback)] (auto res) {
- callback(convert_result(std::move(res)));
+ callback(convert_result<value_type>(std::move(res)));
});
}
@@ -523,9 +524,10 @@ public:
*/
void get_all_async(transaction *tx, std::vector<value_type> keys,
ignite_callback<std::vector<std::optional<value_type>>> callback) {
- m_delegate.get_all_async(tx, values_to_tuples(std::move(keys)),
[callback = std::move(callback)] (auto res) {
- callback(convert_result(std::move(res)));
- });
+ m_delegate.get_all_async(tx,
values_to_tuples<value_type>(std::move(keys)),
+ [callback = std::move(callback)] (auto res) {
+ callback(convert_result<value_type>(std::move(res)));
+ });
}
/**
@@ -578,7 +580,7 @@ public:
* @param callback Callback that is called on operation completion.
*/
void upsert_all_async(transaction *tx, std::vector<value_type> records,
ignite_callback<void> callback) {
- m_delegate.upsert_all_async(tx, values_to_tuples(std::move(records)),
std::move(callback));
+ m_delegate.upsert_all_async(tx,
values_to_tuples<value_type>(std::move(records)), std::move(callback));
}
/**
@@ -606,7 +608,7 @@ public:
void get_and_upsert_async(
transaction *tx, const value_type &record,
ignite_callback<std::optional<value_type>> callback) {
m_delegate.get_and_upsert_async(tx, convert_to_tuple(record),
[callback = std::move(callback)] (auto res) {
- callback(convert_result(std::move(res)));
+ callback(convert_result<value_type>(std::move(res)));
});
}
@@ -659,9 +661,9 @@ public:
*/
void insert_all_async(
transaction *tx, std::vector<value_type> records,
ignite_callback<std::vector<value_type>> callback) {
- m_delegate.insert_all_async(tx, values_to_tuples(std::move(records)),
+ m_delegate.insert_all_async(tx,
values_to_tuples<value_type>(std::move(records)),
[callback = std::move(callback)] (auto res) {
- callback(convert_result(std::move(res)));
+ callback(convert_result<value_type>(std::move(res)));
}
);
}
@@ -753,7 +755,7 @@ public:
void get_and_replace_async(
transaction *tx, const value_type &record,
ignite_callback<std::optional<value_type>> callback) {
m_delegate.get_and_replace_async(tx, convert_to_tuple(record),
[callback = std::move(callback)] (auto res) {
- callback(convert_result(std::move(res)));
+ callback(convert_result<value_type>(std::move(res)));
});
}
@@ -837,7 +839,7 @@ public:
void get_and_remove_async(
transaction *tx, const value_type &key,
ignite_callback<std::optional<value_type>> callback) {
m_delegate.get_and_remove_async(tx, convert_to_tuple(key), [callback =
std::move(callback)] (auto res) {
- callback(convert_result(std::move(res)));
+ callback(convert_result<value_type>(std::move(res)));
});
}
@@ -866,8 +868,8 @@ public:
*/
void remove_all_async(
transaction *tx, std::vector<value_type> keys,
ignite_callback<std::vector<value_type>> callback) {
- m_delegate.remove_all_async(tx, values_to_tuples(std::move(keys)),
[callback = std::move(callback)] (auto res) {
- callback(convert_result(std::move(res)));
+ m_delegate.remove_all_async(tx,
values_to_tuples<value_type>(std::move(keys)), [callback = std::move(callback)]
(auto res) {
+ callback(convert_result<value_type>(std::move(res)));
});
}
@@ -898,9 +900,9 @@ public:
*/
void remove_all_exact_async(
transaction *tx, std::vector<value_type> records,
ignite_callback<std::vector<value_type>> callback) {
- m_delegate.remove_all_exact_async(tx,
values_to_tuples(std::move(records)),
+ m_delegate.remove_all_exact_async(tx,
values_to_tuples<value_type>(std::move(records)),
[callback = std::move(callback)] (auto res) {
- callback(convert_result(std::move(res)));
+ callback(convert_result<value_type>(std::move(res)));
}
);
}
@@ -921,88 +923,6 @@ public:
}
private:
- /**
- * Convert values to tuples.
- * @param vals Values.
- * @return Tuples.
- */
- static std::vector<ignite_tuple> values_to_tuples(std::vector<value_type>
values) {
- //TODO: Optimize memory usage (IGNITE-19198)
- std::vector<ignite_tuple> tuples;
- tuples.reserve(values.size());
- for (auto &&value : std::move(values)) {
- tuples.push_back(convert_to_tuple(std::move(value)));
- }
- return tuples;
- }
-
- /**
- * Tuples to values.
- * @param tuples Tuples.
- * @return Values.
- */
- static std::vector<value_type> tuples_to_values(std::vector<ignite_tuple>
tuples) {
- //TODO: Optimize memory usage (IGNITE-19198)
- std::vector<value_type> values;
- values.reserve(tuples.size());
- for (auto &&tuple : std::move(tuples)) {
-
values.emplace_back(convert_from_tuple<value_type>(std::move(tuple)));
- }
- return values;
- }
-
- /**
- * Optional tuples to optional values.
- * @param tuples Tuples.
- * @return Values.
- */
- static std::vector<std::optional<value_type>>
tuples_to_values(std::vector<std::optional<ignite_tuple>> tuples) {
- //TODO: Optimize memory usage (IGNITE-19198)
- std::vector<std::optional<value_type>> values;
- values.reserve(tuples.size());
- for (auto &&tuple : std::move(tuples)) {
-
values.emplace_back(convert_from_tuple<value_type>(std::move(tuple)));
- }
- return values;
- }
-
- /**
- * Convert result from tuple-based type to user type.
- * @param res Result to convert.
- * @return Converted result.
- */
- static ignite_result<std::optional<value_type>>
convert_result(ignite_result<std::optional<ignite_tuple>> &&res) {
- if (res.has_error())
- return {std::move(res).error()};
-
- return {convert_from_tuple<value_type>(std::move(res).value())};
- }
-
- /**
- * Convert result from tuple-based type to user type.
- * @param res Result to convert.
- * @return Converted result.
- */
- static ignite_result<std::vector<std::optional<value_type>>>
convert_result(
- ignite_result<std::vector<std::optional<ignite_tuple>>> &&res) {
- if (res.has_error())
- return {std::move(res).error()};
-
- return {tuples_to_values(std::move(res).value())};
- }
-
- /**
- * Convert result from tuple-based type to user type.
- * @param res Result to convert.
- * @return Converted result.
- */
- static ignite_result<std::vector<value_type>>
convert_result(ignite_result<std::vector<ignite_tuple>> &&res) {
- if (res.has_error())
- return {std::move(res).error()};
-
- return {tuples_to_values(std::move(res).value())};
- }
-
/**
* Constructor
*
diff --git a/modules/platforms/cpp/ignite/client/table/table.h
b/modules/platforms/cpp/ignite/client/table/table.h
index e1097ebb2c..23d17cf22a 100644
--- a/modules/platforms/cpp/ignite/client/table/table.h
+++ b/modules/platforms/cpp/ignite/client/table/table.h
@@ -81,10 +81,23 @@ public:
/**
* Gets the key-value binary view.
*
- * @return Record binary view.
+ * @return Key-value binary view.
*/
[[nodiscard]] IGNITE_API key_value_view<ignite_tuple, ignite_tuple>
get_key_value_binary_view() const noexcept;
+ /**
+ * Gets the key-value view.
+ *
+ * Template functions @c convert_to_tuple() and @c convert_from_tuple()
should be specialized for the types K and V.
+ * @see See type_mapping.h for details.
+ *
+ * @return Key-value view.
+ */
+ template<typename K, typename V>
+ [[nodiscard]] key_value_view<K, V> get_key_value_view() const noexcept {
+ return key_value_view<K, V>{get_key_value_binary_view()};
+ }
+
private:
/**
* Constructor
diff --git a/modules/platforms/cpp/tests/client-test/CMakeLists.txt
b/modules/platforms/cpp/tests/client-test/CMakeLists.txt
index c8772c72e5..521b028675 100644
--- a/modules/platforms/cpp/tests/client-test/CMakeLists.txt
+++ b/modules/platforms/cpp/tests/client-test/CMakeLists.txt
@@ -25,6 +25,7 @@ set(SOURCES
ignite_client_test.cpp
ignite_runner_suite.h
key_value_binary_view_test.cpp
+ key_value_view_test.cpp
main.cpp
record_binary_view_test.cpp
record_view_test.cpp
diff --git a/modules/platforms/cpp/tests/client-test/all_fields_type.h
b/modules/platforms/cpp/tests/client-test/all_fields_type.h
new file mode 100644
index 0000000000..409e2077a1
--- /dev/null
+++ b/modules/platforms/cpp/tests/client-test/all_fields_type.h
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ignite/client/table/ignite_tuple.h>
+#include <ignite/client/type_mapping.h>
+
+#include <ignite/common/ignite_date.h>
+#include <ignite/common/ignite_date_time.h>
+#include <ignite/common/ignite_time.h>
+#include <ignite/common/ignite_timestamp.h>
+#include <ignite/common/uuid.h>
+#include <ignite/common/bit_array.h>
+#include <ignite/common/big_decimal.h>
+
+#include <string>
+#include <cstdint>
+
+
+/**
+ * All columns type table mapping (@see
ignite_runner_suite::TABLE_NAME_ALL_COLUMNS).
+ */
+struct all_fields_type {
+ all_fields_type() = default;
+ explicit all_fields_type(std::int64_t key) : m_key(key) {}
+
+ std::int64_t m_key{0};
+ std::string m_str;
+ std::int8_t m_int8{0};
+ std::int16_t m_int16{0};
+ std::int32_t m_int32{0};
+ std::int64_t m_int64{0};
+ float m_float{.0f};
+ double m_double{.0};
+ ignite::uuid m_uuid;
+ ignite::ignite_date m_date;
+ ignite::bit_array m_bitmask;
+ ignite::ignite_time m_time;
+ ignite::ignite_time m_time2;
+ ignite::ignite_date_time m_datetime;
+ ignite::ignite_date_time m_datetime2;
+ ignite::ignite_timestamp m_timestamp;
+ ignite::ignite_timestamp m_timestamp2;
+ std::vector<std::byte> m_blob;
+ ignite::big_decimal m_decimal;
+};
+
+namespace ignite {
+
+template<>
+inline ignite_tuple convert_to_tuple(all_fields_type &&value) {
+ ignite_tuple tuple;
+
+ tuple.set("key", value.m_key);
+ tuple.set("str", value.m_str);
+ tuple.set("int8", value.m_int8);
+ tuple.set("int16", value.m_int16);
+ tuple.set("int32", value.m_int32);
+ tuple.set("int64", value.m_int64);
+ tuple.set("float", value.m_float);
+ tuple.set("double", value.m_double);
+ tuple.set("uuid", value.m_uuid);
+ tuple.set("date", value.m_date);
+ tuple.set("bitmask", value.m_bitmask);
+ tuple.set("time", value.m_time);
+ tuple.set("time2", value.m_time2);
+ tuple.set("datetime", value.m_datetime);
+ tuple.set("datetime2", value.m_datetime2);
+ tuple.set("timestamp", value.m_timestamp);
+ tuple.set("timestamp2", value.m_timestamp2);
+ tuple.set("blob", value.m_blob);
+ tuple.set("decimal", value.m_decimal);
+
+ return tuple;
+}
+
+template<>
+inline all_fields_type convert_from_tuple(ignite_tuple&& value) {
+ all_fields_type res;
+
+ res.m_key = value.get<std::int64_t>("key");
+
+ if (value.column_count() > 1) {
+ res.m_str = value.get<std::string>("str");
+ res.m_int8 = value.get<std::int8_t>("int8");
+ res.m_int16 = value.get<std::int16_t>("int16");
+ res.m_int32 = value.get<std::int32_t>("int32");
+ res.m_int64 = value.get<std::int64_t>("int64");
+ res.m_float = value.get<float>("float");
+ res.m_double = value.get<double>("double");
+ res.m_uuid = value.get<uuid>("uuid");
+ res.m_date = value.get<ignite_date>("date");
+ res.m_bitmask = value.get<bit_array>("bitmask");
+ res.m_time = value.get<ignite_time>("time");
+ res.m_time2 = value.get<ignite_time>("time2");
+ res.m_datetime = value.get<ignite_date_time>("datetime");
+ res.m_datetime2 = value.get<ignite_date_time>("datetime2");
+ res.m_timestamp = value.get<ignite_timestamp>("timestamp");
+ res.m_timestamp2 = value.get<ignite_timestamp>("timestamp2");
+ res.m_blob = value.get<std::vector<std::byte>>("blob");
+ res.m_decimal = value.get<big_decimal>("decimal");
+ }
+
+ return res;
+}
+
+} // namespace ignite
+
diff --git
a/modules/platforms/cpp/tests/client-test/key_value_binary_view_test.cpp
b/modules/platforms/cpp/tests/client-test/key_value_binary_view_test.cpp
index a0627cc657..e6ef6d7646 100644
--- a/modules/platforms/cpp/tests/client-test/key_value_binary_view_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/key_value_binary_view_test.cpp
@@ -54,7 +54,7 @@ protected:
/** Ignite client. */
ignite_client m_client;
- /** Record binary view. */
+ /** Key-Value binary view. */
key_value_view<ignite_tuple, ignite_tuple> kv_view;
};
@@ -770,7 +770,7 @@ TEST_F(key_value_binary_view_test,
remove_exact_empty_throws) {
}
TEST_F(key_value_binary_view_test, get_and_remove_nonexisting) {
- auto res = kv_view.get_and_replace(nullptr, get_tuple(42),
get_tuple("foo"));
+ auto res = kv_view.get_and_remove(nullptr, get_tuple(42));
ASSERT_FALSE(res.has_value());
auto res_tuple = kv_view.get(nullptr, get_tuple(42));
diff --git a/modules/platforms/cpp/tests/client-test/key_value_view_test.cpp
b/modules/platforms/cpp/tests/client-test/key_value_view_test.cpp
new file mode 100644
index 0000000000..6aa892d873
--- /dev/null
+++ b/modules/platforms/cpp/tests/client-test/key_value_view_test.cpp
@@ -0,0 +1,825 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "all_fields_type.h"
+#include "ignite_runner_suite.h"
+
+#include "tests/test-common/test_utils.h"
+
+#include "ignite/client/ignite_client.h"
+#include "ignite/client/ignite_client_configuration.h"
+
+#include <gtest/gtest.h>
+
+#include <chrono>
+
+using namespace ignite;
+
+/**
+ * Test key type mapping (@see ignite_runner_suite::TABLE_1).
+ */
+struct test_key_type {
+ test_key_type() = default;
+ explicit test_key_type(std::int64_t key) : key(key) {}
+
+ std::int64_t key{0};
+};
+
+/**
+ * Test value type mapping (@see ignite_runner_suite::TABLE_1).
+ */
+struct test_value_type {
+ test_value_type() = default;
+ explicit test_value_type(std::string val) : val(std::move(val)) {}
+
+ std::string val;
+};
+
+
+namespace ignite {
+
+template<>
+ignite_tuple convert_to_tuple(test_key_type &&value) {
+ ignite_tuple tuple;
+
+ tuple.set("key", value.key);
+
+ return tuple;
+}
+
+template<>
+test_key_type convert_from_tuple(ignite_tuple&& value) {
+ test_key_type res;
+
+ res.key = value.get<std::int64_t>("key");
+
+ return res;
+}
+
+template<>
+ignite_tuple convert_to_tuple(test_value_type &&value) {
+ ignite_tuple tuple;
+
+ tuple.set("val", value.val);
+
+ return tuple;
+}
+
+template<>
+test_value_type convert_from_tuple(ignite_tuple&& value) {
+ test_value_type res;
+
+ res.val = value.get<std::string>("val");
+
+ return res;
+}
+
+}
+
+/**
+ * Test suite.
+ */
+class key_value_view_test : public ignite_runner_suite {
+protected:
+ void SetUp() override {
+ ignite_client_configuration cfg{get_node_addrs()};
+ cfg.set_logger(get_logger());
+
+ m_client = ignite_client::start(cfg, std::chrono::seconds(30));
+ auto table = m_client.get_tables().get_table(TABLE_1);
+
+ kv_view = table->get_key_value_view<test_key_type, test_value_type>();
+ }
+
+ void TearDown() override {
+ std::vector<test_key_type> work_range;
+ work_range.reserve(100);
+ for (int i = -50; i < 50; ++i)
+ work_range.emplace_back(i);
+
+ kv_view.remove_all(nullptr, work_range);
+ }
+
+ /** Ignite client. */
+ ignite_client m_client;
+
+ /** Key-Value view. */
+ key_value_view<test_key_type, test_value_type> kv_view;
+};
+
+TEST_F(key_value_view_test, put_get) {
+ auto key = test_key_type(1);
+ auto val = test_value_type("foo");
+
+ kv_view.put(nullptr, key, val);
+ auto res = kv_view.get(nullptr, key);
+
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ("foo", res->val);
+}
+
+TEST_F(key_value_view_test, put_get_async) {
+ auto key = test_key_type(1);
+ auto val = test_value_type("foo");
+
+ auto all_done =
std::make_shared<std::promise<std::optional<test_value_type>>>();
+
+ kv_view.put_async(nullptr, key, val, [&](ignite_result<void> &&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ kv_view.get_async(nullptr, key, [&](auto res) {
result_set_promise(*all_done, std::move(res)); });
+ });
+
+ auto res = all_done->get_future().get();
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ("foo", res->val);
+}
+
+TEST_F(key_value_view_test, put_overrides_value) {
+ auto key = test_key_type(1);
+ auto val = test_value_type("foo");
+
+ kv_view.put(nullptr, key, val);
+ auto res = kv_view.get(nullptr, key);
+
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ("foo", res->val);
+
+ val.val = "bar";
+ kv_view.put(nullptr, key, val);
+ res = kv_view.get(nullptr, key);
+
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ("bar", res->val);
+}
+
+TEST_F(key_value_view_test, get_all_empty) {
+ auto res = kv_view.get_all(nullptr, {});
+ EXPECT_TRUE(res.empty());
+}
+
+TEST_F(key_value_view_test, get_all_nonexisting) {
+ auto res = kv_view.get_all(nullptr, {test_key_type(-42)});
+
+ ASSERT_TRUE(res.empty());
+}
+
+TEST_F(key_value_view_test, put_all_empty_no_throw) {
+ kv_view.put_all(nullptr, {});
+}
+
+TEST_F(key_value_view_test, put_all_get_all) {
+ static constexpr std::size_t records_num = 10;
+
+ std::vector<std::pair<test_key_type, test_value_type>> records;
+ records.reserve(records_num);
+ for (std::int64_t i = 1; i < 1 + std::int64_t(records_num); ++i)
+ records.emplace_back(i, "Val" + std::to_string(i));
+
+ std::vector<test_key_type> keys;
+ for (std::int64_t i = 9; i < 13; ++i)
+ keys.emplace_back(i);
+
+ kv_view.put_all(nullptr, records);
+ auto res = kv_view.get_all(nullptr, keys);
+
+ // TODO: Key order should be preserved by the server (IGNITE-16004).
+ EXPECT_EQ(res.size(), 2);
+
+ ASSERT_TRUE(res[0].has_value());
+ EXPECT_EQ("Val9", res[0]->val);
+
+ ASSERT_TRUE(res[1].has_value());
+ EXPECT_EQ("Val10", res[1]->val);
+}
+
+TEST_F(key_value_view_test, put_all_get_all_async) {
+ static constexpr std::size_t records_num = 10;
+
+ std::vector<std::pair<test_key_type, test_value_type>> records;
+ records.reserve(records_num);
+ for (std::int64_t i = 1; i < 1 + std::int64_t(records_num); ++i)
+ records.emplace_back(i, "Val" + std::to_string(i));
+
+ std::vector<test_key_type> keys;
+ for (std::int64_t i = 9; i < 13; ++i)
+ keys.emplace_back(i);
+
+ auto all_done =
std::make_shared<std::promise<std::vector<std::optional<test_value_type>>>>();
+
+ kv_view.put_all_async(nullptr, records, [&](ignite_result<void> &&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ // TODO: Key order should be preserved by the server (IGNITE-16004).
+ kv_view.get_all_async(nullptr, keys, [&](auto res) {
result_set_promise(*all_done, std::move(res)); });
+ });
+
+ auto res = all_done->get_future().get();
+
+ EXPECT_EQ(res.size(), 2);
+
+ ASSERT_TRUE(res[0].has_value());
+ EXPECT_EQ("Val9", res[0]->val);
+
+ ASSERT_TRUE(res[1].has_value());
+ EXPECT_EQ("Val10", res[1]->val);
+}
+
+TEST_F(key_value_view_test, get_and_put_new_record) {
+ auto key = test_key_type(42);
+ auto val = test_value_type("foo");
+ auto res = kv_view.get_and_put(nullptr, key, val);
+
+ ASSERT_FALSE(res.has_value());
+}
+
+TEST_F(key_value_view_test, get_and_put_existing_record) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+ auto res = kv_view.get_and_put(nullptr, key, val1);
+
+ ASSERT_FALSE(res.has_value());
+
+ auto val2 = test_value_type("bar");
+ res = kv_view.get_and_put(nullptr, key, val2);
+
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ("foo", res->val);
+
+ res = kv_view.get(nullptr, key);
+
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ("bar", res->val);
+}
+
+TEST_F(key_value_view_test, get_and_put_existing_record_async) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+ auto val2 = test_value_type("bar");
+
+ auto first =
std::make_shared<std::promise<std::optional<test_value_type>>>();
+
+ kv_view.get_and_put_async(nullptr, key, val1, [&](auto res) {
+ if (!check_and_set_operation_error(*first, res))
+ return;
+
+ if (res.value().has_value())
+
first->set_exception(std::make_exception_ptr(ignite_error("Expected nullopt on
first insertion")));
+
+ kv_view.get_and_put_async(
+ nullptr, key, val2, [&](auto res) { result_set_promise(*first,
std::move(res)); });
+ });
+
+ auto res = first->get_future().get();
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ(val1.val, res->val);
+
+ auto second =
std::make_shared<std::promise<std::optional<test_value_type>>>();
+ kv_view.get_async(nullptr, key, [&](auto res) {
result_set_promise(*second, std::move(res)); });
+
+ res = second->get_future().get();
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ(val2.val, res->val);
+}
+
+TEST_F(key_value_view_test, insert_new_record) {
+ auto key = test_key_type(42);
+ auto val = test_value_type("foo");
+ auto res = kv_view.put_if_absent(nullptr, key, val);
+
+ ASSERT_TRUE(res);
+}
+
+TEST_F(key_value_view_test, put_if_absent_existing_record) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+ auto put_res = kv_view.put_if_absent(nullptr, key, val1);
+ ASSERT_TRUE(put_res);
+
+ auto val2 = test_value_type("bar");
+ put_res = kv_view.put_if_absent(nullptr, key, val2);
+ ASSERT_FALSE(put_res);
+
+ auto res = kv_view.get(nullptr, key);
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ("foo", res->val);
+}
+
+TEST_F(key_value_view_test, put_if_absent_existing_record_async) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+ auto val2 = test_value_type("bar");
+
+ auto all_done =
std::make_shared<std::promise<std::optional<test_value_type>>>();
+
+ kv_view.put_if_absent_async(nullptr, key, val1, [&](ignite_result<bool>
&&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (!res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected true on
first insertion")));
+
+ kv_view.put_if_absent_async(nullptr, key, val2,
[&](ignite_result<bool> &&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected false on
second insertion")));
+
+ kv_view.get_async(nullptr, key, [&](auto res) {
result_set_promise(*all_done, std::move(res)); });
+ });
+ });
+
+ auto res = all_done->get_future().get();
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ(val1.val, res->val);
+}
+
+TEST_F(key_value_view_test, replace_nonexisting) {
+ auto key = test_key_type(42);
+ auto val = test_value_type("foo");
+
+ auto res1 = kv_view.replace(nullptr, key, val);
+ ASSERT_FALSE(res1);
+
+ auto res2 = kv_view.get(nullptr, key);
+ ASSERT_FALSE(res2.has_value());
+}
+
+TEST_F(key_value_view_test, replace_existing) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+
+ auto res = kv_view.put_if_absent(nullptr, key, val1);
+ ASSERT_TRUE(res);
+
+ auto val2 = test_value_type("bar");
+ res = kv_view.replace(nullptr, key, val2);
+ ASSERT_TRUE(res);
+
+ auto res2 = kv_view.get(nullptr, key);
+ ASSERT_TRUE(res2.has_value());
+ EXPECT_EQ("bar", res2->val);
+}
+
+TEST_F(key_value_view_test, replace_existing_async) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+ auto val2 = test_value_type("bar");
+
+ auto all_done =
std::make_shared<std::promise<std::optional<test_value_type>>>();
+
+ kv_view.put_if_absent_async(nullptr, key, val1, [&](ignite_result<bool>
&&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (!res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected true on
insertion")));
+
+ kv_view.replace_async(nullptr, key, val2, [&](ignite_result<bool>
&&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (!res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected true on
replace")));
+
+ kv_view.get_async(nullptr, key, [&](auto res) {
result_set_promise(*all_done, std::move(res)); });
+ });
+ });
+
+ auto res = all_done->get_future().get();
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ(val2.val, res->val);
+}
+
+TEST_F(key_value_view_test, replace_exact_nonexisting) {
+ auto res1 = kv_view.replace(nullptr, test_key_type(42),
test_value_type("foo"), test_value_type("bar"));
+ ASSERT_FALSE(res1);
+
+ auto res2 = kv_view.get(nullptr, test_key_type(42));
+ ASSERT_FALSE(res2.has_value());
+}
+
+TEST_F(key_value_view_test, replace_exact_existing_wrong) {
+ auto res1 = kv_view.put_if_absent(nullptr, test_key_type(42),
test_value_type("foo"));
+ ASSERT_TRUE(res1);
+
+ res1 = kv_view.replace(nullptr, test_key_type(42), test_value_type("bar"),
test_value_type("baz"));
+ ASSERT_FALSE(res1);
+
+ auto res2 = kv_view.get(nullptr, test_key_type(42));
+ ASSERT_TRUE(res2.has_value());
+ EXPECT_EQ("foo", res2->val);
+}
+
+TEST_F(key_value_view_test, replace_exact_existing_right) {
+ auto res1 = kv_view.put_if_absent(nullptr, test_key_type(42),
test_value_type("foo"));
+ ASSERT_TRUE(res1);
+
+ res1 = kv_view.replace(nullptr, test_key_type(42), test_value_type("foo"),
test_value_type("baz"));
+ ASSERT_TRUE(res1);
+
+ auto res2 = kv_view.get(nullptr, test_key_type(42));
+ ASSERT_TRUE(res2.has_value());
+ EXPECT_EQ("baz", res2->val);
+}
+
+TEST_F(key_value_view_test, replace_exact_existing_right_async) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+ auto val2 = test_value_type("bar");
+
+ auto all_done =
std::make_shared<std::promise<std::optional<test_value_type>>>();
+
+ kv_view.put_if_absent_async(nullptr, key, val1, [&](ignite_result<bool>
&&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (!res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected true on
insertion")));
+
+ kv_view.replace_async(nullptr, key, val1, val2,
[&](ignite_result<bool> &&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (!res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected true on
replace")));
+
+ kv_view.get_async(nullptr, key, [&](auto res) {
result_set_promise(*all_done, std::move(res)); });
+ });
+ });
+
+ auto res = all_done->get_future().get();
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ(val2.val, res->val);
+}
+
+TEST_F(key_value_view_test, get_and_replace_nonexisting) {
+ auto key = test_key_type(42);
+ auto val = test_value_type("foo");
+ auto res1 = kv_view.get_and_replace(nullptr, key, val);
+ ASSERT_FALSE(res1.has_value());
+
+ auto res2 = kv_view.get(nullptr, key);
+ ASSERT_FALSE(res2.has_value());
+}
+
+TEST_F(key_value_view_test, get_and_replace_existing) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+ auto res1 = kv_view.put_if_absent(nullptr, key, val1);
+ ASSERT_TRUE(res1);
+
+ auto val2 = test_value_type("bar");
+ auto res2 = kv_view.get_and_replace(nullptr, key, val2);
+
+ ASSERT_TRUE(res2.has_value());
+ EXPECT_EQ("foo", res2->val);
+
+ res2 = kv_view.get(nullptr, test_key_type(42));
+ ASSERT_TRUE(res2.has_value());
+ EXPECT_EQ("bar", res2->val);
+}
+
+TEST_F(key_value_view_test, get_and_replace_existing_async) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+ auto val2 = test_value_type("bar");
+
+ auto all_done =
std::make_shared<std::promise<std::optional<test_value_type>>>();
+
+ kv_view.put_if_absent_async(nullptr, key, val1, [&](ignite_result<bool>
&&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (!res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected true on
insertion")));
+
+ kv_view.get_and_replace_async(
+ nullptr, key, val2, [&](auto res) { result_set_promise(*all_done,
std::move(res)); });
+ });
+
+ auto res = all_done->get_future().get();
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ(val1.val, res->val);
+}
+
+TEST_F(key_value_view_test, remove_nonexisting) {
+ auto res1 = kv_view.remove(nullptr, test_key_type(1));
+ ASSERT_FALSE(res1);
+
+ auto res2 = kv_view.get(nullptr, test_key_type(1));
+ ASSERT_FALSE(res2.has_value());
+}
+
+TEST_F(key_value_view_test, remove_existing) {
+ auto res = kv_view.put_if_absent(nullptr, test_key_type(1),
test_value_type("foo"));
+ ASSERT_TRUE(res);
+
+ res = kv_view.remove(nullptr, test_key_type(1));
+ ASSERT_TRUE(res);
+
+ auto res2 = kv_view.get(nullptr, test_key_type(1));
+ ASSERT_FALSE(res2.has_value());
+}
+
+TEST_F(key_value_view_test, remove_existing_async) {
+ auto all_done = std::make_shared<std::promise<bool>>();
+
+ kv_view.put_if_absent_async(nullptr, test_key_type(42),
test_value_type("foo"), [&](ignite_result<bool> &&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (!res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected true on
insertion")));
+
+ kv_view.remove_async(nullptr, test_key_type(42), [&](auto res) {
result_set_promise(*all_done, std::move(res)); });
+ });
+
+ auto res = all_done->get_future().get();
+ ASSERT_TRUE(res);
+}
+
+TEST_F(key_value_view_test, remove_exact_nonexisting) {
+ auto res = kv_view.remove(nullptr, test_key_type(1),
test_value_type("foo"));
+ ASSERT_FALSE(res);
+}
+
+TEST_F(key_value_view_test, remove_exact_existing) {
+ auto res = kv_view.put_if_absent(nullptr, test_key_type(1),
test_value_type("foo"));
+ ASSERT_TRUE(res);
+
+ res = kv_view.remove(nullptr, test_key_type(1), test_value_type("bar"));
+ ASSERT_FALSE(res);
+
+ res = kv_view.remove(nullptr, test_key_type(1), test_value_type("foo"));
+ ASSERT_TRUE(res);
+
+ auto res2 = kv_view.get(nullptr, test_key_type(1));
+ ASSERT_FALSE(res2.has_value());
+}
+
+TEST_F(key_value_view_test, remove_exact_existing_async) {
+ auto key = test_key_type(42);
+ auto val = test_value_type("foo");
+
+ auto all_done = std::make_shared<std::promise<bool>>();
+
+ auto res = kv_view.put_if_absent(nullptr, key, val);
+ ASSERT_TRUE(res);
+
+ kv_view.remove_async(nullptr, key, test_value_type("bar"), [&](auto res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected false on
second remove")));
+
+ kv_view.remove_async(
+ nullptr, key, val, [&](auto res) { result_set_promise(*all_done,
std::move(res)); });
+ });
+
+ auto res2 = all_done->get_future().get();
+ ASSERT_TRUE(res2);
+}
+
+TEST_F(key_value_view_test, get_and_remove_nonexisting) {
+ auto res1 = kv_view.get_and_remove(nullptr, test_key_type(42));
+ ASSERT_FALSE(res1.has_value());
+
+ auto res2 = kv_view.get(nullptr, test_key_type(42));
+ ASSERT_FALSE(res2.has_value());
+}
+
+TEST_F(key_value_view_test, get_and_remove_existing) {
+ auto res1 = kv_view.put_if_absent(nullptr, test_key_type(42),
test_value_type("foo"));
+ ASSERT_TRUE(res1);
+
+ auto res2 = kv_view.get_and_remove(nullptr, test_key_type(42));
+
+ ASSERT_TRUE(res2.has_value());
+ EXPECT_EQ("foo", res2->val);
+
+ res2 = kv_view.get(nullptr, test_key_type(42));
+ ASSERT_FALSE(res2.has_value());
+}
+
+TEST_F(key_value_view_test, get_and_remove_existing_async) {
+ auto key = test_key_type(42);
+ auto val1 = test_value_type("foo");
+
+ auto all_done =
std::make_shared<std::promise<std::optional<test_value_type>>>();
+
+ kv_view.put_if_absent_async(nullptr, key, val1, [&](ignite_result<bool>
&&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (!res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected true on
insertion")));
+
+ kv_view.get_and_remove_async(
+ nullptr, key, [&](auto res) { result_set_promise(*all_done,
std::move(res)); });
+ });
+
+ auto res = all_done->get_future().get();
+ ASSERT_TRUE(res.has_value());
+ EXPECT_EQ(val1.val, res->val);
+}
+
+TEST_F(key_value_view_test, contains) {
+ auto res = kv_view.contains(nullptr, test_key_type(1));
+ ASSERT_FALSE(res);
+
+ res = kv_view.put_if_absent(nullptr, test_key_type(1),
test_value_type("foo"));
+ ASSERT_TRUE(res);
+
+ res = kv_view.contains(nullptr, test_key_type(1));
+ ASSERT_TRUE(res);
+}
+
+TEST_F(key_value_view_test, contains_async) {
+ auto all_done = std::make_shared<std::promise<bool>>();
+
+ kv_view.contains_async(nullptr, test_key_type(1), [&](ignite_result<bool>
&&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected to not
contain")));
+
+ kv_view.put_if_absent_async(nullptr, test_key_type(1),
test_value_type("foo"), [&](ignite_result<bool> &&res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ if (!res.value())
+
all_done->set_exception(std::make_exception_ptr(ignite_error("Expected true on
insert")));
+
+ kv_view.contains_async(nullptr, test_key_type(1),
[&](ignite_result<bool> &&res) {
+ result_set_promise(*all_done, std::move(res));
+ });
+ });
+ });
+
+ auto res = all_done->get_future().get();
+ ASSERT_TRUE(res);
+}
+
+TEST_F(key_value_view_test, remove_all_nonexisting_keys_return_all) {
+ std::vector<test_key_type> non_existing = {test_key_type(1),
test_key_type(2)};
+ auto res = kv_view.remove_all(nullptr, non_existing);
+
+ EXPECT_EQ(res.size(), 2);
+
+ // TODO: Key order should be preserved by the server (IGNITE-16004).
+ EXPECT_EQ(2, res[0].key);
+ EXPECT_EQ(1, res[1].key);
+}
+
+TEST_F(key_value_view_test, remove_all_only_existing) {
+ std::vector<std::pair<test_key_type, test_value_type>> to_insert = {
+ {test_key_type(1), test_value_type("foo")}, {test_key_type(2),
test_value_type("bar")}};
+ kv_view.put_all(nullptr, to_insert);
+
+ auto res = kv_view.remove_all(nullptr, {test_key_type(1),
test_key_type(2)});
+
+ EXPECT_TRUE(res.empty());
+}
+
+TEST_F(key_value_view_test, remove_all_overlapped) {
+ static constexpr std::size_t records_num = 10;
+
+ std::vector<std::pair<test_key_type, test_value_type>> to_insert;
+ to_insert.reserve(records_num);
+ for (std::int64_t i = 1; i < 1 + std::int64_t(records_num); ++i)
+ to_insert.emplace_back(i, "Val" + std::to_string(i));
+
+ kv_view.put_all(nullptr, to_insert);
+
+ std::vector<test_key_type> to_remove;
+ for (std::int64_t i = 9; i < 13; ++i)
+ to_remove.emplace_back(i);
+
+ auto res = kv_view.remove_all(nullptr, to_remove);
+
+ EXPECT_EQ(res.size(), 2);
+
+ // TODO: Key order should be preserved by the server (IGNITE-16004).
+ EXPECT_EQ(12, res[0].key);
+ EXPECT_EQ(11, res[1].key);
+}
+
+TEST_F(key_value_view_test, remove_all_empty) {
+ auto res = kv_view.remove_all(nullptr, std::vector<test_key_type>{});
+ EXPECT_TRUE(res.empty());
+}
+
+TEST_F(key_value_view_test, remove_all_exact_nonexisting) {
+ auto res = kv_view.remove_all(nullptr, {
+ {test_key_type(1), test_value_type("foo")}, {test_key_type(2),
test_value_type("bar")}});
+
+ // TODO: Key order should be preserved by the server (IGNITE-16004).
+ ASSERT_EQ(2, res.size());
+}
+
+TEST_F(key_value_view_test, remove_all_exact_overlapped) {
+ kv_view.put_all(nullptr, {{test_key_type(1), test_value_type("foo")},
{test_key_type(2), test_value_type("bar")}});
+
+ auto res = kv_view.remove_all(nullptr, {
+ {test_key_type(1), test_value_type("baz")}, {test_key_type(2),
test_value_type("bar")}});
+
+ EXPECT_EQ(res.size(), 1);
+ EXPECT_EQ(1, res.front().key);
+
+ auto tuple2 = kv_view.get(nullptr, test_key_type(2));
+
+ ASSERT_FALSE(tuple2.has_value());
+}
+
+TEST_F(key_value_view_test, remove_all_exact_overlapped_async) {
+ auto all_done =
std::make_shared<std::promise<std::vector<test_key_type>>>();
+
+ kv_view.put_all_async(nullptr, {{test_key_type(1),
test_value_type("foo")}, {test_key_type(2), test_value_type("bar")}}, [&](auto
res) {
+ if (!check_and_set_operation_error(*all_done, res))
+ return;
+
+ kv_view.remove_all_async(nullptr, {{test_key_type(1),
test_value_type("baz")}, {test_key_type(2), test_value_type("bar")}},
+ [&](auto res) { result_set_promise(*all_done, std::move(res)); });
+ });
+
+ auto res = all_done->get_future().get();
+ EXPECT_EQ(res.size(), 1);
+ EXPECT_EQ(1, res.front().key);
+}
+
+TEST_F(key_value_view_test, remove_all_exact_empty) {
+ auto res = kv_view.remove_all(nullptr,
std::vector<std::pair<test_key_type, test_value_type>>{});
+ EXPECT_TRUE(res.empty());
+}
+
+TEST_F(key_value_view_test, types_test) {
+ auto table = m_client.get_tables().get_table(TABLE_NAME_ALL_COLUMNS);
+ auto kv_view = table->get_key_value_view<test_key_type, all_fields_type>();
+
+ all_fields_type inserted;
+ inserted.m_key = 42;
+ inserted.m_str = "test";
+ inserted.m_int8 = 1;
+ inserted.m_int16 = 2;
+ inserted.m_int32 = 3;
+ inserted.m_int64 = 4;
+ inserted.m_float = .5f;
+ inserted.m_double = .6f;
+ inserted.m_uuid = {0x123e4567e89b12d3, 0x7456426614174000};
+ inserted.m_date = {2023, 2, 7};
+ inserted.m_bitmask = bit_array{16, true};
+ inserted.m_time = {17, 4, 12, 3543634};
+ inserted.m_time2 = {17, 4, 12, 3543634};
+ inserted.m_datetime = {{2020, 7, 28}, {2, 15, 52, 6349879}};
+ inserted.m_datetime2 = {{2020, 7, 28}, {2, 15, 52, 6349879}};
+ inserted.m_timestamp = {3875238472, 248760634};
+ inserted.m_timestamp2 = {3875238472, 248760634};
+ inserted.m_blob = {std::byte(1), std::byte(2), std::byte(42)};
+ inserted.m_decimal = big_decimal{123456789098765};
+
+ kv_view.put(nullptr, test_key_type(42), inserted);
+ auto res = kv_view.get(nullptr, test_key_type(42));
+
+ ASSERT_TRUE(res.has_value());
+
+ EXPECT_EQ(inserted.m_key, res->m_key);
+ EXPECT_EQ(inserted.m_str, res->m_str);
+ EXPECT_EQ(inserted.m_int8, res->m_int8);
+ EXPECT_EQ(inserted.m_int16, res->m_int16);
+ EXPECT_EQ(inserted.m_int32, res->m_int32);
+ EXPECT_EQ(inserted.m_int64, res->m_int64);
+ EXPECT_EQ(inserted.m_float, res->m_float);
+ EXPECT_EQ(inserted.m_double, res->m_double);
+ EXPECT_EQ(inserted.m_uuid, res->m_uuid);
+ EXPECT_EQ(inserted.m_date, res->m_date);
+ EXPECT_EQ(inserted.m_bitmask, res->m_bitmask);
+ EXPECT_EQ(inserted.m_time, res->m_time);
+ EXPECT_EQ(inserted.m_datetime, res->m_datetime);
+ EXPECT_EQ(inserted.m_timestamp, res->m_timestamp);
+ EXPECT_EQ(inserted.m_blob, res->m_blob);
+ EXPECT_EQ(inserted.m_decimal, res->m_decimal);
+
+ EXPECT_EQ(ignite_time(17, 4, 12), res->m_time2);
+ EXPECT_EQ(ignite_date_time({2020, 7, 28}, {2, 15, 52, 6000000}),
res->m_datetime2);
+ EXPECT_EQ(ignite_timestamp(3875238472, 248700000), res->m_timestamp2);
+}
diff --git a/modules/platforms/cpp/tests/client-test/record_view_test.cpp
b/modules/platforms/cpp/tests/client-test/record_view_test.cpp
index a8f882eb5c..91b7c24624 100644
--- a/modules/platforms/cpp/tests/client-test/record_view_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/record_view_test.cpp
@@ -16,6 +16,8 @@
*/
#include "ignite_runner_suite.h"
+#include "all_fields_type.h"
+
#include "tests/test-common/test_utils.h"
#include "ignite/client/ignite_client.h"
@@ -940,95 +942,6 @@ TEST_F(record_view_test, remove_all_exact_empty) {
EXPECT_TRUE(res.empty());
}
-/**
- * All columns type table mapping (@see
ignite_runner_suite::TABLE_NAME_ALL_COLUMNS).
- */
-struct all_fields_type {
- all_fields_type() = default;
- explicit all_fields_type(std::int64_t key) : m_key(key) {}
-
- std::int64_t m_key{0};
- std::string m_str;
- std::int8_t m_int8{0};
- std::int16_t m_int16{0};
- std::int32_t m_int32{0};
- std::int64_t m_int64{0};
- float m_float{.0f};
- double m_double{.0};
- uuid m_uuid;
- ignite_date m_date;
- bit_array m_bitmask;
- ignite_time m_time;
- ignite_time m_time2;
- ignite_date_time m_datetime;
- ignite_date_time m_datetime2;
- ignite_timestamp m_timestamp;
- ignite_timestamp m_timestamp2;
- std::vector<std::byte> m_blob;
- big_decimal m_decimal;
-};
-
-namespace ignite {
-
-template<>
-ignite_tuple convert_to_tuple(all_fields_type &&value) {
- ignite_tuple tuple;
-
- tuple.set("key", value.m_key);
- tuple.set("str", value.m_str);
- tuple.set("int8", value.m_int8);
- tuple.set("int16", value.m_int16);
- tuple.set("int32", value.m_int32);
- tuple.set("int64", value.m_int64);
- tuple.set("float", value.m_float);
- tuple.set("double", value.m_double);
- tuple.set("uuid", value.m_uuid);
- tuple.set("date", value.m_date);
- tuple.set("bitmask", value.m_bitmask);
- tuple.set("time", value.m_time);
- tuple.set("time2", value.m_time2);
- tuple.set("datetime", value.m_datetime);
- tuple.set("datetime2", value.m_datetime2);
- tuple.set("timestamp", value.m_timestamp);
- tuple.set("timestamp2", value.m_timestamp2);
- tuple.set("blob", value.m_blob);
- tuple.set("decimal", value.m_decimal);
-
- return tuple;
-}
-
-template<>
-all_fields_type convert_from_tuple(ignite_tuple&& value) {
- all_fields_type res;
-
- res.m_key = value.get<std::int64_t>("key");
-
- if (value.column_count() > 1) {
- res.m_str = value.get<std::string>("str");
- res.m_int8 = value.get<std::int8_t>("int8");
- res.m_int16 = value.get<std::int16_t>("int16");
- res.m_int32 = value.get<std::int32_t>("int32");
- res.m_int64 = value.get<std::int64_t>("int64");
- res.m_float = value.get<float>("float");
- res.m_double = value.get<double>("double");
- res.m_uuid = value.get<uuid>("uuid");
- res.m_date = value.get<ignite_date>("date");
- res.m_bitmask = value.get<bit_array>("bitmask");
- res.m_time = value.get<ignite_time>("time");
- res.m_time2 = value.get<ignite_time>("time2");
- res.m_datetime = value.get<ignite_date_time>("datetime");
- res.m_datetime2 = value.get<ignite_date_time>("datetime2");
- res.m_timestamp = value.get<ignite_timestamp>("timestamp");
- res.m_timestamp2 = value.get<ignite_timestamp>("timestamp2");
- res.m_blob = value.get<std::vector<std::byte>>("blob");
- res.m_decimal = value.get<big_decimal>("decimal");
- }
-
- return res;
-}
-
-}
-
TEST_F(record_view_test, types_test) {
auto table = m_client.get_tables().get_table(TABLE_NAME_ALL_COLUMNS);
auto view2 = table->get_record_view<all_fields_type>();