summaryrefslogtreecommitdiffstats
path: root/ml/Database.h
blob: cc7b758724c483a320af09f3b3c1953d1d7943bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef ML_DATABASE_H
#define ML_DATABASE_H

#include "Dimension.h"
#include "ml-private.h"

#include "json/single_include/nlohmann/json.hpp"

namespace ml {

class Statement {
public:
    using RowCallback = std::function<void(sqlite3_stmt *Stmt)>;

public:
    Statement(const char *RawStmt) : RawStmt(RawStmt), ParsedStmt(nullptr) {}

    template<typename ...ArgTypes>
    bool exec(sqlite3 *Conn, RowCallback RowCb, ArgTypes ...Args) {
        if (!prepare(Conn))
            return false;

        switch (bind(1, Args...)) {
        case 0:
            return false;
        case sizeof...(Args):
            break;
        default:
            return resetAndClear(false);
        }

        while (true) {
            switch (int RC = sqlite3_step(ParsedStmt)) {
            case SQLITE_BUSY: case SQLITE_LOCKED:
                usleep(SQLITE_INSERT_DELAY * USEC_PER_MS);
                continue;
            case SQLITE_ROW:
                RowCb(ParsedStmt);
                continue;
            case SQLITE_DONE:
                return resetAndClear(true);
            default:
                error("Stepping through '%s' returned rc=%d", RawStmt, RC);
                return resetAndClear(false);
            }
        }
    }

    ~Statement() {
        if (!ParsedStmt)
            return;

        int RC = sqlite3_finalize(ParsedStmt);
        if (RC != SQLITE_OK)
            error("Could not properly finalize statement (rc=%d)", RC);
    }

private:
    bool prepare(sqlite3 *Conn);

    bool bindValue(size_t Pos, const int Value);
    bool bindValue(size_t Pos, const std::string &Value);

    template<typename ArgType, typename ...ArgTypes>
    size_t bind(size_t Pos, ArgType T) {
        return bindValue(Pos, T);
    }

    template<typename ArgType, typename ...ArgTypes>
    size_t bind(size_t Pos, ArgType T, ArgTypes ...Args) {
        return bindValue(Pos, T) + bind(Pos + 1, Args...);
    }

    bool resetAndClear(bool Ret);

private:
    const char *RawStmt;
    sqlite3_stmt *ParsedStmt;
};

class Database {
private:
    static const char *SQL_CREATE_ANOMALIES_TABLE;
    static const char *SQL_INSERT_ANOMALY;
    static const char *SQL_SELECT_ANOMALY;
    static const char *SQL_SELECT_ANOMALY_EVENTS;

public:
    Database(const std::string &Path);

    ~Database();

    template<typename ...ArgTypes>
    bool insertAnomaly(ArgTypes... Args) {
        Statement::RowCallback RowCb = [](sqlite3_stmt *Stmt) { (void) Stmt; };
        return InsertAnomalyStmt.exec(Conn, RowCb, Args...);
    }

    template<typename ...ArgTypes>
    bool getAnomalyInfo(nlohmann::json &Json, ArgTypes&&... Args) {
        Statement::RowCallback RowCb = [&](sqlite3_stmt *Stmt) {
            const char *Text = static_cast<const char *>(sqlite3_column_blob(Stmt, 0));
            Json = nlohmann::json::parse(Text);
        };
        return GetAnomalyInfoStmt.exec(Conn, RowCb, Args...);
    }

    template<typename ...ArgTypes>
    bool getAnomaliesInRange(std::vector<std::pair<time_t, time_t>> &V, ArgTypes&&... Args) {
        Statement::RowCallback RowCb = [&](sqlite3_stmt *Stmt) {
            V.push_back({
                sqlite3_column_int64(Stmt, 0),
                sqlite3_column_int64(Stmt, 1)
            });
        };
        return GetAnomaliesInRangeStmt.exec(Conn, RowCb, Args...);
    }

private:
    sqlite3 *Conn;

    Statement InsertAnomalyStmt{SQL_INSERT_ANOMALY};
    Statement GetAnomalyInfoStmt{SQL_SELECT_ANOMALY};
    Statement GetAnomaliesInRangeStmt{SQL_SELECT_ANOMALY_EVENTS};
};

}

#endif /* ML_DATABASE_H */