PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::storage::index_database Class Reference

#include <index_database.h>

Collaboration diagram for kcenon::pacs::storage::index_database:
Collaboration graph

Classes

struct  storage_stats
 Storage statistics structure. More...
 

Public Member Functions

 ~index_database ()
 Destructor - closes database connection.
 
 index_database (const index_database &)=delete
 
auto operator= (const index_database &) -> index_database &=delete
 
 index_database (index_database &&) noexcept
 
auto operator= (index_database &&) noexcept -> index_database &
 
auto upsert_patient (std::string_view patient_id, std::string_view patient_name="", std::string_view birth_date="", std::string_view sex="") -> Result< int64_t >
 Insert or update a patient record.
 
auto upsert_patient (const patient_record &record) -> Result< int64_t >
 Insert or update a patient record with full details.
 
auto find_patient (std::string_view patient_id) const -> std::optional< patient_record >
 Find a patient by patient ID.
 
auto find_patient_by_pk (int64_t pk) const -> std::optional< patient_record >
 Find a patient by primary key.
 
auto search_patients (const patient_query &query) const -> Result< std::vector< patient_record > >
 Search patients with query criteria.
 
auto delete_patient (std::string_view patient_id) -> VoidResult
 Delete a patient by patient ID.
 
auto patient_count () const -> Result< size_t >
 Get total patient count.
 
auto upsert_study (int64_t patient_pk, std::string_view study_uid, std::string_view study_id="", std::string_view study_date="", std::string_view study_time="", std::string_view accession_number="", std::string_view referring_physician="", std::string_view study_description="") -> Result< int64_t >
 Insert or update a study record.
 
auto upsert_study (const study_record &record) -> Result< int64_t >
 Insert or update a study record with full details.
 
auto find_study (std::string_view study_uid) const -> std::optional< study_record >
 Find a study by Study Instance UID.
 
auto find_study_by_pk (int64_t pk) const -> std::optional< study_record >
 Find a study by primary key.
 
auto list_studies (std::string_view patient_id) const -> Result< std::vector< study_record > >
 List all studies for a patient.
 
auto search_studies (const study_query &query) const -> Result< std::vector< study_record > >
 Search studies with query criteria.
 
auto delete_study (std::string_view study_uid) -> VoidResult
 Delete a study by Study Instance UID.
 
auto study_count () const -> Result< size_t >
 Get total study count.
 
auto study_count (std::string_view patient_id) const -> Result< size_t >
 Get study count for a specific patient.
 
auto update_modalities_in_study (int64_t study_pk) -> VoidResult
 Update modalities in study (denormalized field)
 
auto upsert_series (int64_t study_pk, std::string_view series_uid, std::string_view modality="", std::optional< int > series_number=std::nullopt, std::string_view series_description="", std::string_view body_part_examined="", std::string_view station_name="") -> Result< int64_t >
 Insert or update a series record.
 
auto upsert_series (const series_record &record) -> Result< int64_t >
 Insert or update a series record with full details.
 
auto find_series (std::string_view series_uid) const -> std::optional< series_record >
 Find a series by Series Instance UID.
 
auto find_series_by_pk (int64_t pk) const -> std::optional< series_record >
 Find a series by primary key.
 
auto list_series (std::string_view study_uid) const -> Result< std::vector< series_record > >
 List all series for a study.
 
auto search_series (const series_query &query) const -> Result< std::vector< series_record > >
 Search series with query criteria.
 
auto delete_series (std::string_view series_uid) -> VoidResult
 Delete a series by Series Instance UID.
 
auto series_count () const -> Result< size_t >
 Get total series count.
 
auto series_count (std::string_view study_uid) const -> Result< size_t >
 Get series count for a specific study.
 
auto upsert_instance (int64_t series_pk, std::string_view sop_uid, std::string_view sop_class_uid, std::string_view file_path, int64_t file_size, std::string_view transfer_syntax="", std::optional< int > instance_number=std::nullopt) -> Result< int64_t >
 Insert or update an instance record.
 
auto upsert_instance (const instance_record &record) -> Result< int64_t >
 Insert or update an instance record with full details.
 
auto find_instance (std::string_view sop_uid) const -> std::optional< instance_record >
 Find an instance by SOP Instance UID.
 
auto find_instance_by_pk (int64_t pk) const -> std::optional< instance_record >
 Find an instance by primary key.
 
auto list_instances (std::string_view series_uid) const -> Result< std::vector< instance_record > >
 List all instances for a series.
 
auto search_instances (const instance_query &query) const -> Result< std::vector< instance_record > >
 Search instances with query criteria.
 
auto delete_instance (std::string_view sop_uid) -> VoidResult
 Delete an instance by SOP Instance UID.
 
auto instance_count () const -> Result< size_t >
 Get total instance count.
 
auto instance_count (std::string_view series_uid) const -> Result< size_t >
 Get instance count for a specific series.
 
auto create_mpps (std::string_view mpps_uid, std::string_view station_ae="", std::string_view modality="", std::string_view study_uid="", std::string_view accession_no="", std::string_view start_datetime="") -> Result< int64_t >
 Create a new MPPS record (N-CREATE)
 
auto create_mpps (const mpps_record &record) -> Result< int64_t >
 Create a new MPPS record with full details.
 
auto update_mpps (std::string_view mpps_uid, std::string_view new_status, std::string_view end_datetime="", std::string_view performed_series="") -> VoidResult
 Update an existing MPPS record (N-SET)
 
auto update_mpps (const mpps_record &record) -> VoidResult
 Update an existing MPPS record with partial data.
 
auto find_mpps (std::string_view mpps_uid) const -> std::optional< mpps_record >
 Find an MPPS by SOP Instance UID.
 
auto find_mpps_by_pk (int64_t pk) const -> std::optional< mpps_record >
 Find an MPPS by primary key.
 
auto list_active_mpps (std::string_view station_ae) const -> Result< std::vector< mpps_record > >
 List active (IN PROGRESS) MPPS records for a station.
 
auto find_mpps_by_study (std::string_view study_uid) const -> Result< std::vector< mpps_record > >
 Find MPPS records by Study Instance UID.
 
auto search_mpps (const mpps_query &query) const -> Result< std::vector< mpps_record > >
 Search MPPS records with query criteria.
 
auto delete_mpps (std::string_view mpps_uid) -> VoidResult
 Delete an MPPS record.
 
auto mpps_count () const -> Result< size_t >
 Get total MPPS count.
 
auto mpps_count (std::string_view status) const -> Result< size_t >
 Get MPPS count by status.
 
auto add_worklist_item (const worklist_item &item) -> Result< int64_t >
 Add a new worklist item.
 
auto update_worklist_status (std::string_view step_id, std::string_view accession_no, std::string_view new_status) -> VoidResult
 Update worklist item status.
 
auto query_worklist (const worklist_query &query) const -> Result< std::vector< worklist_item > >
 Query worklist items.
 
auto find_worklist_item (std::string_view step_id, std::string_view accession_no) const -> std::optional< worklist_item >
 Find a worklist item by step ID and accession number.
 
auto find_worklist_by_pk (int64_t pk) const -> std::optional< worklist_item >
 Find a worklist item by primary key.
 
auto delete_worklist_item (std::string_view step_id, std::string_view accession_no) -> VoidResult
 Delete a worklist item.
 
auto cleanup_old_worklist_items (std::chrono::hours age) -> Result< size_t >
 Cleanup old worklist items.
 
auto cleanup_worklist_items_before (std::chrono::system_clock::time_point before) -> Result< size_t >
 
auto worklist_count () const -> Result< size_t >
 Get total worklist count.
 
auto worklist_count (std::string_view status) const -> Result< size_t >
 Get worklist count by status.
 
auto create_ups_workitem (const ups_workitem &workitem) -> Result< int64_t >
 Create a new UPS workitem (N-CREATE)
 
auto update_ups_workitem (const ups_workitem &workitem) -> VoidResult
 Update an existing UPS workitem.
 
auto change_ups_state (std::string_view workitem_uid, std::string_view new_state, std::string_view transaction_uid="") -> VoidResult
 Change UPS workitem state.
 
auto find_ups_workitem (std::string_view workitem_uid) const -> std::optional< ups_workitem >
 Find a UPS workitem by SOP Instance UID.
 
auto search_ups_workitems (const ups_workitem_query &query) const -> Result< std::vector< ups_workitem > >
 Search UPS workitems with query criteria.
 
auto delete_ups_workitem (std::string_view workitem_uid) -> VoidResult
 Delete a UPS workitem.
 
auto ups_workitem_count () const -> Result< size_t >
 Get total UPS workitem count.
 
auto ups_workitem_count (std::string_view state) const -> Result< size_t >
 Get UPS workitem count by state.
 
auto subscribe_ups (const ups_subscription &subscription) -> Result< int64_t >
 Subscribe to UPS workitem events.
 
auto unsubscribe_ups (std::string_view subscriber_ae, std::string_view workitem_uid="") -> VoidResult
 Unsubscribe from UPS workitem events.
 
auto get_ups_subscriptions (std::string_view subscriber_ae) const -> Result< std::vector< ups_subscription > >
 Get all subscriptions for a subscriber.
 
auto get_ups_subscribers (std::string_view workitem_uid) const -> Result< std::vector< std::string > >
 Get all subscribers for a workitem.
 
auto add_audit_log (const audit_record &record) -> Result< int64_t >
 Add a new audit log entry.
 
auto query_audit_log (const audit_query &query) const -> Result< std::vector< audit_record > >
 Query audit log entries.
 
auto find_audit_by_pk (int64_t pk) const -> std::optional< audit_record >
 Find an audit log entry by primary key.
 
auto audit_count () const -> Result< size_t >
 Get total audit log count.
 
auto cleanup_old_audit_logs (std::chrono::hours age) -> Result< size_t >
 Cleanup old audit log entries.
 
auto path () const -> std::string_view
 Get the database file path.
 
auto schema_version () const -> int
 Get the current schema version.
 
auto is_open () const noexcept -> bool
 Check if the database is open.
 
auto get_file_path (std::string_view sop_instance_uid) const -> Result< std::optional< std::string > >
 Get file path for a SOP Instance UID.
 
auto get_study_files (std::string_view study_instance_uid) const -> Result< std::vector< std::string > >
 Get all file paths for a study.
 
auto get_series_files (std::string_view series_instance_uid) const -> Result< std::vector< std::string > >
 Get all file paths for a series.
 
auto vacuum () -> VoidResult
 Reclaim unused space in the database.
 
auto analyze () -> VoidResult
 Update database statistics for query optimization.
 
auto verify_integrity () const -> VoidResult
 Verify database integrity.
 
auto native_handle () const noexcept -> sqlite3 *
 Get the raw SQLite database handle.
 
auto checkpoint (bool truncate=false) -> VoidResult
 Checkpoint WAL file.
 
auto get_storage_stats () const -> Result< storage_stats >
 Get storage statistics.
 

Static Public Member Functions

