From 6f5956c7bd0c1910dbf674e44cc3314d99df32af Mon Sep 17 00:00:00 2001 From: Ezra Chung Date: Fri, 14 Nov 2025 14:04:39 -0600 Subject: [PATCH] v1::read_preference (CXX-3237, CXX-3238) --- .../include/mongocxx/v1/read_preference.hpp | 5 + .../v_noabi/mongocxx/read_preference.hpp | 198 +++++++++------ .../lib/mongocxx/v1/read_preference.cpp | 173 ++++++++++++- .../lib/mongocxx/v1/read_preference.hh | 35 +++ .../lib/mongocxx/v_noabi/mongocxx/client.cpp | 10 +- .../mongocxx/v_noabi/mongocxx/collection.cpp | 42 ++-- .../mongocxx/v_noabi/mongocxx/database.cpp | 23 +- .../mongocxx/events/topology_description.cpp | 2 +- .../v_noabi/mongocxx/options/transaction.hh | 23 +- .../v_noabi/mongocxx/read_preference.cpp | 141 +++-------- .../v_noabi/mongocxx/read_preference.hh | 18 +- .../v_noabi/mongocxx/search_index_view.hh | 13 +- .../lib/mongocxx/v_noabi/mongocxx/uri.cpp | 7 +- src/mongocxx/test/CMakeLists.txt | 1 + src/mongocxx/test/v1/read_preference.cpp | 238 ++++++++++++++++++ src/mongocxx/test/v1/read_preference.hh | 29 +++ 16 files changed, 710 insertions(+), 248 deletions(-) create mode 100644 src/mongocxx/lib/mongocxx/v1/read_preference.hh create mode 100644 src/mongocxx/test/v1/read_preference.cpp create mode 100644 src/mongocxx/test/v1/read_preference.hh diff --git a/src/mongocxx/include/mongocxx/v1/read_preference.hpp b/src/mongocxx/include/mongocxx/v1/read_preference.hpp index 9f6c0fedd8..6158b8c75d 100644 --- a/src/mongocxx/include/mongocxx/v1/read_preference.hpp +++ b/src/mongocxx/include/mongocxx/v1/read_preference.hpp @@ -200,6 +200,11 @@ class read_preference { } /// @} /// + + class internal; + + private: + /* explicit(false) */ read_preference(void* impl); }; } // namespace v1 diff --git a/src/mongocxx/include/mongocxx/v_noabi/mongocxx/read_preference.hpp b/src/mongocxx/include/mongocxx/v_noabi/mongocxx/read_preference.hpp index 150403cba8..bc6367a061 100644 --- a/src/mongocxx/include/mongocxx/v_noabi/mongocxx/read_preference.hpp +++ b/src/mongocxx/include/mongocxx/v_noabi/mongocxx/read_preference.hpp @@ -14,25 +14,35 @@ #pragma once +#include // IWYU pragma: export + +// + +#include + +#include + #include #include -#include +#include // IWYU pragma: keep: backward compatibility, to be removed. #include // IWYU pragma: keep: backward compatibility, to be removed. +#include -#include -#include -#include -#include -#include -#include // IWYU pragma: export -#include -#include +#include // IWYU pragma: keep: backward compatibility, to be removed. +#include // IWYU pragma: keep: backward compatibility, to be removed. +#include // IWYU pragma: keep: backward compatibility, to be removed. +#include // IWYU pragma: keep: backward compatibility, to be removed. +#include // IWYU pragma: keep: backward compatibility, to be removed. +#include // IWYU pragma: keep: backward compatibility, to be removed. +#include // IWYU pragma: keep: backward compatibility, to be removed. +#include #include +#include #include #include -#include +#include // IWYU pragma: keep: backward compatibility, to be removed. #include @@ -47,6 +57,9 @@ namespace v_noabi { /// - [Read Preference (MongoDB Manual)](https://www.mongodb.com/docs/manual/core/read-preference/) /// class read_preference { + private: + v1::read_preference _rp; + public: /// /// Determines which members in a replica set are acceptable to read from. @@ -90,7 +103,31 @@ class read_preference { /// /// Constructs a new read_preference with read_mode set to k_primary. /// - MONGOCXX_ABI_EXPORT_CDECL() read_preference(); + read_preference() = default; + + /// + /// Construct with the @ref mongocxx::v1 equivalent. + /// + /* explicit(false) */ read_preference(v1::read_preference rp) : _rp{std::move(rp)} {} + + /// + /// Convert to the @ref mongocxx::v1 equivalent. + /// + /// @par Postconditions: + /// - `other` is in an assign-or-destroy-only state. + /// + /// @warning Invalidates all associated iterators and views. + /// + explicit operator v1::read_preference() && { + return std::move(_rp); + } + + /// + /// Convert to the @ref mongocxx::v1 equivalent. + /// + explicit operator v1::read_preference() const& { + return _rp; + } // @cond DOXYGEN_DISABLE struct deprecated_tag {}; @@ -104,10 +141,12 @@ class read_preference { /// /// @deprecated Use @ref mode instead. /// - MONGOCXX_DEPRECATED MONGOCXX_ABI_EXPORT_CDECL() read_preference(read_mode mode); + MONGOCXX_DEPRECATED read_preference(read_mode mode) : read_preference{mode, deprecated_tag{}} {} // @cond DOXYGEN_DISABLE - MONGOCXX_ABI_EXPORT_CDECL() read_preference(read_mode mode, deprecated_tag); + read_preference(read_mode mode, deprecated_tag) { + this->mode(mode); + } // @endcond /// @@ -123,40 +162,15 @@ class read_preference { /// /// @deprecated Use @ref tags instead. /// - MONGOCXX_DEPRECATED MONGOCXX_ABI_EXPORT_CDECL() read_preference( - read_mode mode, - bsoncxx::v_noabi::document::view_or_value tags); + MONGOCXX_DEPRECATED read_preference(read_mode mode, bsoncxx::v_noabi::document::view_or_value tags) + : read_preference{mode, tags, deprecated_tag{}} {} // @cond DOXYGEN_DISABLE - MONGOCXX_ABI_EXPORT_CDECL() - read_preference(read_mode mode, bsoncxx::v_noabi::document::view_or_value tags, deprecated_tag); + read_preference(read_mode mode, bsoncxx::v_noabi::document::view_or_value tags, deprecated_tag) { + this->mode(mode).tags(tags.view()); + } // @endcond - /// - /// Copy constructs a read_preference. - /// - MONGOCXX_ABI_EXPORT_CDECL() read_preference(read_preference const&); - - /// - /// Copy assigns a read_preference. - /// - MONGOCXX_ABI_EXPORT_CDECL(read_preference&) operator=(read_preference const&); - - /// - /// Move constructs a read_preference. - /// - MONGOCXX_ABI_EXPORT_CDECL() read_preference(read_preference&&) noexcept; - - /// - /// Move assigns a read_preference. - /// - MONGOCXX_ABI_EXPORT_CDECL(read_preference&) operator=(read_preference&&) noexcept; - - /// - /// Destroys a read_preference. - /// - MONGOCXX_ABI_EXPORT_CDECL() ~read_preference(); - /// /// Sets a new mode for this read_preference. /// @@ -167,14 +181,19 @@ class read_preference { /// A reference to the object on which this member function is being called. This facilitates /// method chaining. /// - MONGOCXX_ABI_EXPORT_CDECL(read_preference&) mode(read_mode mode); + read_preference& mode(read_mode mode) { + _rp.mode(static_cast(mode)); + return *this; + } /// /// Returns the current read_mode for this read_preference. /// /// @return The current read_mode. /// - MONGOCXX_ABI_EXPORT_CDECL(read_mode) mode() const; + read_mode mode() const { + return static_cast(_rp.mode()); + } /// /// Sets or updates the tag set list for this read_preference. @@ -189,8 +208,10 @@ class read_preference { /// A reference to the object on which this member function is being called. This facilitates /// method chaining. /// - MONGOCXX_ABI_EXPORT_CDECL(read_preference&) - tags(bsoncxx::v_noabi::document::view_or_value tag_set_list); + read_preference& tags(bsoncxx::v_noabi::document::view_or_value tag_set_list) { + _rp.tags(bsoncxx::v_noabi::to_v1(tag_set_list.view())); + return *this; + } /// /// Sets or updates the tag set list for this read_preference. @@ -205,8 +226,10 @@ class read_preference { /// A reference to the object on which this member function is being called. This facilitates /// method chaining. /// - MONGOCXX_ABI_EXPORT_CDECL(read_preference&) - tags(bsoncxx::v_noabi::array::view_or_value tag_set_list); + read_preference& tags(bsoncxx::v_noabi::array::view_or_value tag_set_list) { + _rp.tags(bsoncxx::v_noabi::to_v1(tag_set_list.view())); + return *this; + } /// /// Sets or updates the tag set list for this read_preference. @@ -216,8 +239,17 @@ class read_preference { /// @see /// - https://www.mongodb.com/docs/manual/core/read-preference-tags/ /// - MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) - tags() const; + bsoncxx::v_noabi::stdx::optional tags() const { + bsoncxx::v_noabi::stdx::optional ret; + + auto const v = _rp.tags(); + + if (!v.empty()) { + ret.emplace(v); + } + + return ret; + } /// /// Sets the max staleness setting for this read_preference. Secondary @@ -256,8 +288,13 @@ class read_preference { /// /// @return The optionally current max staleness setting. /// - MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional) - max_staleness() const; + bsoncxx::v_noabi::stdx::optional max_staleness() const { + return _rp.max_staleness(); + } + + BSONCXX_PRIVATE_WARNINGS_PUSH(); + BSONCXX_PRIVATE_WARNINGS_DISABLE(GNU("-Wdeprecated-declarations")); + BSONCXX_PRIVATE_WARNINGS_DISABLE(MSVC(4996)); /// /// Sets the hedge document to be used for the read preference. Sharded clusters running MongoDB @@ -279,8 +316,10 @@ class read_preference { /// @return A reference to the object on which this member function is being called. This /// facilitates method chaining. /// - MONGOCXX_DEPRECATED MONGOCXX_ABI_EXPORT_CDECL(read_preference&) hedge( - bsoncxx::v_noabi::document::view_or_value hedge); + MONGOCXX_DEPRECATED read_preference& hedge(bsoncxx::v_noabi::document::view_or_value hedge) { + _rp.hedge(bsoncxx::v_noabi::to_v1(hedge.view())); + return *this; + } /// /// Gets the current hedge document to be used for the read preference. @@ -290,7 +329,15 @@ class read_preference { /// @return A hedge document if one was set. /// MONGOCXX_DEPRECATED MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::optional const) - hedge() const; + hedge() const { + bsoncxx::v_noabi::stdx::optional ret; + if (auto const opt = _rp.hedge()) { + ret.emplace(*opt); + } + return ret; + } + + BSONCXX_PRIVATE_WARNINGS_POP(); /// /// @relates mongocxx::v_noabi::read_preference @@ -298,26 +345,32 @@ class read_preference { /// Compares two read_preference objects for (in)-equality. /// /// @{ - friend MONGOCXX_ABI_EXPORT_CDECL(bool) operator==(read_preference const&, read_preference const&); - friend MONGOCXX_ABI_EXPORT_CDECL(bool) operator!=(read_preference const&, read_preference const&); + friend bool operator==(read_preference const& lhs, read_preference const& rhs) { + return (lhs.mode() == rhs.mode()) && (lhs.tags() == rhs.tags()) && (lhs.max_staleness() == rhs.max_staleness()); + } + + friend bool operator!=(read_preference const& lhs, read_preference const& rhs) { + return !(lhs == rhs); + } /// @} /// - private: - friend ::mongocxx::v_noabi::client; - friend ::mongocxx::v_noabi::collection; - friend ::mongocxx::v_noabi::database; - friend ::mongocxx::v_noabi::events::topology_description; - friend ::mongocxx::v_noabi::options::transaction; - friend ::mongocxx::v_noabi::search_index_view; - friend ::mongocxx::v_noabi::uri; - - class impl; + class internal; +}; - read_preference(std::unique_ptr&& implementation); +/// +/// Convert to the @ref mongocxx::v_noabi equivalent of `v`. +/// +inline v_noabi::read_preference from_v1(v1::read_preference v) { + return {std::move(v)}; +} - std::unique_ptr _impl; -}; +/// +/// Convert to the @ref mongocxx::v1 equivalent of `v`. +/// +inline v1::read_preference to_v1(v_noabi::read_preference v) { + return v1::read_preference{std::move(v)}; +} } // namespace v_noabi } // namespace mongocxx @@ -328,3 +381,6 @@ class read_preference { /// @file /// Provides @ref mongocxx::v_noabi::read_preference. /// +/// @par Includes +/// - @ref mongocxx/v1/read_preference.hpp +/// diff --git a/src/mongocxx/lib/mongocxx/v1/read_preference.cpp b/src/mongocxx/lib/mongocxx/v1/read_preference.cpp index c953cde00a..6488b96c5f 100644 --- a/src/mongocxx/lib/mongocxx/v1/read_preference.cpp +++ b/src/mongocxx/lib/mongocxx/v1/read_preference.cpp @@ -12,4 +12,175 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include + +// + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +namespace mongocxx { +namespace v1 { + +namespace { + +mongoc_read_prefs_t* to_mongoc(void* ptr) { + return static_cast(ptr); +} + +} // namespace + +read_preference::~read_preference() { + libmongoc::read_prefs_destroy(to_mongoc(_impl)); +} + +read_preference::read_preference(read_preference&& other) noexcept : _impl{exchange(other._impl, nullptr)} {} + +read_preference& read_preference::operator=(read_preference&& other) noexcept { + if (this != &other) { + libmongoc::read_prefs_destroy(to_mongoc(exchange(_impl, exchange(other._impl, nullptr)))); + } + return *this; +} + +read_preference::read_preference(read_preference const& other) + : _impl{libmongoc::read_prefs_copy(to_mongoc(other._impl))} {} + +read_preference& read_preference::operator=(read_preference const& other) { + if (this != &other) { + libmongoc::read_prefs_destroy(to_mongoc(exchange(_impl, libmongoc::read_prefs_copy(to_mongoc(other._impl))))); + } + return *this; +} + +read_preference::read_preference() : _impl{libmongoc::read_prefs_new(MONGOC_READ_PRIMARY)} {} + +read_preference& read_preference::hedge(bsoncxx::v1::document::view v) { + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_BEGIN + libmongoc::read_prefs_set_hedge(to_mongoc(_impl), scoped_bson_view{v}.bson()); + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_END + return *this; +} + +bsoncxx::v1::stdx::optional read_preference::hedge() const { + bsoncxx::v1::stdx::optional ret; + + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_BEGIN + auto const doc = libmongoc::read_prefs_get_hedge(to_mongoc(_impl)); + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_END + + if (!bson_empty(doc)) { + ret.emplace(bson_get_data(doc), doc->len); + } + + return ret; +} + +read_preference& read_preference::mode(read_mode v) { + switch (v) { + default: + case read_mode::k_primary: + libmongoc::read_prefs_set_mode(to_mongoc(_impl), MONGOC_READ_PRIMARY); + break; + + case read_mode::k_primary_preferred: + libmongoc::read_prefs_set_mode(to_mongoc(_impl), MONGOC_READ_PRIMARY_PREFERRED); + break; + + case read_mode::k_secondary: + libmongoc::read_prefs_set_mode(to_mongoc(_impl), MONGOC_READ_SECONDARY); + break; + + case read_mode::k_secondary_preferred: + libmongoc::read_prefs_set_mode(to_mongoc(_impl), MONGOC_READ_SECONDARY_PREFERRED); + break; + + case read_mode::k_nearest: + libmongoc::read_prefs_set_mode(to_mongoc(_impl), MONGOC_READ_NEAREST); + break; + } + + return *this; +} + +read_preference::read_mode read_preference::mode() const { + switch (libmongoc::read_prefs_get_mode(to_mongoc(_impl))) { + default: + case MONGOC_READ_PRIMARY: + return read_mode::k_primary; + case MONGOC_READ_PRIMARY_PREFERRED: + return read_mode::k_primary_preferred; + case MONGOC_READ_SECONDARY: + return read_mode::k_secondary; + case MONGOC_READ_SECONDARY_PREFERRED: + return read_mode::k_secondary_preferred; + case MONGOC_READ_NEAREST: + return read_mode::k_nearest; + } +} + +read_preference& read_preference::tags(bsoncxx::v1::array::view v) { + libmongoc::read_prefs_set_tags(to_mongoc(_impl), scoped_bson_view{v}.bson()); + return *this; +} + +read_preference& read_preference::tags(bsoncxx::v1::document::view v) { + libmongoc::read_prefs_set_tags(to_mongoc(_impl), scoped_bson_view{v}.bson()); + return *this; +} + +bsoncxx::v1::array::view read_preference::tags() const { + auto const doc = libmongoc::read_prefs_get_tags(to_mongoc(_impl)); + return {bson_get_data(doc), doc->len}; +} + +read_preference& read_preference::max_staleness(std::chrono::seconds v) { + libmongoc::read_prefs_set_max_staleness_seconds(to_mongoc(_impl), v.count()); + return *this; +} + +bsoncxx::v1::stdx::optional read_preference::max_staleness() const { + bsoncxx::v1::stdx::optional ret; + + auto const v = libmongoc::read_prefs_get_max_staleness_seconds(to_mongoc(_impl)); + + if (v != MONGOC_NO_MAX_STALENESS) { + ret.emplace(v); + } + + return ret; +} + +bool operator==(read_preference const& lhs, read_preference const& rhs) { + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_BEGIN + + // Lexicographic comparison of data members. + return std::make_tuple(lhs.hedge(), lhs.mode(), lhs.tags(), lhs.max_staleness()) == + std::make_tuple(rhs.hedge(), rhs.mode(), rhs.tags(), rhs.max_staleness()); + + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_END +} + +read_preference::read_preference(void* impl) : _impl{impl} {} + +read_preference read_preference::internal::make(mongoc_read_prefs_t* rc) { + return {rc}; +} + +mongoc_read_prefs_t const* read_preference::internal::as_mongoc(read_preference const& self) { + return to_mongoc(self._impl); +} + +} // namespace v1 +} // namespace mongocxx diff --git a/src/mongocxx/lib/mongocxx/v1/read_preference.hh b/src/mongocxx/lib/mongocxx/v1/read_preference.hh new file mode 100644 index 0000000000..cb23dcfff3 --- /dev/null +++ b/src/mongocxx/lib/mongocxx/v1/read_preference.hh @@ -0,0 +1,35 @@ +// 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 +#include + +namespace mongocxx { +namespace v1 { + +class read_preference::internal { + public: + static MONGOCXX_ABI_EXPORT_CDECL_TESTING(read_preference) make(mongoc_read_prefs_t* rc); + + static mongoc_read_prefs_t const* as_mongoc(read_preference const& self); +}; + +} // namespace v1 +} // namespace mongocxx diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client.cpp index 992d474a16..710ec9279d 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/client.cpp @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include #include @@ -163,7 +165,7 @@ mongocxx::v_noabi::read_concern client::read_concern() const { } void client::read_preference_deprecated(mongocxx::v_noabi::read_preference rp) { - libmongoc::client_set_read_prefs(_get_impl().client_t, rp._impl->read_preference_t); + libmongoc::client_set_read_prefs(_get_impl().client_t, v_noabi::read_preference::internal::as_mongoc(rp)); } void client::read_preference(mongocxx::v_noabi::read_preference rp) { @@ -171,10 +173,8 @@ void client::read_preference(mongocxx::v_noabi::read_preference rp) { } mongocxx::v_noabi::read_preference client::read_preference() const { - mongocxx::v_noabi::read_preference rp( - bsoncxx::make_unique( - libmongoc::read_prefs_copy(libmongoc::client_get_read_prefs(_get_impl().client_t)))); - return rp; + return v1::read_preference::internal::make( + libmongoc::read_prefs_copy(libmongoc::client_get_read_prefs(_get_impl().client_t))); } mongocxx::v_noabi::uri client::uri() const { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/collection.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/collection.cpp index 21a245d662..b6b220a578 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/collection.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/collection.cpp @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include #include #include @@ -385,9 +387,9 @@ bsoncxx::v_noabi::builder::basic::document build_find_options_document(options:: } // namespace cursor collection::_find(client_session const* session, view_or_value filter, options::find const& options) { - mongoc_read_prefs_t const* rp_ptr = nullptr; - if (options.read_preference()) { - rp_ptr = options.read_preference()->_impl->read_preference_t; + mongoc_read_prefs_t const* read_prefs = nullptr; + if (auto const& opt = options.read_preference()) { + read_prefs = v_noabi::read_preference::internal::as_mongoc(*opt); } bsoncxx::v_noabi::builder::basic::document options_builder{build_find_options_document(options)}; @@ -400,7 +402,7 @@ cursor collection::_find(client_session const* session, view_or_value filter, op _get_impl().collection_t, mongocxx::to_scoped_bson_view(filter), mongocxx::to_scoped_bson_view(options_builder), - rp_ptr), + read_prefs), options.cursor_type()}; if (options.max_await_time()) { @@ -455,10 +457,10 @@ collection::_aggregate(client_session const* session, pipeline const& pipeline, b.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - ::mongoc_read_prefs_t const* rp_ptr = nullptr; + mongoc_read_prefs_t const* read_prefs = nullptr; - if (options.read_preference()) { - rp_ptr = options.read_preference()->_impl->read_preference_t; + if (auto const& opt = options.read_preference()) { + read_prefs = v_noabi::read_preference::internal::as_mongoc(*opt); } return cursor( @@ -467,7 +469,7 @@ collection::_aggregate(client_session const* session, pipeline const& pipeline, static_cast<::mongoc_query_flags_t>(0), mongocxx::to_scoped_bson_view(pipeline._impl->view_array()), mongocxx::to_scoped_bson_view(b), - rp_ptr)); + read_prefs)); } cursor collection::aggregate(pipeline const& pipeline, options::aggregate const& options) { @@ -1038,8 +1040,8 @@ collection::_count_documents(client_session const* session, view_or_value filter bson_error_t error; mongoc_read_prefs_t const* read_prefs = nullptr; - if (auto const& rp = options.read_preference()) { - read_prefs = rp->_impl->read_preference_t; + if (auto const& opt = options.read_preference()) { + read_prefs = v_noabi::read_preference::internal::as_mongoc(*opt); } bsoncxx::v_noabi::builder::basic::document opts_builder; @@ -1100,8 +1102,8 @@ std::int64_t collection::estimated_document_count(options::estimated_document_co mongoc_read_prefs_t const* read_prefs = nullptr; - if (auto const& rp = options.read_preference()) { - read_prefs = rp->_impl->read_preference_t; + if (auto const& opt = options.read_preference()) { + read_prefs = v_noabi::read_preference::internal::as_mongoc(*opt); } bsoncxx::v_noabi::builder::basic::document opts_builder; @@ -1186,9 +1188,9 @@ cursor collection::_distinct( opts_builder.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - mongoc_read_prefs_t const* rp_ptr = nullptr; - if (auto const& rp = options.read_preference()) { - rp_ptr = rp->_impl->read_preference_t; + mongoc_read_prefs_t const* read_prefs = nullptr; + if (auto const& opt = options.read_preference()) { + read_prefs = v_noabi::read_preference::internal::as_mongoc(*opt); } // @@ -1200,7 +1202,7 @@ cursor collection::_distinct( auto result = libmongoc::collection_read_command_with_opts( _get_impl().collection_t, mongocxx::to_scoped_bson_view(command_builder), - rp_ptr, + read_prefs, mongocxx::to_scoped_bson_view(opts_builder), reply.out_ptr(), &error); @@ -1318,14 +1320,12 @@ mongocxx::v_noabi::read_concern collection::read_concern() const { } void collection::read_preference(mongocxx::v_noabi::read_preference rp) { - libmongoc::collection_set_read_prefs(_get_impl().collection_t, rp._impl->read_preference_t); + libmongoc::collection_set_read_prefs(_get_impl().collection_t, v_noabi::read_preference::internal::as_mongoc(rp)); } mongocxx::v_noabi::read_preference collection::read_preference() const { - mongocxx::v_noabi::read_preference rp( - bsoncxx::make_unique( - libmongoc::read_prefs_copy(libmongoc::collection_get_read_prefs(_get_impl().collection_t)))); - return rp; + return v1::read_preference::internal::make( + libmongoc::read_prefs_copy(libmongoc::collection_get_read_prefs(_get_impl().collection_t))); } void collection::write_concern(mongocxx::v_noabi::write_concern wc) { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/database.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/database.cpp index 9500c82abd..3c41968d8a 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/database.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/database.cpp @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include #include @@ -123,15 +125,18 @@ database::_aggregate(client_session const* session, pipeline const& pipeline, op b.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - ::mongoc_read_prefs_t const* rp_ptr = nullptr; + ::mongoc_read_prefs_t const* read_prefs = nullptr; - if (options.read_preference()) { - rp_ptr = options.read_preference()->_impl->read_preference_t; + if (auto const& opt = options.read_preference()) { + read_prefs = v_noabi::read_preference::internal::as_mongoc(*opt); } return cursor( libmongoc::database_aggregate( - _get_impl().database_t, to_scoped_bson_view(pipeline._impl->view_array()), to_scoped_bson_view(b), rp_ptr)); + _get_impl().database_t, + to_scoped_bson_view(pipeline._impl->view_array()), + to_scoped_bson_view(b), + read_prefs)); } cursor database::aggregate(pipeline const& pipeline, options::aggregate const& options) { @@ -248,7 +253,7 @@ bsoncxx::v_noabi::document::value database::run_command( _get_impl().client_impl->client_t, _get_impl().name.c_str(), to_scoped_bson_view(command.view()), - read_preference()._impl->read_preference_t, + libmongoc::database_get_read_prefs(_get_impl().database_t), server_id, reply.out_ptr(), &error); @@ -345,7 +350,7 @@ mongocxx::v_noabi::read_concern database::read_concern() const { } void database::read_preference(mongocxx::v_noabi::read_preference rp) { - libmongoc::database_set_read_prefs(_get_impl().database_t, rp._impl->read_preference_t); + libmongoc::database_set_read_prefs(_get_impl().database_t, v_noabi::read_preference::internal::as_mongoc(rp)); } bool database::has_collection(bsoncxx::v_noabi::string::view_or_value name) const { @@ -359,10 +364,8 @@ bool database::has_collection(bsoncxx::v_noabi::string::view_or_value name) cons } mongocxx::v_noabi::read_preference database::read_preference() const { - mongocxx::v_noabi::read_preference rp( - bsoncxx::make_unique( - libmongoc::read_prefs_copy(libmongoc::database_get_read_prefs(_get_impl().database_t)))); - return rp; + return v1::read_preference::internal::make( + libmongoc::read_prefs_copy(libmongoc::database_get_read_prefs(_get_impl().database_t))); } void database::write_concern(mongocxx::v_noabi::write_concern wc) { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/events/topology_description.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/events/topology_description.cpp index 09de2dd222..d1fdb6ce34 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/events/topology_description.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/events/topology_description.cpp @@ -85,7 +85,7 @@ bsoncxx::v_noabi::stdx::string_view topology_description::type() const { bool topology_description::has_readable_server(mongocxx::v_noabi::read_preference const& pref) const { return libmongoc::topology_description_has_readable_server( - static_cast(_td), pref._impl->read_preference_t); + static_cast(_td), v_noabi::read_preference::internal::as_mongoc(pref)); } bool topology_description::has_writable_server() const { 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 9ff2a0e567..67b303bf6e 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.hh +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/options/transaction.hh @@ -18,15 +18,19 @@ // +#include + #include #include -#include - #include #include #include +#include + +#include + namespace mongocxx { namespace v_noabi { namespace options { @@ -86,17 +90,18 @@ class transaction::impl { } void read_preference(mongocxx::v_noabi::read_preference const& rp) { - libmongoc::transaction_opts_set_read_prefs(_transaction_opt_t.get(), rp._impl->read_preference_t); + 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 { - auto rp = libmongoc::transaction_opts_get_read_prefs(_transaction_opt_t.get()); - if (!rp) { - return bsoncxx::v_noabi::stdx::nullopt; + 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))); } - mongocxx::v_noabi::read_preference rpi( - bsoncxx::make_unique(libmongoc::read_prefs_copy(rp))); - return bsoncxx::v_noabi::stdx::optional(std::move(rpi)); + + return ret; } void max_commit_time_ms(std::chrono::milliseconds ms) { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.cpp index 49e59f16bc..3df5d1f611 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.cpp @@ -12,135 +12,60 @@ // 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 v_noabi { - -read_preference::read_preference(read_preference&&) noexcept = default; -read_preference& read_preference::operator=(read_preference&&) noexcept = default; - -read_preference::read_preference(read_preference const& other) - : _impl(bsoncxx::make_unique(libmongoc::read_prefs_copy(other._impl->read_preference_t))) {} - -read_preference& read_preference::operator=(read_preference const& other) { - _impl.reset(bsoncxx::make_unique(libmongoc::read_prefs_copy(other._impl->read_preference_t)).release()); - return *this; -} - -read_preference::read_preference(std::unique_ptr&& implementation) { - _impl.reset(implementation.release()); -} - -read_preference::read_preference() - : _impl( - bsoncxx::make_unique( - libmongoc::read_prefs_new(v_noabi::conversions::read_mode_t_from_read_mode(read_mode::k_primary)))) {} - -read_preference::read_preference(read_mode mode) : read_preference(mode, deprecated_tag{}) {} - -read_preference::read_preference(read_mode mode, deprecated_tag) - : _impl( - bsoncxx::make_unique( - libmongoc::read_prefs_new(v_noabi::conversions::read_mode_t_from_read_mode(mode)))) {} - -read_preference::read_preference(read_mode mode, bsoncxx::v_noabi::document::view_or_value tags) - : read_preference(mode, std::move(tags), deprecated_tag{}) {} +// -read_preference::read_preference(read_mode mode, bsoncxx::v_noabi::document::view_or_value tags, deprecated_tag) - : read_preference(mode, deprecated_tag{}) { - read_preference::tags(std::move(tags)); -} +#include -read_preference::~read_preference() = default; +#include -read_preference& read_preference::mode(read_mode mode) { - libmongoc::read_prefs_set_mode(_impl->read_preference_t, v_noabi::conversions::read_mode_t_from_read_mode(mode)); +#include +#include - return *this; -} +#include -read_preference& read_preference::tags(bsoncxx::v_noabi::document::view_or_value tag_set_list) { - libmongoc::read_prefs_set_tags(_impl->read_preference_t, to_scoped_bson_view(tag_set_list)); - return *this; -} +namespace { +namespace static_assertions { +namespace read_mode { -read_preference& read_preference::tags(bsoncxx::v_noabi::array::view_or_value tag_set_list) { - libmongoc::read_prefs_set_tags(_impl->read_preference_t, to_scoped_bson_view(tag_set_list)); - return *this; -} +using lv1 = mongocxx::v1::read_preference::read_mode; +using lv_noabi = mongocxx::v_noabi::read_preference::read_mode; -read_preference::read_mode read_preference::mode() const { - return v_noabi::conversions::read_mode_from_read_mode_t(libmongoc::read_prefs_get_mode(_impl->read_preference_t)); -} +template +struct check { + static_assert( + static_cast(lhs) == static_cast(rhs), + "read_preference::read_mode: v1 and v_noabi must have the same values"); +}; -bsoncxx::v_noabi::stdx::optional read_preference::tags() const { - bson_t const* bson_tags = libmongoc::read_prefs_get_tags(_impl->read_preference_t); +template struct check; +template struct check; +template struct check; +template struct check; +template struct check; - if (bson_count_keys(bson_tags)) - return bsoncxx::v_noabi::document::view(bson_get_data(bson_tags), bson_tags->len); +} // namespace read_mode +} // namespace static_assertions +} // namespace - return bsoncxx::v_noabi::stdx::optional{}; -} +namespace mongocxx { +namespace v_noabi { read_preference& read_preference::max_staleness(std::chrono::seconds max_staleness) { - auto max_staleness_sec = max_staleness.count(); - if (max_staleness_sec < -1 || max_staleness_sec == 0) { - throw logic_error{error_code::k_invalid_parameter}; - } - libmongoc::read_prefs_set_max_staleness_seconds(_impl->read_preference_t, max_staleness_sec); + auto const v = max_staleness.count(); - return *this; -} - -bsoncxx::v_noabi::stdx::optional read_preference::max_staleness() const { - auto staleness = libmongoc::read_prefs_get_max_staleness_seconds(_impl->read_preference_t); - - // libmongoc signals "disabled" with the value -1. - if (staleness == -1) { - return bsoncxx::v_noabi::stdx::nullopt; + if (v < -1 || v == 0) { + throw logic_error{error_code::k_invalid_parameter}; } - return std::chrono::seconds{staleness}; -} + _rp.max_staleness(max_staleness); -read_preference& read_preference::hedge(bsoncxx::v_noabi::document::view_or_value hedge) { - BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_BEGIN - libmongoc::read_prefs_set_hedge(_impl->read_preference_t, to_scoped_bson_view(hedge)); - BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_END return *this; } -bsoncxx::v_noabi::stdx::optional const read_preference::hedge() const { - BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_BEGIN - bson_t const* hedge_bson = libmongoc::read_prefs_get_hedge(_impl->read_preference_t); - BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_END - - if (!bson_empty(hedge_bson)) { - return bsoncxx::v_noabi::document::view(bson_get_data(hedge_bson), hedge_bson->len); - } - - return bsoncxx::v_noabi::stdx::optional{}; -} - -bool operator==(read_preference const& lhs, read_preference const& rhs) { - return (lhs.mode() == rhs.mode()) && (lhs.tags() == rhs.tags()) && (lhs.max_staleness() == rhs.max_staleness()); -} - -bool operator!=(read_preference const& lhs, read_preference const& rhs) { - return !(lhs == rhs); +mongoc_read_prefs_t const* read_preference::internal::as_mongoc(read_preference const& self) { + return v1::read_preference::internal::as_mongoc(self._rp); } } // namespace v_noabi diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.hh b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.hh index f2d0945214..21ae346a96 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.hh +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/read_preference.hh @@ -16,26 +16,16 @@ #include // IWYU pragma: export +// + #include namespace mongocxx { namespace v_noabi { -class read_preference::impl { +class read_preference::internal { public: - impl(mongoc_read_prefs_t* read_pref) : read_preference_t(read_pref) {} - - ~impl() { - libmongoc::read_prefs_destroy(read_preference_t); - } - - impl(impl&&) = delete; - impl& operator=(impl&&) = delete; - - impl(impl const&) = delete; - impl& operator=(impl const&) = delete; - - mongoc_read_prefs_t* read_preference_t; + static mongoc_read_prefs_t const* as_mongoc(read_preference const& self); }; } // namespace v_noabi diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/search_index_view.hh b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/search_index_view.hh index 63b37075b4..619950e4c8 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/search_index_view.hh +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/search_index_view.hh @@ -9,10 +9,11 @@ #include // IWYU pragma: export -#include - #include #include +#include +#include + #include namespace mongocxx { @@ -73,8 +74,10 @@ class search_index_view::impl { opts_doc.append(bsoncxx::v_noabi::builder::concatenate_doc{session->_get_impl().to_document()}); } - mongoc_read_prefs_t const* const rp_ptr = - options.read_preference() ? options.read_preference()->_impl->read_preference_t : nullptr; + mongoc_read_prefs_t const* const read_prefs = [&options] { + auto const& opt = options.read_preference(); + return opt ? v_noabi::read_preference::internal::as_mongoc(*opt) : nullptr; + }(); auto coll_copy = copy_and_apply_default_rw_concerns(_coll); return libmongoc::collection_aggregate( @@ -82,7 +85,7 @@ class search_index_view::impl { mongoc_query_flags_t(), to_scoped_bson_view(pipeline.view_array()), to_scoped_bson_view(opts_doc), - rp_ptr); + read_prefs); } std::string create_one(client_session const* session, search_index_model const& model) { diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/uri.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/uri.cpp index cc6ed9e05c..92a5f98fb7 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/uri.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/uri.cpp @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include #include @@ -101,9 +103,8 @@ mongocxx::v_noabi::read_concern uri::read_concern() const { } mongocxx::v_noabi::read_preference uri::read_preference() const { - auto rp = libmongoc::uri_get_read_prefs_t(_impl->uri_t); - return mongocxx::v_noabi::read_preference( - bsoncxx::make_unique(libmongoc::read_prefs_copy(rp))); + return v1::read_preference::internal::make( + libmongoc::read_prefs_copy(libmongoc::uri_get_read_prefs_t(_impl->uri_t))); } std::string uri::replica_set() const { diff --git a/src/mongocxx/test/CMakeLists.txt b/src/mongocxx/test/CMakeLists.txt index d815badfdb..562904aa7c 100644 --- a/src/mongocxx/test/CMakeLists.txt +++ b/src/mongocxx/test/CMakeLists.txt @@ -104,6 +104,7 @@ set(mongocxx_test_sources_v1 v1/bsoncxx.cpp v1/exception.cpp v1/logger.cpp + v1/read_preference.cpp ) set(mongocxx_test_sources_spec diff --git a/src/mongocxx/test/v1/read_preference.cpp b/src/mongocxx/test/v1/read_preference.cpp new file mode 100644 index 0000000000..7f4ba9ce7b --- /dev/null +++ b/src/mongocxx/test/v1/read_preference.cpp @@ -0,0 +1,238 @@ +// 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 + +#include +#include + +namespace mongocxx { +namespace v1 { + +TEST_CASE("ownership", "[mongocxx][v1][read_preference]") { + using mode = read_preference::read_mode; + + read_preference source; + read_preference target; + + source.mode(mode::k_primary_preferred); + target.mode(mode::k_secondary_preferred); + + SECTION("move") { + auto move = std::move(source); + + // source is in an assign-or-move-only state. + + CHECK(move.mode() == mode::k_primary_preferred); + + target = std::move(move); + + // source is in an assign-or-move-only state. + + CHECK(target.mode() == mode::k_primary_preferred); + } + + SECTION("copy") { + auto copy = source; + + CHECK(source.mode() == mode::k_primary_preferred); + CHECK(copy.mode() == mode::k_primary_preferred); + + target = copy; + + CHECK(copy.mode() == mode::k_primary_preferred); + CHECK(target.mode() == mode::k_primary_preferred); + } +} + +TEST_CASE("default", "[mongocxx][v1][read_preference]") { + using mode = read_preference::read_mode; + + read_preference const rp; + + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_BEGIN + CHECK_FALSE(rp.hedge().has_value()); + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_END + + CHECK(rp.mode() == mode::k_primary); + CHECK(rp.tags().empty()); + CHECK_FALSE(rp.max_staleness().has_value()); +} + +TEST_CASE("hedge", "[mongocxx][v1][read_preference]") { + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_BEGIN + + read_preference rp; + + auto const v = GENERATE(values({ + scoped_bson{}, + scoped_bson{R"({})"}, + scoped_bson{R"({"enabled": false})"}, + scoped_bson{R"({"enabled": true})"}, + })); + + CHECK_NOTHROW(rp.hedge(v.view())); + + CHECKED_IF(v.view().empty()) { + CHECK_FALSE(rp.hedge().has_value()); + } + + else { + CHECK(rp.hedge() == v.view()); + } + + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_END +} + +TEST_CASE("mode", "[mongocxx][v1][read_preference]") { + using mode = read_preference::read_mode; + + mode input = {}; + mode expected = {}; + + std::tie(input, expected) = GENERATE( + table({ + {mode::k_primary, mode::k_primary}, + {mode::k_primary_preferred, mode::k_primary_preferred}, + {mode::k_secondary, mode::k_secondary}, + {mode::k_secondary_preferred, mode::k_secondary_preferred}, + {mode::k_nearest, mode::k_nearest}, + {static_cast(-1), mode::k_primary}, + {static_cast(5), mode::k_primary}, + })); + + CAPTURE(input); + + read_preference rp; + CHECK_NOTHROW(rp.mode(input)); + CHECK(rp.mode() == expected); +} + +TEST_CASE("tags", "[mongocxx][v1][read_preference]") { + auto const v = GENERATE(values({ + scoped_bson{R"([])"}, + scoped_bson{R"(["x"])"}, + scoped_bson{R"(["a", "b", "c"])"}, + })); + + CAPTURE(v.view()); + + read_preference rp; + + CHECK_NOTHROW(rp.tags(v.view())); + CHECK(rp.tags() == v.array_view()); + + CHECK_NOTHROW(rp.tags(v.array_view())); + CHECK(rp.tags() == v.array_view()); +} + +TEST_CASE("max_staleness", "[mongocxx][v1][read_preference]") { + using secs = std::chrono::seconds; + + // std::chrono::seconds only guarantees Rep = int35. + auto const v = GENERATE(values({ + secs{secs::min()}, + secs{-2}, + secs{-1}, + secs{0}, + secs{1}, + secs{secs::max()}, + })); + + CAPTURE(v); + + read_preference rp; + CHECK_NOTHROW(rp.max_staleness(v)); + + CHECKED_IF(v.count() == -1) { + CHECK_FALSE(rp.max_staleness().has_value()); + } + + else { + CHECK(rp.max_staleness() == v); + + CHECK_NOTHROW(rp.max_staleness(secs{-1})); + CHECK_FALSE(rp.max_staleness().has_value()); + } +} + +TEST_CASE("equality", "[mongocxx][v1][read_preference]") { + using mode = read_preference::read_mode; + using secs = std::chrono::seconds; + + read_preference lhs; + read_preference rhs; + + CHECK(lhs == lhs); + CHECK(rhs == rhs); + CHECK(lhs == rhs); + + SECTION("hedge") { + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_BEGIN + CHECK_NOTHROW(rhs.hedge(scoped_bson{R"({"enabled": true})"}.view())); + BSONCXX_SUPPRESS_DEPRECATION_WARNINGS_END + + CHECK(lhs == lhs); + CHECK(rhs == rhs); + CHECK(lhs != rhs); + } + + SECTION("mode") { + CHECK_NOTHROW(rhs.mode(mode::k_primary_preferred)); + + CHECK(lhs == lhs); + CHECK(rhs == rhs); + CHECK(lhs != rhs); + } + + SECTION("tags") { + scoped_bson const tags{R"(["x"])"}; + + CHECK_NOTHROW(rhs.tags(tags.view())); + + CHECK(lhs == lhs); + CHECK(rhs == rhs); + CHECK(lhs != rhs); + + CHECK_NOTHROW(lhs.tags(tags.array_view())); + + CHECK(lhs == lhs); + CHECK(rhs == rhs); + CHECK(lhs == rhs); + } + + SECTION("max_staleness") { + CHECK_NOTHROW(rhs.max_staleness(secs{123})); + + CHECK(lhs == lhs); + CHECK(rhs == rhs); + CHECK(lhs != rhs); + } +} + +} // namespace v1 +} // namespace mongocxx diff --git a/src/mongocxx/test/v1/read_preference.hh b/src/mongocxx/test/v1/read_preference.hh new file mode 100644 index 0000000000..bd81e05004 --- /dev/null +++ b/src/mongocxx/test/v1/read_preference.hh @@ -0,0 +1,29 @@ +// 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 + +CATCH_REGISTER_ENUM( + mongocxx::v1::read_preference::read_mode, + mongocxx::v1::read_preference::read_mode::k_primary, + mongocxx::v1::read_preference::read_mode::k_primary_preferred, + mongocxx::v1::read_preference::read_mode::k_secondary, + mongocxx::v1::read_preference::read_mode::k_secondary_preferred, + mongocxx::v1::read_preference::read_mode::k_nearest)