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

Repository for key image persistence (legacy SQLite interface) More...

#include <key_image_repository.h>

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

Public Member Functions

 key_image_repository (sqlite3 *db)
 
 ~key_image_repository ()
 
 key_image_repository (const key_image_repository &)=delete
 
auto operator= (const key_image_repository &) -> key_image_repository &=delete
 
 key_image_repository (key_image_repository &&) noexcept
 
auto operator= (key_image_repository &&) noexcept -> key_image_repository &
 
auto save (const key_image_record &record) -> VoidResult
 
auto find_by_id (std::string_view key_image_id) const -> std::optional< key_image_record >
 
auto find_by_pk (int64_t pk) const -> std::optional< key_image_record >
 
auto find_by_study (std::string_view study_uid) const -> std::vector< key_image_record >
 
auto search (const key_image_query &query) const -> std::vector< key_image_record >
 
auto remove (std::string_view key_image_id) -> VoidResult
 
auto exists (std::string_view key_image_id) const -> bool
 
auto count () const -> size_t
 
auto count_by_study (std::string_view study_uid) const -> size_t
 
auto is_valid () const noexcept -> bool
 

Private Member Functions

auto parse_row (void *stmt) const -> key_image_record
 

Private Attributes

sqlite3 * db_ {nullptr}
 

Detailed Description

Repository for key image persistence (legacy SQLite interface)

This is the legacy interface maintained for builds without database_system. New code should use the base_repository version when PACS_WITH_DATABASE_SYSTEM is defined.

Definition at line 162 of file key_image_repository.h.

Constructor & Destructor Documentation

◆ key_image_repository() [1/3]

kcenon::pacs::storage::key_image_repository::key_image_repository ( sqlite3 * db)
explicit

◆ ~key_image_repository()

kcenon::pacs::storage::key_image_repository::~key_image_repository ( )
default

◆ key_image_repository() [2/3]

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

◆ key_image_repository() [3/3]

kcenon::pacs::storage::key_image_repository::key_image_repository ( key_image_repository && )
defaultnoexcept

Member Function Documentation

◆ count()

size_t kcenon::pacs::storage::key_image_repository::count ( ) const -> size_t
nodiscard

Definition at line 584 of file key_image_repository.cpp.

588 {
589 if (!db_) return 0;
590
591 static constexpr const char* sql = "SELECT COUNT(*) FROM key_images";
592
593 sqlite3_stmt* stmt = nullptr;
594 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
595 return 0;
596 }
597
598 size_t result = 0;
599 if (sqlite3_step(stmt) == SQLITE_ROW) {
600 result = static_cast<size_t>(sqlite3_column_int64(stmt, 0));
601 }

◆ count_by_study()

size_t kcenon::pacs::storage::key_image_repository::count_by_study ( std::string_view study_uid) const -> size_t
nodiscard

Definition at line 603 of file key_image_repository.cpp.

607 {
608 if (!db_) return 0;
609
610 static constexpr const char* sql =
611 "SELECT COUNT(*) FROM key_images WHERE study_uid = ?";
612
613 sqlite3_stmt* stmt = nullptr;
614 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
615 return 0;
616 }
617
618 sqlite3_bind_text(stmt, 1, study_uid.data(),
619 static_cast<int>(study_uid.size()), SQLITE_TRANSIENT);
620
621 size_t result = 0;
622 if (sqlite3_step(stmt) == SQLITE_ROW) {
623 result = static_cast<size_t>(sqlite3_column_int64(stmt, 0));
624 }

◆ exists()

bool kcenon::pacs::storage::key_image_repository::exists ( std::string_view key_image_id) const -> bool
nodiscard

Definition at line 565 of file key_image_repository.cpp.

569 {
570 if (!db_) return false;
571
572 static constexpr const char* sql =
573 "SELECT 1 FROM key_images WHERE key_image_id = ?";
574
575 sqlite3_stmt* stmt = nullptr;
576 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
577 return false;
578 }
579
580 sqlite3_bind_text(stmt, 1, key_image_id.data(),
581 static_cast<int>(key_image_id.size()), SQLITE_TRANSIENT);
582

Referenced by kcenon::pacs::web::endpoints::register_key_image_endpoints_impl().

Here is the caller graph for this function:

◆ find_by_id()

std::optional< key_image_record > kcenon::pacs::storage::key_image_repository::find_by_id ( std::string_view key_image_id) const -> std::optional<key_image_record>
nodiscard

Definition at line 421 of file key_image_repository.cpp.

