initial sqlite, store user

This commit is contained in:
ouwou
2020-11-19 19:18:59 -05:00
parent 1463d8da9e
commit deb482a8db
13 changed files with 381 additions and 78 deletions

View File

@@ -1,7 +1,71 @@
#include "store.hpp"
// hopefully the casting between signed and unsigned int64 doesnt cause issues
Store::Store() {
m_db_path = std::filesystem::temp_directory_path() / "abaddon-store.db";
m_db_err = sqlite3_open(m_db_path.string().c_str(), &m_db);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "error opening database: %s\n", sqlite3_errstr(m_db_err));
return;
}
m_db_err = sqlite3_exec(m_db, "PRAGMA journal_mode = WAL", nullptr, nullptr, nullptr);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "enabling write-ahead-log failed: %s\n", sqlite3_errstr(m_db_err));
return;
}
m_db_err = sqlite3_exec(m_db, "PRAGMA synchronous = NORMAL", nullptr, nullptr, nullptr);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "setting synchronous failed: %s\n", sqlite3_errstr(m_db_err));
return;
}
CreateTables();
CreateStatements();
}
Store::~Store() {
Cleanup();
m_db_err = sqlite3_close(m_db);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "error closing database: %s\n", sqlite3_errstr(m_db_err));
return;
}
std::filesystem::remove(m_db_path);
}
bool Store::IsValid() const {
return m_db_err == SQLITE_OK;
}
void Store::SetUser(Snowflake id, const User &user) {
m_users[id] = user;
if ((uint64_t)id == 0) {
printf("???: %s\n", user.Username.c_str());
}
Bind(m_set_user_stmt, 1, id);
Bind(m_set_user_stmt, 2, user.Username);
Bind(m_set_user_stmt, 3, user.Discriminator);
Bind(m_set_user_stmt, 4, user.Avatar);
Bind(m_set_user_stmt, 5, user.IsBot);
Bind(m_set_user_stmt, 6, user.IsSystem);
Bind(m_set_user_stmt, 7, user.IsMFAEnabled);
Bind(m_set_user_stmt, 8, user.Locale);
Bind(m_set_user_stmt, 9, user.IsVerified);
Bind(m_set_user_stmt, 10, user.Email);
Bind(m_set_user_stmt, 11, user.Flags);
Bind(m_set_user_stmt, 12, user.PremiumType);
Bind(m_set_user_stmt, 13, user.PublicFlags);
if (!RunInsert(m_set_user_stmt)) {
fprintf(stderr, "user insert failed: %s\n", sqlite3_errstr(m_db_err));
}
// m_users[id] = user;
}
void Store::SetChannel(Snowflake id, const Channel &channel) {
@@ -32,18 +96,33 @@ void Store::SetEmoji(Snowflake id, const Emoji &emoji) {
m_emojis[id] = emoji;
}
User *Store::GetUser(Snowflake id) {
auto it = m_users.find(id);
if (it == m_users.end())
return nullptr;
return &it->second;
}
std::optional<User> Store::GetUser(Snowflake id) const {
Bind(m_get_user_stmt, 1, id);
if (!FetchOne(m_get_user_stmt)) {
if (m_db_err != SQLITE_DONE) // not an error, just means user isnt found
fprintf(stderr, "error while fetching user info: %s\n", sqlite3_errstr(m_db_err));
Reset(m_get_user_stmt);
return std::nullopt;
}
const User *Store::GetUser(Snowflake id) const {
auto it = m_users.find(id);
if (it == m_users.end())
return nullptr;
return &it->second;
User ret;
Get(m_get_user_stmt, 0, ret.ID);
Get(m_get_user_stmt, 1, ret.Username);
Get(m_get_user_stmt, 2, ret.Discriminator);
Get(m_get_user_stmt, 3, ret.Avatar);
Get(m_get_user_stmt, 4, ret.IsBot);
Get(m_get_user_stmt, 5, ret.IsSystem);
Get(m_get_user_stmt, 6, ret.IsMFAEnabled);
Get(m_get_user_stmt, 7, ret.Locale);
Get(m_get_user_stmt, 8, ret.IsVerified);
Get(m_get_user_stmt, 9, ret.Email);
Get(m_get_user_stmt, 10, ret.Flags);
Get(m_get_user_stmt, 11, ret.PremiumType);
Get(m_get_user_stmt, 12, ret.PublicFlags);
Reset(m_get_user_stmt);
return std::optional<User>(std::move(ret));
}
Channel *Store::GetChannel(Snowflake id) {
@@ -186,3 +265,136 @@ void Store::ClearAll() {
m_roles.clear();
m_users.clear();
}
void Store::BeginTransaction() {
m_db_err = sqlite3_exec(m_db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr);
}
void Store::EndTransaction() {
m_db_err = sqlite3_exec(m_db, "COMMIT", nullptr, nullptr, nullptr);
}
bool Store::CreateTables() {
constexpr const char *create_users = R"(
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL,
discriminator TEXT NOT NULL,
avatar TEXT,
bot BOOL,
system BOOL,
mfa BOOL,
locale TEXT,
verified BOOl,
email TEXT,
flags INTEGER,
premium INTEGER,
pubflags INTEGER
)
)";
m_db_err = sqlite3_exec(m_db, create_users, nullptr, nullptr, nullptr);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "failed to create user table\n");
return false;
}
return true;
}
bool Store::CreateStatements() {
constexpr const char *set_user = R"(
REPLACE INTO users VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
)";
constexpr const char *get_user = R"(
SELECT * FROM users WHERE id = ?
)";
m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "failed to prepare set user statement\n");
return false;
}
m_db_err = sqlite3_prepare_v2(m_db, get_user, -1, &m_get_user_stmt, nullptr);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "failed to prepare get user statement\n");
return false;
}
return true;
}
void Store::Cleanup() {
sqlite3_finalize(m_set_user_stmt);
sqlite3_finalize(m_get_user_stmt);
}
void Store::Bind(sqlite3_stmt *stmt, int index, int num) const {
m_db_err = sqlite3_bind_int(stmt, index, num);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
}
}
void Store::Bind(sqlite3_stmt *stmt, int index, uint64_t num) const {
m_db_err = sqlite3_bind_int64(stmt, index, num);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
}
}
void Store::Bind(sqlite3_stmt *stmt, int index, const std::string &str) const {
m_db_err = sqlite3_bind_text(stmt, index, str.c_str(), -1, nullptr);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
}
}
void Store::Bind(sqlite3_stmt *stmt, int index, bool val) const {
m_db_err = sqlite3_bind_int(stmt, index, val ? 1 : 0);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
}
}
bool Store::RunInsert(sqlite3_stmt *stmt) {
m_db_err = sqlite3_step(stmt);
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
return m_db_err == SQLITE_DONE;
}
bool Store::FetchOne(sqlite3_stmt *stmt) const {
m_db_err = sqlite3_step(stmt);
return m_db_err == SQLITE_ROW;
}
void Store::Get(sqlite3_stmt *stmt, int index, int &out) const {
out = sqlite3_column_int(stmt, index);
}
void Store::Get(sqlite3_stmt *stmt, int index, std::string &out) const {
const unsigned char *ptr = sqlite3_column_text(stmt, index);
if (ptr == nullptr)
out = "";
else
out = reinterpret_cast<const char *>(ptr);
}
void Store::Get(sqlite3_stmt *stmt, int index, bool &out) const {
out = sqlite3_column_int(stmt, index) != 0;
}
void Store::Get(sqlite3_stmt *stmt, int index, Snowflake &out) const {
const int64_t num = sqlite3_column_int64(stmt, index);
out = static_cast<uint64_t>(num);
}
void Store::Reset(sqlite3_stmt *stmt) const {
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
}