From 46b4551fee612242043692c8445eeafc3e9b6571 Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Fri, 5 Dec 2025 14:20:12 -0600 Subject: [PATCH 1/5] v1: transaction (CXX-3237, CXX-3238) --- .../include/mongocxx/v1/transaction.hpp | 5 + .../mongocxx/options/transaction-fwd.hpp | 7 +- .../v_noabi/mongocxx/options/transaction.hpp | 99 +++++++++---- src/mongocxx/lib/mongocxx/v1/transaction.cpp | 125 +++++++++++++++- src/mongocxx/lib/mongocxx/v1/transaction.hh | 36 +++++ .../v_noabi/mongocxx/client_session.hh | 26 ++-- .../v_noabi/mongocxx/options/transaction.cpp | 75 +++++----- .../v_noabi/mongocxx/options/transaction.hh | 109 +------------- src/mongocxx/test/CMakeLists.txt | 1 + src/mongocxx/test/v1/transaction.cpp | 138 ++++++++++++++++++ 10 files changed, 442 insertions(+), 179 deletions(-) create mode 100644 src/mongocxx/lib/mongocxx/v1/transaction.hh create mode 100644 src/mongocxx/test/v1/transaction.cpp diff --git a/src/mongocxx/include/mongocxx/v1/transaction.hpp b/src/mongocxx/include/mongocxx/v1/transaction.hpp index 1b0da5035f..9a0fcbf50f 100644 --- a/src/mongocxx/include/mongocxx/v1/transaction.hpp +++ b/src/mongocxx/include/mongocxx/v1/transaction.hpp @@ -132,6 +132,11 @@ class transaction { /// Return the current "writeConcern" field. /// MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v1::stdx::optional) write_concern() const; + + class internal; + + private: + /* explicit(false) */ transaction(void* impl); }; } // namespace v1 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..6e744bb143 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 + #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-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..1560551b46 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 _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 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() && { + return std::move(_txn); + } + + /// + /// Convert to the @ref mongocxx::v1 equivalent. + /// + explicit operator v1::transaction() 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 v) { + return {std::move(v)}; +} + +/// +/// Convert to the @ref mongocxx::v1 equivalent of `v`. +/// +inline v1::transaction to_v1(v_noabi::options::transaction v) { + return v1::transaction{std::move(v)}; +} + +} // namespace v_noabi +} // namespace mongocxx + #include /// /// @file /// Provides @ref mongocxx::v_noabi::options::transaction. /// +/// @par Includes +/// - @ref mongocxx/v1/transaction.hpp +/// diff --git a/src/mongocxx/lib/mongocxx/v1/transaction.cpp b/src/mongocxx/lib/mongocxx/v1/transaction.cpp index 298cf03a14..59c81c684a 100644 --- a/src/mongocxx/lib/mongocxx/v1/transaction.cpp +++ b/src/mongocxx/lib/mongocxx/v1/transaction.cpp @@ -12,4 +12,127 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#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::~transaction() { + libmongoc::transaction_opts_destroy(to_mongoc(_impl)); +} + +transaction::transaction(transaction&& other) noexcept : _impl{exchange(other._impl, nullptr)} {} + +transaction& transaction::operator=(transaction&& other) noexcept { + if (this != &other) { + libmongoc::transaction_opts_destroy(to_mongoc(exchange(_impl, exchange(other._impl, nullptr)))); + } + return *this; +} + +transaction::transaction(transaction const& other) : _impl{libmongoc::transaction_opts_clone(to_mongoc(other._impl))} {} + +transaction& transaction::operator=(transaction const& other) { + if (this != &other) { + libmongoc::transaction_opts_destroy( + to_mongoc(exchange(_impl, libmongoc::transaction_opts_clone(to_mongoc(other._impl))))); + } + return *this; +} + +transaction::transaction() : _impl{libmongoc::transaction_opts_new()} {} + +transaction& transaction::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::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& transaction::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::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& transaction::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::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& transaction::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::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::internal::as_mongoc(transaction const& self) { + return to_mongoc(self._impl); +} + +void transaction::internal::set_read_concern(transaction& self, mongoc_read_concern_t const* v) { + libmongoc::transaction_opts_set_read_concern(to_mongoc(self._impl), v); +} + +void transaction::internal::set_read_preference(transaction& self, mongoc_read_prefs_t const* v) { + libmongoc::transaction_opts_set_read_prefs(to_mongoc(self._impl), v); +} + +void transaction::internal::set_write_concern(transaction& 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.hh b/src/mongocxx/lib/mongocxx/v1/transaction.hh new file mode 100644 index 0000000000..f0a4e7eef7 --- /dev/null +++ b/src/mongocxx/lib/mongocxx/v1/transaction.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::internal { + public: + static mongoc_transaction_opt_t const* as_mongoc(transaction const& self); + + static void set_read_concern(transaction& self, mongoc_read_concern_t const* v); + static void set_read_preference(transaction& self, mongoc_read_prefs_t const* v); + static void set_write_concern(transaction& 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..a153dd5ec7 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,85 @@ // +#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::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::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::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::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::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..442d818eee 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.cpp v1/update_many_options.cpp v1/update_one_options.cpp v1/write_concern.cpp diff --git a/src/mongocxx/test/v1/transaction.cpp b/src/mongocxx/test/v1/transaction.cpp new file mode 100644 index 0000000000..85619195df --- /dev/null +++ b/src/mongocxx/test/v1/transaction.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]") { + using secs = std::chrono::seconds; + + transaction source; + transaction target; + + auto const source_secs = secs{123}; + auto const target_secs = secs{123}; + + 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]") { + transaction 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]") { + 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 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]") { + auto const v = GENERATE(values({ + read_concern{}, + std::move(read_concern{}.acknowledge_level(read_concern::level::k_majority)), + })); + CAPTURE(v.acknowledge_level()); + + CHECK(transaction{}.read_concern(v).read_concern() == v); +} + +TEST_CASE("read_preference", "[mongocxx][v1][transaction]") { + auto const v = GENERATE(values({ + read_preference{}, + std::move(read_preference{}.mode(read_preference::read_mode::k_primary_preferred)), + })); + CAPTURE(v.mode()); + + CHECK(transaction{}.read_preference(v).read_preference() == v); +} + +TEST_CASE("write_concern", "[mongocxx][v1][transaction]") { + auto const v = GENERATE(values({ + write_concern{}, + std::move(write_concern{}.acknowledge_level(write_concern::level::k_majority)), + })); + CAPTURE(v.acknowledge_level()); + + CHECK(transaction{}.write_concern(v).write_concern() == v); +} + +} // namespace v1 +} // namespace mongocxx From 56fa7916dec166d30cf672137e06d5d813c77d55 Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Mon, 8 Dec 2025 12:33:42 -0600 Subject: [PATCH 2/5] Fix target vs. source value distinction --- src/mongocxx/test/v1/transaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mongocxx/test/v1/transaction.cpp b/src/mongocxx/test/v1/transaction.cpp index 85619195df..98f28f9255 100644 --- a/src/mongocxx/test/v1/transaction.cpp +++ b/src/mongocxx/test/v1/transaction.cpp @@ -36,7 +36,7 @@ TEST_CASE("ownership", "[mongocxx][v1][transaction]") { transaction target; auto const source_secs = secs{123}; - auto const target_secs = secs{123}; + auto const target_secs = secs{456}; source.max_commit_time_ms(source_secs); target.max_commit_time_ms(target_secs); From 805d10c2744392a84dd96dfec295ab07d064c670 Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Mon, 8 Dec 2025 12:33:42 -0600 Subject: [PATCH 3/5] Publically document 0 == unset behavior --- src/mongocxx/include/mongocxx/v1/transaction.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mongocxx/include/mongocxx/v1/transaction.hpp b/src/mongocxx/include/mongocxx/v1/transaction.hpp index 9a0fcbf50f..d9f8911165 100644 --- a/src/mongocxx/include/mongocxx/v1/transaction.hpp +++ b/src/mongocxx/include/mongocxx/v1/transaction.hpp @@ -96,6 +96,8 @@ class transaction { /// /// Set the "maxCommitTimeMS" field. /// + /// @note `0` is equivalent to "unset". + /// MONGOCXX_ABI_EXPORT_CDECL(transaction&) max_commit_time_ms(std::chrono::milliseconds v); /// From 24d894bfbdf8a56c4aead4ed4e2e5d29f64ba73a Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Mon, 8 Dec 2025 12:33:42 -0600 Subject: [PATCH 4/5] CXX-3236 Rename `v1::transaction` -> `v1::transaction_options` --- .../include/mongocxx/v1/client_session.hpp | 16 ++++---- ...on-fwd.hpp => transaction_options-fwd.hpp} | 4 +- ...ransaction.hpp => transaction_options.hpp} | 28 ++++++------- .../mongocxx/options/transaction-fwd.hpp | 4 +- .../v_noabi/mongocxx/options/transaction.hpp | 18 ++++----- src/mongocxx/lib/CMakeLists.txt | 2 +- ...ransaction.cpp => transaction_options.cpp} | 40 ++++++++++--------- ...{transaction.hh => transaction_options.hh} | 12 +++--- .../v_noabi/mongocxx/options/transaction.cpp | 13 +++--- src/mongocxx/test/CMakeLists.txt | 2 +- ...ransaction.cpp => transaction_options.cpp} | 28 ++++++------- 11 files changed, 86 insertions(+), 81 deletions(-) rename src/mongocxx/include/mongocxx/v1/{transaction-fwd.hpp => transaction_options-fwd.hpp} (90%) rename src/mongocxx/include/mongocxx/v1/{transaction.hpp => transaction_options.hpp} (74%) rename src/mongocxx/lib/mongocxx/v1/{transaction.cpp => transaction_options.cpp} (63%) rename src/mongocxx/lib/mongocxx/v1/{transaction.hh => transaction_options.hh} (66%) rename src/mongocxx/test/v1/{transaction.cpp => transaction_options.cpp} (79%) 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 74% rename from src/mongocxx/include/mongocxx/v1/transaction.hpp rename to src/mongocxx/include/mongocxx/v1/transaction_options.hpp index d9f8911165..79c37320be 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,14 +91,14 @@ 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. /// /// @note `0` is equivalent to "unset". /// - MONGOCXX_ABI_EXPORT_CDECL(transaction&) max_commit_time_ms(std::chrono::milliseconds v); + MONGOCXX_ABI_EXPORT_CDECL(transaction_options&) max_commit_time_ms(std::chrono::milliseconds v); /// /// Return the current "maxCommitTimeMS" field. @@ -108,7 +108,7 @@ class transaction { /// /// 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. @@ -118,7 +118,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. @@ -128,7 +128,7 @@ 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. @@ -138,7 +138,7 @@ class transaction { class internal; private: - /* explicit(false) */ transaction(void* impl); + /* explicit(false) */ transaction_options(void* impl); }; } // namespace v1 @@ -148,5 +148,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 6e744bb143..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,7 +14,7 @@ #pragma once -#include +#include // IWYU pragma: export #include @@ -43,5 +43,5 @@ using v_noabi::options::transaction; /// Declares @ref mongocxx::v_noabi::options::transaction. /// /// @par Includes -/// - @ref mongocxx/v1/transaction-fwd.hpp +/// - @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 1560551b46..5c40a8e9d6 100644 --- a/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction.hpp +++ b/src/mongocxx/include/mongocxx/v_noabi/mongocxx/options/transaction.hpp @@ -18,7 +18,7 @@ // -#include // IWYU pragma: export +#include // IWYU pragma: export #include #include // IWYU pragma: keep: backward compatibility, to be removed. @@ -42,7 +42,7 @@ namespace options { /// class transaction { private: - v1::transaction _txn; + v1::transaction_options _txn; public: /// @@ -78,7 +78,7 @@ class transaction { /// /// Construct with the @ref mongocxx::v1 equivalent. /// - /* explicit(false) */ transaction(v1::transaction txn) : _txn{std::move(txn)} {} + /* explicit(false) */ transaction(v1::transaction_options txn) : _txn{std::move(txn)} {} /// /// Convert to the @ref mongocxx::v1 equivalent. @@ -86,14 +86,14 @@ class transaction { /// @par Postconditions: /// - `*this` is in an assign-or-destroy-only state. /// - explicit operator v1::transaction() && { + explicit operator v1::transaction_options() && { return std::move(_txn); } /// /// Convert to the @ref mongocxx::v1 equivalent. /// - explicit operator v1::transaction() const& { + explicit operator v1::transaction_options() const& { return _txn; } @@ -197,15 +197,15 @@ namespace v_noabi { /// /// Convert to the @ref v_noabi equivalent of `v`. /// -inline v_noabi::options::transaction from_v1(v1::transaction 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 to_v1(v_noabi::options::transaction v) { - return v1::transaction{std::move(v)}; +inline v1::transaction_options to_v1(v_noabi::options::transaction v) { + return v1::transaction_options{std::move(v)}; } } // namespace v_noabi @@ -218,5 +218,5 @@ inline v1::transaction to_v1(v_noabi::options::transaction v) { /// Provides @ref mongocxx::v_noabi::options::transaction. /// /// @par Includes -/// - @ref mongocxx/v1/transaction.hpp +/// - @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_options.cpp similarity index 63% rename from src/mongocxx/lib/mongocxx/v1/transaction.cpp rename to src/mongocxx/lib/mongocxx/v1/transaction_options.cpp index 59c81c684a..d3c0a706e2 100644 --- a/src/mongocxx/lib/mongocxx/v1/transaction.cpp +++ b/src/mongocxx/lib/mongocxx/v1/transaction_options.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include // @@ -38,22 +38,24 @@ mongoc_transaction_opt_t* to_mongoc(void* ptr) { } // namespace -transaction::~transaction() { +transaction_options::~transaction_options() { libmongoc::transaction_opts_destroy(to_mongoc(_impl)); } -transaction::transaction(transaction&& other) noexcept : _impl{exchange(other._impl, nullptr)} {} +transaction_options::transaction_options(transaction_options&& other) noexcept + : _impl{exchange(other._impl, nullptr)} {} -transaction& transaction::operator=(transaction&& other) noexcept { +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::transaction(transaction const& other) : _impl{libmongoc::transaction_opts_clone(to_mongoc(other._impl))} {} +transaction_options::transaction_options(transaction_options const& other) + : _impl{libmongoc::transaction_opts_clone(to_mongoc(other._impl))} {} -transaction& transaction::operator=(transaction const& other) { +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))))); @@ -61,14 +63,14 @@ transaction& transaction::operator=(transaction const& other) { return *this; } -transaction::transaction() : _impl{libmongoc::transaction_opts_new()} {} +transaction_options::transaction_options() : _impl{libmongoc::transaction_opts_new()} {} -transaction& transaction::max_commit_time_ms(std::chrono::milliseconds v) { +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::max_commit_time_ms() const { +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". @@ -79,12 +81,12 @@ bsoncxx::v1::stdx::optional transaction::max_commit_t return ret; } -transaction& transaction::read_concern(v1::read_concern const& v) { +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::read_concern() const { +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)); } @@ -92,12 +94,12 @@ bsoncxx::v1::stdx::optional transaction::read_concern() const return {}; } -transaction& transaction::read_preference(v1::read_preference const& v) { +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::read_preference() const { +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)); } @@ -105,12 +107,12 @@ bsoncxx::v1::stdx::optional transaction::read_preference() return {}; } -transaction& transaction::write_concern(v1::write_concern const& v) { +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::write_concern() const { +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)); } @@ -118,19 +120,19 @@ bsoncxx::v1::stdx::optional transaction::write_concern() cons return {}; } -mongoc_transaction_opt_t const* transaction::internal::as_mongoc(transaction const& self) { +mongoc_transaction_opt_t const* transaction_options::internal::as_mongoc(transaction_options const& self) { return to_mongoc(self._impl); } -void transaction::internal::set_read_concern(transaction& self, mongoc_read_concern_t const* v) { +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::internal::set_read_preference(transaction& self, mongoc_read_prefs_t const* 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::internal::set_write_concern(transaction& self, mongoc_write_concern_t const* 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); } diff --git a/src/mongocxx/lib/mongocxx/v1/transaction.hh b/src/mongocxx/lib/mongocxx/v1/transaction_options.hh similarity index 66% rename from src/mongocxx/lib/mongocxx/v1/transaction.hh rename to src/mongocxx/lib/mongocxx/v1/transaction_options.hh index f0a4e7eef7..7af7388b80 100644 --- a/src/mongocxx/lib/mongocxx/v1/transaction.hh +++ b/src/mongocxx/lib/mongocxx/v1/transaction_options.hh @@ -14,7 +14,7 @@ #pragma once -#include // IWYU pragma: export +#include // IWYU pragma: export // @@ -23,13 +23,13 @@ namespace mongocxx { namespace v1 { -class transaction::internal { +class transaction_options::internal { public: - static mongoc_transaction_opt_t const* as_mongoc(transaction const& self); + static mongoc_transaction_opt_t const* as_mongoc(transaction_options const& self); - static void set_read_concern(transaction& self, mongoc_read_concern_t const* v); - static void set_read_preference(transaction& self, mongoc_read_prefs_t const* v); - static void set_write_concern(transaction& self, mongoc_write_concern_t const* v); + 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 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 a153dd5ec7..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,7 +16,7 @@ // -#include +#include #include #include @@ -40,7 +40,7 @@ namespace { template Transaction& check_moved_from(Transaction& txn) { - if (!v1::transaction::internal::as_mongoc(txn)) { + if (!v1::transaction_options::internal::as_mongoc(txn)) { throw logic_error{error_code::k_invalid_transaction_options_object}; } return txn; @@ -56,7 +56,8 @@ transaction& transaction::operator=(transaction const& other) { } transaction& transaction::read_concern(v_noabi::read_concern const& rc) { - v1::transaction::internal::set_read_concern(check_moved_from(_txn), v_noabi::read_concern::internal::as_mongoc(rc)); + v1::transaction_options::internal::set_read_concern( + check_moved_from(_txn), v_noabi::read_concern::internal::as_mongoc(rc)); return *this; } @@ -65,7 +66,7 @@ bsoncxx::v_noabi::stdx::optional transaction::read_concer } transaction& transaction::write_concern(v_noabi::write_concern const& wc) { - v1::transaction::internal::set_write_concern( + v1::transaction_options::internal::set_write_concern( check_moved_from(_txn), v_noabi::write_concern::internal::as_mongoc(wc)); return *this; } @@ -75,7 +76,7 @@ bsoncxx::v_noabi::stdx::optional transaction::write_conc } transaction& transaction::read_preference(v_noabi::read_preference const& rp) { - v1::transaction::internal::set_read_preference( + v1::transaction_options::internal::set_read_preference( check_moved_from(_txn), v_noabi::read_preference::internal::as_mongoc(rp)); return *this; } @@ -94,7 +95,7 @@ bsoncxx::v_noabi::stdx::optional transaction::max_com } mongoc_transaction_opt_t const* transaction::internal::as_mongoc(transaction const& self) { - return v1::transaction::internal::as_mongoc(check_moved_from(self._txn)); + return v1::transaction_options::internal::as_mongoc(check_moved_from(self._txn)); } } // namespace options diff --git a/src/mongocxx/test/CMakeLists.txt b/src/mongocxx/test/CMakeLists.txt index 442d818eee..0eb61abf21 100644 --- a/src/mongocxx/test/CMakeLists.txt +++ b/src/mongocxx/test/CMakeLists.txt @@ -125,7 +125,7 @@ set(mongocxx_test_sources_v1 v1/rewrap_many_datakey_options.cpp v1/server_error.cpp v1/tls.cpp - v1/transaction.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.cpp b/src/mongocxx/test/v1/transaction_options.cpp similarity index 79% rename from src/mongocxx/test/v1/transaction.cpp rename to src/mongocxx/test/v1/transaction_options.cpp index 98f28f9255..908cbf75cc 100644 --- a/src/mongocxx/test/v1/transaction.cpp +++ b/src/mongocxx/test/v1/transaction_options.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include // @@ -29,11 +29,11 @@ namespace mongocxx { namespace v1 { -TEST_CASE("ownership", "[mongocxx][v1][transaction]") { +TEST_CASE("ownership", "[mongocxx][v1][transaction_options]") { using secs = std::chrono::seconds; - transaction source; - transaction target; + transaction_options source; + transaction_options target; auto const source_secs = secs{123}; auto const target_secs = secs{456}; @@ -68,8 +68,8 @@ TEST_CASE("ownership", "[mongocxx][v1][transaction]") { } } -TEST_CASE("default", "[mongocxx][v1][transaction]") { - transaction const txn; +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()); @@ -77,7 +77,7 @@ TEST_CASE("default", "[mongocxx][v1][transaction]") { CHECK_FALSE(txn.write_concern().has_value()); } -TEST_CASE("max_commit_time_ms", "[mongocxx][v1][transaction]") { +TEST_CASE("max_commit_time_ms", "[mongocxx][v1][transaction_options]") { using msecs = std::chrono::milliseconds; auto const v = GENERATE(values({ @@ -91,7 +91,7 @@ TEST_CASE("max_commit_time_ms", "[mongocxx][v1][transaction]") { CAPTURE(v); - transaction txn; + transaction_options txn; CHECK_NOTHROW(txn.max_commit_time_ms(v)); // DEFAULT_MAX_COMMIT_TIME_MS (0) is equivalent to "unset". @@ -104,34 +104,34 @@ TEST_CASE("max_commit_time_ms", "[mongocxx][v1][transaction]") { } } -TEST_CASE("read_concern", "[mongocxx][v1][transaction]") { +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{}.read_concern(v).read_concern() == v); + CHECK(transaction_options{}.read_concern(v).read_concern() == v); } -TEST_CASE("read_preference", "[mongocxx][v1][transaction]") { +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{}.read_preference(v).read_preference() == v); + CHECK(transaction_options{}.read_preference(v).read_preference() == v); } -TEST_CASE("write_concern", "[mongocxx][v1][transaction]") { +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{}.write_concern(v).write_concern() == v); + CHECK(transaction_options{}.write_concern(v).write_concern() == v); } } // namespace v1 From 7e01a3083095b8726ca28e0469ae4fc83917e4db Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Mon, 8 Dec 2025 12:35:53 -0600 Subject: [PATCH 5/5] Also document 0 == unset for getter --- src/mongocxx/include/mongocxx/v1/transaction_options.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mongocxx/include/mongocxx/v1/transaction_options.hpp b/src/mongocxx/include/mongocxx/v1/transaction_options.hpp index 79c37320be..c479f84c95 100644 --- a/src/mongocxx/include/mongocxx/v1/transaction_options.hpp +++ b/src/mongocxx/include/mongocxx/v1/transaction_options.hpp @@ -103,6 +103,8 @@ class transaction_options { /// /// Return the current "maxCommitTimeMS" field. /// + /// @note `0` is equivalent to "unset". + /// MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v1::stdx::optional) max_commit_time_ms() const; ///