FOSSredder 0.5.0
Loading...
Searching...
No Matches
SqliteAnnualRepository.cpp
Go to the documentation of this file.
1
5
10#include <sqlite3.h>
11#include <stdexcept>
12
13#include <vector>
14
15namespace {
16
17std::vector<std::string> loadAnalysisIds(sqlite3* db,
18 const std::string& annualId) {
19 std::vector<std::string> out;
20 if (!db || annualId.empty()) {
21 return out;
22 }
23
24 persistence::StmtGuard stmt(db, "SELECT analysis_id FROM annual_analyses "
25 "WHERE annual_id = ? ORDER BY position;");
26 if (!stmt) {
27 return out;
28 }
29
30 stmt.bindText(1, annualId);
31 while (stmt.step() == SQLITE_ROW) {
32 out.push_back(stmt.columnText(0));
33 }
34 return out;
35}
36
37constexpr auto kSelectAnnual =
38 "SELECT id, name, year, created_at, updated_at FROM annuals";
39
40void saveAnalysisIds(sqlite3* db, const std::string& annualId,
41 const std::vector<std::string>& analysisIds) {
42 if (!db || annualId.empty()) {
43 return;
44 }
45
46 persistence::StmtGuard deleteStmt(
47 db, "DELETE FROM annual_analyses WHERE annual_id = ?;");
48 if (!deleteStmt) {
49 return;
50 }
51 deleteStmt.bindText(1, annualId);
52 deleteStmt.step();
53
54 persistence::StmtGuard insertStmt(
55 db, "INSERT OR IGNORE INTO annual_analyses (annual_id, analysis_id, "
56 "position) VALUES (?, ?, ?);");
57 if (!insertStmt) {
58 return;
59 }
60
61 for (std::size_t index = 0; index < analysisIds.size(); ++index) {
62 if (analysisIds[index].empty()) {
63 continue;
64 }
65 insertStmt.reset();
66 insertStmt.bindText(1, annualId);
67 insertStmt.bindText(2, analysisIds[index]);
68 insertStmt.bindInt(3, static_cast<int>(index));
69 insertStmt.step();
70 }
71}
72
73std::shared_ptr<Annual> readAnnual(sqlite3* db, persistence::StmtGuard& s) {
74 auto a = std::make_shared<Annual>();
75 a->setId(s.columnText(0));
76 a->rename(s.columnText(1));
77 a->setYear(s.columnInt(2));
78 a->setCreatedAt(s.columnText(3));
79 a->setUpdatedAt(s.columnText(4));
80 a->setAnalysisIds(loadAnalysisIds(db, a->id()));
81 return a;
82}
83
84} // namespace
85
87 std::shared_ptr<SqliteDb> db;
88};
89
91 : SqliteAnnualRepository(std::make_shared<SqliteDb>(dbPath)) {}
92
94 : pimpl_(std::make_unique<Impl>()) {
95 if (!db) {
96 throw std::runtime_error("db is null");
97 }
98
99 pimpl_->db = std::move(db);
100}
101
103
104void SqliteAnnualRepository::addAnnual(const std::shared_ptr<Annual>& annual) {
105 if (!annual || annual->id().empty()) {
106 return;
107 }
108
109 persistence::StmtGuard stmt(pimpl_->db->handle(),
110 "INSERT OR IGNORE INTO annuals"
111 " (id, name, year, created_at, updated_at)"
112 " VALUES (?, ?, ?, ?, ?);");
113 if (!stmt) {
114 return;
115 }
116 stmt.bindText(1, annual->id());
117 stmt.bindText(2, annual->name());
118 stmt.bindInt(3, annual->year());
119 stmt.bindText(4, annual->createdAt());
120 stmt.bindText(5, annual->updatedAt());
121 stmt.step();
122 saveAnalysisIds(pimpl_->db->handle(), annual->id(), annual->analysisIds());
123}
124
125std::vector<std::shared_ptr<Annual>>
127 std::vector<std::shared_ptr<Annual>> out;
128 persistence::StmtGuard stmt(pimpl_->db->handle(),
129 std::string(kSelectAnnual) + " ORDER BY year;");
130 if (!stmt) {
131 return out;
132 }
133
134 while (stmt.step() == SQLITE_ROW) {
135 out.push_back(readAnnual(pimpl_->db->handle(), stmt));
136 }
137 return out;
138}
139
140std::optional<std::shared_ptr<Annual>>
141SqliteAnnualRepository::getAnnualById(const std::string& id) const {
142 persistence::StmtGuard stmt(pimpl_->db->handle(),
143 std::string(kSelectAnnual) +
144 " WHERE id = ? LIMIT 1;");
145 if (!stmt) {
146 return std::nullopt;
147 }
148
149 stmt.bindText(1, id);
150 if (stmt.step() != SQLITE_ROW) {
151 return std::nullopt;
152 }
153 return readAnnual(pimpl_->db->handle(), stmt);
154}
155
156void SqliteAnnualRepository::removeAnnual(const std::string& id) {
157 persistence::StmtGuard stmt(pimpl_->db->handle(),
158 "DELETE FROM annuals WHERE id = ?;");
159 if (!stmt) {
160 return;
161 }
162
163 stmt.bindText(1, id);
164 stmt.step();
165}
166
168 const std::shared_ptr<Annual>& annual) {
169 if (!annual || annual->id().empty()) {
170 return;
171 }
172
173 persistence::StmtGuard stmt(pimpl_->db->handle(),
174 "UPDATE annuals SET name=?, year=?, "
175 "created_at=?, updated_at=? WHERE id=?;");
176 if (!stmt) {
177 return;
178 }
179 stmt.bindText(1, annual->name());
180 stmt.bindInt(2, annual->year());
181 stmt.bindText(3, annual->createdAt());
182 stmt.bindText(4, annual->updatedAt());
183 stmt.bindText(5, annual->id());
184 stmt.step();
185 saveAnalysisIds(pimpl_->db->handle(), annual->id(), annual->analysisIds());
186}
187
189 const std::shared_ptr<Annual>& annual) {
190 if (!annual || annual->id().empty()) {
191 return;
192 }
193
194 updateAnnual(annual);
195 if (sqlite3_changes(pimpl_->db->handle()) == 0) {
196 addAnnual(annual);
197 }
198}
199
201 char* err = nullptr;
202 sqlite3_exec(pimpl_->db->handle(), "DELETE FROM annuals;", nullptr, nullptr,
203 &err);
204 if (err) {
205 sqlite3_free(err);
206 }
207}
208
209sqlite3* SqliteAnnualRepository::sqliteHandle() const noexcept {
210 return pimpl_ && pimpl_->db ? pimpl_->db->handle() : nullptr;
211}
Domain model for annual aggregates.
Declares the SQLite-backed annual repository.
Declares the lightweight SQLite connection wrapper.
RAII wrapper for sqlite3_stmt* that auto-finalizes on destruction.
~SqliteAnnualRepository() override
Destroy the repository.
void clearAnnuals() override
Remove all annual entries.
void removeAnnual(const std::string &id) override
Remove an annual entry by identifier.
SqliteAnnualRepository(const std::string &dbPath)
Create an annual repository for the database at the given path.
sqlite3 * sqliteHandle() const noexcept override
Return the SQLite handle.
void upsertAnnual(const std::shared_ptr< core::domain::Annual > &annual) override
Insert or update an annual entry.
std::optional< std::shared_ptr< core::domain::Annual > > getAnnualById(const std::string &id) const override
Retrieve an annual entry by identifier.
void addAnnual(const std::shared_ptr< core::domain::Annual > &annual) override
Insert a new annual entry.
std::vector< std::shared_ptr< core::domain::Annual > > getAnnuals() const override
Retrieve all annual entries.
void updateAnnual(const std::shared_ptr< core::domain::Annual > &annual) override
Update an existing annual entry.
std::string columnText(int col) const noexcept
Definition StmtGuard.h:57
void bindInt(int col, int v) noexcept
Definition StmtGuard.h:47
int step() noexcept
Definition StmtGuard.h:37
void bindText(int col, const std::string &v) noexcept
Definition StmtGuard.h:44
int columnInt(int col) const noexcept
Definition StmtGuard.h:61
std::shared_ptr< SqliteDb > db