21 template<
class KeyT,
class ValueT>
45 template<template <class...> class ContainerT>
63 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
79 template<
template <
class...>
class ContainerT = std::multimap>
81 ContainerT<KeyT, ValueT> container;
97 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
99 ContainerT<KeyT, ValueContainerT<ValueT>> container;
116 template<
template <
class...>
class ContainerT>
118 ContainerT<KeyT, ValueT>& container,
129 template<
template <
class...>
class ContainerT>
131 ContainerT<KeyT, ValueT>& container) {
142 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
144 ContainerT<KeyT, ValueContainerT<ValueT>>& container,
156 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
158 ContainerT<KeyT, ValueContainerT<ValueT>>& container) {
168 template<
template <
class...>
class ContainerT>
171 ContainerT<KeyT, ValueT> container;
182 template<
template <
class...>
class ContainerT>
184 ContainerT<KeyT, ValueT> container;
196 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
199 ContainerT<KeyT, ValueContainerT<ValueT>> container;
211 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
213 ContainerT<KeyT, ValueContainerT<ValueT>> container;
224 template<
template <
class...>
class ContainerT>
226 const ContainerT<KeyT, ValueT>& container,
237 template<
template <
class...>
class ContainerT>
239 const ContainerT<KeyT, ValueT>& container) {
250 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
252 const ContainerT<KeyT, ValueContainerT<ValueT>>& container,
264 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
266 const ContainerT<KeyT, ValueContainerT<ValueT>>& container) {
276 template<
template <
class...>
class ContainerT>
278 const ContainerT<KeyT, ValueT>& container,
289 template<
template <
class...>
class ContainerT>
291 const ContainerT<KeyT, ValueT>& container) {
302 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
304 const ContainerT<KeyT, ValueContainerT<ValueT>>& container,
316 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
317 void reconcile(
const ContainerT<KeyT, ValueContainerT<ValueT>>& container) {
343 const ValueT &value) {
353 const std::pair<KeyT, ValueT> &pair,
364 const std::pair<KeyT, ValueT> &pair) {
377 const std::size_t& value_count) {
391 const std::size_t& value_count) {
413 std::size_t
count(
const KeyT& key,
const ValueT& value)
const {
424 template<
template <
class...>
class ContainerT>
425 bool find(
const KeyT &key, ContainerT<ValueT>& values) {
451 void remove(
const KeyT &key,
const ValueT &value) {
527 const std::string keys_table = config.table_name.empty() ?
"keys_store" : config.table_name +
"_keys";
528 const std::string values_table = config.table_name.empty() ?
"values_store" : config.table_name +
"_values";
529 const std::string key_value_table = config.table_name.empty() ?
"key_value_store" : config.table_name +
"_key_value";
531 const std::string keys_temp_table = config.table_name.empty() ?
"keys_temp_store" : config.table_name +
"_temp_keys";
532 const std::string values_temp_table = config.table_name.empty() ?
"values_temp_store" : config.table_name +
"_temp_values";
535 const std::string create_keys_table_sql =
536 "CREATE TABLE IF NOT EXISTS " + keys_table +
" ("
537 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
541 const std::string create_values_table_sql =
542 "CREATE TABLE IF NOT EXISTS " + values_table +
" ("
543 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
547 const std::string create_key_value_table_sql =
548 "CREATE TABLE IF NOT EXISTS " + key_value_table +
" ("
549 "key_id INTEGER NOT NULL, "
550 "value_id INTEGER NOT NULL, "
551 "value_count INTEGER DEFAULT 1, "
552 "FOREIGN KEY(key_id) REFERENCES " + keys_table +
"(id) ON DELETE CASCADE, "
553 "FOREIGN KEY(value_id) REFERENCES " + values_table +
"(id) ON DELETE CASCADE, "
554 "PRIMARY KEY (key_id, value_id));";
558 const std::string create_keys_temp_table_sql =
559 "CREATE TEMPORARY TABLE IF NOT EXISTS " + keys_temp_table +
" ("
560 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
564 const std::string create_values_temp_table_sql =
565 "CREATE TEMPORARY TABLE IF NOT EXISTS " + values_temp_table +
" ("
566 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
575 "SELECT " + keys_table +
".key, " + values_table +
".value, " + key_value_table +
".value_count "
576 "FROM " + keys_table +
" "
577 "JOIN " + key_value_table +
" ON " + keys_table +
".id = " + key_value_table +
".key_id "
578 "JOIN " + values_table +
" ON " + key_value_table +
".value_id = " + values_table +
".id;");
588 "SELECT value_count FROM " + key_value_table +
589 " WHERE key_id = (SELECT id FROM " + keys_table +
590 " WHERE key = ?) AND value_id = (SELECT id FROM " + values_table +
591 " WHERE value = ?);");
609 "UPDATE " + key_value_table +
610 " SET value_count = ? WHERE key_id = (SELECT id FROM " + keys_table +
611 " WHERE key = ?) AND value_id = (SELECT id FROM " + values_table +
612 " WHERE value = ?);");
616 "SELECT v.value, kv.value_count "
617 "FROM " + values_table +
" v "
618 "JOIN " + key_value_table +
" kv ON v.id = kv.value_id "
619 "JOIN " + keys_table +
" k ON kv.key_id = k.id "
623 m_stmt_remove_key_value.
init(
m_sqlite_db,
"DELETE FROM " + key_value_table +
" WHERE key_id = (SELECT id FROM " + keys_table +
" WHERE key = ?) AND value_id = (SELECT id FROM " + values_table +
" WHERE value = ?);");
635 template<
template <
class...>
class ContainerT>
636 void db_load(ContainerT<KeyT, ValueT>& container) {
644 add_value(container, key, value, value_count);
646 if (err == SQLITE_DONE) {
650 if (err == SQLITE_BUSY) {
657 std::string err_msg =
"SQLite error: ";
658 err_msg += std::to_string(err);
666 "Unknown error occurred while loading data from database.");
675 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
676 void db_load(ContainerT<KeyT, ValueContainerT<ValueT>>& container) {
684 add_value(container[key], value, value_count);
686 if (err == SQLITE_DONE) {
690 if (err == SQLITE_BUSY) {
697 std::string err_msg =
"SQLite error: ";
698 err_msg += std::to_string(err);
706 "Unknown error occurred while loading data from database.");
714 template<
template <
class...>
class ContainerT>
715 void db_append(
const ContainerT<KeyT, ValueT>& container) {
717 for (
const auto& pair : container) {
724 if (key_id == -1)
continue;
727 if (value_id == -1)
continue;
740 std::current_exception(), {
744 "Unknown error occurred while appending key-value pairs to the database.");
753 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
755 const ContainerT<KeyT, ValueContainerT<ValueT>>& container) {
757 for (
const auto& pair : container) {
762 if (key_id == -1)
continue;
763 for (
const auto& value : pair.second) {
768 if (value_id == -1)
continue;
782 std::current_exception(), {
786 "Unknown error occurred while appending key-value pairs to the database.");
796 const ValueT &value) {
819 std::current_exception(), {
823 "Unknown error occurred while inserting key-value pair.");
834 template<
template <
class...>
class ContainerT>
836 const ContainerT<KeyT, ValueT>& container) {
839 std::unordered_map<KeyT, std::vector<std::pair<ValueT, int>>> temp_container;
840 for (
const auto& pair : container) {
841 auto& vec = temp_container[pair.first];
847 for (
const auto& item : temp_container) {
850 for (
const auto& pair : item.second) {
855 for (
const auto& pair : container) {
857 if (key_id == -1)
throw sqlite_exception(
"Failed to retrieve key ID for the provided key during reconciliation.");
859 if (value_id == -1)
throw sqlite_exception(
"Failed to retrieve value ID for the provided value during reconciliation.");
868 for (
const auto& item : temp_container) {
870 if (key_id == -1)
continue;
871 for (
const auto& pair : item.second) {
873 if (value_id == -1)
continue;
879 std::current_exception(), {
885 "Unknown error occurred while reconciling data.");
899 typename std::vector<std::pair<T, int>>::iterator
find_or_insert(std::vector<std::pair<T, int>>& vec,
const T& value,
900 typename std::enable_if<
901 !std::is_integral<T>::value &&
902 !std::is_floating_point<T>::value &&
903 !std::is_same<T, std::string>::value &&
904 !std::is_same<T, std::vector<char>>::value &&
905 !std::is_same<T, std::vector<uint8_t>>::value &&
906 std::is_trivially_copyable<T>::value
908 auto it = std::find_if(vec.begin(), vec.end(), [&value](
const std::pair<T, int>& element) {
909 return byte_compare(element.first, value);
911 if (it == vec.end()) {
913 it = vec.emplace(it, std::make_pair(value, 0));
926 typename std::vector<std::pair<T, int>>::iterator
find_or_insert(std::vector<std::pair<T, int>>& vec,
const T& value,
927 typename std::enable_if<
928 std::is_integral<T>::value ||
929 std::is_floating_point<T>::value ||
930 std::is_same<T, std::string>::value ||
931 std::is_same<T, std::vector<char>>::value ||
932 std::is_same<T, std::vector<uint8_t>>::value>::type* = 0) {
933 auto it = std::find_if(vec.begin(), vec.end(), [&value](
const std::pair<T, int>& element) {
934 return element.first == value;
936 if (it == vec.end()) {
937 it = vec.insert(it, {value, 0});
947 template<
template <
class...>
class ContainerT,
template <
class...>
class ValueContainerT>
949 const ContainerT<KeyT, ValueContainerT<ValueT>>& container) {
952 std::unordered_map<KeyT, std::unordered_map<ValueT, int>> temp_container;
953 for (
const auto& pair : container) {
954 auto it_key = temp_container.find(pair.first);
955 for (
const ValueT& value : pair.second) {
956 if (it_key == temp_container.end()) {
957 temp_container[pair.first][value] = 1;
959 auto it_value = it_key->second.find(value);
960 if (it_value == it_key->second.end()) {
961 it_key->second[value] = 1;
970 for (
const auto& item : temp_container) {
973 for (
const auto& pair : item.second) {
979 for (
const auto& pair : container) {
981 if (key_id == -1)
continue;
982 for (
const ValueT& value : pair.second) {
984 if (value_id == -1)
continue;
986 if (value_count)
continue;
993 for (
const auto& item : temp_container) {
995 if (key_id == -1)
continue;
996 for (
const auto& pair : item.second) {
998 if (value_id == -1)
continue;
1004 std::current_exception(), {
1010 "Unknown error occurred while reconciling data.");
1020 template<
template <
class...>
class ContainerT>
1021 bool db_find(
const KeyT &key, ContainerT<ValueT>& container) {
1028 add_value(container, value, value_count);
1033 std::current_exception(),
1035 "Unknown error occurred while finding key-value pairs.");
1037 return !container.empty();
1055 std::current_exception(),
1057 "Unknown error occurred while setting value count for key-value pair.");
1074 std::current_exception(),
1076 "Unknown error occurred while removing key-value pair.");
1091 std::current_exception(),
1093 "Unknown error occurred while removing values by key.");
1104 size_t value_count = 0;
1116 std::current_exception(),
1118 "Unknown error occurred while retrieving value count for key-value pair.");
1126 std::size_t
count = 0;
1133 if (err == SQLITE_DONE) {
1137 if (err == SQLITE_BUSY) {
1144 std::string err_msg =
"SQLite error: ";
1145 err_msg += std::to_string(err);
1152 {&
m_stmt_count_key},
"Unknown error occurred while counting the number of unique keys.");
1162 for (
auto* stmt : stmts) {
1168 std::current_exception(),
1171 "Unknown error occurred while clearing the database tables.");
1191 int64_t key_id = -1;
1216 int64_t value_id = -1;
1265 std::size_t value_count = 0;
Base class for SQLite database management in sqlite_containers.
#define SQLITE_CONTAINERS_BUSY_RETRY_DELAY_MS
Base class for SQLite database management.
Config get_config() const
Gets the current configuration of the database.
void execute_in_transaction(Func operation, const TransactionMode &mode)
Executes an operation inside a transaction.
void set_config(const Config &config)
Sets the configuration for the database.
std::mutex m_sqlite_mutex
void db_handle_exception(std::exception_ptr ex, const std::vector< SqliteStmt * > &stmts, const std::string &message="Unknown error occurred.") const
Handles an exception by resetting and clearing bindings of prepared SQL statements.
Configuration class for SQLite database settings.
TransactionMode default_txn_mode
Template class for managing key-value pairs in a SQLite database, where each key can map to multiple ...
std::size_t db_get_value_count(const int64_t &key_id, const int64_t &value_id)
Retrieves the count of values associated with a specific key-value pair.
void insert(const std::pair< KeyT, ValueT > &pair)
Inserts a key-value pair into the database.
SqliteStmt m_stmt_set_value_count
Statement for setting value count for a key-value pair.
SqliteStmt m_stmt_remove_key_value
Statement for removing a specific key-value pair.
ContainerT< KeyT, ValueContainerT< ValueT > > retrieve_all(const TransactionMode &mode)
Retrieves all key-value pairs from the database with a transaction.
void load(ContainerT< KeyT, ValueT > &container, const TransactionMode &mode)
Loads data from the database into the container.
SqliteStmt m_stmt_clear_values_temp
Statement for clearing the temporary values table.
void reconcile(const ContainerT< KeyT, ValueT > &container)
Reconciles the content of the container with the database.
void db_reconcile(const ContainerT< KeyT, ValueContainerT< ValueT > > &container)
Reconciles the database with the provided container, ensuring data integrity.
ContainerT< KeyT, ValueContainerT< ValueT > > retrieve_all()
Retrieves all key-value pairs from the database.
SqliteStmt m_stmt_clear_keys
Statement for clearing the keys table.
void append(const ContainerT< KeyT, ValueT > &container, const TransactionMode &mode)
Appends the content of the container to the database with a transaction.
void set_value_count(const KeyT &key, const ValueT &value, const std::size_t &value_count)
Sets the count of values associated with a specific key-value pair in the database.
SqliteStmt m_stmt_get_value_id
Statement for retrieving value ID.
void db_insert_value_temp(const ValueT &value)
Inserts a value into the temporary values table.
std::size_t db_count_key() const
Returns the number of elements in the database.
void db_insert_key_temp(const KeyT &key)
Inserts a key into the temporary keys table.
int64_t db_get_key_id(const KeyT &key)
Retrieves the ID of a key from the database.
void db_insert_key_value(const int64_t &key_id, const int64_t &value_id)
Inserts a key-value pair into the key-value table.
ContainerT< KeyT, ValueT > retrieve_all()
Retrieves all key-value pairs from the database.
~KeyMultiValueDB() override final=default
Destructor.
KeyMultiValueDB()
Default constructor.
std::size_t count() const
Returns the number of elements in the database. This method returns the number of unique keys stored ...
void db_clear()
Clears all key-value pairs from the database.
void db_set_value_count_key_value(const KeyT &key, const ValueT &value, const size_t &value_count)
Sets the value count for a key-value pair in the database.
SqliteStmt m_stmt_remove_all_values
Statement for removing all values associated with a key.
void db_set_value_count(const int64_t &key_id, const int64_t &value_id, const size_t &value_count)
Sets the count of values associated with a specific key-value pair.
void db_purge_old_data()
Removes old keys and values that are no longer in the temporary tables.
int64_t db_get_value_id(const ValueT &value)
Retrieves the ID of a value from the database.
SqliteStmt m_stmt_insert_key
Statement for inserting a key.
ContainerT< KeyT, ValueT > retrieve_all(const TransactionMode &mode)
Retrieves all key-value pairs from the database with a transaction.
void insert(const KeyT &key, const ValueT &value, const TransactionMode &mode)
Inserts a key-value pair into the database with a transaction.
void insert(const std::pair< KeyT, ValueT > &pair, const TransactionMode &mode)
Inserts a key-value pair into the database with a transaction.
std::vector< std::pair< T, int > >::iterator find_or_insert(std::vector< std::pair< T, int > > &vec, const T &value, typename std::enable_if< std::is_integral< T >::value||std::is_floating_point< T >::value||std::is_same< T, std::string >::value||std::is_same< T, std::vector< char > >::value||std::is_same< T, std::vector< uint8_t > >::value >::type *=0)
Finds or inserts a value into a sorted vector. This method finds a value in the vector,...
void reconcile(const ContainerT< KeyT, ValueContainerT< ValueT > > &container, const TransactionMode &mode)
Reconciles the content of the container with the database with a transaction.
SqliteStmt m_stmt_insert_key_temp
Statement for inserting keys into the temporary table.
ContainerT< KeyT, ValueT > operator()()
Loads all key-value pairs from the database into a container.
KeyMultiValueDB & operator=(const ContainerT< KeyT, ValueContainerT< ValueT > > &container)
Assigns a container where each key maps to a collection of values to the database.
void db_append(const ContainerT< KeyT, ValueContainerT< ValueT > > &container)
Appends the content of the container to the database.
void db_clear_temp_tables()
Clears the temporary keys and values tables.
void clear(const TransactionMode &mode)
Clears all key-value pairs from the database with a transaction.
SqliteStmt m_stmt_clear_keys_temp
Statement for clearing the temporary keys table.
void insert(const KeyT &key, const ValueT &value)
Inserts a key-value pair into the database.
void append(const ContainerT< KeyT, ValueContainerT< ValueT > > &container, const TransactionMode &mode)
Appends the content of the container to the database with a transaction.
void load(ContainerT< KeyT, ValueT > &container)
Loads data from the database into the container.
void db_load(ContainerT< KeyT, ValueContainerT< ValueT > > &container)
Loads data from the database into the container.
void load(ContainerT< KeyT, ValueContainerT< ValueT > > &container, const TransactionMode &mode)
Loads data from the database into the container.
SqliteStmt m_stmt_insert_value_temp
Statement for inserting values into the temporary table.
SqliteStmt m_stmt_get_key_id
Statement for retrieving key ID.
void load(ContainerT< KeyT, ValueContainerT< ValueT > > &container)
Loads data from the database into the container.
void reconcile(const ContainerT< KeyT, ValueT > &container, const TransactionMode &mode)
Reconciles the content of the container with the database with a transaction.
std::size_t count(const KeyT &key, const ValueT &value) const
Alias for get_value_count(). This method is an alias for get_value_count() and performs the same oper...
void append(const ContainerT< KeyT, ValueT > &container)
Appends the content of the container to the database.
ContainerT< KeyT, ValueContainerT< ValueT > > operator()()
Loads all key-value pairs, where each key maps to a collection of values, from the database.
void db_reconcile(const ContainerT< KeyT, ValueT > &container)
Reconciles the database with the provided container. This method compares the content of the provided...
void set_count(const KeyT &key, const ValueT &value, const std::size_t &value_count)
Alias for set_value_count(). This method is an alias for set_value_count() and performs the same oper...
SqliteStmt m_stmt_insert_value
Statement for inserting a value.
void db_load(ContainerT< KeyT, ValueT > &container)
Loads data from the database into the container.
void db_insert(const KeyT &key, const ValueT &value)
Inserts a key-value pair into the database.
std::vector< std::pair< T, int > >::iterator find_or_insert(std::vector< std::pair< T, int > > &vec, const T &value, typename std::enable_if< !std::is_integral< T >::value &&!std::is_floating_point< T >::value &&!std::is_same< T, std::string >::value &&!std::is_same< T, std::vector< char > >::value &&!std::is_same< T, std::vector< uint8_t > >::value &&std::is_trivially_copyable< T >::value >::type *=0)
Finds or inserts a value into a sorted vector. This method finds a value in the vector,...
void append(const ContainerT< KeyT, ValueContainerT< ValueT > > &container)
Appends the content of the container to the database.
void db_remove_all_values(const KeyT &key)
Removes all values associated with a key from the database.
bool empty() const
Checks if the database is empty. This method checks if there are any keys stored in the database.
SqliteStmt m_stmt_clear_values
Statement for clearing the values table.
SqliteStmt m_stmt_count_key
Statement for counting the number of keys.
SqliteStmt m_stmt_insert_key_value
Statement for inserting a key-value pair.
void db_create_table(const Config &config) override final
Creates the tables in the database. This method creates both the main and temporary tables for keys,...
void db_append(const ContainerT< KeyT, ValueT > &container)
Appends the content of the container to the database.
void reconcile(const ContainerT< KeyT, ValueContainerT< ValueT > > &container)
Reconciles the content of the container with the database.
KeyMultiValueDB(const Config &config)
Constructor with configuration.
std::size_t get_value_count(const KeyT &key, const ValueT &value) const
Retrieves the count of values associated with a specific key-value pair from the database....
SqliteStmt m_stmt_purge_values
Statement for purging old values.
void db_remove_key_value(const KeyT &key, const ValueT &value)
Removes a specific key-value pair from the database.
void clear()
Clears all key-value pairs from the database.
SqliteStmt m_stmt_purge_keys
Statement for purging old keys.
void remove(const KeyT &key)
Removes all values associated with a key from the database.
void db_insert_value(const ValueT &value)
Inserts a value into the database.
SqliteStmt m_stmt_find
Statement for finding values by key.
SqliteStmt m_stmt_get_value_count
Statement for retrieving the count of a value.
SqliteStmt m_stmt_set_value_count_kv
Statement for setting value count by key-value pair.
bool find(const KeyT &key, ContainerT< ValueT > &values)
Finds values by key in the database.
std::size_t db_get_value_count_key_value(const KeyT &key, const ValueT &value) const
Retrieves the count of a specific value associated with a key in the database.
bool db_find(const KeyT &key, ContainerT< ValueT > &container)
Finds values by key in the database.
void remove(const KeyT &key, const ValueT &value)
Removes a specific key-value pair from the database.
SqliteStmt m_stmt_get_value_count_kv
Statement for retrieving the count of a value by key-value pair.
SqliteStmt m_stmt_load
Statement for loading data from the database.
SqliteStmt m_stmt_clear_key_values
Statement for clearing the key-value pairs table.
void db_insert_key(const KeyT &key)
Inserts a key into the database.
Class for managing SQLite prepared statements.
void clear_bindings()
Clears all bindings on the prepared statement.
void execute(sqlite3 *sqlite_db)
Executes the prepared statement.
T extract_column(const int &index, typename std::enable_if< std::is_integral< T >::value >::type *=0)
Extracts a value from a SQLite statement column.
void reset()
Resets the prepared statement.
void init(sqlite3 *sqlite_db, const char *query)
Initializes the statement.
bool bind_value(const int &index, const T &value, typename std::enable_if< std::is_integral< T >::value >::type *=0)
Binds a value to a SQLite statement.
Exception class for SQLite errors.
void execute(sqlite3_stmt *stmt)
Executes a SQLite statement.
std::enable_if< std::is_trivially_copyable< typenameT::value_type >::value &&std::is_same< T, std::vector< typenameT::value_type > >::value, std::string >::type get_sqlite_type()
TransactionMode
Defines SQLite transaction modes.
void add_value(ContainerT< T > &container, T &value, typename std::enable_if< std::is_same< ContainerT< T >, std::set< T > >::value||std::is_same< ContainerT< T >, std::unordered_set< T > >::value >::type *=0)
Adds a value to a container (set or unordered_set).