422 {
423 if (!db_) return std::nullopt;
424
425 static constexpr const char* sql = R"(
426 SELECT pk, key_image_id, study_uid, sop_instance_uid, frame_number,
427 user_id, reason, document_title, created_at
428 FROM key_images WHERE key_image_id = ?
429 )";
430
431 sqlite3_stmt* stmt = nullptr;
432 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
433 return std::nullopt;
434 }
435
436 sqlite3_bind_text(stmt, 1, key_image_id.data(),
437 static_cast<int>(key_image_id.size()), SQLITE_TRANSIENT);
438
439 std::optional<key_image_record> result;
440 if (sqlite3_step(stmt) == SQLITE_ROW) {
441 result = parse_row(stmt);
442 }
443
444 sqlite3_finalize(stmt);
445 return result;
446}
auto parse_row(void *stmt) const -> key_image_record

References db_, and parse_row().

Here is the call graph for this function:

◆ find_by_pk()

std::optional< key_image_record > kcenon::pacs::storage::key_image_repository::find_by_pk ( int64_t pk) const -> std::optional<key_image_record>
nodiscard

Definition at line 448 of file key_image_repository.cpp.

449 {
450 if (!db_) return std::nullopt;
451
452 static constexpr const char* sql = R"(
453 SELECT pk, key_image_id, study_uid, sop_instance_uid, frame_number,
454 user_id, reason, document_title, created_at
455 FROM key_images WHERE pk = ?
456 )";
457
458 sqlite3_stmt* stmt = nullptr;
459 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
460 return std::nullopt;
461 }
462
463 sqlite3_bind_int64(stmt, 1, pk);
464
465 std::optional<key_image_record> result;
466 if (sqlite3_step(stmt) == SQLITE_ROW) {
467 result = parse_row(stmt);
468 }
469
470 sqlite3_finalize(stmt);
471 return result;
472}

References db_, and parse_row().

Here is the call graph for this function:

◆ find_by_study()

std::vector< key_image_record > kcenon::pacs::storage::key_image_repository::find_by_study ( std::string_view study_uid) const -> std::vector<key_image_record>
nodiscard

Definition at line 474 of file key_image_repository.cpp.

475 {
476 key_image_query query;
477 query.study_uid = std::string(study_uid);
478 return search(query);
479}
auto search(const key_image_query &query) const -> std::vector< key_image_record >
const atna_coded_value query
Query (110112)

References search().

Referenced by kcenon::pacs::web::endpoints::register_key_image_endpoints_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_valid()

bool kcenon::pacs::storage::key_image_repository::is_valid ( ) const -> bool
nodiscardnoexcept

Definition at line 626 of file key_image_repository.cpp.

◆ operator=() [1/2]

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

◆ operator=() [2/2]

auto kcenon::pacs::storage::key_image_repository::operator= ( key_image_repository && ) -> key_image_repository &
defaultnoexcept

◆ parse_row()

key_image_record kcenon::pacs::storage::key_image_repository::parse_row ( void * stmt) const -> key_image_record
nodiscardprivate

Definition at line 628 of file key_image_repository.cpp.