static auto open (std::string_view db_path) -> Result< std::unique_ptr< index_database > >
 Open or create a database with default configuration.
 
static auto open (std::string_view db_path, const index_config &config) -> Result< std::unique_ptr< index_database > >
 Open or create a database with custom configuration.
 

Private Member Functions

 index_database (sqlite3 *db, std::string path)
 Private constructor - use open() factory method.
 
auto parse_patient_row (void *stmt) const -> patient_record
 Parse a patient record from a prepared statement.
 
auto parse_study_row (void *stmt) const -> study_record
 Parse a study record from a prepared statement.
 
auto parse_series_row (void *stmt) const -> series_record
 Parse a series record from a prepared statement.
 
auto parse_instance_row (void *stmt) const -> instance_record
 Parse an instance record from a prepared statement.
 
auto parse_mpps_row (void *stmt) const -> mpps_record
 Parse an MPPS record from a prepared statement.
 
auto parse_worklist_row (void *stmt) const -> worklist_item
 Parse a worklist record from a prepared statement.
 
auto parse_ups_workitem_row (void *stmt) const -> ups_workitem
 Parse a UPS workitem record from a prepared statement.
 
auto parse_audit_row (void *stmt) const -> audit_record
 Parse an audit record from a prepared statement.
 
auto initialize_repositories () -> VoidResult
 Initialize extracted repositories for facade delegation.
 

Static Private Member Functions

static auto to_like_pattern (std::string_view pattern) -> std::string
 Convert wildcard pattern to SQL LIKE pattern.
 

Private Attributes

sqlite3 * db_ {nullptr}
 SQLite database handle (used for migrations and fallback)
 
std::string path_
 Database file path.
 
bool remove_on_close_ {false}
 Remove the backing file on destruction for adapter-compatible memory DBs.
 
std::shared_ptr< patient_repositorypatient_repository_
 Extracted repositories used by the facade API.
 
std::shared_ptr< study_repositorystudy_repository_
 
std::shared_ptr< series_repositoryseries_repository_
 
std::shared_ptr< instance_repositoryinstance_repository_
 
std::shared_ptr< mpps_repositorympps_repository_
 
std::shared_ptr< worklist_repositoryworklist_repository_
 
std::shared_ptr< ups_repositoryups_repository_
 
std::shared_ptr< audit_repositoryaudit_repository_
 
migration_runner migration_runner_
 Migration runner for schema management.
 

Detailed Description

Constructor & Destructor Documentation

◆ ~index_database()

kcenon::pacs::storage::index_database::~index_database ( )

Destructor - closes database connection.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 282 of file index_database.cpp.

282 {
283 patient_repository_.reset();
284 study_repository_.reset();
285 series_repository_.reset();
286 instance_repository_.reset();
287 mpps_repository_.reset();
288 worklist_repository_.reset();
289 ups_repository_.reset();
290 audit_repository_.reset();
291#ifdef PACS_WITH_DATABASE_SYSTEM
292 if (db_adapter_) {
293 (void)db_adapter_->disconnect();
294 db_adapter_.reset();
295 }
296#endif
297 if (db_) {
298 sqlite3_close(db_);
299 db_ = nullptr;
300 }
301 if (remove_on_close_) {
302 remove_database_sidecars(path_);
303 }
304}
std::shared_ptr< mpps_repository > mpps_repository_
std::shared_ptr< audit_repository > audit_repository_
std::shared_ptr< patient_repository > patient_repository_
Extracted repositories used by the facade API.
std::shared_ptr< study_repository > study_repository_
std::shared_ptr< worklist_repository > worklist_repository_
std::shared_ptr< ups_repository > ups_repository_
std::shared_ptr< instance_repository > instance_repository_
std::string path_
Database file path.
bool remove_on_close_
Remove the backing file on destruction for adapter-compatible memory DBs.
sqlite3 * db_
SQLite database handle (used for migrations and fallback)
std::shared_ptr< series_repository > series_repository_

References audit_repository_, db_, instance_repository_, mpps_repository_, path_, patient_repository_, remove_on_close_, series_repository_, study_repository_, ups_repository_, and worklist_repository_.

◆ index_database() [1/3]

kcenon::pacs::storage::index_database::index_database ( const index_database & )
delete

◆ index_database() [2/3]

kcenon::pacs::storage::index_database::index_database ( index_database && other)
noexcept

Definition at line 683 of file index_database.cpp.

684 : db_(other.db_),
685 path_(std::move(other.path_)),
686 remove_on_close_(other.remove_on_close_),
687 patient_repository_(std::move(other.patient_repository_)),
688 study_repository_(std::move(other.study_repository_)),
689 series_repository_(std::move(other.series_repository_)),
690 instance_repository_(std::move(other.instance_repository_)),
691 mpps_repository_(std::move(other.mpps_repository_)),
692 worklist_repository_(std::move(other.worklist_repository_)),
693 ups_repository_(std::move(other.ups_repository_)),
694 audit_repository_(std::move(other.audit_repository_)) {
695#ifdef PACS_WITH_DATABASE_SYSTEM
696 db_adapter_ = std::move(other.db_adapter_);
697#endif
698 other.db_ = nullptr;
699 other.remove_on_close_ = false;
700}

◆ index_database() [3/3]

kcenon::pacs::storage::index_database::index_database ( sqlite3 * db,
std::string path )
explicitprivate

Private constructor - use open() factory method.

Definition at line 279 of file index_database.cpp.

280 : db_(db), path_(std::move(path)) {}
auto path() const -> std::string_view
Get the database file path.

Member Function Documentation

◆ add_audit_log()

auto kcenon::pacs::storage::index_database::add_audit_log ( const audit_record & record) -> Result<int64_t>
nodiscard

Add a new audit log entry.

Creates a new audit log record for HIPAA compliance and system monitoring.

Parameters
recordAudit record data (pk field is ignored)
Returns
Result containing the audit log primary key or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1720 of file index_database.cpp.

1721 {
1722 return audit_repository_->add_audit_log(record);
1723}

◆ add_worklist_item()

auto kcenon::pacs::storage::index_database::add_worklist_item ( const worklist_item & item) -> Result<int64_t>
nodiscard

Add a new worklist item.

Creates a new scheduled procedure step entry for Modality Worklist. The step_status is set to 'SCHEDULED' by default.

Parameters
itemWorklist item data (pk field is ignored)
Returns
Result containing the worklist primary key or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1528 of file index_database.cpp.

1529 {
1530 return worklist_repository_->add_worklist_item(item);
1531}

◆ analyze()

auto kcenon::pacs::storage::index_database::analyze ( ) -> VoidResult
nodiscard

Update database statistics for query optimization.

ANALYZE collects statistics about tables and indexes, which helps the query planner choose better execution plans. Should be run periodically, especially after bulk insertions.

Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1181 of file index_database.cpp.

1181 {
1182#ifdef PACS_WITH_DATABASE_SYSTEM
1183 // Prefer pacs_database_adapter for unified database operations (Issue #616)
1184 if (db_adapter_ && db_adapter_->is_connected()) {
1185 return db_adapter_->execute("ANALYZE;");
1186 }
1187#endif
1188
1189 auto rc = sqlite3_exec(db_, "ANALYZE;", nullptr, nullptr, nullptr);
1190 if (rc != SQLITE_OK) {
1191 return make_error<std::monostate>(
1192 rc, kcenon::pacs::compat::format("ANALYZE failed: {}", sqlite3_errmsg(db_)),
1193 "storage");
1194 }
1195 return ok();
1196}

◆ audit_count()

auto kcenon::pacs::storage::index_database::audit_count ( ) const -> Result<size_t>
nodiscard

Get total audit log count.

Returns
Result containing number of audit log entries in the database or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1735 of file index_database.cpp.

1735 {
1736 return audit_repository_->audit_count();
1737}

References audit_repository_.

◆ change_ups_state()

auto kcenon::pacs::storage::index_database::change_ups_state ( std::string_view workitem_uid,
std::string_view new_state,
std::string_view transaction_uid = "" ) -> VoidResult
nodiscard

Change UPS workitem state.

Performs a state transition with validation per PS3.4 Table CC.1.1-2.

Parameters
workitem_uidThe workitem SOP Instance UID
new_stateThe target state
transaction_uidTransaction UID (required for IN PROGRESS transition)
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1627 of file index_database.cpp.

1630 {
1631 return ups_repository_->change_ups_state(workitem_uid, new_state,
1632 transaction_uid);
1633}

◆ checkpoint()

auto kcenon::pacs::storage::index_database::checkpoint ( bool truncate = false) -> VoidResult
nodiscard

Checkpoint WAL file.

Forces a WAL checkpoint, writing all WAL content to the main database file. Useful for ensuring durability before backup.

Parameters
truncateIf true, truncate the WAL file after checkpoint
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1247 of file index_database.cpp.

1247 {
1248 const char* sql =
1249 truncate ? "PRAGMA wal_checkpoint(TRUNCATE);"
1250 : "PRAGMA wal_checkpoint(PASSIVE);";
1251
1252#ifdef PACS_WITH_DATABASE_SYSTEM
1253 // Prefer pacs_database_adapter for unified database operations (Issue #616)
1254 if (db_adapter_ && db_adapter_->is_connected()) {
1255 return db_adapter_->execute(sql);
1256 }
1257#endif
1258
1259 auto rc = sqlite3_exec(db_, sql, nullptr, nullptr, nullptr);
1260 if (rc != SQLITE_OK) {
1261 return make_error<std::monostate>(
1262 rc, kcenon::pacs::compat::format("Checkpoint failed: {}", sqlite3_errmsg(db_)),
1263 "storage");
1264 }
1265 return ok();
1266}

◆ cleanup_old_audit_logs()

auto kcenon::pacs::storage::index_database::cleanup_old_audit_logs ( std::chrono::hours age) -> Result<size_t>
nodiscard

Cleanup old audit log entries.

Removes audit log entries older than the specified age.

Parameters
ageMaximum age of entries to keep
Returns
Result containing the number of deleted entries or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1739 of file index_database.cpp.

1740 {
1741 return audit_repository_->cleanup_old_audit_logs(age);
1742}

◆ cleanup_old_worklist_items()

auto kcenon::pacs::storage::index_database::cleanup_old_worklist_items ( std::chrono::hours age) -> Result<size_t>
nodiscard

Cleanup old worklist items.

Removes worklist items older than the specified age. Only deletes items that are not in SCHEDULED status.

Parameters
ageMaximum age of items to keep
Returns
Result containing the number of deleted items or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1563 of file index_database.cpp.

1564 {
1565 return worklist_repository_->cleanup_old_worklist_items(age);
1566}

◆ cleanup_worklist_items_before()

auto kcenon::pacs::storage::index_database::cleanup_worklist_items_before ( std::chrono::system_clock::time_point before) -> Result<size_t>
nodiscard
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1568 of file index_database.cpp.

1569 {
1570 return worklist_repository_->cleanup_worklist_items_before(before);
1571}

◆ create_mpps() [1/2]

