FOSSredder 0.5.0
Loading...
Searching...
No Matches
SqliteSchema.cpp
Go to the documentation of this file.
1
5
7
8#include <sqlite3.h>
9
10#include <stdexcept>
11#include <string>
12
13static void exec(sqlite3* db, const char* sql) {
14 char* err = nullptr;
15 if (sqlite3_exec(db, sql, nullptr, nullptr, &err) != SQLITE_OK) {
16 std::string message = err ? err : "unknown";
17 if (err) {
18 sqlite3_free(err);
19 }
20 throw std::runtime_error(message);
21 }
22}
23
24int SqliteSchema::getUserVersion(sqlite3* db) {
25 sqlite3_stmt* stmt = nullptr;
26 if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &stmt, nullptr) !=
27 SQLITE_OK) {
28 return 0;
29 }
30
31 int version = 0;
32 if (sqlite3_step(stmt) == SQLITE_ROW) {
33 version = sqlite3_column_int(stmt, 0);
34 }
35
36 sqlite3_finalize(stmt);
37 return version;
38}
39
40void SqliteSchema::setUserVersion(sqlite3* db, int v) {
41 exec(db, (std::string("PRAGMA user_version = ") + std::to_string(v) + ";")
42 .c_str());
43}
44
45void SqliteSchema::ensure(sqlite3* db) {
46 if (!db) {
47 throw std::runtime_error("db is null");
48 }
49
50 exec(db, "PRAGMA foreign_keys = ON;");
51 migrate(db);
52}
53
54void SqliteSchema::migrate(sqlite3* db) {
55 const int version = getUserVersion(db);
56 exec(
57 db,
58 "BEGIN;"
59 "CREATE TABLE IF NOT EXISTS configs (name TEXT PRIMARY KEY, value TEXT);"
60 "CREATE TABLE IF NOT EXISTS actors ("
61 "id TEXT PRIMARY KEY,"
62 "name TEXT NOT NULL UNIQUE,"
63 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
64 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
65 ");"
66 "CREATE TABLE IF NOT EXISTS actor_aliases ("
67 "actor_id TEXT NOT NULL,"
68 "alias TEXT NOT NULL,"
69 "hit_count INTEGER NOT NULL DEFAULT 1,"
70 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
71 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
72 "last_used_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
73 "PRIMARY KEY(actor_id, alias),"
74 "FOREIGN KEY(actor_id) REFERENCES actors(id) ON DELETE CASCADE"
75 ");"
76 "CREATE TABLE IF NOT EXISTS properties ("
77 "id TEXT PRIMARY KEY,"
78 "name TEXT NOT NULL UNIQUE,"
79 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
80 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
81 ");"
82 "CREATE TABLE IF NOT EXISTS property_aliases ("
83 "property_id TEXT NOT NULL,"
84 "alias TEXT NOT NULL,"
85 "hit_count INTEGER NOT NULL DEFAULT 1,"
86 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
87 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
88 "last_used_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
89 "PRIMARY KEY(property_id, alias),"
90 "FOREIGN KEY(property_id) REFERENCES properties(id) ON DELETE CASCADE"
91 ");"
92 "CREATE TABLE IF NOT EXISTS contracts ("
93 "id TEXT PRIMARY KEY,"
94 "name TEXT NOT NULL,"
95 "type TEXT NOT NULL DEFAULT '',"
96 "allocatable_mode TEXT NOT NULL DEFAULT 'mixed',"
97 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
98 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
99 ");"
100 "CREATE TABLE IF NOT EXISTS contract_aliases ("
101 "contract_id TEXT NOT NULL,"
102 "alias TEXT NOT NULL,"
103 "hit_count INTEGER NOT NULL DEFAULT 1,"
104 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
105 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
106 "last_used_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
107 "PRIMARY KEY(contract_id, alias),"
108 "FOREIGN KEY(contract_id) REFERENCES contracts(id) ON DELETE CASCADE"
109 ");"
110 "CREATE TABLE IF NOT EXISTS contract_actors ("
111 "contract_id TEXT NOT NULL,"
112 "actor_id TEXT NOT NULL,"
113 "PRIMARY KEY(contract_id, actor_id),"
114 "FOREIGN KEY(contract_id) REFERENCES contracts(id) ON DELETE CASCADE,"
115 "FOREIGN KEY(actor_id) REFERENCES actors(id) ON DELETE CASCADE"
116 ");"
117 "CREATE TABLE IF NOT EXISTS contract_properties ("
118 "contract_id TEXT NOT NULL,"
119 "property_id TEXT NOT NULL,"
120 "PRIMARY KEY(contract_id, property_id),"
121 "FOREIGN KEY(contract_id) REFERENCES contracts(id) ON DELETE CASCADE,"
122 "FOREIGN KEY(property_id) REFERENCES properties(id) ON DELETE CASCADE"
123 ");"
124 "CREATE TABLE IF NOT EXISTS statements ("
125 "id TEXT PRIMARY KEY,"
126 "name TEXT NOT NULL DEFAULT '',"
127 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
128 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
129 ");"
130 "CREATE TABLE IF NOT EXISTS statement_transactions ("
131 "statement_id TEXT NOT NULL,"
132 "transaction_id TEXT NOT NULL,"
133 "position INTEGER NOT NULL DEFAULT 0,"
134 "PRIMARY KEY(statement_id, transaction_id),"
135 "FOREIGN KEY(statement_id) REFERENCES statements(id) ON DELETE CASCADE,"
136 "FOREIGN KEY(transaction_id) REFERENCES transactions(id) ON DELETE "
137 "CASCADE"
138 ");"
139 "CREATE TABLE IF NOT EXISTS statement_drafts ("
140 "id TEXT PRIMARY KEY,"
141 "name TEXT NOT NULL DEFAULT '',"
142 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
143 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
144 ");"
145 "CREATE TABLE IF NOT EXISTS statement_draft_transactions ("
146 "statement_draft_id TEXT NOT NULL,"
147 "transaction_draft_id TEXT NOT NULL,"
148 "position INTEGER NOT NULL DEFAULT 0,"
149 "PRIMARY KEY(statement_draft_id, transaction_draft_id),"
150 "FOREIGN KEY(statement_draft_id) REFERENCES statement_drafts(id) ON "
151 "DELETE CASCADE,"
152 "FOREIGN KEY(transaction_draft_id) REFERENCES transaction_drafts(id) ON "
153 "DELETE CASCADE"
154 ");"
155 "CREATE TABLE IF NOT EXISTS transaction_drafts ("
156 "id TEXT PRIMARY KEY,"
157 "statement_draft_id TEXT,"
158 "position INTEGER NOT NULL DEFAULT 0,"
159 "name TEXT NOT NULL DEFAULT '',"
160 "booking_date TEXT NOT NULL DEFAULT '',"
161 "valuta TEXT NOT NULL DEFAULT '',"
162 "amount REAL NOT NULL DEFAULT 0,"
163 "actor_text TEXT NOT NULL DEFAULT '',"
164 "property_text TEXT NOT NULL DEFAULT '',"
165 "actor_id TEXT NOT NULL DEFAULT '',"
166 "actor_selected INTEGER NOT NULL DEFAULT 0,"
167 "contract_id TEXT NOT NULL DEFAULT '',"
168 "contract_selected INTEGER NOT NULL DEFAULT 0,"
169 "metadata TEXT NOT NULL DEFAULT '',"
170 "proof_image_data BLOB,"
171 "type TEXT NOT NULL DEFAULT '',"
172 "allocatable INTEGER NOT NULL DEFAULT 0,"
173 "allocatable_selected INTEGER NOT NULL DEFAULT 0,"
174 "status INTEGER NOT NULL DEFAULT 1,"
175 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
176 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
177 "FOREIGN KEY(statement_draft_id) REFERENCES statement_drafts(id) ON "
178 "DELETE CASCADE"
179 ");"
180 "CREATE TABLE IF NOT EXISTS transaction_draft_properties ("
181 "transaction_draft_id TEXT NOT NULL,"
182 "property_position INTEGER NOT NULL,"
183 "property_id TEXT NOT NULL,"
184 "PRIMARY KEY(transaction_draft_id, property_position),"
185 "FOREIGN KEY(transaction_draft_id) REFERENCES transaction_drafts(id) ON "
186 "DELETE CASCADE"
187 ");"
188 "CREATE TABLE IF NOT EXISTS transactions ("
189 "id TEXT PRIMARY KEY,"
190 "name TEXT NOT NULL DEFAULT '',"
191 "booking_date TEXT NOT NULL DEFAULT '',"
192 "amount REAL NOT NULL DEFAULT 0,"
193 "statement_id TEXT,"
194 "status INTEGER NOT NULL DEFAULT 0,"
195 "actor_id TEXT,"
196 "contract_id TEXT,"
197 "valuta TEXT NOT NULL DEFAULT '',"
198 "allocatable INTEGER NOT NULL DEFAULT 0,"
199 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
200 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
201 "FOREIGN KEY(actor_id) REFERENCES actors(id) ON DELETE SET NULL,"
202 "FOREIGN KEY(contract_id) REFERENCES contracts(id) ON DELETE SET NULL,"
203 "FOREIGN KEY(statement_id) REFERENCES statements(id) ON DELETE CASCADE"
204 ");"
205 "CREATE TABLE IF NOT EXISTS transaction_properties ("
206 "transaction_id TEXT NOT NULL,"
207 "property_id TEXT NOT NULL,"
208 "PRIMARY KEY(transaction_id, property_id),"
209 "FOREIGN KEY(transaction_id) REFERENCES transactions(id) ON DELETE "
210 "CASCADE,"
211 "FOREIGN KEY(property_id) REFERENCES properties(id) ON DELETE CASCADE"
212 ");"
213 "CREATE TABLE IF NOT EXISTS analyses ("
214 "id TEXT PRIMARY KEY,"
215 "name TEXT NOT NULL DEFAULT '',"
216 "type TEXT NOT NULL DEFAULT '',"
217 "config_json TEXT NOT NULL DEFAULT '',"
218 "filter_spec TEXT NOT NULL DEFAULT '',"
219 "export_format TEXT NOT NULL DEFAULT '',"
220 "include_calc_adjustments INTEGER NOT NULL DEFAULT 1,"
221 "export_state_json TEXT NOT NULL DEFAULT '{}',"
222 "snapshot_transactions_json TEXT NOT NULL DEFAULT '{}',"
223 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
224 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
225 ");"
226 "CREATE TABLE IF NOT EXISTS analysis_adjustments ("
227 "analysis_id TEXT NOT NULL,"
228 "adjustment_key TEXT NOT NULL,"
229 "adjustment_value REAL NOT NULL DEFAULT 0,"
230 "position INTEGER NOT NULL DEFAULT 0,"
231 "PRIMARY KEY(analysis_id, adjustment_key),"
232 "FOREIGN KEY(analysis_id) REFERENCES analyses(id) ON DELETE CASCADE"
233 ");"
234 "CREATE TABLE IF NOT EXISTS annuals ("
235 "id TEXT PRIMARY KEY,"
236 "name TEXT NOT NULL DEFAULT '',"
237 "year INTEGER NOT NULL DEFAULT 0,"
238 "created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
239 "updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
240 ");"
241 "CREATE TABLE IF NOT EXISTS annual_analyses ("
242 "annual_id TEXT NOT NULL,"
243 "analysis_id TEXT NOT NULL,"
244 "position INTEGER NOT NULL DEFAULT 0,"
245 "PRIMARY KEY(annual_id, analysis_id),"
246 "FOREIGN KEY(annual_id) REFERENCES annuals(id) ON DELETE CASCADE,"
247 "FOREIGN KEY(analysis_id) REFERENCES analyses(id) ON DELETE CASCADE"
248 ");"
249 "CREATE TABLE IF NOT EXISTS import_logs ("
250 "id TEXT PRIMARY KEY,"
251 "time TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
252 "type TEXT NOT NULL DEFAULT '',"
253 "file TEXT NOT NULL DEFAULT '',"
254 "status TEXT NOT NULL DEFAULT '',"
255 "message TEXT NOT NULL DEFAULT '',"
256 "draft_attached INTEGER NOT NULL DEFAULT 0,"
257 "draft_id TEXT NOT NULL DEFAULT '',"
258 "statement_id TEXT NOT NULL DEFAULT ''"
259 ");"
260 "CREATE TABLE IF NOT EXISTS import_log_statement_drafts ("
261 "import_log_id TEXT NOT NULL,"
262 "statement_draft_id TEXT NOT NULL,"
263 "position INTEGER NOT NULL DEFAULT 0,"
264 "PRIMARY KEY(import_log_id, statement_draft_id),"
265 "FOREIGN KEY(import_log_id) REFERENCES import_logs(id) ON DELETE CASCADE,"
266 "FOREIGN KEY(statement_draft_id) REFERENCES statement_drafts(id) ON "
267 "DELETE CASCADE"
268 ");"
269 "CREATE TABLE IF NOT EXISTS export_logs ("
270 "id TEXT PRIMARY KEY,"
271 "time TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,"
272 "target_path TEXT NOT NULL DEFAULT '',"
273 "status TEXT NOT NULL DEFAULT '',"
274 "message TEXT NOT NULL DEFAULT '',"
275 "payload TEXT NOT NULL DEFAULT ''"
276 ");"
277 "CREATE TABLE IF NOT EXISTS export_log_annuals ("
278 "export_log_id TEXT NOT NULL,"
279 "annual_id TEXT NOT NULL,"
280 "position INTEGER NOT NULL DEFAULT 0,"
281 "PRIMARY KEY(export_log_id, annual_id),"
282 "FOREIGN KEY(export_log_id) REFERENCES export_logs(id) ON DELETE CASCADE,"
283 "FOREIGN KEY(annual_id) REFERENCES annuals(id) ON DELETE CASCADE"
284 ");"
285 "CREATE TABLE IF NOT EXISTS export_log_analyses ("
286 "export_log_id TEXT NOT NULL,"
287 "analysis_id TEXT NOT NULL,"
288 "position INTEGER NOT NULL DEFAULT 0,"
289 "PRIMARY KEY(export_log_id, analysis_id),"
290 "FOREIGN KEY(export_log_id) REFERENCES export_logs(id) ON DELETE CASCADE,"
291 "FOREIGN KEY(analysis_id) REFERENCES analyses(id) ON DELETE CASCADE"
292 ");"
293 "CREATE INDEX IF NOT EXISTS idx_transactions_contract_id ON "
294 "transactions(contract_id);"
295 "CREATE INDEX IF NOT EXISTS idx_contract_actors_actor_id ON "
296 "contract_actors(actor_id);"
297 "CREATE INDEX IF NOT EXISTS idx_contract_properties_property_id ON "
298 "contract_properties(property_id);"
299 "CREATE INDEX IF NOT EXISTS idx_transaction_properties_property_id ON "
300 "transaction_properties(property_id);"
301 "CREATE INDEX IF NOT EXISTS idx_statement_transactions_transaction_id ON "
302 "statement_transactions(transaction_id);"
303 "CREATE INDEX IF NOT EXISTS "
304 "idx_statement_draft_transactions_transaction_draft_id ON "
305 "statement_draft_transactions(transaction_draft_id);"
306 "CREATE INDEX IF NOT EXISTS idx_actor_aliases_alias ON "
307 "actor_aliases(alias);"
308 "CREATE INDEX IF NOT EXISTS idx_property_aliases_alias ON "
309 "property_aliases(alias);"
310 "CREATE INDEX IF NOT EXISTS idx_contract_aliases_alias ON "
311 "contract_aliases(alias);"
312 "CREATE INDEX IF NOT EXISTS idx_import_logs_time ON import_logs(time "
313 "DESC);"
314 "CREATE INDEX IF NOT EXISTS idx_export_logs_time ON export_logs(time "
315 "DESC);"
316 "CREATE INDEX IF NOT EXISTS idx_analysis_adjustments_analysis_id ON "
317 "analysis_adjustments(analysis_id);"
318 "CREATE INDEX IF NOT EXISTS idx_annual_analyses_analysis_id ON "
319 "annual_analyses(analysis_id);"
320 "CREATE INDEX IF NOT EXISTS "
321 "idx_import_log_statement_drafts_statement_draft_id ON "
322 "import_log_statement_drafts(statement_draft_id);"
323 "CREATE INDEX IF NOT EXISTS idx_export_log_annuals_annual_id ON "
324 "export_log_annuals(annual_id);"
325 "CREATE INDEX IF NOT EXISTS idx_export_log_analyses_analysis_id ON "
326 "export_log_analyses(analysis_id);"
327 "COMMIT;");
328
329 if (version >= 1 && version < 2) {
330 exec(db, "ALTER TABLE contracts ADD COLUMN allocatable_mode TEXT NOT NULL "
331 "DEFAULT 'mixed';");
332 setUserVersion(db, 2);
333 } else if (version < 1) {
334 setUserVersion(db, 2);
335 }
336}
static void exec(sqlite3 *db, const char *sql)
Declares schema initialization and migration helpers for SQLite.
static void migrate(sqlite3 *db)
Run schema migrations for the database.
static void ensure(sqlite3 *db)
Ensure the database schema exists and is migrated.