GitWatcherBot  1.0.0
A Telegram Bot that notifies you when a new change is made in your repositories (issues, pull requests, stars, forks, and watches)
All Classes Namespaces Files Functions Variables Typedefs Macros
Database.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "models/User.hpp"
4 #include "models/Repository.hpp"
5 #include "models/Log.hpp"
6 #include "tgbotxx/utils/DateTimeUtils.hpp"
7 #include "sqlite_orm/sqlite_orm.h"
8 #include <filesystem>
9 
10 namespace fs = std::filesystem;
11 using namespace sqlite_orm;
12 using namespace models;
13 
14 class Database {
15 private:
16  static std::mutex m_mutex;
17 
18 public:
21  [[nodiscard]] static std::mutex &getDbMutex() noexcept;
22 
23 public:
26  static auto& getStorage() {
27  static auto storage = make_storage(fs::path(RES_DIR) / "Database.db",
28  Repository::table(),
29  User::table(),
30  Log::table()
31  );
32  static bool schemaSynced = false;
33  if (!storage.on_open) {
34  storage.on_open = []([[maybe_unused]] sqlite3 *handle) {
35  if (not schemaSynced) {
36  int rc = sqlite3_exec(handle, "PRAGMA synchronous=NORMAL;" // wait for data to be written to disk io
37  "PRAGMA locking_mode=EXCLUSIVE;" // Only 1 connection can write to db at a time, others will be blocked
38  "PRAGMA journal_mode=WAL;" // record changes before they are applied to the main database file
39  "PRAGMA cache_size=50000;" // 50000=50mb 800000=800MB (default -2000 which is 2kb)
40  "PRAGMA temp_store=MEMORY;" // Storing temporary tables and indices in memory can improve performance, but it can also increase memory usage and the risk of running out of memory, especially for large temporary datasets.
41  "PRAGMA auto_vacuum=0;", // DO NOT Vacuum
42  nullptr, nullptr, nullptr);
43  if (rc != SQLITE_OK) {
44  sqlite_orm::throw_translated_sqlite_error(handle);
45  }
46  storage.sync_schema(/*preserve*/true); // PRESERVE=TRUE Don't delete my table data when I add a new column in a table. (https://github.com/fnc12/sqlite_orm/issues/1261)
47  schemaSynced = true;
48  }
49  };
50  }
51  return storage;
52  }
53 
55  static void backup();
56 
57 public: // Users
59  static bool userExists(const models::UserId userId);
62  static models::User getUser(const models::UserId userId);
64  static void addUser(const models::User& newUser);
66  static models::UserStatus getUserStatus(const models::UserId userId);
68  static void updateUserStatus(const models::UserId userId, const models::UserStatus newStatus);
70  static void updateUser(const models::User& updatedUser);
72  static int userReposCount(const models::UserId userId);
73 
74 public: // Repositories
76  static bool repoExists(const models::RepositoryId repoId);
78  static bool repoExistsByFullName(const std::string& full_name);
80  static void addRepo(const models::Repository& newRepo);
82  static void updateRepo(const models::Repository& updatedRepo);
84  static void removeUserRepo(const models::UserId watcherId, const models::RepositoryId repoId);
87  static void iterateRepos(const std::function<void(const models::Repository&)>& callback);
89  static std::vector<std::string> getUserReposFullnames(const models::UserId watcherId);
91  static std::vector<models::Repository> getUserRepos(const models::UserId watcherId);
92 
93 public: // Logs
95  static std::int64_t addLog(const models::Log& newLog);
96 };
97 
static std::vector< models::Repository > getUserRepos(const models::UserId watcherId)
Returns all Repositories objects that a User is watching.
static models::User getUser(const models::UserId userId)
Returns User object by id.
static void removeUserRepo(const models::UserId watcherId, const models::RepositoryId repoId)
Removes Repository from User's watch list.
static void addUser(const models::User &newUser)
Adds a new user to the database.
static bool repoExists(const models::RepositoryId repoId)
Returns true if a Repository exists with same id.
static void updateUserStatus(const models::UserId userId, const models::UserStatus newStatus)
Update User's status by id.
static std::int64_t addLog(const models::Log &newLog)
Adds a new Log object to the database.
static void addRepo(const models::Repository &newRepo)
Adds a new Repository object to the database.
static void iterateRepos(const std::function< void(const models::Repository &)> &callback)
Lock secure iterate over repositories to not hold the db mutex for a long time.
static void updateUser(const models::User &updatedUser)
Updates existing user changed properties.
static void backup()
Call this periodically to backup the database in res/DbBackups/ periodically.
static bool userExists(const models::UserId userId)
Returns true if User with id exists in the database.
static void updateRepo(const models::Repository &updatedRepo)
Updates existing repository changed properties.
static models::UserStatus getUserStatus(const models::UserId userId)
Returns UserStatus by id.
static int userReposCount(const models::UserId userId)
Returns the count of repositories this user is watching.
static bool repoExistsByFullName(const std::string &full_name)
Returns true if Repository exists with same full_name (example: "torvalds/linux")
static std::vector< std::string > getUserReposFullnames(const models::UserId watcherId)
Returns full names of all repositories that a User is watching.
static std::mutex & getDbMutex() noexcept
Returns Database mutex to be used by multiple threads for writing/reading into/from the database.
Definition: Log.hpp:12
std::int64_t RepositoryId
Definition: Repository.hpp:11
decltype(tgbotxx::User::id) UserId
Definition: User.hpp:12