MDBX Containers
Loading...
Searching...
No Matches
KeyValueTable.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef _MDBX_CONTAINERS_KEY_VALUE_TABLE_HPP_INCLUDED
3#define _MDBX_CONTAINERS_KEY_VALUE_TABLE_HPP_INCLUDED
4
7
8#include "common.hpp"
9#include <map>
10#include <unordered_set>
11
12namespace mdbxc {
13
26 template<class KeyT, class ValueT>
27 class KeyValueTable final : public BaseTable {
28 public:
29
34 KeyValueTable(std::shared_ptr<Connection> connection,
35 std::string name = "kv_store",
36 MDBX_db_flags_t flags = MDBX_DB_DEFAULTS | MDBX_CREATE)
37 : BaseTable(std::move(connection),
38 std::move(name),
39 flags | get_mdbx_flags<KeyT>()) {}
40
45 explicit KeyValueTable(const Config& config,
46 std::string name = "kv_store",
47 MDBX_db_flags_t flags = MDBX_DB_DEFAULTS | MDBX_CREATE)
48 : BaseTable(Connection::create(config),
49 std::move(name),
50 flags | get_mdbx_flags<KeyT>()) {}
51
53 ~KeyValueTable() override final = default;
54
55 // --- Operators ---
56
62 template<template <class...> class ContainerT>
63 KeyValueTable& operator=(const ContainerT<KeyT, ValueT>& container) {
64 with_transaction([this, &container](MDBX_txn* txn) {
65 db_reconcile(container, txn);
67 return *this;
68 }
69
75 KeyValueTable& operator=(const std::vector<std::pair<KeyT, ValueT>>& container) {
76 with_transaction([this, &container](MDBX_txn* txn) {
77 db_reconcile(container, txn);
79 return *this;
80 }
81
86 template<template<class...> class ContainerT = std::map>
87 auto operator()() {
88 using ReturnT = std::conditional_t<
89 std::is_same_v<ContainerT<KeyT, ValueT>, std::vector<std::pair<KeyT, ValueT>>>,
90 std::vector<std::pair<KeyT, ValueT>>,
91 ContainerT<KeyT, ValueT>
92 >;
93
94 ReturnT container;
95 with_transaction([this, &container](MDBX_txn* txn) {
96 db_load(container, txn);
98 return container;
99 }
100
103 public:
108 : m_db(db), m_key(std::move(key)) {}
109
113 AssignmentProxy& operator=(const ValueT& value) {
114 m_db.insert_or_assign(m_key, value);
115 return *this;
116 }
117
120 operator ValueT() const {
121 auto val = m_db.find(m_key);
122 if (val) return *val;
123 ValueT def{}; // default construct if missing
124 m_db.insert_or_assign(m_key, def); // persist the default value
125 return def;
126 }
127
128 private:
130 KeyT m_key;
131 };
132
136 AssignmentProxy operator[](const KeyT& key) {
137 return AssignmentProxy(*this, key);
138 }
139
140 // --- Existing methods ---
141
147 template<template <class...> class ContainerT>
148 void load(ContainerT<KeyT, ValueT>& container, MDBX_txn* txn = nullptr) {
149 with_transaction([this, &container](MDBX_txn* txn) {
150 db_load(container, txn);
152 }
153
159 template<template <class...> class ContainerT>
160 void load(ContainerT<KeyT, ValueT>& container, const Transaction& txn) {
161 load(container, txn.handle());
162 }
163
168 void load(std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn = nullptr) {
169 with_transaction([this, &container](MDBX_txn* txn) {
170 db_load(container, txn);
172 }
173
178 void load(std::vector<std::pair<KeyT, ValueT>>& container, const Transaction& txn) {
179 load(container, txn.handle());
180 }
181
187 template<template<class...> class ContainerT = std::map>
188 auto retrieve_all(MDBX_txn* txn = nullptr) {
189 using ReturnT = std::conditional_t<
190 std::is_same_v<ContainerT<KeyT, ValueT>, std::vector<std::pair<KeyT, ValueT>>>,
191 std::vector<std::pair<KeyT, ValueT>>,
192 ContainerT<KeyT, ValueT>
193 >;
194
195 ReturnT container;
196 with_transaction([this, &container](MDBX_txn* txn) {
197 db_load(container, txn);
199 return container;
200 }
201
207 template<template<class...> class ContainerT = std::map>
208 auto retrieve_all(const Transaction& txn) {
209 return retrieve_all<ContainerT>(txn.handle());
210 }
211
217 template<template <class...> class ContainerT>
218 void append(const ContainerT<KeyT, ValueT>& container, MDBX_txn* txn = nullptr) {
219 with_transaction([this, &container](MDBX_txn* txn) {
220 db_append(container, txn);
222 }
223
229 template<template <class...> class ContainerT>
230 void append(const ContainerT<KeyT, ValueT>& container, const Transaction& txn) {
231 append(container, txn.handle());
232 }
233
234
239 void append(const std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn = nullptr) {
240 with_transaction([this, &container](MDBX_txn* txn) {
241 db_append(container, txn);
243 }
244
249 void append(const std::vector<std::pair<KeyT, ValueT>>& container, const Transaction& txn) {
250 append(container, txn.handle());
251 }
252
258 template<template <class...> class ContainerT>
259 void reconcile(const ContainerT<KeyT, ValueT>& container, MDBX_txn* txn = nullptr) {
260 with_transaction([this, &container](MDBX_txn* txn) {
261 db_reconcile(container, txn);
263 }
264
270 template<template <class...> class ContainerT>
271 void reconcile(const ContainerT<KeyT, ValueT>& container, const Transaction& txn) {
272 reconcile(container, txn.handle());
273 }
274
279 void reconcile(const std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn = nullptr) {
280 with_transaction([this, &container](MDBX_txn* txn) {
281 db_reconcile(container, txn);
283 }
284
289 void reconcile(const std::vector<std::pair<KeyT, ValueT>>& container, const Transaction& txn) {
290 reconcile(container, txn.handle());
291 }
292
299 bool insert(const KeyT &key, const ValueT &value, MDBX_txn* txn = nullptr) {
300 bool res;
301 with_transaction([this, &key, &value, &res](MDBX_txn* txn) {
302 res = db_insert_if_absent(key, value, txn);
304 return res;
305 }
306
313 bool insert(const KeyT &key, const ValueT &value, const Transaction& txn) {
314 return insert(key, value, txn.handle());
315 }
316
322 bool insert(const std::pair<KeyT, ValueT> &pair, MDBX_txn* txn = nullptr) {
323 bool res;
324 with_transaction([this, &pair, &res](MDBX_txn* txn) {
325 res = db_insert_if_absent(pair.first, pair.second, txn);
327 return res;
328 }
329
335 bool insert(const std::pair<KeyT, ValueT> &pair, const Transaction& txn) {
336 return insert(pair, txn.handle());
337 }
338
344 void insert_or_assign(const KeyT &key, const ValueT &value, MDBX_txn* txn = nullptr) {
345 with_transaction([this, &key, &value](MDBX_txn* txn) {
346 db_insert_or_assign(key, value, txn);
348 }
349
355 void insert_or_assign(const KeyT &key, const ValueT &value, const Transaction& txn) {
356 insert_or_assign(key, value, txn.handle());
357 }
358
363 void insert_or_assign(const std::pair<KeyT, ValueT> &pair, MDBX_txn* txn = nullptr) {
364 insert_or_assign([&pair](MDBX_txn* txn) {
365 db_insert_or_assign(pair.first, pair.second, txn);
367 }
368
373 void insert_or_assign(const std::pair<KeyT, ValueT> &pair, const Transaction& txn) {
374 insert_or_assign(pair, txn.handle());
375 }
376
383 ValueT at(const KeyT& key, MDBX_txn* txn = nullptr) const {
384 ValueT value;
385 with_transaction([this, &key, &value](MDBX_txn* txn) {
386 if (!db_get(key, value, txn)) {
387 throw std::out_of_range("Key not found in database");
388 }
390 return value;
391 }
392
399 ValueT at(const KeyT& key, const Transaction& txn) const {
400 return at(key, txn.handle());
401 }
402
409 bool try_get(const KeyT& key, ValueT& out, MDBX_txn* txn) const {
410 bool res;
411 with_transaction([this, &key, &out, &res](MDBX_txn* txn) {
412 res = db_get(key, out, txn);
414 return res;
415 }
416
423 bool try_get(const KeyT& key, ValueT& out, const Transaction& txn) const {
424 return try_get(key, out, txn.handle());
425 }
426
427#if __cplusplus >= 201703L
433 std::optional<ValueT> find(const KeyT& key, MDBX_txn* txn = nullptr) const {
434 std::optional<ValueT> result;
435 with_transaction([this, &key, &result](MDBX_txn* txn) {
436 ValueT tmp;
437 if (db_get(key, tmp, txn)) {
438 result = std::move(tmp);
439 }
441 return result;
442 }
443
449 std::optional<ValueT> find(const KeyT& key, const Transaction& txn) const {
450 return find(key, txn.handle());
451 }
452#endif
453
459 std::pair<bool, ValueT> find_compat(const KeyT& key, MDBX_txn* txn = nullptr) const {
460 std::pair<bool, ValueT> result{false, ValueT{}};
461 with_transaction([this, &key, &result](MDBX_txn* txn) {
462 if (db_get(key, result.second, txn)) {
463 result.first = true;
464 }
466 return result;
467 }
468
474 std::pair<bool, ValueT> find_compat(const KeyT& key, const Transaction& txn) const {
475 return find_compat(key, txn.handle());
476 }
477
483 bool contains(const KeyT& key, MDBX_txn* txn = nullptr) const {
484 bool res;
485 with_transaction([this, &key, &res](MDBX_txn* txn) {
486 res = db_contains(key, txn);
488 return res;
489 }
490
496 bool contains(const KeyT& key, const Transaction& txn) const {
497 return contains(key, txn.handle());
498 }
499
504 std::size_t count(MDBX_txn* txn = nullptr) const {
505 std::size_t res = 0;
506 with_transaction([this, &res](MDBX_txn* txn) {
507 res = db_count(txn);
509 return res;
510 }
511
516 std::size_t count(const Transaction& txn) const {
517 return count(txn.handle());
518 }
519
524 bool empty(MDBX_txn* txn = nullptr) const {
525 std::size_t res = 0;
526 with_transaction([this, &res](MDBX_txn* txn) {
527 res = db_count(txn);
529 return (res == 0);
530 }
531
536 bool empty(const Transaction& txn) const {
537 return empty(txn.handle());
538 }
539
545 bool erase(const KeyT &key, MDBX_txn* txn = nullptr) {
546 bool res;
547 with_transaction([this, &key, &res](MDBX_txn* txn) {
548 res = db_erase(key, txn);
550 return res;
551 }
552
558 bool erase(const KeyT &key, const Transaction& txn) {
559 return erase(key, txn.handle());
560 }
561
565 void clear(MDBX_txn* txn = nullptr) {
566 with_transaction([this](MDBX_txn* txn) {
567 db_clear(txn);
569 }
570
574 void clear(const Transaction& txn) {
575 clear(txn.handle());
576 }
577
578 private:
579
585 template<typename F>
586 void with_transaction(F&& action, TransactionMode mode = TransactionMode::WRITABLE, MDBX_txn* txn = nullptr) const {
587 if (txn) {
588 action(txn);
589 return;
590 }
591 txn = thread_txn(); // reuse transaction bound to this thread if any
592 if (txn) {
593 action(txn);
594 return;
595 }
596
597 auto txn_guard = m_connection->transaction(mode);
598 try {
599 action(txn_guard.handle());
600 txn_guard.commit();
601 } catch(...) {
602 // Ensure rollback on any exception and rethrow to the caller
603 try {
604 txn_guard.rollback();
605 } catch(...) {
606 // Ignore rollback errors here
607 }
608 throw;
609 }
610 }
611
617 template<template <class...> class ContainerT>
618 void db_load(ContainerT<KeyT, ValueT>& container, MDBX_txn* txn_handle) {
619 MDBX_cursor* cursor = nullptr;
620 check_mdbx(mdbx_cursor_open(txn_handle, m_dbi, &cursor), "Failed to open MDBX cursor");
621
622 MDBX_val db_key, db_val;
623 while (mdbx_cursor_get(cursor, &db_key, &db_val, MDBX_NEXT) == MDBX_SUCCESS) {
624 auto&& key = deserialize_value<KeyT>(db_key);
625 auto&& value = deserialize_value<ValueT>(db_val);
626 container.emplace(std::move(key), std::move(value));
627 }
628
629 mdbx_cursor_close(cursor);
630 }
631
636 void db_load(std::vector<std::pair<KeyT, ValueT>>& out_vector, MDBX_txn* txn) {
637 MDBX_cursor* cursor = nullptr;
638 check_mdbx(mdbx_cursor_open(txn, m_dbi, &cursor), "Failed to open MDBX cursor");
639
640 MDBX_val db_key, db_val;
641 while (mdbx_cursor_get(cursor, &db_key, &db_val, MDBX_NEXT) == MDBX_SUCCESS) {
642 auto&& key = deserialize_value<KeyT>(db_key);
643 auto&& value = deserialize_value<ValueT>(db_val);
644 out_vector.emplace_back(std::move(key), std::move(value));
645 }
646
647 mdbx_cursor_close(cursor);
648 }
649
656 bool db_get(const KeyT& key, ValueT& value, MDBX_txn* txn_handle) const {
657 MDBX_val db_key = serialize_key(key);
658 MDBX_val db_val;
659 int rc = mdbx_get(txn_handle, m_dbi, &db_key, &db_val);
660 if (rc == MDBX_NOTFOUND) return false;
661 check_mdbx(rc, "Failed to retrieve value");
662 value = deserialize_value<ValueT>(db_val);
663 return true;
664 }
665
671 bool db_contains(const KeyT& key, MDBX_txn* txn_handle) const {
672 MDBX_val db_key = serialize_key(key);
673 MDBX_val db_val; // dummy
674 int rc = mdbx_get(txn_handle, m_dbi, &db_key, &db_val);
675 if (rc == MDBX_NOTFOUND) return false;
676 check_mdbx(rc, "Failed to check key presence");
677 return true;
678 }
679
684 std::size_t db_count(MDBX_txn* txn_handle) const {
685 MDBX_stat stat;
686 check_mdbx(mdbx_dbi_stat(txn_handle, m_dbi, &stat, sizeof(stat)), "Failed to query database statistics");
687 return stat.ms_entries;
688 }
689
695 template<template <class...> class ContainerT>
696 void db_append(const ContainerT<KeyT, ValueT>& container, MDBX_txn* txn_handle) {
697 for (const auto& pair : container) {
698 MDBX_val db_key = serialize_key(pair.first);
699 MDBX_val db_val = serialize_value(pair.second);
701 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT),
702 "Failed to write record"
703 );
704 }
705 }
706
711 void db_append(const std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn_handle) {
712 for (const auto& [key, value] : container) {
713 MDBX_val db_key = serialize_key(key);
714 MDBX_val db_val = serialize_value(value);
716 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT),
717 "Failed to write record"
718 );
719 }
720 }
721
729 template<template <class...> class ContainerT>
730 void db_reconcile(const ContainerT<KeyT, ValueT>& container, MDBX_txn* txn_handle) {
731 // 1. Collect all keys from the container
732 std::unordered_set<KeyT> new_keys;
733 for (const auto& pair : container) {
734 new_keys.insert(pair.first);
735 MDBX_val db_key = serialize_key(pair.first);
736 MDBX_val db_val = serialize_value(pair.second);
738 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT),
739 "Failed to write record"
740 );
741 }
742
743 // 2. Iterate over existing keys in the DB and remove the extras
744 MDBX_cursor* cursor = nullptr;
745 check_mdbx(mdbx_cursor_open(txn_handle, m_dbi, &cursor), "Failed to open MDBX cursor");
746
747 MDBX_val db_key, db_val;
748 while (mdbx_cursor_get(cursor, &db_key, &db_val, MDBX_NEXT) == MDBX_SUCCESS) {
749 auto&& key = deserialize_value<KeyT>(db_key);
750 if (new_keys.find(key) == new_keys.end()) {
751 check_mdbx(mdbx_cursor_del(cursor, MDBX_CURRENT), "Failed to delete record using cursor");
752 }
753 }
754
755 mdbx_cursor_close(cursor);
756 }
757
763 void db_reconcile(const std::vector<std::pair<KeyT, ValueT>>& container, MDBX_txn* txn_handle) {
764 // 1. Collect keys and upsert values
765 std::unordered_set<KeyT> new_keys;
766 for (size_t i = 0; i < container.size(); ++i) {
767 const KeyT& key = container[i].first;
768 const ValueT& value = container[i].second;
769
770 new_keys.insert(key);
771
772 MDBX_val db_key = serialize_key(key);
773 MDBX_val db_val = serialize_value(value);
775 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT),
776 "Failed to write record"
777 );
778 }
779
780 // 2. Delete stale keys from DB
781 MDBX_cursor* cursor = nullptr;
782 check_mdbx(mdbx_cursor_open(txn_handle, m_dbi, &cursor), "Failed to open MDBX cursor");
783
784 MDBX_val db_key, db_val;
785 while (mdbx_cursor_get(cursor, &db_key, &db_val, MDBX_NEXT) == MDBX_SUCCESS) {
786 KeyT key = deserialize_value<KeyT>(db_key);
787 if (new_keys.find(key) == new_keys.end()) {
788 check_mdbx(mdbx_cursor_del(cursor, MDBX_CURRENT), "Failed to delete record using cursor");
789 }
790 }
791
792 mdbx_cursor_close(cursor);
793 }
794
801 bool db_insert_if_absent(const KeyT& key, const ValueT& value, MDBX_txn* txn_handle) {
802 MDBX_val db_key = serialize_key(key);
803 MDBX_val db_val = serialize_value(value);
804 int rc = mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_NOOVERWRITE);
805
806 if (rc == MDBX_SUCCESS)
807 return true;
808 if (rc == MDBX_KEYEXIST)
809 return false;
810
811 check_mdbx(rc, "Failed to insert key-value pair");
812 return false;
813 }
814
820 void db_insert_or_assign(const KeyT& key, const ValueT& value, MDBX_txn* txn_handle) {
821 MDBX_val db_key = serialize_key(key);
822 MDBX_val db_val = serialize_value(value);
824 mdbx_put(txn_handle, m_dbi, &db_key, &db_val, MDBX_UPSERT), // or 0
825 "Failed to insert or assign key-value pair"
826 );
827 }
828
834 bool db_erase(const KeyT& key, MDBX_txn* txn_handle) {
835 MDBX_val db_key = serialize_key(key);
836 int rc = mdbx_del(txn_handle, m_dbi, &db_key, nullptr);
837 if (rc == MDBX_SUCCESS) return true;
838 if (rc == MDBX_NOTFOUND) return false;
839 check_mdbx(rc, "Failed to erase key");
840 return false;
841 }
842
845 void db_clear(MDBX_txn* txn_handle) {
846 check_mdbx(mdbx_drop(txn_handle, m_dbi, 0), "Failed to clear table");
847 }
848
849 }; // KeyValueTable
850
851}; // namespace mdbxc
852
853#endif // _MDBX_CONTAINERS_KEY_VALUE_TABLE_HPP_INCLUDED
MDBX_txn * thread_txn() const
Returns the transaction bound to the current thread, if any.
Definition BaseTable.hpp:94
MDBX_dbi m_dbi
DBI handle for the opened table.
Definition BaseTable.hpp:90
BaseTable(std::shared_ptr< Connection > connection, std::string name, MDBX_db_flags_t flags)
Construct the database table accessor.
Definition BaseTable.hpp:22
std::shared_ptr< Connection > m_connection
Shared connection to MDBX environment.
Definition BaseTable.hpp:89
Parameters used by Connection to create the MDBX environment.
Definition Config.hpp:17
Manages a single MDBX environment and an optional read-only transaction.
Helper proxy for convenient assignment via operator[].
AssignmentProxy(KeyValueTable &db, KeyT key)
Constructs the proxy for a specific key.
KeyValueTable & m_db
Reference to the owning table.
KeyT m_key
Key associated with this proxy.
AssignmentProxy & operator=(const ValueT &value)
Assigns a value to the stored key.
auto operator()()
Loads all key-value pairs from the database into a container.
void load(ContainerT< KeyT, ValueT > &container, const Transaction &txn)
Loads data from the database into the container using provided transaction.
void db_reconcile(const std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn_handle)
Reconciles the content of the database with the given vector of key-value pairs.
bool db_insert_if_absent(const KeyT &key, const ValueT &value, MDBX_txn *txn_handle)
Inserts a key-value pair only if the key does not already exist.
std::size_t count(MDBX_txn *txn=nullptr) const
Returns the number of elements in the database.
std::size_t db_count(MDBX_txn *txn_handle) const
Returns the number of elements in the database.
void load(ContainerT< KeyT, ValueT > &container, MDBX_txn *txn=nullptr)
Loads data from the database into the container.
bool insert(const KeyT &key, const ValueT &value, MDBX_txn *txn=nullptr)
Inserts key-value only if key is absent.
bool empty(MDBX_txn *txn=nullptr) const
Checks if the database is empty.
void insert_or_assign(const KeyT &key, const ValueT &value, MDBX_txn *txn=nullptr)
Inserts or replaces key-value pair.
void load(std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn=nullptr)
Loads all key-value pairs into a std::vector of pairs.
bool contains(const KeyT &key, const Transaction &txn) const
Checks whether a key exists in the database.
KeyValueTable & operator=(const std::vector< std::pair< KeyT, ValueT > > &container)
Assigns a vector of key-value pairs to the database.
void reconcile(const std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn=nullptr)
Reconciles the database with the vector of key-value pairs.
bool try_get(const KeyT &key, ValueT &out, const Transaction &txn) const
Tries to find value by key.
void insert_or_assign(const std::pair< KeyT, ValueT > &pair, MDBX_txn *txn=nullptr)
Inserts or replaces key-value pair.
bool insert(const KeyT &key, const ValueT &value, const Transaction &txn)
Inserts key-value only if key is absent.
bool db_erase(const KeyT &key, MDBX_txn *txn_handle)
Removes a key from the database.
bool try_get(const KeyT &key, ValueT &out, MDBX_txn *txn) const
Tries to find value by key.
void db_append(const ContainerT< KeyT, ValueT > &container, MDBX_txn *txn_handle)
Appends the content of the container to the database.
void insert_or_assign(const std::pair< KeyT, ValueT > &pair, const Transaction &txn)
Inserts or replaces key-value pair.
AssignmentProxy operator[](const KeyT &key)
Provides convenient access to insert or read a value by key.
std::pair< bool, ValueT > find_compat(const KeyT &key, MDBX_txn *txn=nullptr) const
Finds value by key.
void db_load(std::vector< std::pair< KeyT, ValueT > > &out_vector, MDBX_txn *txn)
Loads all key-value pairs into a std::vector of pairs.
KeyValueTable(const Config &config, std::string name="kv_store", MDBX_db_flags_t flags=MDBX_DB_DEFAULTS|MDBX_CREATE)
Constructor with configuration.
bool contains(const KeyT &key, MDBX_txn *txn=nullptr) const
Checks whether a key exists in the database.
void db_load(ContainerT< KeyT, ValueT > &container, MDBX_txn *txn_handle)
Loads data from the database into the container.
void reconcile(const std::vector< std::pair< KeyT, ValueT > > &container, const Transaction &txn)
Reconciles the database with the vector of key-value pairs using provided transaction.
bool empty(const Transaction &txn) const
Checks if the database is empty.
void db_clear(MDBX_txn *txn_handle)
Clears all key-value pairs from the database.
void db_insert_or_assign(const KeyT &key, const ValueT &value, MDBX_txn *txn_handle)
Inserts or replaces the key-value pair.
void db_append(const std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn_handle)
Appends the content of the vector to the database.
auto retrieve_all(const Transaction &txn)
Retrieves all key-value pairs into the specified container type.
void clear(const Transaction &txn)
Clears all key-value pairs from the database.
void append(const ContainerT< KeyT, ValueT > &container, const Transaction &txn)
Appends data to the database.
ValueT at(const KeyT &key, const Transaction &txn) const
Retrieves value by key or throws.
void reconcile(const ContainerT< KeyT, ValueT > &container, MDBX_txn *txn=nullptr)
Reconciles the database with the container.
bool erase(const KeyT &key, const Transaction &txn)
Removes key from DB.
std::size_t count(const Transaction &txn) const
Returns the number of elements in the database.
void clear(MDBX_txn *txn=nullptr)
Clears all key-value pairs from the database.
void load(std::vector< std::pair< KeyT, ValueT > > &container, const Transaction &txn)
Loads all key-value pairs into a std::vector of pairs.
void db_reconcile(const ContainerT< KeyT, ValueT > &container, MDBX_txn *txn_handle)
Reconciles the content of the database with the container.
ValueT at(const KeyT &key, MDBX_txn *txn=nullptr) const
Retrieves value by key or throws.
void reconcile(const ContainerT< KeyT, ValueT > &container, const Transaction &txn)
Reconciles the database with the container.
bool db_contains(const KeyT &key, MDBX_txn *txn_handle) const
Checks whether a key exists in the database.
std::pair< bool, ValueT > find_compat(const KeyT &key, const Transaction &txn) const
Finds value by key.
bool insert(const std::pair< KeyT, ValueT > &pair, const Transaction &txn)
Inserts key-value only if key is absent.
KeyValueTable(std::shared_ptr< Connection > connection, std::string name="kv_store", MDBX_db_flags_t flags=MDBX_DB_DEFAULTS|MDBX_CREATE)
Default constructor.
void append(const std::vector< std::pair< KeyT, ValueT > > &container, MDBX_txn *txn=nullptr)
Appends data from a vector to the database.
bool erase(const KeyT &key, MDBX_txn *txn=nullptr)
Removes key from DB.
~KeyValueTable() override final=default
Destructor.
void insert_or_assign(const KeyT &key, const ValueT &value, const Transaction &txn)
Inserts or replaces key-value pair.
bool db_get(const KeyT &key, ValueT &value, MDBX_txn *txn_handle) const
Gets a value by key from the database.
void append(const ContainerT< KeyT, ValueT > &container, MDBX_txn *txn=nullptr)
Appends data to the database.
auto retrieve_all(MDBX_txn *txn=nullptr)
Retrieves all key-value pairs into the specified container type.
void append(const std::vector< std::pair< KeyT, ValueT > > &container, const Transaction &txn)
Appends data from a vector to the database using a provided transaction.
void with_transaction(F &&action, TransactionMode mode=TransactionMode::WRITABLE, MDBX_txn *txn=nullptr) const
Executes a functor within a transaction context.
bool insert(const std::pair< KeyT, ValueT > &pair, MDBX_txn *txn=nullptr)
Inserts key-value only if key is absent.
Manages MDBX transactions with automatic cleanup and error handling.
MDBX_txn * handle() const noexcept
Returns the internal MDBX transaction handle.
Publicly usable low-level components of the MDBX Containers library.
std::enable_if<!has_value_type< T >::value &&!std::is_same< T, std::vector< typenameT::value_type > >::value &&!std::is_trivially_copyable< typenameT::value_type >::value &&!has_to_bytes< T >::value &&!std::is_same< T, std::string >::value &&!std::is_trivially_copyable< T >::value, MDBX_val >::type serialize_value(const T &value)
Serializes a general value into MDBX_val.
Definition utils.hpp:280
std::enable_if<!has_from_bytes< T >::value &&!std::is_same< T, std::string >::value &&!std::is_trivially_copyable< T >::value, T >::type deserialize_value(const MDBX_val &val)
Deserializes a value from MDBX_val into type T.
Definition utils.hpp:403
std::enable_if<!has_to_bytes< T >::value &&!std::is_same< T, std::string >::value &&!std::is_trivially_copyable< T >::value, MDBX_val >::type serialize_key(const T &key)
Serializes a key into MDBX_val for database operations.
Definition utils.hpp:132
MDBX_db_flags_t get_mdbx_flags()
Returns MDBX flags for a given key type.
Definition utils.hpp:71
void check_mdbx(int rc, const std::string &context)
Throws an MdbxException if MDBX return code indicates an error.
Definition utils.hpp:18
TransactionMode
Specifies the access mode of a transaction.
@ READ_ONLY
Read-only transaction (no write operations allowed).
@ WRITABLE
Writable transaction (allows inserts, updates, deletes).