auto kcenon::pacs::storage::index_database::create_mpps ( const mpps_record & record) -> Result<int64_t>
nodiscard

Create a new MPPS record with full details.

Parameters
recordComplete MPPS record (pk field is ignored)
Returns
Result containing the MPPS primary key or error

Definition at line 1356 of file index_database.cpp.

1356 {
1357 return mpps_repository_->create_mpps(record);
1358}

◆ create_mpps() [2/2]

auto kcenon::pacs::storage::index_database::create_mpps ( std::string_view mpps_uid,
std::string_view station_ae = "",
std::string_view modality = "",
std::string_view study_uid = "",
std::string_view accession_no = "",
std::string_view start_datetime = "" ) -> Result<int64_t>
nodiscard

Create a new MPPS record (N-CREATE)

Creates a new MPPS with status "IN PROGRESS". This corresponds to the DICOM N-CREATE operation received from modalities.

Parameters
mpps_uidSOP Instance UID for the MPPS (required, must be unique)
station_aePerforming station AE Title
modalityModality type (CT, MR, etc.)
study_uidRelated Study Instance UID
accession_noAccession number
start_datetimeProcedure step start date/time (YYYYMMDDHHMMSS)
Returns
Result containing the MPPS primary key or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1344 of file index_database.cpp.

1350 {
1351 return mpps_repository_->create_mpps(mpps_uid, station_ae, modality,
1352 study_uid, accession_no,
1353 start_datetime);
1354}

◆ create_ups_workitem()

auto kcenon::pacs::storage::index_database::create_ups_workitem ( const ups_workitem & workitem) -> Result<int64_t>
nodiscard

Create a new UPS workitem (N-CREATE)

Creates a new UPS workitem with state "SCHEDULED". This corresponds to the DICOM N-CREATE operation.

Parameters
workitemThe workitem data (pk field is ignored)
Returns
Result containing the workitem primary key or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1617 of file index_database.cpp.

1618 {
1619 return ups_repository_->create_ups_workitem(workitem);
1620}

◆ delete_instance()

auto kcenon::pacs::storage::index_database::delete_instance ( std::string_view sop_uid) -> VoidResult
nodiscard

Delete an instance by SOP Instance UID.

Parameters
sop_uidThe SOP Instance UID to delete
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1082 of file index_database.cpp.

1082 {
1083 return instance_repository_->delete_instance(sop_uid);
1084}

◆ delete_mpps()

auto kcenon::pacs::storage::index_database::delete_mpps ( std::string_view mpps_uid) -> VoidResult
nodiscard

Delete an MPPS record.

Parameters
mpps_uidThe MPPS SOP Instance UID to delete
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1398 of file index_database.cpp.

1398 {
1399 return mpps_repository_->delete_mpps(mpps_uid);
1400}

◆ delete_patient()

auto kcenon::pacs::storage::index_database::delete_patient ( std::string_view patient_id) -> VoidResult
nodiscard

Delete a patient by patient ID.

This operation cascades to delete all related studies, series, and instances.

Parameters
patient_idThe patient ID to delete
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 774 of file index_database.cpp.

774 {
775 return patient_repository_->delete_patient(patient_id);
776}

◆ delete_series()

auto kcenon::pacs::storage::index_database::delete_series ( std::string_view series_uid) -> VoidResult
nodiscard

Delete a series by Series Instance UID.

This operation cascades to delete all related instances.

Parameters
series_uidThe Series Instance UID to delete
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 995 of file index_database.cpp.

995 {
996 auto existing = find_series(series_uid);
997 auto result = series_repository_->delete_series(series_uid);
998 if (result.is_ok() && existing.has_value() && existing->study_pk > 0) {
999 (void)update_modalities_in_study(existing->study_pk);
1000 }
1001 return result;
1002}
auto update_modalities_in_study(int64_t study_pk) -> VoidResult
Update modalities in study (denormalized field)
auto find_series(std::string_view series_uid) const -> std::optional< series_record >
Find a series by Series Instance UID.

◆ delete_study()

auto kcenon::pacs::storage::index_database::delete_study ( std::string_view study_uid) -> VoidResult
nodiscard

Delete a study by Study Instance UID.

This operation cascades to delete all related series and instances.

Parameters
study_uidThe Study Instance UID to delete
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 886 of file index_database.cpp.

886 {
887 return study_repository_->delete_study(study_uid);
888}

◆ delete_ups_workitem()

auto kcenon::pacs::storage::index_database::delete_ups_workitem ( std::string_view workitem_uid) -> VoidResult
nodiscard

Delete a UPS workitem.

Only COMPLETED or CANCELED workitems can be deleted unless no subscribers have a deletion lock.

Parameters
workitem_uidThe workitem SOP Instance UID
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1645 of file index_database.cpp.

1646 {
1647 return ups_repository_->delete_ups_workitem(workitem_uid);
1648}

◆ delete_worklist_item()

auto kcenon::pacs::storage::index_database::delete_worklist_item ( std::string_view step_id,
std::string_view accession_no ) -> VoidResult
nodiscard

Delete a worklist item.

Parameters
step_idScheduled Procedure Step ID
accession_noAccession Number
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1557 of file index_database.cpp.

1559 {
1560 return worklist_repository_->delete_worklist_item(step_id, accession_no);
1561}

◆ find_audit_by_pk()

auto kcenon::pacs::storage::index_database::find_audit_by_pk ( int64_t pk) const -> std::optional<audit_record>
nodiscard

Find an audit log entry by primary key.

Parameters
pkThe audit log primary key
Returns
Optional containing the audit record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1730 of file index_database.cpp.

1731 {
1732 return audit_repository_->find_audit_by_pk(pk);
1733}

◆ find_instance()

auto kcenon::pacs::storage::index_database::find_instance ( std::string_view sop_uid) const -> std::optional<instance_record>
nodiscard

Find an instance by SOP Instance UID.

Parameters
sop_uidThe SOP Instance UID to search for
Returns
Optional containing the instance record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 1062 of file index_database.cpp.

1063 {
1064 return instance_repository_->find_instance(sop_uid);
1065}

◆ find_instance_by_pk()

auto kcenon::pacs::storage::index_database::find_instance_by_pk ( int64_t pk) const -> std::optional<instance_record>
nodiscard

Find an instance by primary key.

Parameters
pkThe instance's primary key
Returns
Optional containing the instance record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1067 of file index_database.cpp.

1068 {
1069 return instance_repository_->find_instance_by_pk(pk);
1070}

◆ find_mpps()

auto kcenon::pacs::storage::index_database::find_mpps ( std::string_view mpps_uid) const -> std::optional<mpps_record>
nodiscard

Find an MPPS by SOP Instance UID.

Parameters
mpps_uidThe MPPS SOP Instance UID to search for
Returns
Optional containing the MPPS record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1373 of file index_database.cpp.

1374 {
1375 return mpps_repository_->find_mpps(mpps_uid);
1376}

◆ find_mpps_by_pk()

auto kcenon::pacs::storage::index_database::find_mpps_by_pk ( int64_t pk) const -> std::optional<mpps_record>
nodiscard

Find an MPPS by primary key.

Parameters
pkThe MPPS primary key
Returns
Optional containing the MPPS record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1378 of file index_database.cpp.

1379 {
1380 return mpps_repository_->find_mpps_by_pk(pk);
1381}

◆ find_mpps_by_study()

auto kcenon::pacs::storage::index_database::find_mpps_by_study ( std::string_view study_uid) const -> Result<std::vector<mpps_record>>
nodiscard

Find MPPS records by Study Instance UID.

Parameters
study_uidThe Study Instance UID to search for
Returns
Result containing vector of MPPS records associated with the study or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1388 of file index_database.cpp.

1389 {
1390 return mpps_repository_->find_mpps_by_study(study_uid);
1391}

◆ find_patient()

auto kcenon::pacs::storage::index_database::find_patient ( std::string_view patient_id) const -> std::optional<patient_record>
nodiscard

Find a patient by patient ID.

Parameters
patient_idThe patient ID to search for
Returns
Optional containing the patient record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 759 of file index_database.cpp.

760 {
761 return patient_repository_->find_patient(patient_id);
762}

◆ find_patient_by_pk()

auto kcenon::pacs::storage::index_database::find_patient_by_pk ( int64_t pk) const -> std::optional<patient_record>
nodiscard

Find a patient by primary key.

Parameters
pkThe patient's primary key
Returns
Optional containing the patient record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 764 of file index_database.cpp.

765 {
766 return patient_repository_->find_patient_by_pk(pk);
767}

◆ find_series()

auto kcenon::pacs::storage::index_database::find_series ( std::string_view series_uid) const -> std::optional<series_record>
nodiscard

Find a series by Series Instance UID.

Parameters
series_uidThe Series Instance UID to search for
Returns
Optional containing the series record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 975 of file index_database.cpp.

976 {
977 return series_repository_->find_series(series_uid);
978}

◆ find_series_by_pk()

auto kcenon::pacs::storage::index_database::find_series_by_pk ( int64_t pk) const -> std::optional<series_record>
nodiscard

Find a series by primary key.

Parameters
pkThe series's primary key
Returns
Optional containing the series record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 980 of file index_database.cpp.

981 {
982 return series_repository_->find_series_by_pk(pk);
983}

◆ find_study()

auto kcenon::pacs::storage::index_database::find_study ( std::string_view study_uid) const -> std::optional<study_record>
nodiscard

Find a study by Study Instance UID.

Parameters
study_uidThe Study Instance UID to search for
Returns
Optional containing the study record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 864 of file index_database.cpp.

865 {
866 return study_repository_->find_study(study_uid);
867}

◆ find_study_by_pk()

auto kcenon::pacs::storage::index_database::find_study_by_pk ( int64_t pk) const -> std::optional<study_record>
nodiscard

Find a study by primary key.

Parameters
pkThe study's primary key
Returns
Optional containing the study record if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 869 of file index_database.cpp.

870 {
871 return study_repository_->find_study_by_pk(pk);
872}

◆ find_ups_workitem()

auto kcenon::pacs::storage::index_database::find_ups_workitem ( std::string_view workitem_uid) const -> std::optional<ups_workitem>
nodiscard

Find a UPS workitem by SOP Instance UID.

Parameters
workitem_uidThe workitem SOP Instance UID
Returns
Optional containing the workitem if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1635 of file index_database.cpp.

1636 {
1637 return ups_repository_->find_ups_workitem(workitem_uid);
1638}

◆ find_worklist_by_pk()

auto kcenon::pacs::storage::index_database::find_worklist_by_pk ( int64_t pk) const -> std::optional<worklist_item>
nodiscard

Find a worklist item by primary key.

Parameters
pkThe worklist primary key
Returns
Optional containing the worklist item if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1552 of file index_database.cpp.

1553 {
1554 return worklist_repository_->find_worklist_by_pk(pk);
1555}

◆ find_worklist_item()

auto kcenon::pacs::storage::index_database::find_worklist_item ( std::string_view step_id,
std::string_view accession_no ) const -> std::optional<worklist_item>
nodiscard

