2018-12-31 20:04:05 +01:00
|
|
|
//
|
2022-12-31 22:28:08 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "td/db/SqliteDb.h"
|
|
|
|
#include "td/db/SqliteStatement.h"
|
|
|
|
|
2022-02-10 09:55:32 +01:00
|
|
|
#include "td/utils/common.h"
|
2022-02-07 22:04:34 +01:00
|
|
|
#include "td/utils/FlatHashMap.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/utils/Slice.h"
|
2021-05-17 14:21:11 +02:00
|
|
|
#include "td/utils/SliceBuilder.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/utils/Status.h"
|
|
|
|
|
|
|
|
namespace td {
|
2018-05-24 23:37:43 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
class SqliteKeyValue {
|
|
|
|
public:
|
2018-07-22 01:56:40 +02:00
|
|
|
static Status drop(SqliteDb &connection, Slice table_name) TD_WARN_UNUSED_RESULT {
|
|
|
|
return connection.exec(PSLICE() << "DROP TABLE IF EXISTS " << table_name);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
static Status init(SqliteDb &connection, Slice table_name) TD_WARN_UNUSED_RESULT {
|
|
|
|
return connection.exec(PSLICE() << "CREATE TABLE IF NOT EXISTS " << table_name << " (k BLOB PRIMARY KEY, v BLOB)");
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
bool empty() const {
|
|
|
|
return db_.empty();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
Status init_with_connection(SqliteDb connection, string table_name) TD_WARN_UNUSED_RESULT;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
void close() {
|
2018-08-06 16:22:22 +02:00
|
|
|
*this = SqliteKeyValue();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-08-06 16:22:22 +02:00
|
|
|
Status drop();
|
2018-07-22 01:56:40 +02:00
|
|
|
|
2021-12-12 13:41:06 +01:00
|
|
|
void set(Slice key, Slice value);
|
2018-07-22 01:56:40 +02:00
|
|
|
|
2022-02-07 20:41:07 +01:00
|
|
|
void set_all(const FlatHashMap<string, string> &key_values);
|
2021-12-12 20:34:19 +01:00
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
string get(Slice key);
|
|
|
|
|
2021-12-12 13:41:06 +01:00
|
|
|
void erase(Slice key);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2023-02-12 01:29:19 +01:00
|
|
|
void erase_batch(vector<string> keys);
|
|
|
|
|
2021-10-07 12:18:00 +02:00
|
|
|
Status begin_read_transaction() TD_WARN_UNUSED_RESULT {
|
|
|
|
return db_.begin_read_transaction();
|
|
|
|
}
|
2021-12-12 20:34:19 +01:00
|
|
|
|
2021-10-07 12:18:00 +02:00
|
|
|
Status begin_write_transaction() TD_WARN_UNUSED_RESULT {
|
|
|
|
return db_.begin_write_transaction();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2021-12-12 20:34:19 +01:00
|
|
|
|
2018-07-17 23:41:26 +02:00
|
|
|
Status commit_transaction() TD_WARN_UNUSED_RESULT {
|
2018-12-31 20:04:05 +01:00
|
|
|
return db_.commit_transaction();
|
|
|
|
}
|
|
|
|
|
2018-07-22 01:56:40 +02:00
|
|
|
void erase_by_prefix(Slice prefix);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2022-02-07 20:41:07 +01:00
|
|
|
FlatHashMap<string, string> get_all() {
|
|
|
|
FlatHashMap<string, string> res;
|
2019-05-01 16:15:54 +02:00
|
|
|
get_by_prefix("", [&](Slice key, Slice value) {
|
2022-02-09 22:59:52 +01:00
|
|
|
CHECK(!key.empty());
|
2019-05-01 16:15:54 +02:00
|
|
|
res.emplace(key.str(), value.str());
|
|
|
|
return true;
|
|
|
|
});
|
2018-12-31 20:04:05 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class CallbackT>
|
|
|
|
void get_by_prefix(Slice prefix, CallbackT &&callback) {
|
|
|
|
string next;
|
|
|
|
if (!prefix.empty()) {
|
|
|
|
next = next_prefix(prefix);
|
|
|
|
}
|
|
|
|
get_by_range(prefix, next, callback);
|
|
|
|
}
|
2018-07-22 01:56:40 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
template <class CallbackT>
|
|
|
|
void get_by_range(Slice from, Slice till, CallbackT &&callback) {
|
|
|
|
SqliteStatement *stmt = nullptr;
|
|
|
|
if (from.empty()) {
|
|
|
|
stmt = &get_all_stmt_;
|
|
|
|
} else {
|
|
|
|
if (till.empty()) {
|
|
|
|
stmt = &get_by_prefix_rare_stmt_;
|
|
|
|
stmt->bind_blob(1, till).ensure();
|
|
|
|
} else {
|
|
|
|
stmt = &get_by_prefix_stmt_;
|
|
|
|
stmt->bind_blob(1, from).ensure();
|
|
|
|
stmt->bind_blob(2, till).ensure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto guard = stmt->guard();
|
|
|
|
stmt->step().ensure();
|
|
|
|
while (stmt->has_row()) {
|
2019-05-01 16:15:54 +02:00
|
|
|
if (!callback(stmt->view_blob(0), stmt->view_blob(1))) {
|
|
|
|
return;
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
stmt->step().ensure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-07-22 01:56:40 +02:00
|
|
|
string table_name_;
|
2018-12-31 20:04:05 +01:00
|
|
|
SqliteDb db_;
|
|
|
|
SqliteStatement get_stmt_;
|
|
|
|
SqliteStatement set_stmt_;
|
|
|
|
SqliteStatement erase_stmt_;
|
|
|
|
SqliteStatement get_all_stmt_;
|
|
|
|
SqliteStatement erase_by_prefix_stmt_;
|
|
|
|
SqliteStatement erase_by_prefix_rare_stmt_;
|
|
|
|
SqliteStatement get_by_prefix_stmt_;
|
|
|
|
SqliteStatement get_by_prefix_rare_stmt_;
|
|
|
|
|
2021-10-18 18:26:14 +02:00
|
|
|
static string next_prefix(Slice prefix);
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
2018-05-24 23:37:43 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
} // namespace td
|