PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
pacs_database_adapter.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
23#pragma once
24
25#include <kcenon/common/patterns/result.h>
26
27#include <chrono>
28#include <cstdint>
29#include <filesystem>
30#include <functional>
31#include <map>
32#include <memory>
33#include <string>
34#include <vector>
35
36#ifdef PACS_WITH_DATABASE_SYSTEM
37#include <database/database_types.h>
38#include <database/integrated/unified_database_system.h>
39#include <database/query_builder.h>
40#endif
41
42namespace kcenon::pacs::storage {
43
45template <typename T>
47
49using VoidResult = kcenon::common::VoidResult;
50
51#ifdef PACS_WITH_DATABASE_SYSTEM
52
59using database_row = std::map<std::string, std::string>;
60
67struct database_result {
69 std::vector<database_row> rows;
70
72 std::size_t affected_rows{0};
73
75 std::chrono::microseconds execution_time{0};
76
78 [[nodiscard]] auto empty() const noexcept -> bool { return rows.empty(); }
79
81 [[nodiscard]] auto size() const noexcept -> std::size_t {
82 return rows.size();
83 }
84
86 [[nodiscard]] auto operator[](std::size_t index) const
87 -> const database_row& {
88 return rows.at(index);
89 }
90
92 [[nodiscard]] auto operator[](std::size_t index) -> database_row& {
93 return rows.at(index);
94 }
95
96 // Iterator support
97 auto begin() { return rows.begin(); }
98 auto end() { return rows.end(); }
99 [[nodiscard]] auto begin() const { return rows.begin(); }
100 [[nodiscard]] auto end() const { return rows.end(); }
101};
102
103// Forward declaration
104class scoped_transaction;
105class pacs_database_adapter;
106class pacs_unit_of_work;
107
114class pacs_storage_session {
115public:
116 explicit pacs_storage_session(pacs_database_adapter& adapter) noexcept;
117
118 [[nodiscard]] auto create_query_builder() const -> database::query_builder;
119 [[nodiscard]] auto select(const std::string& query)
120 -> Result<database_result>;
121 [[nodiscard]] auto insert(const std::string& query) -> Result<uint64_t>;
122 [[nodiscard]] auto update(const std::string& query) -> Result<uint64_t>;
123 [[nodiscard]] auto remove(const std::string& query) -> Result<uint64_t>;
124 [[nodiscard]] auto execute(const std::string& query) -> VoidResult;
125 [[nodiscard]] auto last_insert_rowid() const -> int64_t;
126 [[nodiscard]] auto begin_unit_of_work() -> Result<pacs_unit_of_work>;
127
128private:
129 pacs_database_adapter* adapter_{nullptr};
130};
131
135class pacs_unit_of_work {
136public:
137 pacs_unit_of_work() = default;
138 pacs_unit_of_work(pacs_database_adapter& adapter, bool active) noexcept;
139 ~pacs_unit_of_work();
140
141 pacs_unit_of_work(const pacs_unit_of_work&) = delete;
142 auto operator=(const pacs_unit_of_work&) -> pacs_unit_of_work& = delete;
143 pacs_unit_of_work(pacs_unit_of_work&& other) noexcept;
144 auto operator=(pacs_unit_of_work&& other) noexcept -> pacs_unit_of_work&;
145
146 [[nodiscard]] auto create_query_builder() const -> database::query_builder;
147 [[nodiscard]] auto select(const std::string& query)
148 -> Result<database_result>;
149 [[nodiscard]] auto insert(const std::string& query) -> Result<uint64_t>;
150 [[nodiscard]] auto update(const std::string& query) -> Result<uint64_t>;
151 [[nodiscard]] auto remove(const std::string& query) -> Result<uint64_t>;
152 [[nodiscard]] auto execute(const std::string& query) -> VoidResult;
153 [[nodiscard]] auto last_insert_rowid() const -> int64_t;
154 [[nodiscard]] auto commit() -> VoidResult;
155 [[nodiscard]] auto rollback() -> VoidResult;
156 [[nodiscard]] auto is_active() const noexcept -> bool;
157
158private:
159 pacs_database_adapter* adapter_{nullptr};
160 bool active_{false};
161};
162
206class pacs_database_adapter {
207public:
216 explicit pacs_database_adapter(const std::filesystem::path& db_path);
217
226 pacs_database_adapter(database::database_types type,
227 const std::string& connection_string);
228
232 ~pacs_database_adapter();
233
234 // Non-copyable
235 pacs_database_adapter(const pacs_database_adapter&) = delete;
236 auto operator=(const pacs_database_adapter&)
237 -> pacs_database_adapter& = delete;
238
239 // Movable
240 pacs_database_adapter(pacs_database_adapter&&) noexcept;
241 auto operator=(pacs_database_adapter&&) noexcept -> pacs_database_adapter&;
242
243 // ========================================================================
244 // Connection Management
245 // ========================================================================
246
254 [[nodiscard]] auto connect() -> VoidResult;
255
263 [[nodiscard]] auto disconnect() -> VoidResult;
264
270 [[nodiscard]] auto is_connected() const noexcept -> bool;
271
278 [[nodiscard]] auto open_session() -> pacs_storage_session;
279 [[nodiscard]] auto open_session() const -> pacs_storage_session;
280
284 [[nodiscard]] auto begin_unit_of_work() -> Result<pacs_unit_of_work>;
285
286 // ========================================================================
287 // Query Builder Factory
288 // ========================================================================
289
309 [[nodiscard]] auto create_query_builder() -> database::query_builder;
310
311 // ========================================================================
312 // CRUD Operations
313 // ========================================================================
314
321 [[nodiscard]] auto select(const std::string& query)
322 -> Result<database_result>;
323
332 [[nodiscard]] auto insert(const std::string& query) -> Result<uint64_t>;
333
342 [[nodiscard]] auto update(const std::string& query) -> Result<uint64_t>;
343
352 [[nodiscard]] auto remove(const std::string& query) -> Result<uint64_t>;
353
363 [[nodiscard]] auto execute(const std::string& query) -> VoidResult;
364
365 // ========================================================================
366 // Transaction Support
367 // ========================================================================
368
374 [[nodiscard]] auto begin_transaction() -> VoidResult;
375
381 [[nodiscard]] auto commit() -> VoidResult;
382
388 [[nodiscard]] auto rollback() -> VoidResult;
389
395 [[nodiscard]] auto in_transaction() const noexcept -> bool;
396
421 template <typename Func>
422 [[nodiscard]] auto transaction(Func&& func) -> VoidResult {
423 auto begin_result = begin_transaction();
424 if (begin_result.is_err()) {
425 return begin_result;
426 }
427
428 try {
429 auto result = std::forward<Func>(func)();
430 if (result.is_err()) {
431 (void)rollback();
432 return result;
433 }
434
435 return commit();
436 } catch (const std::exception& e) {
437 (void)rollback();
438 return VoidResult(kcenon::common::error_info{
439 -1, std::string("Transaction failed: ") + e.what(), "storage"});
440 }
441 }
442
443 // ========================================================================
444 // SQLite Compatibility
445 // ========================================================================
446
455 [[nodiscard]] auto last_insert_rowid() const -> int64_t;
456
462 [[nodiscard]] auto last_error() const -> std::string;
463
464private:
465 friend class pacs_storage_session;
466 friend class pacs_unit_of_work;
467
468 [[nodiscard]] auto run_select(const std::string& query)
469 -> Result<database_result>;
470 [[nodiscard]] auto run_insert(const std::string& query)
471 -> Result<uint64_t>;
472 [[nodiscard]] auto run_update(const std::string& query)
473 -> Result<uint64_t>;
474 [[nodiscard]] auto run_remove(const std::string& query)
475 -> Result<uint64_t>;
476 [[nodiscard]] auto run_execute(const std::string& query) -> VoidResult;
477 [[nodiscard]] auto begin_transaction_internal() -> VoidResult;
478 [[nodiscard]] auto commit_internal() -> VoidResult;
479 [[nodiscard]] auto rollback_internal() -> VoidResult;
480
481 struct impl;
482 std::unique_ptr<impl> impl_;
483};
484
506class scoped_transaction {
507public:
514 explicit scoped_transaction(pacs_database_adapter& db);
515
519 ~scoped_transaction();
520
521 // Non-copyable, non-movable
522 scoped_transaction(const scoped_transaction&) = delete;
523 auto operator=(const scoped_transaction&) -> scoped_transaction& = delete;
524 scoped_transaction(scoped_transaction&&) = delete;
525 auto operator=(scoped_transaction&&) -> scoped_transaction& = delete;
526
534 [[nodiscard]] auto commit() -> VoidResult;
535
541 void rollback() noexcept;
542
548 [[nodiscard]] auto is_active() const noexcept -> bool;
549
550private:
551 pacs_database_adapter& db_;
552 bool committed_{false};
553 bool active_{false};
554};
555
556#endif // PACS_WITH_DATABASE_SYSTEM
557
558} // namespace kcenon::pacs::storage
constexpr dicom_tag rows
Rows.
@ empty
Z - Replace with zero-length value.
kcenon::common::Result< T > Result
Result type alias for operations returning a value.