591 {
592 if (
record.patient_id.empty()) {
593 return make_error<int64_t>(-1, "Patient ID is required", "storage");
594 }
595
596 if (
record.patient_id.length() > 64) {
597 return make_error<int64_t>(
598 -1, "Patient ID exceeds maximum length of 64 characters",
599 "storage");
600 }
601
604 return make_error<int64_t>(
605 -1, "Invalid sex value. Must be M, F, or O", "storage");
606 }
607
608 const char* sql = R"(
609 INSERT INTO patients (
610 patient_id, patient_name, birth_date, sex,
611 other_ids, ethnic_group, comments, updated_at
612 ) VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))
613 ON CONFLICT(patient_id) DO UPDATE SET
614 patient_name = excluded.patient_name,
615 birth_date = excluded.birth_date,
616 sex = excluded.sex,
617 other_ids = excluded.other_ids,
618 ethnic_group = excluded.ethnic_group,
619 comments = excluded.comments,
620 updated_at = datetime('now')
621 RETURNING patient_pk;
622 )";
623
624 sqlite3_stmt* stmt = nullptr;
625 auto rc = sqlite3_prepare_v2(
db_, sql, -1, &stmt,
nullptr);
626 if (rc != SQLITE_OK) {
627 return make_error<int64_t>(
628 rc,
629 kcenon::pacs::compat::format(
"Failed to prepare statement: {}", sqlite3_errmsg(
db_)),
630 "storage");
631 }
632
633 sqlite3_bind_text(stmt, 1,
record.patient_id.c_str(), -1, SQLITE_TRANSIENT);
634 sqlite3_bind_text(stmt, 2,
record.patient_name.c_str(), -1, SQLITE_TRANSIENT);
635 sqlite3_bind_text(stmt, 3,
record.birth_date.c_str(), -1, SQLITE_TRANSIENT);
636 sqlite3_bind_text(stmt, 4,
record.sex.c_str(), -1, SQLITE_TRANSIENT);
637 sqlite3_bind_text(stmt, 5,
record.other_ids.c_str(), -1, SQLITE_TRANSIENT);
638 sqlite3_bind_text(stmt, 6,
record.ethnic_group.c_str(), -1, SQLITE_TRANSIENT);
639 sqlite3_bind_text(stmt, 7,
record.comments.c_str(), -1, SQLITE_TRANSIENT);
640
641 rc = sqlite3_step(stmt);
642 if (rc != SQLITE_ROW) {
643 auto error_msg = sqlite3_errmsg(
db_);
644 sqlite3_finalize(stmt);
645 return make_error<int64_t>(
646 rc, kcenon::pacs::compat::format("Failed to upsert patient: {}", error_msg),
647 "storage");
648 }
649
650 auto pk = sqlite3_column_int64(stmt, 0);
651 sqlite3_finalize(stmt);
652
653 return pk;
654}