Find a worklist item by step ID and accession number.

Parameters
step_idScheduled Procedure Step ID
accession_noAccession Number
Returns
Optional containing the worklist item if found
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1546 of file index_database.cpp.

1548 {
1549 return worklist_repository_->find_worklist_item(step_id, accession_no);
1550}

◆ get_file_path()

auto kcenon::pacs::storage::index_database::get_file_path ( std::string_view sop_instance_uid) const -> Result<std::optional<std::string>>
nodiscard

Get file path for a SOP Instance UID.

Convenience method to quickly look up the file path for a specific DICOM instance without loading the full record.

Parameters
sop_instance_uidThe SOP Instance UID to look up
Returns
Result containing optional file path (empty if not found) or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1145 of file index_database.cpp.

1146 {
1147 return instance_repository_->get_file_path(sop_instance_uid);
1148}

◆ get_series_files()

auto kcenon::pacs::storage::index_database::get_series_files ( std::string_view series_instance_uid) const -> Result<std::vector<std::string>>
nodiscard

Get all file paths for a series.

Returns all DICOM file paths associated with a series.

Parameters
series_instance_uidThe Series Instance UID
Returns
Result containing vector of file paths for all instances in the series or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1155 of file index_database.cpp.

1156 {
1157 return instance_repository_->get_series_files(series_instance_uid);
1158}

◆ get_storage_stats()

auto kcenon::pacs::storage::index_database::get_storage_stats ( ) const -> Result<storage_stats>
nodiscard

Get storage statistics.

Returns aggregate statistics about the database contents.

Returns
Result containing storage statistics structure or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1283 of file index_database.cpp.

1283 {
1284 storage_stats stats;
1285
1286 auto patient_count_result = patient_count();
1287 if (patient_count_result.is_err()) {
1288 return Result<storage_stats>::err(patient_count_result.error());
1289 }
1290 stats.total_patients = patient_count_result.value();
1291
1292 auto study_count_result = study_count();
1293 if (study_count_result.is_err()) {
1294 return Result<storage_stats>::err(study_count_result.error());
1295 }
1296 stats.total_studies = study_count_result.value();
1297
1298 auto series_count_result = series_count();
1299 if (series_count_result.is_err()) {
1300 return Result<storage_stats>::err(series_count_result.error());
1301 }
1302 stats.total_series = series_count_result.value();
1303
1304 auto instance_count_result = instance_count();
1305 if (instance_count_result.is_err()) {
1306 return Result<storage_stats>::err(instance_count_result.error());
1307 }
1308 stats.total_instances = instance_count_result.value();
1309
1310 // Get total file size
1311 const char* file_size_sql =
1312 "SELECT COALESCE(SUM(file_size), 0) AS total_size FROM instances;";
1313
1314 sqlite3_stmt* stmt = nullptr;
1315 auto rc = sqlite3_prepare_v2(db_, file_size_sql, -1, &stmt, nullptr);
1316 if (rc != SQLITE_OK) {
1319 kcenon::pacs::compat::format("Failed to prepare query: {}",
1320 sqlite3_errmsg(db_)));
1321 }
1322
1323 if (sqlite3_step(stmt) == SQLITE_ROW) {
1324 stats.total_file_size = sqlite3_column_int64(stmt, 0);
1325 }
1326 sqlite3_finalize(stmt);
1327
1328 // Get database file size
1329 if (path_ != ":memory:") {
1330 std::error_code ec;
1331 auto size = std::filesystem::file_size(path_, ec);
1332 if (!ec) {
1333 stats.database_size = static_cast<int64_t>(size);
1334 }
1335 }
1336
1337 return ok(std::move(stats));
1338}
auto patient_count() const -> Result< size_t >
Get total patient count.
auto study_count() const -> Result< size_t >
Get total study count.
auto series_count() const -> Result< size_t >
Get total series count.
auto instance_count() const -> Result< size_t >
Get total instance count.
constexpr int database_query_error
Definition result.h:122
Result< T > pacs_error(int code, const std::string &message, const std::string &details="")
Create a PACS error result with module context.
Definition result.h:234

References kcenon::pacs::error_codes::database_query_error, db_, instance_count(), kcenon::pacs::pacs_error(), path_, patient_count(), series_count(), and study_count().

Here is the call graph for this function:

◆ get_study_files()

auto kcenon::pacs::storage::index_database::get_study_files ( std::string_view study_instance_uid) const -> Result<std::vector<std::string>>
nodiscard

Get all file paths for a study.

Returns all DICOM file paths associated with a study. Useful for bulk operations like C-MOVE or study export.

Parameters
study_instance_uidThe Study Instance UID
Returns
Result containing vector of file paths for all instances in the study or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1150 of file index_database.cpp.

1151 {
1152 return instance_repository_->get_study_files(study_instance_uid);
1153}

◆ get_ups_subscribers()

auto kcenon::pacs::storage::index_database::get_ups_subscribers ( std::string_view workitem_uid) const -> Result<std::vector<std::string>>
nodiscard

Get all subscribers for a workitem.

Returns subscribers that would receive notifications for the specified workitem (workitem-specific + global subscriptions).

Parameters
workitem_uidThe workitem SOP Instance UID
Returns
Result containing vector of subscriber AE Titles or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1679 of file index_database.cpp.

1680 {
1681 return ups_repository_->get_ups_subscribers(workitem_uid);
1682}

◆ get_ups_subscriptions()

auto kcenon::pacs::storage::index_database::get_ups_subscriptions ( std::string_view subscriber_ae) const -> Result<std::vector<ups_subscription>>
nodiscard

Get all subscriptions for a subscriber.

Parameters
subscriber_aeThe subscriber AE Title
Returns
Result containing vector of subscriptions or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1674 of file index_database.cpp.

1675 {
1676 return ups_repository_->get_ups_subscriptions(subscriber_ae);
1677}

◆ initialize_repositories()

auto kcenon::pacs::storage::index_database::initialize_repositories ( ) -> VoidResult
nodiscardprivate

Initialize extracted repositories for facade delegation.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 645 of file index_database.cpp.

645 {
646#ifdef PACS_WITH_DATABASE_SYSTEM
647 if (!db_adapter_ || !db_adapter_->is_connected()) {
648 return make_error<std::monostate>(
650 "PACS database adapter is not connected",
651 "storage");
652 }
653
654 patient_repository_ = std::make_shared<patient_repository>(db_adapter_);
655 study_repository_ = std::make_shared<study_repository>(db_adapter_);
656 series_repository_ = std::make_shared<series_repository>(db_adapter_);
657 instance_repository_ = std::make_shared<instance_repository>(db_adapter_);
658 mpps_repository_ = std::make_shared<mpps_repository>(db_adapter_);
659 worklist_repository_ = std::make_shared<worklist_repository>(db_adapter_);
660 ups_repository_ = std::make_shared<ups_repository>(db_adapter_);
661 audit_repository_ = std::make_shared<audit_repository>(db_adapter_);
662#else
663 if (db_ == nullptr) {
664 return make_error<std::monostate>(
666 "SQLite database handle is not available",
667 "storage");
668 }
669
670 patient_repository_ = std::make_shared<patient_repository>(db_);
671 study_repository_ = std::make_shared<study_repository>(db_);
672 series_repository_ = std::make_shared<series_repository>(db_);
673 instance_repository_ = std::make_shared<instance_repository>(db_);
674 mpps_repository_ = std::make_shared<mpps_repository>(db_);
675 worklist_repository_ = std::make_shared<worklist_repository>(db_);
676 ups_repository_ = std::make_shared<ups_repository>(db_);
677 audit_repository_ = std::make_shared<audit_repository>(db_);
678#endif
679
680 return ok();
681}
constexpr int database_connection_error
Definition result.h:121

References kcenon::pacs::error_codes::database_connection_error.

◆ instance_count() [1/2]

auto kcenon::pacs::storage::index_database::instance_count ( ) const -> Result<size_t>
nodiscard

Get total instance count.

Returns
Result containing number of instances in the database or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1086 of file index_database.cpp.

1086 {
1087 return instance_repository_->instance_count();
1088}

References instance_repository_.

Referenced by get_storage_stats().

Here is the caller graph for this function:

◆ instance_count() [2/2]

auto kcenon::pacs::storage::index_database::instance_count ( std::string_view series_uid) const -> Result<size_t>
nodiscard

Get instance count for a specific series.

Parameters
series_uidThe Series Instance UID
Returns
Result containing number of instances for the series or error

Definition at line 1090 of file index_database.cpp.

1091 {
1092 return instance_repository_->instance_count(series_uid);
1093}

◆ is_open()

auto kcenon::pacs::storage::index_database::is_open ( ) const -> bool
nodiscardnoexcept

Check if the database is open.

Returns
true if the database connection is active
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 792 of file index_database.cpp.

792{ return db_ != nullptr; }

References db_.

◆ list_active_mpps()

auto kcenon::pacs::storage::index_database::list_active_mpps ( std::string_view station_ae) const -> Result<std::vector<mpps_record>>
nodiscard

List active (IN PROGRESS) MPPS records for a station.

Parameters
station_aeThe station AE Title to filter by
Returns
Result containing vector of active MPPS records or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1383 of file index_database.cpp.

1384 {
1385 return mpps_repository_->list_active_mpps(station_ae);
1386}

◆ list_instances()

auto kcenon::pacs::storage::index_database::list_instances ( std::string_view series_uid) const -> Result<std::vector<instance_record>>
nodiscard

List all instances for a series.

Parameters
series_uidThe Series Instance UID to list instances for
Returns
Result containing vector of instance records for the series or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 1072 of file index_database.cpp.

1073 {
1074 return instance_repository_->list_instances(series_uid);
1075}

◆ list_series()

auto kcenon::pacs::storage::index_database::list_series ( std::string_view study_uid) const -> Result<std::vector<series_record>>
nodiscard

List all series for a study.

Parameters
study_uidThe Study Instance UID to list series for
Returns
Result containing vector of series records for the study or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 985 of file index_database.cpp.

986 {
987 return series_repository_->list_series(study_uid);
988}

◆ list_studies()

auto kcenon::pacs::storage::index_database::list_studies ( std::string_view patient_id) const -> Result<std::vector<study_record>>
nodiscard

List all studies for a patient.

Parameters
patient_idThe patient ID to list studies for
Returns
Result containing vector of study records for the patient or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 874 of file index_database.cpp.

875 {
876 study_query query;
877 query.patient_id = std::string(patient_id);
878 return study_repository_->search_studies(query);
879}
const atna_coded_value query
Query (110112)

◆ mpps_count() [1/2]

auto kcenon::pacs::storage::index_database::mpps_count ( ) const -> Result<size_t>
nodiscard

Get total MPPS count.

Returns
Result containing number of MPPS records in the database or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1402 of file index_database.cpp.

1402 {
1403 return mpps_repository_->mpps_count();
1404}

References mpps_repository_.

◆ mpps_count() [2/2]

