17std::vector<std::string> loadAnalysisIds(sqlite3* db,
18 const std::string& annualId) {
19 std::vector<std::string> out;
20 if (!db || annualId.empty()) {
25 "WHERE annual_id = ? ORDER BY position;");
30 stmt.bindText(1, annualId);
31 while (stmt.step() == SQLITE_ROW) {
32 out.push_back(stmt.columnText(0));
37constexpr auto kSelectAnnual =
38 "SELECT id, name, year, created_at, updated_at FROM annuals";
40void saveAnalysisIds(sqlite3* db,
const std::string& annualId,
41 const std::vector<std::string>& analysisIds) {
42 if (!db || annualId.empty()) {
47 db,
"DELETE FROM annual_analyses WHERE annual_id = ?;");
51 deleteStmt.bindText(1, annualId);
55 db,
"INSERT OR IGNORE INTO annual_analyses (annual_id, analysis_id, "
56 "position) VALUES (?, ?, ?);");
61 for (std::size_t index = 0; index < analysisIds.size(); ++index) {
62 if (analysisIds[index].empty()) {
66 insertStmt.bindText(1, annualId);
67 insertStmt.bindText(2, analysisIds[index]);
68 insertStmt.bindInt(3,
static_cast<int>(index));
74 auto a = std::make_shared<Annual>();
80 a->setAnalysisIds(loadAnalysisIds(db, a->id()));
87 std::shared_ptr<SqliteDb>
db;
94 : pimpl_(std::make_unique<
Impl>()) {
96 throw std::runtime_error(
"db is null");
99 pimpl_->db = std::move(db);
105 if (!annual || annual->id().empty()) {
110 "INSERT OR IGNORE INTO annuals"
111 " (id, name, year, created_at, updated_at)"
112 " VALUES (?, ?, ?, ?, ?);");
118 stmt.
bindInt(3, annual->year());
119 stmt.
bindText(4, annual->createdAt());
120 stmt.
bindText(5, annual->updatedAt());
122 saveAnalysisIds(pimpl_->db->handle(), annual->id(), annual->analysisIds());
125std::vector<std::shared_ptr<Annual>>
127 std::vector<std::shared_ptr<Annual>> out;
129 std::string(kSelectAnnual) +
" ORDER BY year;");
134 while (stmt.
step() == SQLITE_ROW) {
135 out.push_back(readAnnual(pimpl_->db->handle(), stmt));
140std::optional<std::shared_ptr<Annual>>
143 std::string(kSelectAnnual) +
144 " WHERE id = ? LIMIT 1;");
150 if (stmt.
step() != SQLITE_ROW) {
153 return readAnnual(pimpl_->db->handle(), stmt);
158 "DELETE FROM annuals WHERE id = ?;");
168 const std::shared_ptr<Annual>& annual) {
169 if (!annual || annual->id().empty()) {
174 "UPDATE annuals SET name=?, year=?, "
175 "created_at=?, updated_at=? WHERE id=?;");
180 stmt.
bindInt(2, annual->year());
181 stmt.
bindText(3, annual->createdAt());
182 stmt.
bindText(4, annual->updatedAt());
185 saveAnalysisIds(pimpl_->db->handle(), annual->id(), annual->analysisIds());
189 const std::shared_ptr<Annual>& annual) {
190 if (!annual || annual->id().empty()) {
195 if (sqlite3_changes(pimpl_->db->handle()) == 0) {
202 sqlite3_exec(pimpl_->db->handle(),
"DELETE FROM annuals;",
nullptr,
nullptr,
210 return pimpl_ && pimpl_->db ? pimpl_->db->handle() :
nullptr;
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
void bindInt(int col, int v) noexcept
void bindText(int col, const std::string &v) noexcept
int columnInt(int col) const noexcept
std::shared_ptr< SqliteDb > db