diff --git a/src/mongocxx/include/mongocxx/v1/client_session.hpp b/src/mongocxx/include/mongocxx/v1/client_session.hpp index e0e82061ec..550823e67c 100644 --- a/src/mongocxx/include/mongocxx/v1/client_session.hpp +++ b/src/mongocxx/include/mongocxx/v1/client_session.hpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include @@ -183,7 +183,7 @@ class client_session { /// /// @throws mongocxx::v1::exception when a client-side error is encountered. /// - MONGOCXX_ABI_EXPORT_CDECL(void) start_transaction(v1::transaction opts); + MONGOCXX_ABI_EXPORT_CDECL(void) start_transaction(v1::transaction_options opts); /// /// Start a new transaction. @@ -256,11 +256,13 @@ class client_session { /// @throws mongocxx::v1::exception when a client-side error is encountered. /// @throws mongocxx::v1::server_error when a server-side error is encountered and all retry attempts have failed. /// - MONGOCXX_ABI_EXPORT_CDECL(void) with_transaction(with_transaction_cb const& fn, v1::transaction const& opts); + MONGOCXX_ABI_EXPORT_CDECL(void) with_transaction( + with_transaction_cb const& fn, + v1::transaction_options const& opts); /// - /// Equivalent to @ref with_transaction(with_transaction_cb const& fn, v1::transaction const& opts) with a - /// default-initialized @ref v1::transaction. + /// Equivalent to @ref with_transaction(with_transaction_cb const& fn, v1::transaction_options const& opts) with a + /// default-initialized @ref v1::transaction_options. /// MONGOCXX_ABI_EXPORT_CDECL(void) with_transaction(with_transaction_cb const& fn); }; @@ -344,12 +346,12 @@ class client_session::options { /// /// Set the "defaultTransactionOptions" field. /// - MONGOCXX_ABI_EXPORT_CDECL(options&) default_transaction_opts(v1::transaction v); + MONGOCXX_ABI_EXPORT_CDECL(options&) default_transaction_opts(v1::transaction_options v); /// /// Return the current "defaultTransactionOptions" field. /// - MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v1::stdx::optional) default_transaction_opts() const; + MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v1::stdx::optional) default_transaction_opts() const; }; } // namespace v1 diff --git a/src/mongocxx/include/mongocxx/v1/transaction-fwd.hpp b/src/mongocxx/include/mongocxx/v1/transaction_options-fwd.hpp similarity index 90% rename from src/mongocxx/include/mongocxx/v1/transaction-fwd.hpp rename to src/mongocxx/include/mongocxx/v1/transaction_options-fwd.hpp index c6b8b3d5f9..470c54949f 100644 --- a/src/mongocxx/include/mongocxx/v1/transaction-fwd.hpp +++ b/src/mongocxx/include/mongocxx/v1/transaction_options-fwd.hpp @@ -19,7 +19,7 @@ namespace mongocxx { namespace v1 { -class transaction; +class transaction_options; } // namespace v1 } // namespace mongocxx @@ -28,5 +28,5 @@ class transaction; /// /// @file -/// Declares @ref mongocxx::v1::transaction. +/// Declares @ref mongocxx::v1::transaction_options. /// diff --git a/src/mongocxx/include/mongocxx/v1/transaction.hpp b/src/mongocxx/include/mongocxx/v1/transaction_options.hpp similarity index 71% rename from src/mongocxx/include/mongocxx/v1/transaction.hpp rename to src/mongocxx/include/mongocxx/v1/transaction_options.hpp index 1b0da5035f..c479f84c95 100644 --- a/src/mongocxx/include/mongocxx/v1/transaction.hpp +++ b/src/mongocxx/include/mongocxx/v1/transaction_options.hpp @@ -14,7 +14,7 @@ #pragma once -#include // IWYU pragma: export +#include // IWYU pragma: export // @@ -47,7 +47,7 @@ namespace v1 { /// /// @attention This feature is experimental! It is not ready for use! /// -class transaction { +class transaction_options { private: void* _impl; // mongoc_transaction_opt_t @@ -57,7 +57,7 @@ class transaction { /// /// @warning Invalidates all associated views. /// - MONGOCXX_ABI_EXPORT_CDECL() ~transaction(); + MONGOCXX_ABI_EXPORT_CDECL() ~transaction_options(); /// /// Move constructor. @@ -65,7 +65,7 @@ class transaction { /// @par Postconditions: /// - `other` is in an assign-or-destroy-only state. /// - MONGOCXX_ABI_EXPORT_CDECL() transaction(transaction&& other) noexcept; + MONGOCXX_ABI_EXPORT_CDECL() transaction_options(transaction_options&& other) noexcept; /// /// Move assignment. @@ -73,17 +73,17 @@ class transaction { /// @par Postconditions: /// - `other` is in an assign-or-destroy-only state. /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) operator=(transaction&& other) noexcept; + MONGOCXX_ABI_EXPORT_CDECL(transaction_options&) operator=(transaction_options&& other) noexcept; /// /// Copy construction. /// - MONGOCXX_ABI_EXPORT_CDECL() transaction(transaction const& other); + MONGOCXX_ABI_EXPORT_CDECL() transaction_options(transaction_options const& other); /// /// Copy assignment. /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) operator=(transaction const& other); + MONGOCXX_ABI_EXPORT_CDECL(transaction_options&) operator=(transaction_options const& other); /// /// Default initialization. @@ -91,22 +91,26 @@ class transaction { /// @par Postconditions: /// - All supported fields are "unset" or zero-initialized. /// - MONGOCXX_ABI_EXPORT_CDECL() transaction(); + MONGOCXX_ABI_EXPORT_CDECL() transaction_options(); /// /// Set the "maxCommitTimeMS" field. /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) max_commit_time_ms(std::chrono::milliseconds v); + /// @note `0` is equivalent to "unset". + /// + MONGOCXX_ABI_EXPORT_CDECL(transaction_options&) max_commit_time_ms(std::chrono::milliseconds v); /// /// Return the current "maxCommitTimeMS" field. /// + /// @note `0` is equivalent to "unset". + /// MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v1::stdx::optional) max_commit_time_ms() const; /// /// Set the "readConcern" field. /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) read_concern(v1::read_concern const& v); + MONGOCXX_ABI_EXPORT_CDECL(transaction_options&) read_concern(v1::read_concern const& v); /// /// Return the current "readConcern" field. @@ -116,7 +120,7 @@ class transaction { /// /// Set the "readPreference" field. /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) read_preference(v1::read_preference const& v); + MONGOCXX_ABI_EXPORT_CDECL(transaction_options&) read_preference(v1::read_preference const& v); /// /// Return the current "readPreference" field. @@ -126,12 +130,17 @@ class transaction { /// /// Set the "writeConcern" field. /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) write_concern(v1::write_concern const& v); + MONGOCXX_ABI_EXPORT_CDECL(transaction_options&) write_concern(v1::write_concern const& v); /// /// Return the current "writeConcern" field. /// MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v1::stdx::optional) write_concern() const; + + class internal; + + private: + /* explicit(false) */ transaction_options(void* impl); }; } // namespace v1 @@ -141,5 +150,5 @@ class transaction { /// /// @file -/// Provides @ref mongocxx::v1::transaction. +/// Provides @ref mongocxx::v1::transaction_options. /// diff --git a/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction-fwd.hpp b/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction-fwd.hpp index 415db86b28..06c24b962f 100644 --- a/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction-fwd.hpp +++ b/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction-fwd.hpp @@ -14,6 +14,8 @@ #pragma once +#include // IWYU pragma: export + #include namespace mongocxx { @@ -29,7 +31,7 @@ class transaction; namespace mongocxx { namespace options { -using ::mongocxx::v_noabi::options::transaction; +using v_noabi::options::transaction; } // namespace options } // namespace mongocxx @@ -40,3 +42,6 @@ using ::mongocxx::v_noabi::options::transaction; /// @file /// Declares @ref mongocxx::v_noabi::options::transaction. /// +/// @par Includes +/// - @ref mongocxx/v1/transaction_options-fwd.hpp +/// diff --git a/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction.hpp b/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction.hpp index 8c6be8e82d..5c40a8e9d6 100644 --- a/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction.hpp +++ b/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction.hpp @@ -14,11 +14,17 @@ #pragma once +#include // IWYU pragma: export + +// + +#include // IWYU pragma: export + #include -#include +#include // IWYU pragma: keep: backward compatibility, to be removed. +#include -#include -#include // IWYU pragma: export +#include // IWYU pragma: keep: backward compatibility, to be removed. #include #include #include @@ -35,33 +41,61 @@ namespace options { /// Used by MongoDB transaction operations. /// class transaction { + private: + v1::transaction_options _txn; + public: - MONGOCXX_ABI_EXPORT_CDECL() transaction(); + /// + /// Default initialization. + /// + transaction() = default; /// /// Copy constructs transaction options. /// - MONGOCXX_ABI_EXPORT_CDECL() transaction(transaction const&); + MONGOCXX_ABI_EXPORT_CDECL() transaction(transaction const& other); /// /// Copy assigns transaction options. /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) operator=(transaction const&); + MONGOCXX_ABI_EXPORT_CDECL(transaction&) operator=(transaction const& other); /// /// Move constructs transaction options. /// - MONGOCXX_ABI_EXPORT_CDECL() transaction(transaction&&) noexcept; + transaction(transaction&& other) noexcept = default; /// /// Move assigns transaction options. /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) operator=(transaction&&) noexcept; + transaction& operator=(transaction&& other) noexcept = default; /// /// Destroys the transaction options. /// - MONGOCXX_ABI_EXPORT_CDECL() ~transaction() noexcept; + ~transaction() noexcept = default; + + /// + /// Construct with the @ref mongocxx::v1 equivalent. + /// + /* explicit(false) */ transaction(v1::transaction_options txn) : _txn{std::move(txn)} {} + + /// + /// Convert to the @ref mongocxx::v1 equivalent. + /// + /// @par Postconditions: + /// - `*this` is in an assign-or-destroy-only state. + /// + explicit operator v1::transaction_options() && { + return std::move(_txn); + } + + /// + /// Convert to the @ref mongocxx::v1 equivalent. + /// + explicit operator v1::transaction_options() const& { + return _txn; + } /// /// Sets the transaction read concern. @@ -73,7 +107,7 @@ class transaction { /// A reference to the object on which this member function is being called. This facilitates /// method chaining. /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) read_concern(mongocxx::v_noabi::read_concern const& rc); + MONGOCXX_ABI_EXPORT_CDECL(transaction&) read_concern(v_noabi::read_concern const& rc); /// /// Gets the current transaction read concern. @@ -81,7 +115,7 @@ class transaction { /// @return /// An optional containing the read concern. If the read concern has not been set, a /// disengaged optional is returned. - MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) + MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) read_concern() const; /// @@ -95,7 +129,7 @@ class transaction { /// method chaining. /// MONGOCXX_ABI_EXPORT_CDECL(transaction&) - write_concern(mongocxx::v_noabi::write_concern const& wc); + write_concern(v_noabi::write_concern const& wc); /// /// Gets the current transaction write concern. @@ -105,7 +139,7 @@ class transaction { /// @return /// An optional containing the write concern. If the write concern has not been set, a /// disengaged optional is returned. - MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) + MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) write_concern() const; /// @@ -119,7 +153,7 @@ class transaction { /// method chaining. /// MONGOCXX_ABI_EXPORT_CDECL(transaction&) - read_preference(mongocxx::v_noabi::read_preference const& rp); + read_preference(v_noabi::read_preference const& rp); /// /// Gets the current transaction read preference. @@ -127,7 +161,7 @@ class transaction { /// @return /// An optional containing the read preference. If the read preference has not been set, a /// disengaged optional is returned. - MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) + MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) read_preference() const; /// @@ -148,26 +182,41 @@ class transaction { /// An optional containing the timeout. If the max commit time has not been set, /// a disengaged optional is returned. /// - MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) - max_commit_time_ms() const; - - private: - friend ::mongocxx::v_noabi::client_session; - - class impl; + MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) max_commit_time_ms() const; - impl& _get_impl(); - impl const& _get_impl() const; - std::unique_ptr _impl; + class internal; }; } // namespace options } // namespace v_noabi } // namespace mongocxx +namespace mongocxx { +namespace v_noabi { + +/// +/// Convert to the @ref v_noabi equivalent of `v`. +/// +inline v_noabi::options::transaction from_v1(v1::transaction_options v) { + return {std::move(v)}; +} + +/// +/// Convert to the @ref mongocxx::v1 equivalent of `v`. +/// +inline v1::transaction_options to_v1(v_noabi::options::transaction v) { + return v1::transaction_options{std::move(v)}; +} + +} // namespace v_noabi +} // namespace mongocxx + #include /// /// @file /// Provides @ref mongocxx::v_noabi::options::transaction. /// +/// @par Includes +/// - @ref mongocxx/v1/transaction_options.hpp +/// diff --git a/src/mongocxx/lib/CMakeLists.txt b/src/mongocxx/lib/CMakeLists.txt index dff0682647..5f48c58806 100644 --- a/src/mongocxx/lib/CMakeLists.txt +++ b/src/mongocxx/lib/CMakeLists.txt @@ -192,7 +192,7 @@ set(mongocxx_sources_v1 mongocxx/v1/server_api.cpp mongocxx/v1/server_error.cpp mongocxx/v1/tls.cpp - mongocxx/v1/transaction.cpp + mongocxx/v1/transaction_options.cpp mongocxx/v1/update_many_options.cpp mongocxx/v1/update_many_result.cpp mongocxx/v1/update_one_options.cpp diff --git a/src/mongocxx/lib/mongocxx/v1/transaction.cpp b/src/mongocxx/lib/mongocxx/v1/transaction.cpp deleted file mode 100644 index 298cf03a14..0000000000 --- a/src/mongocxx/lib/mongocxx/v1/transaction.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009-present MongoDB, Inc. -// -// Licensed 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 diff --git a/src/mongocxx/lib/mongocxx/v1/transaction_options.cpp b/src/mongocxx/lib/mongocxx/v1/transaction_options.cpp new file mode 100644 index 0000000000..d3c0a706e2 --- /dev/null +++ b/src/mongocxx/lib/mongocxx/v1/transaction_options.cpp @@ -0,0 +1,140 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed 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 + +// + +#include + +#include +#include +#include + +#include + +#include +#include + +namespace mongocxx { +namespace v1 { + +namespace { + +mongoc_transaction_opt_t* to_mongoc(void* ptr) { + return static_cast(ptr); +} + +} // namespace + +transaction_options::~transaction_options() { + libmongoc::transaction_opts_destroy(to_mongoc(_impl)); +} + +transaction_options::transaction_options(transaction_options&& other) noexcept + : _impl{exchange(other._impl, nullptr)} {} + +transaction_options& transaction_options::operator=(transaction_options&& other) noexcept { + if (this != &other) { + libmongoc::transaction_opts_destroy(to_mongoc(exchange(_impl, exchange(other._impl, nullptr)))); + } + return *this; +} + +transaction_options::transaction_options(transaction_options const& other) + : _impl{libmongoc::transaction_opts_clone(to_mongoc(other._impl))} {} + +transaction_options& transaction_options::operator=(transaction_options const& other) { + if (this != &other) { + libmongoc::transaction_opts_destroy( + to_mongoc(exchange(_impl, libmongoc::transaction_opts_clone(to_mongoc(other._impl))))); + } + return *this; +} + +transaction_options::transaction_options() : _impl{libmongoc::transaction_opts_new()} {} + +transaction_options& transaction_options::max_commit_time_ms(std::chrono::milliseconds v) { + libmongoc::transaction_opts_set_max_commit_time_ms(to_mongoc(_impl), v.count()); + return *this; +} + +bsoncxx::v1::stdx::optional transaction_options::max_commit_time_ms() const { + bsoncxx::v1::stdx::optional ret; + + // DEFAULT_MAX_COMMIT_TIME_MS (0) is equivalent to "unset". + if (auto const v = libmongoc::transaction_opts_get_max_commit_time_ms(to_mongoc(_impl))) { + ret.emplace(v); + } + + return ret; +} + +transaction_options& transaction_options::read_concern(v1::read_concern const& v) { + internal::set_read_concern(*this, v1::read_concern::internal::as_mongoc(v)); + return *this; +} + +bsoncxx::v1::stdx::optional transaction_options::read_concern() const { + if (auto const rc = libmongoc::transaction_opts_get_read_concern(to_mongoc(_impl))) { + return v1::read_concern::internal::make(libmongoc::read_concern_copy(rc)); + } + + return {}; +} + +transaction_options& transaction_options::read_preference(v1::read_preference const& v) { + internal::set_read_preference(*this, v1::read_preference::internal::as_mongoc(v)); + return *this; +} + +bsoncxx::v1::stdx::optional transaction_options::read_preference() const { + if (auto const rp = libmongoc::transaction_opts_get_read_prefs(to_mongoc(_impl))) { + return v1::read_preference::internal::make(libmongoc::read_prefs_copy(rp)); + } + + return {}; +} + +transaction_options& transaction_options::write_concern(v1::write_concern const& v) { + internal::set_write_concern(*this, v1::write_concern::internal::as_mongoc(v)); + return *this; +} + +bsoncxx::v1::stdx::optional transaction_options::write_concern() const { + if (auto const wc = libmongoc::transaction_opts_get_write_concern(to_mongoc(_impl))) { + return v1::write_concern::internal::make(libmongoc::write_concern_copy(wc)); + } + + return {}; +} + +mongoc_transaction_opt_t const* transaction_options::internal::as_mongoc(transaction_options const& self) { + return to_mongoc(self._impl); +} + +void transaction_options::internal::set_read_concern(transaction_options& self, mongoc_read_concern_t const* v) { + libmongoc::transaction_opts_set_read_concern(to_mongoc(self._impl), v); +} + +void transaction_options::internal::set_read_preference(transaction_options& self, mongoc_read_prefs_t const* v) { + libmongoc::transaction_opts_set_read_prefs(to_mongoc(self._impl), v); +} + +void transaction_options::internal::set_write_concern(transaction_options& self, mongoc_write_concern_t const* v) { + libmongoc::transaction_opts_set_write_concern(to_mongoc(self._impl), v); +} + +} // namespace v1 +} // namespace mongocxx diff --git a/src/mongocxx/lib/mongocxx/v1/transaction_options.hh b/src/mongocxx/lib/mongocxx/v1/transaction_options.hh new file mode 100644 index 0000000000..7af7388b80 --- /dev/null +++ b/src/mongocxx/lib/mongocxx/v1/transaction_options.hh @@ -0,0 +1,36 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed 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 // IWYU pragma: export + +// + +#include + +namespace mongocxx { +namespace v1 { + +class transaction_options::internal { + public: + static mongoc_transaction_opt_t const* as_mongoc(transaction_options const& self); + + static void set_read_concern(transaction_options& self, mongoc_read_concern_t const* v); + static void set_read_preference(transaction_options& self, mongoc_read_prefs_t const* v); + static void set_write_concern(transaction_options& self, mongoc_write_concern_t const* v); +}; + +} // namespace v1 +} // namespace mongocxx diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client_session.hh b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client_session.hh index 260fb9f519..757778d0b4 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client_session.hh +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client_session.hh @@ -23,15 +23,15 @@ #include #include +#include +#include #include #include #include #include -#include #include -#include namespace mongocxx { namespace v_noabi { @@ -85,9 +85,9 @@ class client_session::impl { libmongoc::session_opts_set_snapshot(opt_t.get(), session_options.snapshot()); } - if (session_options.default_transaction_opts()) { + if (auto const& opt = session_options.default_transaction_opts()) { libmongoc::session_opts_set_default_transaction_opts( - opt_t.get(), (session_options.default_transaction_opts())->_get_impl().get_transaction_opt_t()); + opt_t.get(), v_noabi::options::transaction::internal::as_mongoc(*opt)); } bson_error_t error; @@ -145,13 +145,11 @@ class client_session::impl { void start_transaction(bsoncxx::v_noabi::stdx::optional const& transaction_opts) { bson_error_t error; - mongoc_transaction_opt_t* transaction_opt_t = nullptr; - - if (transaction_opts) { - transaction_opt_t = transaction_opts->_get_impl().get_transaction_opt_t(); - } - if (!libmongoc::client_session_start_transaction(_session_t.get(), transaction_opt_t, &error)) { + if (!libmongoc::client_session_start_transaction( + _session_t.get(), + transaction_opts ? v_noabi::options::transaction::internal::as_mongoc(*transaction_opts) : nullptr, + &error)) { throw_exception(error); } } @@ -173,7 +171,6 @@ class client_session::impl { void with_transaction(client_session* parent, client_session::with_transaction_cb cb, options::transaction opts) { auto session_t = _session_t.get(); - auto opts_t = opts._get_impl().get_transaction_opt_t(); with_transaction_ctx ctx{parent, std::move(cb), nullptr}; @@ -181,7 +178,12 @@ class client_session::impl { scoped_bson reply; auto res = libmongoc::client_session_with_transaction( - session_t, &with_transaction_cpp_cb, opts_t, &ctx, reply.out_ptr(), &error); + session_t, + &with_transaction_cpp_cb, + v_noabi::options::transaction::internal::as_mongoc(opts), + &ctx, + reply.out_ptr(), + &error); if (!res) { if (ctx.eptr) { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.cpp index aa19b18110..65147494bc 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.cpp @@ -16,76 +16,86 @@ // +#include + +#include +#include + +#include + #include #include -#include +#include +#include +#include + +#include namespace mongocxx { namespace v_noabi { namespace options { -transaction::transaction() : _impl{bsoncxx::make_unique()} {} +namespace { -transaction::transaction(transaction&&) noexcept = default; -transaction& transaction::operator=(transaction&&) noexcept = default; +template +Transaction& check_moved_from(Transaction& txn) { + if (!v1::transaction_options::internal::as_mongoc(txn)) { + throw logic_error{error_code::k_invalid_transaction_options_object}; + } + return txn; +} -transaction::transaction(transaction const& other) - : _impl{bsoncxx::make_unique(other._get_impl().get_transaction_opt_t())} {} +} // namespace + +transaction::transaction(transaction const& other) : _txn{check_moved_from(other._txn)} {} transaction& transaction::operator=(transaction const& other) { - _impl = bsoncxx::make_unique(other._get_impl().get_transaction_opt_t()); + _txn = check_moved_from(other._txn); return *this; } -transaction::~transaction() noexcept = default; - -transaction& transaction::read_concern(mongocxx::v_noabi::read_concern const& rc) { - _impl->read_concern(rc); +transaction& transaction::read_concern(v_noabi::read_concern const& rc) { + v1::transaction_options::internal::set_read_concern( + check_moved_from(_txn), v_noabi::read_concern::internal::as_mongoc(rc)); return *this; } -bsoncxx::v_noabi::stdx::optional transaction::read_concern() const { - return _impl->read_concern(); +bsoncxx::v_noabi::stdx::optional transaction::read_concern() const { + return check_moved_from(_txn).read_concern(); } -transaction& transaction::write_concern(mongocxx::v_noabi::write_concern const& wc) { - _impl->write_concern(wc); +transaction& transaction::write_concern(v_noabi::write_concern const& wc) { + v1::transaction_options::internal::set_write_concern( + check_moved_from(_txn), v_noabi::write_concern::internal::as_mongoc(wc)); return *this; } -bsoncxx::v_noabi::stdx::optional transaction::write_concern() const { - return _impl->write_concern(); +bsoncxx::v_noabi::stdx::optional transaction::write_concern() const { + return check_moved_from(_txn).write_concern(); } -transaction& transaction::read_preference(mongocxx::v_noabi::read_preference const& rp) { - _impl->read_preference(rp); +transaction& transaction::read_preference(v_noabi::read_preference const& rp) { + v1::transaction_options::internal::set_read_preference( + check_moved_from(_txn), v_noabi::read_preference::internal::as_mongoc(rp)); return *this; } -bsoncxx::v_noabi::stdx::optional transaction::read_preference() const { - return _impl->read_preference(); +bsoncxx::v_noabi::stdx::optional transaction::read_preference() const { + return check_moved_from(_txn).read_preference(); } transaction& transaction::max_commit_time_ms(std::chrono::milliseconds ms) { - _impl->max_commit_time_ms(ms); + check_moved_from(_txn).max_commit_time_ms(ms); return *this; } bsoncxx::v_noabi::stdx::optional transaction::max_commit_time_ms() const { - return _impl->max_commit_time_ms(); -} - -transaction::impl const& transaction::_get_impl() const { - if (!_impl) { - throw logic_error{error_code::k_invalid_transaction_options_object}; - } - return *_impl; + return check_moved_from(_txn).max_commit_time_ms(); } -transaction::impl& transaction::_get_impl() { - auto cthis = const_cast(this); - return const_cast(cthis->_get_impl()); +mongoc_transaction_opt_t const* transaction::internal::as_mongoc(transaction const& self) { + return v1::transaction_options::internal::as_mongoc(check_moved_from(self._txn)); } } // namespace options diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.hh b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.hh index 2445f28d5e..c54c2d7aaa 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.hh +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.hh @@ -18,120 +18,15 @@ // -#include -#include -#include - -#include -#include - -#include - -#include - -#include -#include -#include - -#include - #include namespace mongocxx { namespace v_noabi { namespace options { -class transaction::impl { +class transaction::internal { public: - impl() - : _transaction_opt_t( - unique_transaction_opt{libmongoc::transaction_opts_new(), &mongoc_transaction_opts_destroy}) {} - - impl(mongoc_transaction_opt_t* txn_opts) - : _transaction_opt_t( - unique_transaction_opt{libmongoc::transaction_opts_clone(txn_opts), &mongoc_transaction_opts_destroy}) {} - - impl(impl const& other) - : _transaction_opt_t( - unique_transaction_opt{ - libmongoc::transaction_opts_clone(other._transaction_opt_t.get()), - &mongoc_transaction_opts_destroy}) {} - - impl& operator=(impl const& other) { - _transaction_opt_t = unique_transaction_opt{ - libmongoc::transaction_opts_clone(other._transaction_opt_t.get()), &mongoc_transaction_opts_destroy}; - return *this; - } - - ~impl() = default; - - impl(impl&&) = default; - impl& operator=(impl&&) = default; - - void read_concern(mongocxx::v_noabi::read_concern const& rc) { - libmongoc::transaction_opts_set_read_concern( - _transaction_opt_t.get(), v_noabi::read_concern::internal::as_mongoc(rc)); - } - - bsoncxx::v_noabi::stdx::optional read_concern() const { - bsoncxx::v_noabi::stdx::optional ret; - if (auto const rc = libmongoc::transaction_opts_get_read_concern(_transaction_opt_t.get())) { - ret.emplace(v1::read_concern::internal::make(libmongoc::read_concern_copy(rc))); - } - return ret; - } - - void write_concern(mongocxx::v_noabi::write_concern const& wc) { - libmongoc::transaction_opts_set_write_concern( - _transaction_opt_t.get(), v_noabi::write_concern::internal::as_mongoc(wc)); - } - - bsoncxx::v_noabi::stdx::optional write_concern() const { - bsoncxx::v_noabi::stdx::optional ret; - - if (auto const wc = libmongoc::transaction_opts_get_write_concern(_transaction_opt_t.get())) { - ret.emplace(v1::write_concern::internal::make(libmongoc::write_concern_copy(wc))); - } - - return ret; - } - - void read_preference(mongocxx::v_noabi::read_preference const& rp) { - libmongoc::transaction_opts_set_read_prefs( - _transaction_opt_t.get(), v_noabi::read_preference::internal::as_mongoc(rp)); - } - - bsoncxx::v_noabi::stdx::optional read_preference() const { - bsoncxx::v_noabi::stdx::optional ret; - - if (auto const rp = libmongoc::transaction_opts_get_read_prefs(_transaction_opt_t.get())) { - ret.emplace(v1::read_preference::internal::make(libmongoc::read_prefs_copy(rp))); - } - - return ret; - } - - void max_commit_time_ms(std::chrono::milliseconds ms) { - libmongoc::transaction_opts_set_max_commit_time_ms(_transaction_opt_t.get(), ms.count()); - } - - bsoncxx::v_noabi::stdx::optional max_commit_time_ms() const { - auto ms = libmongoc::transaction_opts_get_max_commit_time_ms(_transaction_opt_t.get()); - if (!ms) { - return bsoncxx::v_noabi::stdx::nullopt; - } - return {std::chrono::milliseconds{ms}}; - } - - mongoc_transaction_opt_t* get_transaction_opt_t() const noexcept { - return _transaction_opt_t.get(); - } - - private: - using unique_transaction_opt = - std::unique_ptr; - - unique_transaction_opt _transaction_opt_t; + static mongoc_transaction_opt_t const* as_mongoc(transaction const& self); }; } // namespace options diff --git a/src/mongocxx/test/CMakeLists.txt b/src/mongocxx/test/CMakeLists.txt index c87793f1d2..0eb61abf21 100644 --- a/src/mongocxx/test/CMakeLists.txt +++ b/src/mongocxx/test/CMakeLists.txt @@ -125,6 +125,7 @@ set(mongocxx_test_sources_v1 v1/rewrap_many_datakey_options.cpp v1/server_error.cpp v1/tls.cpp + v1/transaction_options.cpp v1/update_many_options.cpp v1/update_one_options.cpp v1/write_concern.cpp diff --git a/src/mongocxx/test/v1/transaction_options.cpp b/src/mongocxx/test/v1/transaction_options.cpp new file mode 100644 index 0000000000..908cbf75cc --- /dev/null +++ b/src/mongocxx/test/v1/transaction_options.cpp @@ -0,0 +1,138 @@ +// Copyright 2009-present MongoDB, Inc. +// +// Licensed 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 + +// + +#include +#include +#include + +#include +#include + +#include +#include + +namespace mongocxx { +namespace v1 { + +TEST_CASE("ownership", "[mongocxx][v1][transaction_options]") { + using secs = std::chrono::seconds; + + transaction_options source; + transaction_options target; + + auto const source_secs = secs{123}; + auto const target_secs = secs{456}; + + source.max_commit_time_ms(source_secs); + target.max_commit_time_ms(target_secs); + + SECTION("move") { + auto move = std::move(source); + + // source is in an assign-or-move-only state. + + CHECK(move.max_commit_time_ms() == source_secs); + + target = std::move(move); + + // source is in an assign-or-move-only state. + + CHECK(target.max_commit_time_ms() == source_secs); + } + + SECTION("copy") { + auto copy = source; + + CHECK(source.max_commit_time_ms() == source_secs); + CHECK(copy.max_commit_time_ms() == source_secs); + + target = copy; + + CHECK(copy.max_commit_time_ms() == source_secs); + CHECK(target.max_commit_time_ms() == source_secs); + } +} + +TEST_CASE("default", "[mongocxx][v1][transaction_options]") { + transaction_options const txn; + + CHECK_FALSE(txn.max_commit_time_ms().has_value()); + CHECK_FALSE(txn.read_concern().has_value()); + CHECK_FALSE(txn.read_preference().has_value()); + CHECK_FALSE(txn.write_concern().has_value()); +} + +TEST_CASE("max_commit_time_ms", "[mongocxx][v1][transaction_options]") { + using msecs = std::chrono::milliseconds; + + auto const v = GENERATE(values({ + msecs::min(), + msecs{-2}, + msecs{-1}, + msecs{0}, + msecs{1}, + msecs::max(), + })); + + CAPTURE(v); + + transaction_options txn; + CHECK_NOTHROW(txn.max_commit_time_ms(v)); + + // DEFAULT_MAX_COMMIT_TIME_MS (0) is equivalent to "unset". + CHECKED_IF(v.count() == 0) { + CHECK_FALSE(txn.max_commit_time_ms().has_value()); + } + + else { + CHECK(txn.max_commit_time_ms() == v); + } +} + +TEST_CASE("read_concern", "[mongocxx][v1][transaction_options]") { + auto const v = GENERATE(values({ + read_concern{}, + std::move(read_concern{}.acknowledge_level(read_concern::level::k_majority)), + })); + CAPTURE(v.acknowledge_level()); + + CHECK(transaction_options{}.read_concern(v).read_concern() == v); +} + +TEST_CASE("read_preference", "[mongocxx][v1][transaction_options]") { + auto const v = GENERATE(values({ + read_preference{}, + std::move(read_preference{}.mode(read_preference::read_mode::k_primary_preferred)), + })); + CAPTURE(v.mode()); + + CHECK(transaction_options{}.read_preference(v).read_preference() == v); +} + +TEST_CASE("write_concern", "[mongocxx][v1][transaction_options]") { + auto const v = GENERATE(values({ + write_concern{}, + std::move(write_concern{}.acknowledge_level(write_concern::level::k_majority)), + })); + CAPTURE(v.acknowledge_level()); + + CHECK(transaction_options{}.write_concern(v).write_concern() == v); +} + +} // namespace v1 +} // namespace mongocxx