auto kcenon::pacs::storage::index_database::mpps_count ( std::string_view status) const -> Result<size_t>
nodiscard

Get MPPS count by status.

Parameters
statusThe status to count (IN PROGRESS, COMPLETED, DISCONTINUED)
Returns
Result containing number of MPPS records with the given status or error

Definition at line 1406 of file index_database.cpp.

1406 {
1407 return mpps_repository_->mpps_count(status);
1408}

◆ native_handle()

auto kcenon::pacs::storage::index_database::native_handle ( ) const -> sqlite3*
nodiscardnoexcept

Get the raw SQLite database handle.

Returns the underlying SQLite database handle for advanced operations such as creating cursors for streaming queries. The returned handle should not be closed or modified directly.

Warning
The returned handle is managed by this class. Do not close it.
Returns
Raw SQLite database handle
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1268 of file index_database.cpp.

1268 {
1269 return db_;
1270}

References db_.

◆ open() [1/2]

auto kcenon::pacs::storage::index_database::open ( std::string_view db_path) -> Result<std::unique_ptr<index_database>>
staticnodiscard

Open or create a database with default configuration.

Opens an existing database or creates a new one at the specified path. Automatically runs pending migrations. Uses default configuration with WAL mode enabled.

Parameters
db_pathPath to the database file, or ":memory:" for in-memory DB
Returns
Result containing the database instance or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 156 of file index_database.cpp.

157 {
158 return open(db_path, index_config{});
159}
static auto open(std::string_view db_path) -> Result< std::unique_ptr< index_database > >
Open or create a database with default configuration.

Referenced by kcenon::pacs::example::pacs_server_app::setup_database().

Here is the caller graph for this function:

◆ open() [2/2]

auto kcenon::pacs::storage::index_database::open ( std::string_view db_path,
const index_config & config ) -> Result<std::unique_ptr<index_database>>
staticnodiscard

Open or create a database with custom configuration.

Opens an existing database or creates a new one at the specified path. Automatically runs pending migrations.

Parameters
db_pathPath to the database file, or ":memory:" for in-memory DB
configConfiguration options for database behavior
Returns
Result containing the database instance or error

Definition at line 161 of file index_database.cpp.

162 {
163 sqlite3* db = nullptr;
164
165 std::string effective_path;
166#ifdef PACS_WITH_DATABASE_SYSTEM
167 bool remove_on_close = false;
168 if (db_path == ":memory:") {
169 // database_system's SQLite backend expects a filesystem path, so use
170 // a temporary file that both sqlite3 and pacs_database_adapter can open.
171 effective_path = create_adapter_compatible_memory_path();
172 remove_on_close = true;
173 } else {
174 effective_path = std::string(db_path);
175 }
176#else
177 effective_path = std::string(db_path);
178#endif
179
180 auto rc = sqlite3_open_v2(effective_path.c_str(), &db,
181 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI,
182 nullptr);
183 if (rc != SQLITE_OK) {
184 std::string error_msg =
185 db ? sqlite3_errmsg(db) : "Failed to allocate memory";
186 if (db) {
187 sqlite3_close(db);
188 }
189 return make_error<std::unique_ptr<index_database>>(
190 rc, kcenon::pacs::compat::format("Failed to open database: {}", error_msg),
191 "storage");
192 }
193
194 // Enable foreign keys
195 rc = sqlite3_exec(db, "PRAGMA foreign_keys = ON;", nullptr, nullptr,
196 nullptr);
197 if (rc != SQLITE_OK) {
198 sqlite3_close(db);
199 return make_error<std::unique_ptr<index_database>>(
200 rc, "Failed to enable foreign keys", "storage");
201 }
202
203 // Configure WAL mode for better concurrency (except for in-memory DB)
204 if (config.wal_mode && db_path != ":memory:") {
205 rc = sqlite3_exec(db, "PRAGMA journal_mode = WAL;", nullptr, nullptr,
206 nullptr);
207 if (rc != SQLITE_OK) {
208 sqlite3_close(db);
209 return make_error<std::unique_ptr<index_database>>(
210 rc, "Failed to enable WAL mode", "storage");
211 }
212 }
213
214 // Configure cache size (negative value means KB)
215 auto cache_sql =
216 kcenon::pacs::compat::format("PRAGMA cache_size = -{};", config.cache_size_mb * 1024);
217 rc = sqlite3_exec(db, cache_sql.c_str(), nullptr, nullptr, nullptr);
218 if (rc != SQLITE_OK) {
219 sqlite3_close(db);
220 return make_error<std::unique_ptr<index_database>>(
221 rc, "Failed to set cache size", "storage");
222 }
223
224 // Configure memory-mapped I/O
225 if (config.mmap_enabled && db_path != ":memory:") {
226 auto mmap_sql = kcenon::pacs::compat::format("PRAGMA mmap_size = {};", config.mmap_size);
227 rc = sqlite3_exec(db, mmap_sql.c_str(), nullptr, nullptr, nullptr);
228 if (rc != SQLITE_OK) {
229 // mmap failure is not critical, continue with regular I/O
230 }
231 }
232
233 // Set synchronous mode for durability with WAL
234 rc = sqlite3_exec(db, "PRAGMA synchronous = NORMAL;", nullptr, nullptr,
235 nullptr);
236 if (rc != SQLITE_OK) {
237 // Not critical, continue
238 }
239
240 // Create database instance
241 auto instance = std::unique_ptr<index_database>(
242 new index_database(db, effective_path));
243#ifdef PACS_WITH_DATABASE_SYSTEM
244 instance->remove_on_close_ = remove_on_close;
245#endif
246
247 // Run migrations
248 auto migration_result = instance->migration_runner_.run_migrations(db);
249 if (migration_result.is_err()) {
250 return make_error<std::unique_ptr<index_database>>(
251 migration_result.error().code,
252 kcenon::pacs::compat::format("Migration failed: {}",
253 migration_result.error().message),
254 "storage");
255 }
256
257#ifdef PACS_WITH_DATABASE_SYSTEM
258 // Initialize database_system for query building
259 // Support in-memory databases for testing (Issue #625)
260 auto db_init_result = instance->initialize_database_system();
261 if (db_init_result.is_err()) {
262 // unified_database_system may not have SQLite backend support in the
263 // current build, so keep the direct SQLite path available.
264 }
265#endif
266
267 auto repository_result = instance->initialize_repositories();
268 if (repository_result.is_err()) {
269 return make_error<std::unique_ptr<index_database>>(
270 repository_result.error().code,
271 kcenon::pacs::compat::format("Repository initialization failed: {}",
272 repository_result.error().message),
273 "storage");
274 }
275
276 return instance;
277}
index_database(const index_database &)=delete
std::string_view code

References code.

◆ operator=() [1/2]

auto kcenon::pacs::storage::index_database::operator= ( const index_database & ) -> index_database &=delete
delete

◆ operator=() [2/2]

auto kcenon::pacs::storage::index_database::operator= ( index_database && other) -> index_database&
noexcept

Definition at line 702 of file index_database.cpp.

703 {
704 if (this != &other) {
705 patient_repository_.reset();
706 study_repository_.reset();
707 series_repository_.reset();
708 instance_repository_.reset();
709 mpps_repository_.reset();
710 worklist_repository_.reset();
711 ups_repository_.reset();
712 audit_repository_.reset();
713#ifdef PACS_WITH_DATABASE_SYSTEM
714 if (db_adapter_) {
715 (void)db_adapter_->disconnect();
716 }
717 db_adapter_ = std::move(other.db_adapter_);
718#endif
719 if (db_) {
720 sqlite3_close(db_);
721 }
722 if (remove_on_close_) {
723 remove_database_sidecars(path_);
724 }
725 db_ = other.db_;
726 path_ = std::move(other.path_);
727 remove_on_close_ = other.remove_on_close_;
728 patient_repository_ = std::move(other.patient_repository_);
729 study_repository_ = std::move(other.study_repository_);
730 series_repository_ = std::move(other.series_repository_);
731 instance_repository_ = std::move(other.instance_repository_);
732 mpps_repository_ = std::move(other.mpps_repository_);
733 worklist_repository_ = std::move(other.worklist_repository_);
734 ups_repository_ = std::move(other.ups_repository_);
735 audit_repository_ = std::move(other.audit_repository_);
736 other.db_ = nullptr;
737 other.remove_on_close_ = false;
738 }
739 return *this;
740}

◆ parse_audit_row()

auto kcenon::pacs::storage::index_database::parse_audit_row ( void * stmt) const -> audit_record
nodiscardprivate

Parse an audit record from a prepared statement.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1744 of file index_database.cpp.

1744 {
1745 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
1746 audit_record record;
1747
1748 record.pk = sqlite3_column_int64(stmt, 0);
1749 record.event_type = get_text(stmt, 1);
1750 record.outcome = get_text(stmt, 2);
1751
1752 auto timestamp_str = get_text(stmt, 3);
1753 record.timestamp = parse_datetime(timestamp_str.c_str());
1754
1755 record.user_id = get_text(stmt, 4);
1756 record.source_ae = get_text(stmt, 5);
1757 record.target_ae = get_text(stmt, 6);
1758 record.source_ip = get_text(stmt, 7);
1759 record.patient_id = get_text(stmt, 8);
1760 record.study_uid = get_text(stmt, 9);
1761 record.message = get_text(stmt, 10);
1762 record.details = get_text(stmt, 11);
1763
1764 return record;
1765}

◆ parse_instance_row()

auto kcenon::pacs::storage::index_database::parse_instance_row ( void * stmt) const -> instance_record
nodiscardprivate

Parse an instance record from a prepared statement.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1095 of file index_database.cpp.

1096 {
1097 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
1098 instance_record record;
1099
1100 record.pk = sqlite3_column_int64(stmt, 0);
1101 record.series_pk = sqlite3_column_int64(stmt, 1);
1102 record.sop_uid = get_text(stmt, 2);
1103 record.sop_class_uid = get_text(stmt, 3);
1104
1105 // Handle nullable instance_number
1106 if (sqlite3_column_type(stmt, 4) != SQLITE_NULL) {
1107 record.instance_number = sqlite3_column_int(stmt, 4);
1108 }
1109
1110 record.transfer_syntax = get_text(stmt, 5);
1111 record.content_date = get_text(stmt, 6);
1112 record.content_time = get_text(stmt, 7);
1113
1114 // Handle nullable image properties
1115 if (sqlite3_column_type(stmt, 8) != SQLITE_NULL) {
1116 record.rows = sqlite3_column_int(stmt, 8);
1117 }
1118
1119 if (sqlite3_column_type(stmt, 9) != SQLITE_NULL) {
1120 record.columns = sqlite3_column_int(stmt, 9);
1121 }
1122
1123 if (sqlite3_column_type(stmt, 10) != SQLITE_NULL) {
1124 record.bits_allocated = sqlite3_column_int(stmt, 10);
1125 }
1126
1127 if (sqlite3_column_type(stmt, 11) != SQLITE_NULL) {
1128 record.number_of_frames = sqlite3_column_int(stmt, 11);
1129 }
1130
1131 record.file_path = get_text(stmt, 12);
1132 record.file_size = sqlite3_column_int64(stmt, 13);
1133 record.file_hash = get_text(stmt, 14);
1134
1135 auto created_str = get_text(stmt, 15);
1136 record.created_at = parse_datetime(created_str.c_str());
1137
1138 return record;
1139}

