13static void exec(sqlite3* db,
const char* sql) {
15 if (sqlite3_exec(db, sql,
nullptr,
nullptr, &err) != SQLITE_OK) {
16 std::string message = err ? err :
"unknown";
20 throw std::runtime_error(message);
24int SqliteSchema::getUserVersion(sqlite3* db) {
25 sqlite3_stmt* stmt =
nullptr;
26 if (sqlite3_prepare_v2(db,
"PRAGMA user_version;", -1, &stmt,
nullptr) !=
32 if (sqlite3_step(stmt) == SQLITE_ROW) {
33 version = sqlite3_column_int(stmt, 0);
36 sqlite3_finalize(stmt);
40void SqliteSchema::setUserVersion(sqlite3* db,
int v) {
41 exec(db, (std::string(
"PRAGMA user_version = ") + std::to_string(v) +
";")
47 throw std::runtime_error(
"db is null");
50 exec(db,
"PRAGMA foreign_keys = ON;");
55 const int version = getUserVersion(db);
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"
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"
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"
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"
92 "CREATE TABLE IF NOT EXISTS contracts ("
93 "id TEXT PRIMARY KEY,"
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"
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"
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"
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"
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"
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 "
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"
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 "
152 "FOREIGN KEY(transaction_draft_id) REFERENCES transaction_drafts(id) ON "
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 "
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 "
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,"
194 "status INTEGER NOT NULL DEFAULT 0,"
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"
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 "
211 "FOREIGN KEY(property_id) REFERENCES properties(id) ON DELETE CASCADE"
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"
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"
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"
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"
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 ''"
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 "
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 ''"
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"
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"
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 "
314 "CREATE INDEX IF NOT EXISTS idx_export_logs_time ON export_logs(time "
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);"
329 if (version >= 1 && version < 2) {
330 exec(db,
"ALTER TABLE contracts ADD COLUMN allocatable_mode TEXT NOT NULL "
332 setUserVersion(db, 2);
333 }
else if (version < 1) {
334 setUserVersion(db, 2);
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.