Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/mongocxx/include/mongocxx/v1/read_concern.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ class read_concern {
}
/// @}
///

class internal;

private:
/* explicit(false) */ read_concern(void* impl);
};

} // namespace v1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#pragma once

#include <mongocxx/v1/read_concern-fwd.hpp>

#include <mongocxx/config/prelude.hpp>

namespace mongocxx {
Expand All @@ -26,7 +28,7 @@ class read_concern;

namespace mongocxx {

using ::mongocxx::v_noabi::read_concern;
using v_noabi::read_concern;

} // namespace mongocxx

Expand All @@ -36,3 +38,6 @@ using ::mongocxx::v_noabi::read_concern;
/// @file
/// Declares @ref mongocxx::v_noabi::read_concern.
///
/// @par Includes
/// - @ref mongocxx/v1/read_concern-fwd.hpp
///
112 changes: 71 additions & 41 deletions src/mongocxx/include/mongocxx/v_noabi/mongocxx/read_concern.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,26 @@

#pragma once

#include <memory>

#include <mongocxx/client-fwd.hpp>
#include <mongocxx/collection-fwd.hpp>
#include <mongocxx/database-fwd.hpp>
#include <mongocxx/options/transaction-fwd.hpp>
#include <mongocxx/read_concern-fwd.hpp> // IWYU pragma: export
#include <mongocxx/uri-fwd.hpp>

//

#include <mongocxx/v1/read_concern.hpp> // IWYU pragma: export

#include <memory> // IWYU pragma: keep: backward compatibility, to be removed.
#include <utility>

#include <mongocxx/client-fwd.hpp> // IWYU pragma: keep: backward compatibility, to be removed.
#include <mongocxx/collection-fwd.hpp> // IWYU pragma: keep: backward compatibility, to be removed.
#include <mongocxx/database-fwd.hpp> // IWYU pragma: keep: backward compatibility, to be removed.
#include <mongocxx/options/transaction-fwd.hpp> // IWYU pragma: keep: backward compatibility, to be removed.
#include <mongocxx/uri-fwd.hpp> // IWYU pragma: keep: backward compatibility, to be removed.

#include <bsoncxx/document/value.hpp>
#include <bsoncxx/stdx/optional.hpp> // IWYU pragma: keep: backward compatibility, to be removed.
#include <bsoncxx/stdx/string_view.hpp>

#include <mongocxx/options/transaction.hpp>
#include <mongocxx/options/transaction.hpp> // IWYU pragma: keep: backward compatibility, to be removed.

#include <mongocxx/config/prelude.hpp>

Expand All @@ -46,6 +52,9 @@ namespace v_noabi {
/// - [Read Concern (MongoDB Manual)](https://www.mongodb.com/docs/manual/reference/read-concern/)
///
class read_concern {
private:
v1::read_concern _rc;

public:
///
/// A class to represent the read concern level for read operations.
Expand All @@ -71,32 +80,31 @@ class read_concern {
/// run with this read_concern will use the server's default read_concern instead of
/// specifying one.
///
MONGOCXX_ABI_EXPORT_CDECL() read_concern();

///
/// Copy constructs a read_concern.
///
MONGOCXX_ABI_EXPORT_CDECL() read_concern(read_concern const&);
read_concern() = default;

///
/// Copy assigns a read_concern.
/// Construct with the @ref mongocxx::v1 equivalent.
///
MONGOCXX_ABI_EXPORT_CDECL(read_concern&) operator=(read_concern const&);
/* explicit(false) */ read_concern(v1::read_concern rc) : _rc{std::move(rc)} {}

///
/// Move constructs a read_concern.
/// Convert to the @ref mongocxx::v1 equivalent.
///
MONGOCXX_ABI_EXPORT_CDECL() read_concern(read_concern&&) noexcept;

/// @par Postconditions:
/// - `other` is in an assign-or-destroy-only state.
///
/// Move assigns a read_concern.
/// @warning Invalidates all associated iterators and views.
///
MONGOCXX_ABI_EXPORT_CDECL(read_concern&) operator=(read_concern&&) noexcept;
explicit operator v1::read_concern() && {
return std::move(_rc);
}

///
/// Destroys a read_concern.
/// Convert to the @ref mongocxx::v1 equivalent.
///
MONGOCXX_ABI_EXPORT_CDECL() ~read_concern();
explicit operator v1::read_concern() const& {
return _rc;
}

///
/// Sets the read concern level.
Expand All @@ -118,7 +126,9 @@ class read_concern {
///
/// @return The read concern level.
///
MONGOCXX_ABI_EXPORT_CDECL(level) acknowledge_level() const;
level acknowledge_level() const {
return static_cast<level>(_rc.acknowledge_level());
}

///
/// Sets the read concern string. Any valid read concern string (e.g. "local",
Expand All @@ -129,8 +139,9 @@ class read_concern {
/// @param rc_string
/// The read concern string.
///
MONGOCXX_ABI_EXPORT_CDECL(void)
acknowledge_string(bsoncxx::v_noabi::stdx::string_view rc_string);
void acknowledge_string(bsoncxx::v1::stdx::string_view rc_string) {
_rc.acknowledge_string(rc_string);
}

///
/// Gets the current read concern string.
Expand All @@ -140,40 +151,56 @@ class read_concern {
///
/// @return The read concern string.
///
MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::stdx::string_view) acknowledge_string() const;
bsoncxx::v1::stdx::string_view acknowledge_string() const {
auto ret = _rc.acknowledge_string();
if (ret.empty()) {
ret = "";
}
return ret;
}

///
/// Gets the document form of this read_concern.
///
/// @return
/// Document representation of this read_concern.
///
MONGOCXX_ABI_EXPORT_CDECL(bsoncxx::v_noabi::document::value) to_document() const;
bsoncxx::v_noabi::document::value to_document() const {
return bsoncxx::v_noabi::from_v1(_rc.to_document());
}

///
/// @relates mongocxx::v_noabi::read_concern
///
/// Compares two read_concern objects for (in)-equality.
///
/// @{
friend MONGOCXX_ABI_EXPORT_CDECL(bool) operator==(read_concern const&, read_concern const&);
friend MONGOCXX_ABI_EXPORT_CDECL(bool) operator!=(read_concern const&, read_concern const&);
friend bool operator==(read_concern const& lhs, read_concern const& rhs) {
return lhs.acknowledge_level() == rhs.acknowledge_level();
}

friend bool operator!=(read_concern const& lhs, read_concern 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::options::transaction;
friend ::mongocxx::v_noabi::uri;

class impl;
class internal;
};

read_concern(std::unique_ptr<impl>&& implementation);
///
/// Convert to the @ref mongocxx::v_noabi equivalent of `v`.
///
inline v_noabi::read_concern from_v1(v1::read_concern v) {
return {std::move(v)};
}

std::unique_ptr<impl> _impl;
};
///
/// Convert to the @ref mongocxx::v1 equivalent of `v`.
///
inline v1::read_concern to_v1(v_noabi::read_concern v) {
return v1::read_concern{std::move(v)};
}

} // namespace v_noabi
} // namespace mongocxx
Expand All @@ -184,3 +211,6 @@ class read_concern {
/// @file
/// Provides @ref mongocxx::v_noabi::read_concern.
///
/// @par Includes
/// - @ref mongocxx/v1/read_concern.hpp
///
157 changes: 156 additions & 1 deletion src/mongocxx/lib/mongocxx/v1/read_concern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,159 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <mongocxx/v1/read_concern.hpp>
#include <mongocxx/v1/read_concern.hh>

//

#include <bsoncxx/v1/document/value.hpp>
#include <bsoncxx/v1/stdx/string_view.hpp>

#include <cstring>
#include <string>
#include <unordered_map>

#include <bsoncxx/private/bson.hh>

#include <mongocxx/private/mongoc.hh>
#include <mongocxx/private/scoped_bson.hh>
#include <mongocxx/private/utility.hh>

namespace mongocxx {
namespace v1 {

namespace {

mongoc_read_concern_t* to_mongoc(void* ptr) {
return static_cast<mongoc_read_concern_t*>(ptr);
}

} // namespace

read_concern::~read_concern() {
libmongoc::read_concern_destroy(to_mongoc(_impl));
}

read_concern::read_concern(read_concern&& other) noexcept : _impl{exchange(other._impl, nullptr)} {}

read_concern& read_concern::operator=(read_concern&& other) noexcept {
if (this != &other) {
libmongoc::read_concern_destroy(to_mongoc(exchange(_impl, exchange(other._impl, nullptr))));
}
return *this;
}

read_concern::read_concern(read_concern const& other) : _impl{libmongoc::read_concern_copy(to_mongoc(other._impl))} {}

read_concern& read_concern::operator=(read_concern const& other) {
if (this != &other) {
libmongoc::read_concern_destroy(
to_mongoc(exchange(_impl, libmongoc::read_concern_copy(to_mongoc(other._impl)))));
}
return *this;
}

read_concern::read_concern() : _impl{libmongoc::read_concern_new()} {}

read_concern& read_concern::acknowledge_level(level v) {
// Return value is always true: no input validation by mongoc.
switch (v) {
case level::k_local:
(void)libmongoc::read_concern_set_level(to_mongoc(_impl), MONGOC_READ_CONCERN_LEVEL_LOCAL);
break;
case level::k_majority:
(void)libmongoc::read_concern_set_level(to_mongoc(_impl), MONGOC_READ_CONCERN_LEVEL_MAJORITY);
break;
case level::k_linearizable:
(void)libmongoc::read_concern_set_level(to_mongoc(_impl), MONGOC_READ_CONCERN_LEVEL_LINEARIZABLE);
break;

case level::k_server_default:
(void)libmongoc::read_concern_set_level(to_mongoc(_impl), nullptr);
break;

case level::k_available:
(void)libmongoc::read_concern_set_level(to_mongoc(_impl), MONGOC_READ_CONCERN_LEVEL_AVAILABLE);
break;
case level::k_snapshot:
(void)libmongoc::read_concern_set_level(to_mongoc(_impl), MONGOC_READ_CONCERN_LEVEL_SNAPSHOT);
break;

default:
case level::k_unknown:
// Precondition violation: undocumented but well-defined behavior.
(void)libmongoc::read_concern_set_level(to_mongoc(_impl), nullptr);
break;
}

return *this;
}

read_concern::level read_concern::acknowledge_level() const {
auto const level_cstr = libmongoc::read_concern_get_level(to_mongoc(_impl));

if (!level_cstr) {
return level::k_server_default;
}

std::unordered_map<bsoncxx::v1::stdx::string_view, level> map = {
{MONGOC_READ_CONCERN_LEVEL_LOCAL, level::k_local},
{MONGOC_READ_CONCERN_LEVEL_MAJORITY, level::k_majority},
{MONGOC_READ_CONCERN_LEVEL_LINEARIZABLE, level::k_linearizable},
{MONGOC_READ_CONCERN_LEVEL_AVAILABLE, level::k_available},
{MONGOC_READ_CONCERN_LEVEL_SNAPSHOT, level::k_snapshot},
};

auto const iter = map.find(level_cstr);

return iter != map.end() ? iter->second : level::k_unknown;
}

read_concern& read_concern::acknowledge_string(bsoncxx::v1::stdx::string_view v) {
// Return value is always true: no input validation by mongoc.
(void)libmongoc::read_concern_set_level(to_mongoc(_impl), v.empty() ? nullptr : std::string{v}.c_str());
return *this;
}

bsoncxx::v1::stdx::string_view read_concern::acknowledge_string() const {
bsoncxx::v1::stdx::string_view ret;

if (auto const level_cstr = libmongoc::read_concern_get_level(to_mongoc(_impl))) {
ret = bsoncxx::v1::stdx::string_view{level_cstr};
}

return ret;
}

bsoncxx::v1::document::value read_concern::to_document() const {
scoped_bson doc;

if (auto const level_cstr = libmongoc::read_concern_get_level(to_mongoc(_impl))) {
doc += scoped_bson{BCON_NEW("level", BCON_UTF8(level_cstr))};
}

return std::move(doc).value();
}

bool operator==(read_concern const& lhs, read_concern const& rhs) {
auto const lhs_cstr = libmongoc::read_concern_get_level(to_mongoc(lhs._impl));
auto const rhs_cstr = libmongoc::read_concern_get_level(to_mongoc(rhs._impl));

if (!lhs_cstr != !rhs_cstr) {
return false;
}

return !lhs_cstr || std::strcmp(lhs_cstr, rhs_cstr) == 0;
}

read_concern::read_concern(void* impl) : _impl{impl} {}

read_concern read_concern::internal::make(mongoc_read_concern_t* rc) {
return {rc};
}

mongoc_read_concern_t const* read_concern::internal::as_mongoc(read_concern const& self) {
return to_mongoc(self._impl);
}

} // namespace v1
} // namespace mongocxx
Loading