Database.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #ifndef ML_DATABASE_H
  3. #define ML_DATABASE_H
  4. #include "Dimension.h"
  5. #include "ml-private.h"
  6. #include "json/single_include/nlohmann/json.hpp"
  7. namespace ml {
  8. class Statement {
  9. public:
  10. using RowCallback = std::function<void(sqlite3_stmt *Stmt)>;
  11. public:
  12. Statement(const char *RawStmt) : RawStmt(RawStmt), ParsedStmt(nullptr) {}
  13. template<typename ...ArgTypes>
  14. bool exec(sqlite3 *Conn, RowCallback RowCb, ArgTypes ...Args) {
  15. if (!prepare(Conn))
  16. return false;
  17. switch (bind(1, Args...)) {
  18. case 0:
  19. return false;
  20. case sizeof...(Args):
  21. break;
  22. default:
  23. return resetAndClear(false);
  24. }
  25. while (true) {
  26. switch (int RC = sqlite3_step(ParsedStmt)) {
  27. case SQLITE_BUSY: case SQLITE_LOCKED:
  28. usleep(SQLITE_INSERT_DELAY * USEC_PER_MS);
  29. continue;
  30. case SQLITE_ROW:
  31. RowCb(ParsedStmt);
  32. continue;
  33. case SQLITE_DONE:
  34. return resetAndClear(true);
  35. default:
  36. error("Stepping through '%s' returned rc=%d", RawStmt, RC);
  37. return resetAndClear(false);
  38. }
  39. }
  40. }
  41. ~Statement() {
  42. if (!ParsedStmt)
  43. return;
  44. int RC = sqlite3_finalize(ParsedStmt);
  45. if (RC != SQLITE_OK)
  46. error("Could not properly finalize statement (rc=%d)", RC);
  47. }
  48. private:
  49. bool prepare(sqlite3 *Conn);
  50. bool bindValue(size_t Pos, const int Value);
  51. bool bindValue(size_t Pos, const std::string &Value);
  52. template<typename ArgType, typename ...ArgTypes>
  53. size_t bind(size_t Pos, ArgType T) {
  54. return bindValue(Pos, T);
  55. }
  56. template<typename ArgType, typename ...ArgTypes>
  57. size_t bind(size_t Pos, ArgType T, ArgTypes ...Args) {
  58. return bindValue(Pos, T) + bind(Pos + 1, Args...);
  59. }
  60. bool resetAndClear(bool Ret);
  61. private:
  62. const char *RawStmt;
  63. sqlite3_stmt *ParsedStmt;
  64. };
  65. class Database {
  66. private:
  67. static const char *SQL_CREATE_ANOMALIES_TABLE;
  68. static const char *SQL_INSERT_ANOMALY;
  69. static const char *SQL_SELECT_ANOMALY;
  70. static const char *SQL_SELECT_ANOMALY_EVENTS;
  71. public:
  72. Database(const std::string &Path);
  73. ~Database();
  74. template<typename ...ArgTypes>
  75. bool insertAnomaly(ArgTypes... Args) {
  76. Statement::RowCallback RowCb = [](sqlite3_stmt *Stmt) { (void) Stmt; };
  77. return InsertAnomalyStmt.exec(Conn, RowCb, Args...);
  78. }
  79. template<typename ...ArgTypes>
  80. bool getAnomalyInfo(nlohmann::json &Json, ArgTypes&&... Args) {
  81. Statement::RowCallback RowCb = [&](sqlite3_stmt *Stmt) {
  82. const char *Text = static_cast<const char *>(sqlite3_column_blob(Stmt, 0));
  83. Json = nlohmann::json::parse(Text);
  84. };
  85. return GetAnomalyInfoStmt.exec(Conn, RowCb, Args...);
  86. }
  87. template<typename ...ArgTypes>
  88. bool getAnomaliesInRange(std::vector<std::pair<time_t, time_t>> &V, ArgTypes&&... Args) {
  89. Statement::RowCallback RowCb = [&](sqlite3_stmt *Stmt) {
  90. V.push_back({
  91. sqlite3_column_int64(Stmt, 0),
  92. sqlite3_column_int64(Stmt, 1)
  93. });
  94. };
  95. return GetAnomaliesInRangeStmt.exec(Conn, RowCb, Args...);
  96. }
  97. private:
  98. sqlite3 *Conn;
  99. Statement InsertAnomalyStmt{SQL_INSERT_ANOMALY};
  100. Statement GetAnomalyInfoStmt{SQL_SELECT_ANOMALY};
  101. Statement GetAnomaliesInRangeStmt{SQL_SELECT_ANOMALY_EVENTS};
  102. };
  103. }
  104. #endif /* ML_DATABASE_H */