PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
job_repository.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
21#pragma once
22
24
25#include <kcenon/common/patterns/result.h>
26
27#include <memory>
28#include <optional>
29#include <string>
30#include <string_view>
31#include <vector>
32
33#ifdef PACS_WITH_DATABASE_SYSTEM
34
36
37namespace kcenon::pacs::storage {
38
42struct job_query_options {
43 std::optional<client::job_status> status;
44 std::optional<client::job_type> type;
45 std::optional<std::string> node_id;
46 std::optional<std::string> created_by;
47 size_t limit{100};
48 size_t offset{0};
49 bool order_by_priority{true};
50};
51
81class job_repository
82 : public base_repository<client::job_record, std::string> {
83public:
84 explicit job_repository(std::shared_ptr<pacs_database_adapter> db);
85 ~job_repository() override = default;
86
87 job_repository(const job_repository&) = delete;
88 auto operator=(const job_repository&) -> job_repository& = delete;
89 job_repository(job_repository&&) noexcept = default;
90 auto operator=(job_repository&&) noexcept -> job_repository& = default;
91
92 // =========================================================================
93 // Domain-Specific Operations
94 // =========================================================================
95
102 [[nodiscard]] auto find_by_pk(int64_t pk) -> result_type;
103
110 [[nodiscard]] auto find_jobs(const job_query_options& options = {})
111 -> list_result_type;
112
120 [[nodiscard]] auto find_by_status(client::job_status status,
121 size_t limit = 100) -> list_result_type;
122
132 [[nodiscard]] auto find_pending_jobs(size_t limit = 10) -> list_result_type;
133
140 [[nodiscard]] auto find_by_node(std::string_view node_id)
141 -> list_result_type;
142
149 [[nodiscard]] auto cleanup_old_jobs(std::chrono::hours max_age)
151
152 // =========================================================================
153 // Status Updates
154 // =========================================================================
155
165 [[nodiscard]] auto update_status(std::string_view job_id,
166 client::job_status status,
167 std::string_view error_message = "",
168 std::string_view error_details = "")
169 -> VoidResult;
170
178 [[nodiscard]] auto update_progress(std::string_view job_id,
179 const client::job_progress& progress)
180 -> VoidResult;
181
190 [[nodiscard]] auto mark_started(std::string_view job_id) -> VoidResult;
191
200 [[nodiscard]] auto mark_completed(std::string_view job_id) -> VoidResult;
201
212 [[nodiscard]] auto mark_failed(std::string_view job_id,
213 std::string_view error_message,
214 std::string_view error_details = "")
215 -> VoidResult;
216
223 [[nodiscard]] auto increment_retry(std::string_view job_id) -> VoidResult;
224
225 // =========================================================================
226 // Statistics
227 // =========================================================================
228
235 [[nodiscard]] auto count_by_status(client::job_status status)
237
243 [[nodiscard]] auto count_completed_today() -> Result<size_t>;
244
250 [[nodiscard]] auto count_failed_today() -> Result<size_t>;
251
252protected:
253 // =========================================================================
254 // base_repository overrides
255 // =========================================================================
256
257 [[nodiscard]] auto map_row_to_entity(const database_row& row) const
258 -> client::job_record override;
259
260 [[nodiscard]] auto entity_to_row(const client::job_record& entity) const
261 -> std::map<std::string, database_value> override;
262
263 [[nodiscard]] auto get_pk(const client::job_record& entity) const
264 -> std::string override;
265
266 [[nodiscard]] auto has_pk(const client::job_record& entity) const
267 -> bool override;
268
269 [[nodiscard]] auto select_columns() const
270 -> std::vector<std::string> override;
271
272private:
273 [[nodiscard]] auto parse_timestamp(const std::string& str) const
274 -> std::chrono::system_clock::time_point;
275
276 [[nodiscard]] auto format_timestamp(
277 std::chrono::system_clock::time_point tp) const -> std::string;
278
279 [[nodiscard]] auto format_optional_timestamp(
280 const std::optional<std::chrono::system_clock::time_point>& tp) const
281 -> std::string;
282
283 [[nodiscard]] static auto serialize_instance_uids(
284 const std::vector<std::string>& uids) -> std::string;
285
286 [[nodiscard]] static auto deserialize_instance_uids(std::string_view json)
287 -> std::vector<std::string>;
288
289 [[nodiscard]] static auto serialize_metadata(
290 const std::unordered_map<std::string, std::string>& metadata)
291 -> std::string;
292
293 [[nodiscard]] static auto deserialize_metadata(std::string_view json)
294 -> std::unordered_map<std::string, std::string>;
295};
296
297} // namespace kcenon::pacs::storage
298
299#else // !PACS_WITH_DATABASE_SYSTEM
300
301// Legacy interface for builds without database_system
302struct sqlite3;
303
304namespace kcenon::pacs::storage {
305
306template <typename T>
308
309using VoidResult = kcenon::common::VoidResult;
310
315 std::optional<client::job_status> status;
316 std::optional<client::job_type> type;
317 std::optional<std::string> node_id;
318 std::optional<std::string> created_by;
319 size_t limit{100};
320 size_t offset{0};
321 bool order_by_priority{true};
322};
323
332public:
333 explicit job_repository(sqlite3* db);
335
337 auto operator=(const job_repository&) -> job_repository& = delete;
339 auto operator=(job_repository&&) noexcept -> job_repository&;
340
341 [[nodiscard]] auto save(const client::job_record& job) -> VoidResult;
342 [[nodiscard]] auto find_by_id(std::string_view job_id) const
343 -> std::optional<client::job_record>;
344 [[nodiscard]] auto find_by_pk(int64_t pk) const
345 -> std::optional<client::job_record>;
346 [[nodiscard]] auto find_jobs(const job_query_options& options = {}) const
347 -> std::vector<client::job_record>;
348 [[nodiscard]] auto find_by_status(client::job_status status,
349 size_t limit = 100) const
350 -> std::vector<client::job_record>;
351 [[nodiscard]] auto find_pending_jobs(size_t limit = 10) const
352 -> std::vector<client::job_record>;
353 [[nodiscard]] auto find_by_node(std::string_view node_id) const
354 -> std::vector<client::job_record>;
355 [[nodiscard]] auto remove(std::string_view job_id) -> VoidResult;
356 [[nodiscard]] auto cleanup_old_jobs(std::chrono::hours max_age)
357 -> Result<size_t>;
358 [[nodiscard]] auto exists(std::string_view job_id) const -> bool;
359
360 [[nodiscard]] auto update_status(std::string_view job_id,
361 client::job_status status,
362 std::string_view error_message = "",
363 std::string_view error_details = "")
364 -> VoidResult;
365 [[nodiscard]] auto update_progress(std::string_view job_id,
366 const client::job_progress& progress)
367 -> VoidResult;
368 [[nodiscard]] auto mark_started(std::string_view job_id) -> VoidResult;
369 [[nodiscard]] auto mark_completed(std::string_view job_id) -> VoidResult;
370 [[nodiscard]] auto mark_failed(std::string_view job_id,
371 std::string_view error_message,
372 std::string_view error_details = "")
373 -> VoidResult;
374 [[nodiscard]] auto increment_retry(std::string_view job_id) -> VoidResult;
375
376 [[nodiscard]] auto count() const -> size_t;
377 [[nodiscard]] auto count_by_status(client::job_status status) const
378 -> size_t;
379 [[nodiscard]] auto count_completed_today() const -> size_t;
380 [[nodiscard]] auto count_failed_today() const -> size_t;
381
382 [[nodiscard]] auto is_valid() const noexcept -> bool;
383
384private:
385 [[nodiscard]] auto parse_row(void* stmt) const -> client::job_record;
386
387 [[nodiscard]] static auto serialize_instance_uids(
388 const std::vector<std::string>& uids) -> std::string;
389
390 [[nodiscard]] static auto deserialize_instance_uids(std::string_view json)
391 -> std::vector<std::string>;
392
393 [[nodiscard]] static auto serialize_metadata(
394 const std::unordered_map<std::string, std::string>& metadata)
395 -> std::string;
396
397 [[nodiscard]] static auto deserialize_metadata(std::string_view json)
398 -> std::unordered_map<std::string, std::string>;
399
400 sqlite3* db_{nullptr};
401};
402
403} // namespace kcenon::pacs::storage
404
405#endif // PACS_WITH_DATABASE_SYSTEM
Generic base repository for CRUD operations.
Repository for job persistence (legacy SQLite interface)
auto cleanup_old_jobs(std::chrono::hours max_age) -> Result< size_t >
static auto deserialize_metadata(std::string_view json) -> std::unordered_map< std::string, std::string >
auto save(const client::job_record &job) -> VoidResult
auto find_by_node(std::string_view node_id) const -> std::vector< client::job_record >
job_repository(job_repository &&) noexcept
auto mark_completed(std::string_view job_id) -> VoidResult
static auto serialize_metadata(const std::unordered_map< std::string, std::string > &metadata) -> std::string
auto increment_retry(std::string_view job_id) -> VoidResult
auto remove(std::string_view job_id) -> VoidResult
auto update_status(std::string_view job_id, client::job_status status, std::string_view error_message="", std::string_view error_details="") -> VoidResult
auto mark_started(std::string_view job_id) -> VoidResult
auto find_by_status(client::job_status status, size_t limit=100) const -> std::vector< client::job_record >
auto find_pending_jobs(size_t limit=10) const -> std::vector< client::job_record >
static auto deserialize_instance_uids(std::string_view json) -> std::vector< std::string >
auto operator=(const job_repository &) -> job_repository &=delete
auto find_by_id(std::string_view job_id) const -> std::optional< client::job_record >
auto is_valid() const noexcept -> bool
auto mark_failed(std::string_view job_id, std::string_view error_message, std::string_view error_details="") -> VoidResult
static auto serialize_instance_uids(const std::vector< std::string > &uids) -> std::string
auto find_jobs(const job_query_options &options={}) const -> std::vector< client::job_record >
job_repository(const job_repository &)=delete
auto exists(std::string_view job_id) const -> bool
auto count_by_status(client::job_status status) const -> size_t
auto parse_row(void *stmt) const -> client::job_record
auto update_progress(std::string_view job_id, const client::job_progress &progress) -> VoidResult
auto find_by_pk(int64_t pk) const -> std::optional< client::job_record >
Job types and structures for asynchronous DICOM operations.
job_status
Current status of a job.
Definition job_types.h:90
kcenon::common::Result< T > Result
Result type alias for operations returning a value.
Query options for listing jobs.
size_t offset
Result offset for pagination.
std::optional< client::job_type > type
Filter by type.
bool order_by_priority
Order by priority (desc) then created_at.
std::optional< std::string > node_id
Filter by source or destination node.
std::optional< std::string > created_by
Filter by creator.
std::optional< client::job_status > status
Filter by status.