◆ parse_mpps_row()

auto kcenon::pacs::storage::index_database::parse_mpps_row ( void * stmt) const -> mpps_record
nodiscardprivate

Parse an MPPS record from a prepared statement.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1410 of file index_database.cpp.

1410 {
1411 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
1412 mpps_record record;
1413
1414 record.pk = sqlite3_column_int64(stmt, 0);
1415 record.mpps_uid = get_text(stmt, 1);
1416 record.status = get_text(stmt, 2);
1417 record.start_datetime = get_text(stmt, 3);
1418 record.end_datetime = get_text(stmt, 4);
1419 record.station_ae = get_text(stmt, 5);
1420 record.station_name = get_text(stmt, 6);
1421 record.modality = get_text(stmt, 7);
1422 record.study_uid = get_text(stmt, 8);
1423 record.accession_no = get_text(stmt, 9);
1424 record.scheduled_step_id = get_text(stmt, 10);
1425 record.requested_proc_id = get_text(stmt, 11);
1426 record.performed_series = get_text(stmt, 12);
1427
1428 auto created_str = get_text(stmt, 13);
1429 record.created_at = parse_datetime(created_str.c_str());
1430
1431 auto updated_str = get_text(stmt, 14);
1432 record.updated_at = parse_datetime(updated_str.c_str());
1433
1434 return record;
1435}

◆ parse_patient_row()

auto kcenon::pacs::storage::index_database::parse_patient_row ( void * stmt) const -> patient_record
nodiscardprivate

Parse a patient record from a prepared statement.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 798 of file index_database.cpp.

798 {
799 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
800 patient_record record;
801
802 record.pk = sqlite3_column_int64(stmt, 0);
803 record.patient_id = get_text(stmt, 1);
804 record.patient_name = get_text(stmt, 2);
805 record.birth_date = get_text(stmt, 3);
806 record.sex = get_text(stmt, 4);
807 record.other_ids = get_text(stmt, 5);
808 record.ethnic_group = get_text(stmt, 6);
809 record.comments = get_text(stmt, 7);
810
811 auto created_str = get_text(stmt, 8);
812 record.created_at = parse_datetime(created_str.c_str());
813
814 auto updated_str = get_text(stmt, 9);
815 record.updated_at = parse_datetime(updated_str.c_str());
816
817 return record;
818}

◆ parse_series_row()

auto kcenon::pacs::storage::index_database::parse_series_row ( void * stmt) const -> series_record
nodiscardprivate

Parse a series record from a prepared statement.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1012 of file index_database.cpp.

1012 {
1013 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
1014 series_record record;
1015
1016 record.pk = sqlite3_column_int64(stmt, 0);
1017 record.study_pk = sqlite3_column_int64(stmt, 1);
1018 record.series_uid = get_text(stmt, 2);
1019 record.modality = get_text(stmt, 3);
1020
1021 // Handle nullable series_number
1022 if (sqlite3_column_type(stmt, 4) != SQLITE_NULL) {
1023 record.series_number = sqlite3_column_int(stmt, 4);
1024 }
1025
1026 record.series_description = get_text(stmt, 5);
1027 record.body_part_examined = get_text(stmt, 6);
1028 record.station_name = get_text(stmt, 7);
1029 record.num_instances = sqlite3_column_int(stmt, 8);
1030
1031 auto created_str = get_text(stmt, 9);
1032 record.created_at = parse_datetime(created_str.c_str());
1033
1034 auto updated_str = get_text(stmt, 10);
1035 record.updated_at = parse_datetime(updated_str.c_str());
1036
1037 return record;
1038}

◆ parse_study_row()

auto kcenon::pacs::storage::index_database::parse_study_row ( void * stmt) const -> study_record
nodiscardprivate

Parse a study record from a prepared statement.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 907 of file index_database.cpp.

907 {
908 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
909 study_record record;
910
911 record.pk = sqlite3_column_int64(stmt, 0);
912 record.patient_pk = sqlite3_column_int64(stmt, 1);
913 record.study_uid = get_text(stmt, 2);
914 record.study_id = get_text(stmt, 3);
915 record.study_date = get_text(stmt, 4);
916 record.study_time = get_text(stmt, 5);
917 record.accession_number = get_text(stmt, 6);
918 record.referring_physician = get_text(stmt, 7);
919 record.study_description = get_text(stmt, 8);
920 record.modalities_in_study = get_text(stmt, 9);
921 record.num_series = sqlite3_column_int(stmt, 10);
922 record.num_instances = sqlite3_column_int(stmt, 11);
923
924 auto created_str = get_text(stmt, 12);
925 record.created_at = parse_datetime(created_str.c_str());
926
927 auto updated_str = get_text(stmt, 13);
928 record.updated_at = parse_datetime(updated_str.c_str());
929
930 return record;
931}

◆ parse_ups_workitem_row()

auto kcenon::pacs::storage::index_database::parse_ups_workitem_row ( void * stmt) const -> ups_workitem
nodiscardprivate

Parse a UPS workitem record from a prepared statement.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1684 of file index_database.cpp.

1684 {
1685 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
1686 ups_workitem item;
1687
1688 item.pk = sqlite3_column_int64(stmt, 0);
1689 item.workitem_uid = get_text(stmt, 1);
1690 item.state = get_text(stmt, 2);
1691 item.procedure_step_label = get_text(stmt, 3);
1692 item.worklist_label = get_text(stmt, 4);
1693 item.priority = get_text(stmt, 5);
1694 item.scheduled_start_datetime = get_text(stmt, 6);
1695 item.expected_completion_datetime = get_text(stmt, 7);
1696 item.scheduled_station_name = get_text(stmt, 8);
1697 item.scheduled_station_class = get_text(stmt, 9);
1698 item.scheduled_station_geographic = get_text(stmt, 10);
1699 item.scheduled_human_performers = get_text(stmt, 11);
1700 item.input_information = get_text(stmt, 12);
1701 item.performing_ae = get_text(stmt, 13);
1702 item.progress_description = get_text(stmt, 14);
1703 item.progress_percent = sqlite3_column_int(stmt, 15);
1704 item.output_information = get_text(stmt, 16);
1705 item.transaction_uid = get_text(stmt, 17);
1706
1707 auto created_str = get_text(stmt, 18);
1708 item.created_at = parse_datetime(created_str.c_str());
1709
1710 auto updated_str = get_text(stmt, 19);
1711 item.updated_at = parse_datetime(updated_str.c_str());
1712
1713 return item;
1714}
constexpr dicom_tag item
Item.

◆ parse_worklist_row()

auto kcenon::pacs::storage::index_database::parse_worklist_row ( void * stmt) const -> worklist_item
nodiscardprivate

Parse a worklist record from a prepared statement.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1581 of file index_database.cpp.

1581 {
1582 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
1583 worklist_item item;
1584
1585 item.pk = sqlite3_column_int64(stmt, 0);
1586 item.step_id = get_text(stmt, 1);
1587 item.step_status = get_text(stmt, 2);
1588 item.patient_id = get_text(stmt, 3);
1589 item.patient_name = get_text(stmt, 4);
1590 item.birth_date = get_text(stmt, 5);
1591 item.sex = get_text(stmt, 6);
1592 item.accession_no = get_text(stmt, 7);
1593 item.requested_proc_id = get_text(stmt, 8);
1594 item.study_uid = get_text(stmt, 9);
1595 item.scheduled_datetime = get_text(stmt, 10);
1596 item.station_ae = get_text(stmt, 11);
1597 item.station_name = get_text(stmt, 12);
1598 item.modality = get_text(stmt, 13);
1599 item.procedure_desc = get_text(stmt, 14);
1600 item.protocol_code = get_text(stmt, 15);
1601 item.referring_phys = get_text(stmt, 16);
1602 item.referring_phys_id = get_text(stmt, 17);
1603
1604 auto created_str = get_text(stmt, 18);
1605 item.created_at = parse_datetime(created_str.c_str());
1606
1607 auto updated_str = get_text(stmt, 19);
1608 item.updated_at = parse_datetime(updated_str.c_str());
1609
1610 return item;
1611}

◆ path()

auto kcenon::pacs::storage::index_database::path ( ) const -> std::string_view
nodiscard

Get the database file path.

Returns
Path to the database file
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 786 of file index_database.cpp.

786{ return path_; }

References path_.

◆ patient_count()

auto kcenon::pacs::storage::index_database::patient_count ( ) const -> Result<size_t>
nodiscard

Get total patient count.

Returns
Result containing number of patients in the database or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 778 of file index_database.cpp.

778 {
779 return patient_repository_->patient_count();
780}

References patient_repository_.

Referenced by get_storage_stats().

Here is the caller graph for this function:

◆ query_audit_log()

auto kcenon::pacs::storage::index_database::query_audit_log ( const audit_query & query) const -> Result<std::vector<audit_record>>
nodiscard

Query audit log entries.

Returns audit log entries matching the query criteria.

Parameters
queryQuery parameters with optional filters
Returns
Result containing vector of matching audit records or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1725 of file index_database.cpp.

1726 {
1727 return audit_repository_->query_audit_log(query);
1728}

◆ query_worklist()

auto kcenon::pacs::storage::index_database::query_worklist ( const worklist_query & query) const -> Result<std::vector<worklist_item>>
nodiscard

Query worklist items.

Returns worklist items matching the query criteria. By default, only returns items with status 'SCHEDULED'. Used for MWL C-FIND operations.

Parameters
queryQuery parameters with optional filters
Returns
Result containing vector of matching worklist items or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1541 of file index_database.cpp.

1542 {
1543 return worklist_repository_->query_worklist(query);
1544}

◆ schema_version()

auto kcenon::pacs::storage::index_database::schema_version ( ) const -> int
nodiscard

Get the current schema version.

Returns
Current schema version number
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 788 of file index_database.cpp.

788 {
790}
migration_runner migration_runner_
Migration runner for schema management.
auto get_current_version(sqlite3 *db) const -> int
Get the current schema version.

References db_, kcenon::pacs::storage::migration_runner::get_current_version(), and migration_runner_.

Here is the call graph for this function:

◆ search_instances()

auto kcenon::pacs::storage::index_database::search_instances ( const instance_query & query) const -> Result<std::vector<instance_record>>
nodiscard

Search instances with query criteria.

Can filter by series UID, SOP class, and other attributes.

Parameters
queryQuery parameters with optional filters
Returns
Result containing vector of matching instance records or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 1077 of file index_database.cpp.

1078 {
1079 return instance_repository_->search_instances(query);
1080}

◆ search_mpps()

