1202 {
1204 return VoidResult(kcenon::common::error_info{
1205 -1, "Database not initialized", "job_repository"});
1206 }
1207
1208 static constexpr const char* sql = R"(
1209 INSERT INTO jobs (
1210 job_id, type, status, priority,
1211 source_node_id, destination_node_id,
1212 patient_id, study_uid, series_uid, sop_instance_uid, instance_uids_json,
1213 total_items, completed_items, failed_items, skipped_items, bytes_transferred,
1214 current_item, current_item_description,
1215 error_message, error_details, retry_count, max_retries,
1216 created_by, metadata_json,
1217 created_at, queued_at, started_at, completed_at
1218 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1219 ON CONFLICT(job_id) DO UPDATE SET
1220 status = excluded.status,
1221 priority = excluded.priority,
1222 total_items = excluded.total_items,
1223 completed_items = excluded.completed_items,
1224 failed_items = excluded.failed_items,
1225 skipped_items = excluded.skipped_items,
1226 bytes_transferred = excluded.bytes_transferred,
1227 current_item = excluded.current_item,
1228 current_item_description = excluded.current_item_description,
1229 error_message = excluded.error_message,
1230 error_details = excluded.error_details,
1231 retry_count = excluded.retry_count,
1232 queued_at = excluded.queued_at,
1233 started_at = excluded.started_at,
1234 completed_at = excluded.completed_at
1235 )";
1236
1237 sqlite3_stmt* stmt = nullptr;
1238 if (sqlite3_prepare_v2(
db_, sql, -1, &stmt,
nullptr) != SQLITE_OK) {
1239 return VoidResult(kcenon::common::error_info{
1240 -1,
1241 "Failed to prepare statement: " + std::string(sqlite3_errmsg(
db_)),
1242 "job_repository"});
1243 }
1244
1245 int idx = 1;
1246 sqlite3_bind_text(stmt, idx++,
job.job_id.c_str(), -1, SQLITE_TRANSIENT);
1248 SQLITE_STATIC);
1250 SQLITE_STATIC);
1251 sqlite3_bind_int(stmt, idx++,
static_cast<int>(
job.priority));
1252
1253 sqlite3_bind_text(stmt, idx++,
job.source_node_id.c_str(), -1,
1254 SQLITE_TRANSIENT);
1255 sqlite3_bind_text(stmt, idx++,
job.destination_node_id.c_str(), -1,
1256 SQLITE_TRANSIENT);
1257
1258 bind_optional_text(stmt, idx++,
job.patient_id);
1259 bind_optional_text(stmt, idx++,
job.study_uid);
1260 bind_optional_text(stmt, idx++,
job.series_uid);
1261 bind_optional_text(stmt, idx++,
job.sop_instance_uid);
1262
1264 sqlite3_bind_text(stmt, idx++, uids_json.c_str(), -1, SQLITE_TRANSIENT);
1265
1266 sqlite3_bind_int64(stmt, idx++,
1267 static_cast<int64_t
>(
job.progress.total_items));
1268 sqlite3_bind_int64(stmt, idx++,
1269 static_cast<int64_t
>(
job.progress.completed_items));
1270 sqlite3_bind_int64(stmt, idx++,
1271 static_cast<int64_t
>(
job.progress.failed_items));
1272 sqlite3_bind_int64(stmt, idx++,
1273 static_cast<int64_t
>(
job.progress.skipped_items));
1274 sqlite3_bind_int64(stmt, idx++,
1275 static_cast<int64_t
>(
job.progress.bytes_transferred));
1276
1277 sqlite3_bind_text(stmt, idx++,
job.progress.current_item.c_str(), -1,
1278 SQLITE_TRANSIENT);
1279 sqlite3_bind_text(stmt, idx++,
1280 job.progress.current_item_description.c_str(), -1,
1281 SQLITE_TRANSIENT);
1282
1283 sqlite3_bind_text(stmt, idx++,
job.error_message.c_str(), -1,
1284 SQLITE_TRANSIENT);
1285 sqlite3_bind_text(stmt, idx++,
job.error_details.c_str(), -1,
1286 SQLITE_TRANSIENT);
1287 sqlite3_bind_int(stmt, idx++,
job.retry_count);
1288 sqlite3_bind_int(stmt, idx++,
job.max_retries);
1289
1290 sqlite3_bind_text(stmt, idx++,
job.created_by.c_str(), -1, SQLITE_TRANSIENT);
1291
1293 sqlite3_bind_text(stmt, idx++, metadata_json.c_str(), -1, SQLITE_TRANSIENT);
1294
1295 auto created_str = to_timestamp_string(
job.created_at);
1296 sqlite3_bind_text(stmt, idx++, created_str.c_str(), -1, SQLITE_TRANSIENT);
1297
1298 bind_optional_timestamp(stmt, idx++,
job.queued_at);
1299 bind_optional_timestamp(stmt, idx++,
job.started_at);
1300 bind_optional_timestamp(stmt, idx++,
job.completed_at);
1301
1302 auto rc = sqlite3_step(stmt);
1303 sqlite3_finalize(stmt);
1304
1305 if (rc != SQLITE_DONE) {
1306 return VoidResult(kcenon::common::error_info{
1307 -1,
"Failed to save job: " + std::string(sqlite3_errmsg(
db_)),
1308 "job_repository"});
1309 }
1310
1311 return kcenon::common::ok();
1312}
static auto serialize_metadata(const std::unordered_map< std::string, std::string > &metadata) -> std::string
static auto serialize_instance_uids(const std::vector< std::string > &uids) -> std::string