634 {
636 return VoidResult(kcenon::common::error_info{
637 -1, "Database not initialized", "annotation_repository"});
638 }
639
640 static constexpr const char* sql = R"(
641 INSERT INTO annotations (
642 annotation_id, study_uid, series_uid, sop_instance_uid, frame_number,
643 user_id, annotation_type, geometry_json, text, style_json,
644 created_at, updated_at
645 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
646 ON CONFLICT(annotation_id) DO UPDATE SET
647 geometry_json = excluded.geometry_json,
648 text = excluded.text,
649 style_json = excluded.style_json,
650 updated_at = excluded.updated_at
651 )";
652
653 sqlite3_stmt* stmt = nullptr;
654 if (sqlite3_prepare_v2(
db_, sql, -1, &stmt,
nullptr) != SQLITE_OK) {
655 return VoidResult(kcenon::common::error_info{
656 -1,
"Failed to prepare statement: " + std::string(sqlite3_errmsg(
db_)),
657 "annotation_repository"});
658 }
659
660 auto now = std::chrono::system_clock::now();
661 auto now_str = to_timestamp_string(now);
663
664 int idx = 1;
665 sqlite3_bind_text(stmt, idx++,
record.annotation_id.c_str(), -1, SQLITE_TRANSIENT);
666 sqlite3_bind_text(stmt, idx++,
record.study_uid.c_str(), -1, SQLITE_TRANSIENT);
667 sqlite3_bind_text(stmt, idx++,
record.series_uid.c_str(), -1, SQLITE_TRANSIENT);
668 sqlite3_bind_text(stmt, idx++,
record.sop_instance_uid.c_str(), -1, SQLITE_TRANSIENT);
669 bind_optional_int(stmt, idx++,
record.frame_number);
670 sqlite3_bind_text(stmt, idx++,
record.user_id.c_str(), -1, SQLITE_TRANSIENT);
671 sqlite3_bind_text(stmt, idx++,
to_string(
record.type).c_str(), -1, SQLITE_TRANSIENT);
672 sqlite3_bind_text(stmt, idx++,
record.geometry_json.c_str(), -1, SQLITE_TRANSIENT);
673 sqlite3_bind_text(stmt, idx++,
record.text.c_str(), -1, SQLITE_TRANSIENT);
674 sqlite3_bind_text(stmt, idx++, style_json.c_str(), -1, SQLITE_TRANSIENT);
675 sqlite3_bind_text(stmt, idx++, now_str.c_str(), -1, SQLITE_TRANSIENT);
676 sqlite3_bind_text(stmt, idx++, now_str.c_str(), -1, SQLITE_TRANSIENT);
677
678 auto rc = sqlite3_step(stmt);
679 sqlite3_finalize(stmt);
680
681 if (rc != SQLITE_DONE) {
682 return VoidResult(kcenon::common::error_info{
683 -1,
"Failed to save annotation: " + std::string(sqlite3_errmsg(
db_)),
684 "annotation_repository"});
685 }
686
687 return kcenon::common::ok();
688}
static auto serialize_style(const annotation_style &style) -> std::string
auto to_string(annotation_type type) -> std::string
Convert annotation_type to string.