From 61e0b5b29048a2efd41a5f49e02e2c85436ab5c4 Mon Sep 17 00:00:00 2001 From: Valery Kotov Date: Thu, 2 Nov 2023 20:45:07 +0100 Subject: [PATCH] Added lower bound functionality (#7) --- include/cpp_lmdb/iterators.hpp | 8 +++++++ include/cpp_lmdb/transactions.hpp | 13 +++++++++++ test/unit/test_transaction.cpp | 38 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/include/cpp_lmdb/iterators.hpp b/include/cpp_lmdb/iterators.hpp index 6256636..baddf82 100644 --- a/include/cpp_lmdb/iterators.hpp +++ b/include/cpp_lmdb/iterators.hpp @@ -128,6 +128,14 @@ class ro_iterator base::navigate_cursor(MDB_FIRST, nullptr); } + explicit ro_iterator( + LmdbApi const &api, MDB_cursor &cursor, byte_span const &key) noexcept + : base{api, cursor} + { + auto db_key = details::to_mdb_val(key); + base::navigate_cursor(MDB_SET_RANGE, &db_key); + } + ro_iterator(ro_iterator &&) = default; auto operator=(ro_iterator &&) -> ro_iterator & = default; diff --git a/include/cpp_lmdb/transactions.hpp b/include/cpp_lmdb/transactions.hpp index cd8695f..91c761e 100644 --- a/include/cpp_lmdb/transactions.hpp +++ b/include/cpp_lmdb/transactions.hpp @@ -38,6 +38,8 @@ class transaction { using ro_view = db_view, LmdbApi>; + using ro_lo_view + = db_dup_view, LmdbApi>; using ro_dup_view = db_dup_view< ro_dup_iterator, LmdbApi>; @@ -90,6 +92,17 @@ class transaction { return {}; } + auto lower_bound(key_type const &key) const noexcept + -> std::expected + { + auto cursor = details::make_cursor(_api, _txn.get(), _db_index); + if (!cursor) + return std::unexpected{error_t{cursor.error()}}; + + auto const key_bytes = key_trait::to_bytes(key); + return ro_lo_view{std::move(*cursor), key_bytes}; + } + auto get(key_type const &key) const noexcept -> std::expected requires(!details::key_value_trait_helper< diff --git a/test/unit/test_transaction.cpp b/test/unit/test_transaction.cpp index 0159bb3..ca93049 100644 --- a/test/unit/test_transaction.cpp +++ b/test/unit/test_transaction.cpp @@ -266,4 +266,42 @@ TEST_F(test_transaction, trivial_types_dup_iterate_by_key) ASSERT_TRUE(result); } +TEST_F(test_transaction, trivial_types_transaction_lower_bound) +{ + std::array test_value{0x30, 0x0, 0x0, 0x20}; + + lmdb:: + transaction> + transaction{test_dbi, std::move(txn)}; + + auto *cursor{reinterpret_cast(0x84)}; + + { + InSequence const seq; + + EXPECT_CALL(api, mdb_cursor_open(test_txn, test_dbi, _)) + .WillOnce(DoAll(SetArgPointee<2>(cursor), Return(MDB_SUCCESS))); + + EXPECT_CALL(api, mdb_cursor_get(cursor, Pointee(MdbValBytesAre{0x78, 0x56, 0x34, 0x12}), _, MDB_SET_RANGE)) + .WillOnce(DoAll( + SetArgPointee<2>( + MDB_val{test_value.size(), test_value.data()}), + Return(MDB_SUCCESS))); + + EXPECT_CALL(api, mdb_cursor_close(cursor)); + EXPECT_CALL(api, mdb_txn_abort(test_txn)); + } + + const auto result = transaction.lower_bound(0x12345678); + ASSERT_TRUE(result); + + auto const& db_view = *result; + auto const it = db_view.begin(); + EXPECT_NE(it, db_view.end()); + + auto const& key_value = *it; + EXPECT_EQ(key_value.key(), 0x12345678); + EXPECT_EQ(key_value.value(), 0x20000030); +} + } // namespace cpp_lmdb_tests