768 {
769 if (
record.study_uid.empty()) {
770 return make_error<int64_t>(-1, "Study Instance UID is required",
771 "storage");
772 }
773
774 if (
record.study_uid.length() > 64) {
775 return make_error<int64_t>(
776 -1, "Study Instance UID exceeds maximum length of 64 characters",
777 "storage");
778 }
779
780 if (
record.patient_pk <= 0) {
781 return make_error<int64_t>(-1, "Valid patient_pk is required",
782 "storage");
783 }
784
785 const char* sql = R"(
786 INSERT INTO studies (
787 patient_pk, study_uid, study_id, study_date, study_time,
788 accession_number, referring_physician, study_description,
789 updated_at
790 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
791 ON CONFLICT(study_uid) DO UPDATE SET
792 patient_pk = excluded.patient_pk,
793 study_id = excluded.study_id,
794 study_date = excluded.study_date,
795 study_time = excluded.study_time,
796 accession_number = excluded.accession_number,
797 referring_physician = excluded.referring_physician,
798 study_description = excluded.study_description,
799 updated_at = datetime('now')
800 RETURNING study_pk;
801 )";
802
803 sqlite3_stmt* stmt = nullptr;
804 auto rc = sqlite3_prepare_v2(
db_, sql, -1, &stmt,
nullptr);
805 if (rc != SQLITE_OK) {
806 return make_error<int64_t>(
807 rc,
808 kcenon::pacs::compat::format(
"Failed to prepare statement: {}", sqlite3_errmsg(
db_)),
809 "storage");
810 }
811
812 sqlite3_bind_int64(stmt, 1,
record.patient_pk);
813 sqlite3_bind_text(stmt, 2,
record.study_uid.c_str(), -1, SQLITE_TRANSIENT);
814 sqlite3_bind_text(stmt, 3,
record.study_id.c_str(), -1, SQLITE_TRANSIENT);
815 sqlite3_bind_text(stmt, 4,
record.study_date.c_str(), -1, SQLITE_TRANSIENT);
816 sqlite3_bind_text(stmt, 5,
record.study_time.c_str(), -1, SQLITE_TRANSIENT);
817 sqlite3_bind_text(stmt, 6,
record.accession_number.c_str(), -1,
818 SQLITE_TRANSIENT);
819 sqlite3_bind_text(stmt, 7,
record.referring_physician.c_str(), -1,
820 SQLITE_TRANSIENT);
821 sqlite3_bind_text(stmt, 8,
record.study_description.c_str(), -1,
822 SQLITE_TRANSIENT);
823
824 rc = sqlite3_step(stmt);
825 if (rc != SQLITE_ROW) {
826 auto error_msg = sqlite3_errmsg(
db_);
827 sqlite3_finalize(stmt);
828 return make_error<int64_t>(
829 rc, kcenon::pacs::compat::format("Failed to upsert study: {}", error_msg),
830 "storage");
831 }
832
833 auto pk = sqlite3_column_int64(stmt, 0);
834 sqlite3_finalize(stmt);
835
836 return pk;
837}