auto kcenon::pacs::storage::index_database::search_mpps ( const mpps_query & query) const -> Result<std::vector<mpps_record>>
nodiscard

Search MPPS records with query criteria.

Parameters
queryQuery parameters with optional filters
Returns
Result containing vector of matching MPPS records or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1393 of file index_database.cpp.

1394 {
1395 return mpps_repository_->search_mpps(query);
1396}

◆ search_patients()

auto kcenon::pacs::storage::index_database::search_patients ( const patient_query & query) const -> Result<std::vector<patient_record>>
nodiscard

Search patients with query criteria.

Supports wildcard matching using '' character.

  • "Doe</em>" matches names starting with "Doe"
  • "*John" matches names ending with "John"
  • "*oh*" matches names containing "oh"

Parameters
queryQuery parameters with optional filters
Returns
Result containing vector of matching patient records or error

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 769 of file index_database.cpp.

770 {
771 return patient_repository_->search_patients(query);
772}

◆ search_series()

auto kcenon::pacs::storage::index_database::search_series ( const series_query & query) const -> Result<std::vector<series_record>>
nodiscard

Search series with query criteria.

Supports wildcard matching using '*' character. Can filter by study UID, modality, and other attributes.

Parameters
queryQuery parameters with optional filters
Returns
Result containing vector of matching series records or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 990 of file index_database.cpp.

991 {
992 return series_repository_->search_series(query);
993}

◆ search_studies()

auto kcenon::pacs::storage::index_database::search_studies ( const study_query & query) const -> Result<std::vector<study_record>>
nodiscard

Search studies with query criteria.

Supports wildcard matching using '*' character. Can filter by patient attributes, study attributes, and date ranges.

Parameters
queryQuery parameters with optional filters
Returns
Result containing vector of matching study records or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 881 of file index_database.cpp.

882 {
883 return study_repository_->search_studies(query);
884}

◆ search_ups_workitems()

auto kcenon::pacs::storage::index_database::search_ups_workitems ( const ups_workitem_query & query) const -> Result<std::vector<ups_workitem>>
nodiscard

Search UPS workitems with query criteria.

Used for UPS C-FIND operations.

Parameters
queryQuery parameters with optional filters
Returns
Result containing vector of matching workitems or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1640 of file index_database.cpp.

1641 {
1642 return ups_repository_->search_ups_workitems(query);
1643}

◆ series_count() [1/2]

auto kcenon::pacs::storage::index_database::series_count ( ) const -> Result<size_t>
nodiscard

Get total series count.

Returns
Result containing number of series in the database or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1004 of file index_database.cpp.

1004 {
1005 return series_repository_->series_count();
1006}

References series_repository_.

Referenced by get_storage_stats().

Here is the caller graph for this function:

◆ series_count() [2/2]

auto kcenon::pacs::storage::index_database::series_count ( std::string_view study_uid) const -> Result<size_t>
nodiscard

Get series count for a specific study.

Parameters
study_uidThe Study Instance UID
Returns
Result containing number of series for the study or error

Definition at line 1008 of file index_database.cpp.

1008 {
1009 return series_repository_->series_count(study_uid);
1010}

◆ study_count() [1/2]

auto kcenon::pacs::storage::index_database::study_count ( ) const -> Result<size_t>
nodiscard

Get total study count.

Returns
Result containing number of studies in the database or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 890 of file index_database.cpp.

890 {
891 return study_repository_->study_count();
892}

References study_repository_.

Referenced by get_storage_stats().

Here is the caller graph for this function:

◆ study_count() [2/2]

auto kcenon::pacs::storage::index_database::study_count ( std::string_view patient_id) const -> Result<size_t>
nodiscard

Get study count for a specific patient.

Parameters
patient_idThe patient ID
Returns
Result containing number of studies for the patient or error

Definition at line 894 of file index_database.cpp.

894 {
895 auto patient = patient_repository_->find_patient(patient_id);
896 if (!patient.has_value()) {
897 return ok(static_cast<size_t>(0));
898 }
899 return study_repository_->study_count_for_patient(patient->pk);
900}

◆ subscribe_ups()

auto kcenon::pacs::storage::index_database::subscribe_ups ( const ups_subscription & subscription) -> Result<int64_t>
nodiscard

Subscribe to UPS workitem events.

Parameters
subscriptionThe subscription data (pk field is ignored)
Returns
Result containing the subscription primary key or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1663 of file index_database.cpp.

1664 {
1665 return ups_repository_->subscribe_ups(subscription);
1666}

◆ to_like_pattern()

auto kcenon::pacs::storage::index_database::to_like_pattern ( std::string_view pattern) -> std::string
staticnodiscardprivate

Convert wildcard pattern to SQL LIKE pattern.

Converts '*' to '' for SQL LIKE matching

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 820 of file index_database.cpp.

820 {
821 std::string result;
822 result.reserve(pattern.size());
823
824 for (char c : pattern) {
825 if (c == '*') {
826 result += '%';
827 } else if (c == '?') {
828 result += '_';
829 } else if (c == '%' || c == '_') {
830 // Escape SQL wildcards
831 result += '\\';
832 result += c;
833 } else {
834 result += c;
835 }
836 }
837
838 return result;
839}

◆ unsubscribe_ups()

auto kcenon::pacs::storage::index_database::unsubscribe_ups ( std::string_view subscriber_ae,
std::string_view workitem_uid = "" ) -> VoidResult
nodiscard

Unsubscribe from UPS workitem events.

Parameters
subscriber_aeThe subscriber AE Title
workitem_uidThe workitem UID (empty for global unsubscribe)
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1668 of file index_database.cpp.

1670 {
1671 return ups_repository_->unsubscribe_ups(subscriber_ae, workitem_uid);
1672}

◆ update_modalities_in_study()

auto kcenon::pacs::storage::index_database::update_modalities_in_study ( int64_t study_pk) -> VoidResult
nodiscard

Update modalities in study (denormalized field)

Called after series insert/delete to update the modalities_in_study field.

Parameters
study_pkThe study's primary key
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 902 of file index_database.cpp.

903 {
904 return study_repository_->update_modalities_in_study(study_pk);
905}

◆ update_mpps() [1/2]

auto kcenon::pacs::storage::index_database::update_mpps ( const mpps_record & record) -> VoidResult
nodiscard

Update an existing MPPS record with partial data.

Only non-empty fields in the record will be updated.

Parameters
recordMPPS record with fields to update (mpps_uid required)
Returns
VoidResult indicating success or error

Definition at line 1369 of file index_database.cpp.

1369 {
1370 return mpps_repository_->update_mpps(record);
1371}

◆ update_mpps() [2/2]

auto kcenon::pacs::storage::index_database::update_mpps ( std::string_view mpps_uid,
std::string_view new_status,
std::string_view end_datetime = "",
std::string_view performed_series = "" ) -> VoidResult
nodiscard

Update an existing MPPS record (N-SET)

Updates the MPPS status and attributes. This corresponds to the DICOM N-SET operation. Status transitions are validated:

  • IN PROGRESS -> COMPLETED or DISCONTINUED (allowed)
  • COMPLETED or DISCONTINUED -> any (not allowed, final states)
Parameters
mpps_uidSOP Instance UID of the MPPS to update
new_statusNew status (COMPLETED or DISCONTINUED)
end_datetimeProcedure step end date/time
performed_seriesJSON string of performed series information
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1360 of file index_database.cpp.

1364 {
1365 return mpps_repository_->update_mpps(mpps_uid, new_status, end_datetime,
1366 performed_series);
1367}

◆ update_ups_workitem()

auto kcenon::pacs::storage::index_database::update_ups_workitem ( const ups_workitem & workitem) -> VoidResult
nodiscard

Update an existing UPS workitem.

Updates the workitem attributes. State transitions are validated:

  • SCHEDULED -> IN PROGRESS or CANCELED (allowed)
  • IN PROGRESS -> COMPLETED or CANCELED (allowed)
  • COMPLETED or CANCELED -> any (not allowed, final states)
Parameters
workitemUpdated workitem data (workitem_uid required)
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1622 of file index_database.cpp.

1623 {
1624 return ups_repository_->update_ups_workitem(workitem);
1625}

◆ update_worklist_status()

auto kcenon::pacs::storage::index_database::update_worklist_status ( std::string_view step_id,
std::string_view accession_no,
std::string_view new_status ) -> VoidResult
nodiscard

Update worklist item status.

Called when MPPS is received to update the corresponding worklist item status from SCHEDULED to STARTED or COMPLETED.

Parameters
step_idScheduled Procedure Step ID
accession_noAccession Number
new_statusNew status (STARTED or COMPLETED)
Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1533 of file index_database.cpp.

1536 {
1537 return worklist_repository_->update_worklist_status(step_id, accession_no,
1538 new_status);
1539}

◆ ups_workitem_count() [1/2]

auto kcenon::pacs::storage::index_database::ups_workitem_count ( ) const -> Result<size_t>
nodiscard

Get total UPS workitem count.

Returns
Result containing number of workitems in the database or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1650 of file index_database.cpp.

1650 {
1651 return ups_repository_->ups_workitem_count();
1652}

References ups_repository_.

◆ ups_workitem_count() [2/2]

auto kcenon::pacs::storage::index_database::ups_workitem_count ( std::string_view state) const -> Result<size_t>
nodiscard

Get UPS workitem count by state.

Parameters
stateThe state to count
Returns
Result containing number of workitems with the given state or error

Definition at line 1654 of file index_database.cpp.

1655 {
1656 return ups_repository_->ups_workitem_count(state);
1657}

◆ upsert_instance() [1/2]

auto kcenon::pacs::storage::index_database::upsert_instance ( const instance_record & record) -> Result<int64_t>
nodiscard

Insert or update an instance record with full details.

Parameters
recordComplete instance record (pk field is ignored for insert)
Returns
Result containing the instance's primary key or error

Definition at line 1057 of file index_database.cpp.

1058 {
1059 return instance_repository_->upsert_instance(record);
1060}

◆ upsert_instance() [2/2]

auto kcenon::pacs::storage::index_database::upsert_instance ( int64_t series_pk,
std::string_view sop_uid,
std::string_view sop_class_uid,
std::string_view file_path,
int64_t file_size,
std::string_view transfer_syntax = "",
std::optional< int > instance_number = std::nullopt ) -> Result<int64_t>
nodiscard

Insert or update an instance record.

If an instance with the same sop_uid exists, updates the record. Otherwise, inserts a new record.

Parameters
series_pkForeign key to the series (required)
sop_uidSOP Instance UID (required, max 64 chars)
sop_class_uidSOP Class UID (required)
file_pathPath to the stored DICOM file (required)
file_sizeSize of the file in bytes (required, >= 0)
transfer_syntaxTransfer Syntax UID
instance_numberInstance number
Returns
Result containing the instance's primary key or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 1044 of file index_database.cpp.

1051 {
1052 return instance_repository_->upsert_instance(
1053 series_pk, sop_uid, sop_class_uid, file_path, file_size,
1054 transfer_syntax, instance_number);
1055}