630 { return db_ != nullptr; }
631
632key_image_record key_image_repository::parse_row(void* stmt_ptr) const {
633 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
634 key_image_record record;
635
636 int col = 0;
637 record.pk = get_int64_column(stmt, col++);
638 record.key_image_id = get_text_column(stmt, col++);
639 record.study_uid = get_text_column(stmt, col++);
640 record.sop_instance_uid = get_text_column(stmt, col++);
641 record.frame_number = get_optional_int(stmt, col++);
642 record.user_id = get_text_column(stmt, col++);
643 record.reason = get_text_column(stmt, col++);
644 record.document_title = get_text_column(stmt, col++);
645
646 auto created_str = get_text_column(stmt, col++);

Referenced by find_by_id(), find_by_pk(), and search().

Here is the caller graph for this function:

◆ remove()

VoidResult kcenon::pacs::storage::key_image_repository::remove ( std::string_view key_image_id) -> VoidResult
nodiscard

Definition at line 532 of file key_image_repository.cpp.

536 {
537 if (!db_) {
538 return VoidResult(kcenon::common::error_info{
539 -1, "Database not initialized", "key_image_repository"});
540 }
541
542 static constexpr const char* sql =
543 "DELETE FROM key_images WHERE key_image_id = ?";
544
545 sqlite3_stmt* stmt = nullptr;
546 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
547 return VoidResult(kcenon::common::error_info{
548 -1,
549 "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
550 "key_image_repository"});
551 }
552
553 sqlite3_bind_text(stmt, 1, key_image_id.data(),
554 static_cast<int>(key_image_id.size()), SQLITE_TRANSIENT);
555
556 auto rc = sqlite3_step(stmt);
557 sqlite3_finalize(stmt);
558
559 if (rc != SQLITE_DONE) {
560 return VoidResult(kcenon::common::error_info{
561 -1,
562 "Failed to delete key image: " + std::string(sqlite3_errmsg(db_)),
563 "key_image_repository"});

Referenced by kcenon::pacs::web::endpoints::register_key_image_endpoints_impl().

Here is the caller graph for this function:

◆ save()

VoidResult kcenon::pacs::storage::key_image_repository::save ( const key_image_record & record) -> VoidResult
nodiscard

Definition at line 368 of file key_image_repository.cpp.

368 {
369 if (!db_) {
370 return VoidResult(kcenon::common::error_info{
371 -1, "Database not initialized", "key_image_repository"});
372 }
373
374 static constexpr const char* sql = R"(
375 INSERT INTO key_images (
376 key_image_id, study_uid, sop_instance_uid, frame_number,
377 user_id, reason, document_title, created_at
378 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
379 ON CONFLICT(key_image_id) DO UPDATE SET
380 reason = excluded.reason,
381 document_title = excluded.document_title
382 )";
383
384 sqlite3_stmt* stmt = nullptr;
385 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
386 return VoidResult(kcenon::common::error_info{
387 -1,
388 "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
389 "key_image_repository"});
390 }
391
392 auto now_str = to_timestamp_string(std::chrono::system_clock::now());
393
394 int idx = 1;
395 sqlite3_bind_text(stmt, idx++, record.key_image_id.c_str(), -1,
396 SQLITE_TRANSIENT);
397 sqlite3_bind_text(stmt, idx++, record.study_uid.c_str(), -1,
398 SQLITE_TRANSIENT);
399 sqlite3_bind_text(stmt, idx++, record.sop_instance_uid.c_str(), -1,
400 SQLITE_TRANSIENT);
401 bind_optional_int(stmt, idx++, record.frame_number);
402 sqlite3_bind_text(stmt, idx++, record.user_id.c_str(), -1, SQLITE_TRANSIENT);
403 sqlite3_bind_text(stmt, idx++, record.reason.c_str(), -1, SQLITE_TRANSIENT);
404 sqlite3_bind_text(stmt, idx++, record.document_title.c_str(), -1,
405 SQLITE_TRANSIENT);
406 sqlite3_bind_text(stmt, idx++, now_str.c_str(), -1, SQLITE_TRANSIENT);
407
408 auto rc = sqlite3_step(stmt);
409 sqlite3_finalize(stmt);
410
411 if (rc != SQLITE_DONE) {
412 return VoidResult(kcenon::common::error_info{
413 -1,
414 "Failed to save key image: " + std::string(sqlite3_errmsg(db_)),
415 "key_image_repository"});
416 }
417
418 return kcenon::common::ok();
419}

Referenced by kcenon::pacs::web::endpoints::register_key_image_endpoints_impl().

Here is the caller graph for this function:

◆ search()

std::vector< key_image_record > kcenon::pacs::storage::key_image_repository::search ( const key_image_query & query) const -> std::vector<key_image_record>
nodiscard

Definition at line 481 of file key_image_repository.cpp.

482 {
483 std::vector<key_image_record> result;
484 if (!db_) return result;
485
486 std::ostringstream sql;
487 sql << R"(
488 SELECT pk, key_image_id, study_uid, sop_instance_uid, frame_number,
489 user_id, reason, document_title, created_at
490 FROM key_images WHERE 1=1
491 )";
492
493 std::vector<std::pair<int, std::string>> bindings;
494 int param_idx = 1;
495
496 if (query.study_uid.has_value()) {
497 sql << " AND study_uid = ?";
498 bindings.emplace_back(param_idx++, query.study_uid.value());
499 }
500
501 if (query.sop_instance_uid.has_value()) {
502 sql << " AND sop_instance_uid = ?";
503 bindings.emplace_back(param_idx++, query.sop_instance_uid.value());
504 }
505
506 if (query.user_id.has_value()) {
507 sql << " AND user_id = ?";
508 bindings.emplace_back(param_idx++, query.user_id.value());
509 }
510
511 sql << " ORDER BY created_at DESC";
512
513 if (query.limit > 0) {
514 sql << " LIMIT " << query.limit << " OFFSET " << query.offset;
515 }
516
517 sqlite3_stmt* stmt = nullptr;
518 auto sql_str = sql.str();
519 if (sqlite3_prepare_v2(db_, sql_str.c_str(), -1, &stmt, nullptr) !=
520 SQLITE_OK) {
521 return result;
522 }
523
524 for (const auto& [idx, value] : bindings) {
525 sqlite3_bind_text(stmt, idx, value.c_str(), -1, SQLITE_TRANSIENT);
526 }
527
528 while (sqlite3_step(stmt) == SQLITE_ROW) {
529 result.push_back(parse_row(stmt));
530 }

References db_, and parse_row().

Referenced by find_by_study().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ db_

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

Definition at line 192 of file key_image_repository.h.

192{nullptr};

Referenced by find_by_id(), find_by_pk(), and search().


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