FOSSredder 0.5.0
Loading...
Searching...
No Matches
SqliteTransactionDraftRepository.cpp
Go to the documentation of this file.
1
5
7
11#include "persistence/Uuid.h"
12
13#include <sqlite3.h>
14
15#include <stdexcept>
16#include <utility>
17
18namespace {
19
20void bindNullableText(persistence::StmtGuard& stmt, int column,
21 const std::string& value) {
22 if (value.empty()) {
23 sqlite3_bind_null(stmt.get(), column);
24 return;
25 }
26 stmt.bindText(column, value);
27}
28
29void bindNullableBlob(persistence::StmtGuard& stmt, int column,
30 const std::vector<uint8_t>& value) {
31 if (value.empty()) {
32 sqlite3_bind_null(stmt.get(), column);
33 return;
34 }
35 sqlite3_bind_blob(stmt.get(), column, value.data(),
36 static_cast<int>(value.size()), SQLITE_TRANSIENT);
37}
38
39int nextTransactionDraftPosition(sqlite3* db) {
40 if (!db) {
41 return 0;
42 }
43
45 db, "SELECT COALESCE(MAX(position), -1) + 1 FROM transaction_drafts;");
46 if (!stmt) {
47 return 0;
48 }
49 if (stmt.step() != SQLITE_ROW) {
50 return 0;
51 }
52
53 return stmt.columnInt(0);
54}
55
56void removeTransactionDraftProperties(sqlite3* db, const std::string& id) {
57 persistence::StmtGuard stmt(db, "DELETE FROM transaction_draft_properties "
58 "WHERE transaction_draft_id = ?;");
59 if (!stmt) {
60 return;
61 }
62
63 stmt.bindText(1, id);
64 stmt.step();
65}
66
67void upsertTransactionDraftProperties(
68 sqlite3* db,
71 db, "INSERT OR REPLACE INTO transaction_draft_properties "
72 "(transaction_draft_id, property_position, property_id) VALUES (?, "
73 "?, ?);");
74 if (!stmt) {
75 return;
76 }
77
78 for (std::size_t propertyIndex = 0; propertyIndex < draft.propertyIds.size();
79 ++propertyIndex) {
80 const auto& propertyId = draft.propertyIds[propertyIndex];
81 if (propertyId.empty()) {
82 continue;
83 }
84
85 stmt.reset();
86 stmt.bindText(1, draft.id);
87 stmt.bindInt(2, static_cast<int>(propertyIndex));
88 stmt.bindText(3, propertyId);
89 stmt.step();
90 }
91}
92
93void writeTransactionDraft(
94 sqlite3* db,
95 const std::shared_ptr<
97 const char* sql, bool autoPosition) {
98 if (!db || !draft) {
99 return;
100 }
101
102 if (draft->id.empty()) {
103 draft->id = persistence::generateUuid();
104 }
105 if (autoPosition && draft->position < 0) {
106 draft->position = nextTransactionDraftPosition(db);
107 }
108
109 persistence::StmtGuard stmt(db, sql);
110 if (!stmt) {
111 return;
112 }
113
114 stmt.bindText(1, draft->id);
115 bindNullableText(stmt, 2, draft->statementDraftId);
116 stmt.bindInt(3, draft->position);
117 stmt.bindText(4, draft->name);
118 stmt.bindText(5, draft->bookingDate);
119 stmt.bindText(6, draft->valuta);
120 stmt.bindDouble(7, draft->amount);
121 stmt.bindText(8, draft->actorText);
122 stmt.bindText(9, draft->propertyText);
123 bindNullableText(stmt, 10, draft->actorId);
124 stmt.bindInt(11, draft->actorSelected ? 1 : 0);
125 bindNullableText(stmt, 12, draft->contractId);
126 stmt.bindInt(13, draft->contractSelected ? 1 : 0);
127 stmt.bindText(14, draft->metadata);
128 bindNullableBlob(stmt, 15, draft->proofImageData);
129 stmt.bindText(16, draft->type);
130 stmt.bindInt(17, draft->allocatable ? 1 : 0);
131 stmt.bindInt(18, draft->allocatableSelected ? 1 : 0);
132 stmt.bindInt(19, static_cast<int>(draft->status));
133 stmt.bindText(20, draft->createdAt);
134 stmt.bindText(21, draft->updatedAt);
135 stmt.step();
136
137 removeTransactionDraftProperties(db, draft->id);
138 upsertTransactionDraftProperties(db, *draft);
139}
140
141std::shared_ptr<core::application::importing::draft::TransactionDraft>
142readDraftRow(sqlite3* db, persistence::StmtGuard& stmt) {
143 auto draft =
144 std::make_shared<core::application::importing::draft::TransactionDraft>();
145 draft->id = stmt.columnText(0);
146 draft->statementDraftId = stmt.columnText(1);
147 draft->position = stmt.columnInt(2);
148 draft->name = stmt.columnText(3);
149 draft->bookingDate = stmt.columnText(4);
150 draft->valuta = stmt.columnText(5);
151 draft->amount = stmt.columnDouble(6);
152 draft->actorText = stmt.columnText(7);
153 draft->propertyText = stmt.columnText(8);
154 draft->actorId = stmt.columnText(9);
155 draft->actorSelected = stmt.columnInt(10) != 0;
156 draft->contractId = stmt.columnText(11);
157 draft->contractSelected = stmt.columnInt(12) != 0;
158 draft->metadata = stmt.columnText(13);
159 const auto* blob =
160 static_cast<const uint8_t*>(sqlite3_column_blob(stmt.get(), 14));
161 const int blobSize = sqlite3_column_bytes(stmt.get(), 14);
162 if (blob && blobSize > 0) {
163 draft->proofImageData.assign(blob, blob + blobSize);
164 }
165 draft->type = stmt.columnText(15);
166 draft->allocatable = stmt.columnInt(16) != 0;
167 draft->allocatableSelected = stmt.columnInt(17) != 0;
168 draft->status =
169 static_cast<core::domain::Transaction::Status>(stmt.columnInt(18));
170 draft->createdAt = stmt.columnText(19);
171 draft->updatedAt = stmt.columnText(20);
172
173 persistence::StmtGuard properties(
174 db, "SELECT property_id FROM transaction_draft_properties WHERE "
175 "transaction_draft_id = ? ORDER BY property_position;");
176 if (properties) {
177 properties.bindText(1, draft->id);
178 while (properties.step() == SQLITE_ROW) {
179 draft->propertyIds.push_back(properties.columnText(0));
180 }
181 }
182
183 return draft;
184}
185
186} // namespace
187
189 explicit Impl(std::shared_ptr<SqliteDb> db) : db(std::move(db)) {}
190
191 std::shared_ptr<SqliteDb> db;
192};
193
197
199 std::shared_ptr<SqliteDb> db)
200 : pimpl_(std::make_unique<Impl>(std::move(db))) {
201 if (!pimpl_->db) {
202 throw std::runtime_error("db is null");
203 }
204}
205
207
209 const std::shared_ptr<
211 const auto db = pimpl_->db->handle();
212 writeTransactionDraft(
213 db, draft,
214 "INSERT INTO transaction_drafts (id, statement_draft_id, position, name, "
215 "booking_date, valuta, amount, actor_text, property_text, actor_id, "
216 "actor_selected, contract_id, contract_selected, metadata, "
217 "proof_image_data, type, allocatable, allocatable_selected, status, "
218 "created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
219 "?, ?, ?, ?, ?, ?, ?, ?);",
220 true);
221}
222
223std::vector<
224 std::shared_ptr<core::application::importing::draft::TransactionDraft>>
226 std::vector<
227 std::shared_ptr<core::application::importing::draft::TransactionDraft>>
228 drafts;
229 const auto db = pimpl_->db->handle();
230
232 db,
233 "SELECT id, statement_draft_id, position, name, booking_date, valuta, "
234 "amount, actor_text, property_text, actor_id, actor_selected, "
235 "contract_id, contract_selected, metadata, proof_image_data, type, "
236 "allocatable, allocatable_selected, status, created_at, updated_at FROM "
237 "transaction_drafts ORDER BY statement_draft_id, position, id;");
238 if (!stmt) {
239 return drafts;
240 }
241
242 while (stmt.step() == SQLITE_ROW) {
243 drafts.push_back(readDraftRow(db, stmt));
244 }
245
246 return drafts;
247}
248
249std::optional<
250 std::shared_ptr<core::application::importing::draft::TransactionDraft>>
252 const std::string& id) const {
253 const auto db = pimpl_->db->handle();
255 db,
256 "SELECT id, statement_draft_id, position, name, booking_date, valuta, "
257 "amount, actor_text, property_text, actor_id, actor_selected, "
258 "contract_id, contract_selected, metadata, proof_image_data, type, "
259 "allocatable, allocatable_selected, status, created_at, updated_at FROM "
260 "transaction_drafts WHERE id = ? LIMIT 1;");
261 if (!stmt) {
262 return std::nullopt;
263 }
264
265 stmt.bindText(1, id);
266 if (stmt.step() != SQLITE_ROW) {
267 return std::nullopt;
268 }
269
270 return readDraftRow(db, stmt);
271}
272
274 const std::string& id) {
275 const auto db = pimpl_->db->handle();
276 removeTransactionDraftProperties(db, id);
277
279 "DELETE FROM transaction_drafts WHERE id = ?;");
280 if (!stmt) {
281 return;
282 }
283 stmt.bindText(1, id);
284 stmt.step();
285}
286
288 const std::shared_ptr<
290 const auto db = pimpl_->db->handle();
291 writeTransactionDraft(
292 db, draft,
293 "UPDATE transaction_drafts SET statement_draft_id = ?2, position = ?3, "
294 "name = ?4, booking_date = ?5, valuta = ?6, amount = ?7, actor_text = "
295 "?8, property_text = ?9, actor_id = ?10, actor_selected = ?11, "
296 "contract_id = ?12, contract_selected = ?13, metadata = ?14, "
297 "proof_image_data = ?15, type = ?16, allocatable = ?17, "
298 "allocatable_selected = ?18, status = ?19, created_at = ?20, updated_at "
299 "= ?21 WHERE id = ?1;",
300 false);
301}
302
304 const std::shared_ptr<
306 const auto db = pimpl_->db->handle();
307 writeTransactionDraft(
308 db, draft,
309 "INSERT OR REPLACE INTO transaction_drafts (id, statement_draft_id, "
310 "position, name, booking_date, valuta, amount, actor_text, "
311 "property_text, actor_id, actor_selected, contract_id, "
312 "contract_selected, metadata, proof_image_data, type, allocatable, "
313 "allocatable_selected, status, created_at, updated_at) VALUES (?, ?, ?, "
314 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
315 true);
316}
317
319 const auto db = pimpl_->db->handle();
320
321 persistence::StmtGuard deleteProperties(
322 db, "DELETE FROM transaction_draft_properties;");
323 if (deleteProperties) {
324 deleteProperties.step();
325 }
326
327 persistence::StmtGuard deleteDrafts(db, "DELETE FROM transaction_drafts;");
328 if (deleteDrafts) {
329 deleteDrafts.step();
330 }
331}
Declares the lightweight SQLite connection wrapper.
Declares the SQLite-backed transaction draft repository.
RAII wrapper for sqlite3_stmt* that auto-finalizes on destruction.
Draft transaction model used by import finalization and core application flow.
std::vector< std::shared_ptr< core::application::importing::draft::TransactionDraft > > getTransactionDrafts() const override
Retrieve all transaction drafts.
void updateTransactionDraft(const std::shared_ptr< core::application::importing::draft::TransactionDraft > &draft) override
Update an existing transaction draft.
SqliteTransactionDraftRepository(const std::string &dbPath)
Create a transaction draft repository for the database at the given path.
void upsertTransactionDraft(const std::shared_ptr< core::application::importing::draft::TransactionDraft > &draft) override
Insert or update a transaction draft.
~SqliteTransactionDraftRepository() override
Destroy the repository.
void clearTransactionDrafts() override
Remove all transaction drafts.
void addTransactionDraft(const std::shared_ptr< core::application::importing::draft::TransactionDraft > &draft) override
Insert a new transaction draft.
std::optional< std::shared_ptr< core::application::importing::draft::TransactionDraft > > getTransactionDraftById(const std::string &id) const override
Retrieve a transaction draft by identifier.
void removeTransactionDraft(const std::string &id) override
Remove a transaction draft by identifier.
std::string columnText(int col) const noexcept
Definition StmtGuard.h:57
sqlite3_stmt * get() const noexcept
Definition StmtGuard.h:33
void bindInt(int col, int v) noexcept
Definition StmtGuard.h:47
double columnDouble(int col) const noexcept
Definition StmtGuard.h:67
int step() noexcept
Definition StmtGuard.h:37
void reset() noexcept
Definition StmtGuard.h:40
void bindText(int col, const std::string &v) noexcept
Definition StmtGuard.h:44
int columnInt(int col) const noexcept
Definition StmtGuard.h:61
void bindDouble(int col, double v) noexcept
Definition StmtGuard.h:53
std::string generateUuid()
Definition Uuid.h:9