◆ upsert_patient() [1/2]

auto kcenon::pacs::storage::index_database::upsert_patient ( const patient_record & record) -> Result<int64_t>
nodiscard

Insert or update a patient record with full details.

Parameters
recordComplete patient record (pk field is ignored for insert)
Returns
Result containing the patient's primary key or error

Definition at line 754 of file index_database.cpp.

755 {
756 return patient_repository_->upsert_patient(record);
757}

◆ upsert_patient() [2/2]

auto kcenon::pacs::storage::index_database::upsert_patient ( std::string_view patient_id,
std::string_view patient_name = "",
std::string_view birth_date = "",
std::string_view sex = "" ) -> Result<int64_t>
nodiscard

Insert or update a patient record.

If a patient with the same patient_id exists, updates the record. Otherwise, inserts a new record.

Parameters
patient_idPatient ID (required, max 64 chars)
patient_namePatient's name in DICOM PN format
birth_dateBirth date in YYYYMMDD format
sexSex code (M, F, O)
Returns
Result containing the patient's primary key or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 746 of file index_database.cpp.

749 {
750 return patient_repository_->upsert_patient(patient_id, patient_name,
751 birth_date, sex);
752}

◆ upsert_series() [1/2]

auto kcenon::pacs::storage::index_database::upsert_series ( const series_record & record) -> Result<int64_t>
nodiscard

Insert or update a series record with full details.

Parameters
recordComplete series record (pk field is ignored for insert)
Returns
Result containing the series's primary key or error

Definition at line 956 of file index_database.cpp.

957 {
958 auto existing = find_series(record.series_uid);
959 auto result = series_repository_->upsert_series(record);
960 if (result.is_err()) {
961 return result;
962 }
963
964 if (existing.has_value() && existing->study_pk > 0 &&
965 existing->study_pk != record.study_pk) {
966 (void)update_modalities_in_study(existing->study_pk);
967 }
968 if (record.study_pk > 0) {
969 (void)update_modalities_in_study(record.study_pk);
970 }
971
972 return result;
973}

◆ upsert_series() [2/2]

auto kcenon::pacs::storage::index_database::upsert_series ( int64_t study_pk,
std::string_view series_uid,
std::string_view modality = "",
std::optional< int > series_number = std::nullopt,
std::string_view series_description = "",
std::string_view body_part_examined = "",
std::string_view station_name = "" ) -> Result<int64_t>
nodiscard

Insert or update a series record.

If a series with the same series_uid exists, updates the record. Otherwise, inserts a new record.

Parameters
study_pkForeign key to the study (required)
series_uidSeries Instance UID (required, max 64 chars)
modalityModality (e.g., CT, MR)
series_numberSeries number
series_descriptionSeries description
body_part_examinedBody part examined
station_nameStation name
Returns
Result containing the series's primary key or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 937 of file index_database.cpp.

944 {
945 series_record record;
946 record.study_pk = study_pk;
947 record.series_uid = std::string(series_uid);
948 record.modality = std::string(modality);
949 record.series_number = series_number;
950 record.series_description = std::string(series_description);
951 record.body_part_examined = std::string(body_part_examined);
952 record.station_name = std::string(station_name);
953 return upsert_series(record);
954}
auto upsert_series(int64_t study_pk, std::string_view series_uid, std::string_view modality="", std::optional< int > series_number=std::nullopt, std::string_view series_description="", std::string_view body_part_examined="", std::string_view station_name="") -> Result< int64_t >
Insert or update a series record.
constexpr dicom_tag series_number
Series Number.

◆ upsert_study() [1/2]

auto kcenon::pacs::storage::index_database::upsert_study ( const study_record & record) -> Result<int64_t>
nodiscard

Insert or update a study record with full details.

Parameters
recordComplete study record (pk field is ignored for insert)
Returns
Result containing the study's primary key or error

Definition at line 859 of file index_database.cpp.

860 {
861 return study_repository_->upsert_study(record);
862}

◆ upsert_study() [2/2]

auto kcenon::pacs::storage::index_database::upsert_study ( int64_t patient_pk,
std::string_view study_uid,
std::string_view study_id = "",
std::string_view study_date = "",
std::string_view study_time = "",
std::string_view accession_number = "",
std::string_view referring_physician = "",
std::string_view study_description = "" ) -> Result<int64_t>
nodiscard

Insert or update a study record.

If a study with the same study_uid exists, updates the record. Otherwise, inserts a new record.

Parameters
patient_pkForeign key to the patient (required)
study_uidStudy Instance UID (required, max 64 chars)
study_idStudy ID
study_dateStudy date in YYYYMMDD format
study_timeStudy time in HHMMSS format
accession_numberAccession number
referring_physicianReferring physician's name
study_descriptionStudy description
Returns
Result containing the study's primary key or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h, and qr_scp/main.cpp.

Definition at line 845 of file index_database.cpp.

853 {
854 return study_repository_->upsert_study(
855 patient_pk, study_uid, study_id, study_date, study_time,
856 accession_number, referring_physician, study_description);
857}

◆ vacuum()

auto kcenon::pacs::storage::index_database::vacuum ( ) -> VoidResult
nodiscard

Reclaim unused space in the database.

VACUUM rebuilds the database file, repacking it into a minimal amount of disk space. This can reduce file size after large deletions but may take time for large databases.

Note: This operation requires exclusive access and may take significant time for large databases.

Returns
VoidResult indicating success or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1164 of file index_database.cpp.

1164 {
1165#ifdef PACS_WITH_DATABASE_SYSTEM
1166 // Prefer pacs_database_adapter for unified database operations (Issue #616)
1167 if (db_adapter_ && db_adapter_->is_connected()) {
1168 return db_adapter_->execute("VACUUM;");
1169 }
1170#endif
1171
1172 auto rc = sqlite3_exec(db_, "VACUUM;", nullptr, nullptr, nullptr);
1173 if (rc != SQLITE_OK) {
1174 return make_error<std::monostate>(
1175 rc, kcenon::pacs::compat::format("VACUUM failed: {}", sqlite3_errmsg(db_)),
1176 "storage");
1177 }
1178 return ok();
1179}

◆ verify_integrity()

auto kcenon::pacs::storage::index_database::verify_integrity ( ) const -> VoidResult
nodiscard

Verify database integrity.

Runs SQLite's integrity check to verify the database structure and detect any corruption issues.

Returns
VoidResult indicating success or error with details
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1198 of file index_database.cpp.

1198 {
1199#ifdef PACS_WITH_DATABASE_SYSTEM
1200 // Prefer pacs_database_adapter for unified database operations (Issue #616)
1201 if (db_adapter_ && db_adapter_->is_connected()) {
1202 auto result = db_adapter_->select("PRAGMA integrity_check;");
1203 if (result.is_err()) {
1204 return make_error<std::monostate>(
1205 result.error().code, result.error().message, "storage");
1206 }
1207
1208 for (const auto& row : result.value()) {
1209 auto it = row.find("integrity_check");
1210 if (it != row.end() && it->second != "ok") {
1211 return make_error<std::monostate>(
1212 -1, kcenon::pacs::compat::format("Integrity check failed: {}", it->second),
1213 "storage");
1214 }
1215 }
1216 return ok();
1217 }
1218#endif
1219
1220 const char* sql = "PRAGMA integrity_check;";
1221
1222 sqlite3_stmt* stmt = nullptr;
1223 auto rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
1224 if (rc != SQLITE_OK) {
1225 return make_error<std::monostate>(
1226 rc,
1227 kcenon::pacs::compat::format("Failed to prepare integrity check: {}",
1228 sqlite3_errmsg(db_)),
1229 "storage");
1230 }
1231
1232 std::string result;
1233 while (sqlite3_step(stmt) == SQLITE_ROW) {
1234 result = get_text(stmt, 0);
1235 if (result != "ok") {
1236 sqlite3_finalize(stmt);
1237 return make_error<std::monostate>(
1238 -1, kcenon::pacs::compat::format("Integrity check failed: {}", result),
1239 "storage");
1240 }
1241 }
1242
1243 sqlite3_finalize(stmt);
1244 return ok();
1245}

References db_.

◆ worklist_count() [1/2]

auto kcenon::pacs::storage::index_database::worklist_count ( ) const -> Result<size_t>
nodiscard

Get total worklist count.

Returns
Result containing number of worklist items in the database or error
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1573 of file index_database.cpp.

1573 {
1574 return worklist_repository_->worklist_count();
1575}

References worklist_repository_.

◆ worklist_count() [2/2]

auto kcenon::pacs::storage::index_database::worklist_count ( std::string_view status) const -> Result<size_t>
nodiscard

Get worklist count by status.

Parameters
statusThe status to count (SCHEDULED, STARTED, COMPLETED)
Returns
Result containing number of worklist items with the given status or error

Definition at line 1577 of file index_database.cpp.

1577 {
1578 return worklist_repository_->worklist_count(status);
1579}

Member Data Documentation

◆ audit_repository_

std::shared_ptr<audit_repository> kcenon::pacs::storage::index_database::audit_repository_
mutableprivate

◆ db_

sqlite3* kcenon::pacs::storage::index_database::db_ {nullptr}
private

SQLite database handle (used for migrations and fallback)

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1337 of file index_database.h.

1337{nullptr};

Referenced by get_storage_stats(), is_open(), native_handle(), schema_version(), verify_integrity(), and ~index_database().

◆ instance_repository_

std::shared_ptr<instance_repository> kcenon::pacs::storage::index_database::instance_repository_
mutableprivate

◆ migration_runner_

migration_runner kcenon::pacs::storage::index_database::migration_runner_
private

Migration runner for schema management.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1356 of file index_database.h.

Referenced by schema_version().

◆ mpps_repository_

std::shared_ptr<mpps_repository> kcenon::pacs::storage::index_database::mpps_repository_
mutableprivate

◆ path_

std::string kcenon::pacs::storage::index_database::path_
private

◆ patient_repository_

std::shared_ptr<patient_repository> kcenon::pacs::storage::index_database::patient_repository_
mutableprivate

Extracted repositories used by the facade API.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1346 of file index_database.h.

Referenced by patient_count(), and ~index_database().

◆ remove_on_close_

bool kcenon::pacs::storage::index_database::remove_on_close_ {false}
private

Remove the backing file on destruction for adapter-compatible memory DBs.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/storage/index_database.h.

Definition at line 1343 of file index_database.h.

1343{false};

Referenced by ~index_database().

◆ series_repository_

std::shared_ptr<series_repository> kcenon::pacs::storage::index_database::series_repository_
mutableprivate

◆ study_repository_

std::shared_ptr<study_repository> kcenon::pacs::storage::index_database::study_repository_
mutableprivate

◆ ups_repository_

std::shared_ptr<ups_repository> kcenon::pacs::storage::index_database::ups_repository_
mutableprivate

◆ worklist_repository_

std::shared_ptr<worklist_repository> kcenon::pacs::storage::index_database::worklist_repository_
mutableprivate

The documentation for this class was generated from the following files: