PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::storage::routing_repository Class Reference

Repository for routing rule persistence (legacy SQLite interface) More...

#include <routing_repository.h>

Collaboration diagram for kcenon::pacs::storage::routing_repository:
Collaboration graph

Public Member Functions

 routing_repository (sqlite3 *db)
 
 ~routing_repository ()
 
 routing_repository (const routing_repository &)=delete
 
auto operator= (const routing_repository &) -> routing_repository &=delete
 
 routing_repository (routing_repository &&) noexcept
 
auto operator= (routing_repository &&) noexcept -> routing_repository &
 
auto save (const client::routing_rule &rule) -> VoidResult
 
auto find_by_id (std::string_view rule_id) const -> std::optional< client::routing_rule >
 
auto find_by_pk (int64_t pk) const -> std::optional< client::routing_rule >
 
auto find_rules (const routing_rule_query_options &options={}) const -> std::vector< client::routing_rule >
 
auto find_enabled_rules () const -> std::vector< client::routing_rule >
 
auto remove (std::string_view rule_id) -> VoidResult
 
auto exists (std::string_view rule_id) const -> bool
 
auto update_priority (std::string_view rule_id, int priority) -> VoidResult
 
auto enable_rule (std::string_view rule_id) -> VoidResult
 
auto disable_rule (std::string_view rule_id) -> VoidResult
 
auto increment_triggered (std::string_view rule_id) -> VoidResult
 
auto increment_success (std::string_view rule_id) -> VoidResult
 
auto increment_failure (std::string_view rule_id) -> VoidResult
 
auto reset_statistics (std::string_view rule_id) -> VoidResult
 
auto count () const -> size_t
 
auto count_enabled () const -> size_t
 
auto is_valid () const noexcept -> bool
 

Private Member Functions

auto parse_row (void *stmt) const -> client::routing_rule
 

Static Private Member Functions

static auto serialize_conditions (const std::vector< client::routing_condition > &conditions) -> std::string
 
static auto deserialize_conditions (std::string_view json) -> std::vector< client::routing_condition >
 
static auto serialize_actions (const std::vector< client::routing_action > &actions) -> std::string
 
static auto deserialize_actions (std::string_view json) -> std::vector< client::routing_action >
 

Private Attributes

sqlite3 * db_ {nullptr}
 

Detailed Description

Repository for routing rule persistence (legacy SQLite interface)

This is the legacy interface maintained for builds without database_system. New code should use the base_repository version when PACS_WITH_DATABASE_SYSTEM is defined.

Definition at line 266 of file routing_repository.h.

Constructor & Destructor Documentation

◆ routing_repository() [1/3]

kcenon::pacs::storage::routing_repository::routing_repository ( sqlite3 * db)
explicit

Definition at line 1062 of file routing_repository.cpp.

◆ ~routing_repository()

kcenon::pacs::storage::routing_repository::~routing_repository ( )
default

◆ routing_repository() [2/3]

kcenon::pacs::storage::routing_repository::routing_repository ( const routing_repository & )
delete

◆ routing_repository() [3/3]

kcenon::pacs::storage::routing_repository::routing_repository ( routing_repository && )
defaultnoexcept

Member Function Documentation

◆ count()

size_t kcenon::pacs::storage::routing_repository::count ( ) const -> size_t
nodiscard

Definition at line 1549 of file routing_repository.cpp.

1549 : " + std::string(sqlite3_errmsg(db_)),
1551 }
1552
1553 return kcenon::common::ok();
1554}
1555
1556size_t routing_repository::count() const {
1557 if (!db_) return 0;
1558
1559 static constexpr const char* sql = "SELECT COUNT(*) FROM routing_rules";
1560
1561 sqlite3_stmt* stmt = nullptr;
1562 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1563 return 0;
1564 }
1565
1566 size_t result = 0;
if(!color.empty()) style.color

◆ count_enabled()

size_t kcenon::pacs::storage::routing_repository::count_enabled ( ) const -> size_t
nodiscard

Definition at line 1568 of file routing_repository.cpp.

1575 {
1576 if (!db_) return 0;
1577
1578 static constexpr const char* sql = "SELECT COUNT(*) FROM routing_rules WHERE enabled = 1";
1579
1580 sqlite3_stmt* stmt = nullptr;
1581 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1582 return 0;
1583 }
1584
1585 size_t result = 0;

◆ deserialize_actions()

std::vector< client::routing_action > kcenon::pacs::storage::routing_repository::deserialize_actions ( std::string_view json) -> std::vector<client::routing_action>
staticnodiscardprivate

Definition at line 996 of file routing_repository.cpp.

997 {
998 std::vector<client::routing_action> result;
999 if (json.empty() || json == "[]") return result;
1000
1001 size_t pos = 0;
1002 while (pos < json.size()) {
1003 auto obj_start = json.find('{', pos);
1004 if (obj_start == std::string_view::npos) break;
1005
1006 auto obj_end = json.find('}', obj_start);
1007 if (obj_end == std::string_view::npos) break;
1008
1009 auto obj = json.substr(obj_start, obj_end - obj_start + 1);
1010
1011 client::routing_action action;
1012
1013 // Parse destination
1014 auto dest_pos = obj.find("\"destination\"");
1015 if (dest_pos != std::string_view::npos) {
1016 auto [dest_value, next] = extract_json_string(obj, dest_pos + 13);
1017 action.destination_node_id = dest_value;
1018 }
1019
1020 // Parse priority
1021 auto prio_pos = obj.find("\"priority\"");
1022 if (prio_pos != std::string_view::npos) {
1023 auto [prio_value, next] = extract_json_string(obj, prio_pos + 10);
1024 action.priority = client::job_priority_from_string(prio_value);
1025 }
1026
1027 // Parse delay_minutes
1028 auto delay_pos = obj.find("\"delay_minutes\"");
1029 if (delay_pos != std::string_view::npos) {
1030 auto colon = obj.find(':', delay_pos);
1031 if (colon != std::string_view::npos) {
1032 int minutes = 0;
1033 std::sscanf(obj.data() + colon + 1, "%d", &minutes);
1034 action.delay = std::chrono::minutes{minutes};
1035 }
1036 }
1037
1038 // Parse delete_after_send
1039 auto delete_pos = obj.find("\"delete_after_send\"");
1040 if (delete_pos != std::string_view::npos) {
1041 action.delete_after_send = (obj.find("true", delete_pos) != std::string_view::npos &&
1042 obj.find("true", delete_pos) < obj.find(',', delete_pos + 20));
1043 }
1044
1045 // Parse notify_on_failure
1046 auto notify_pos = obj.find("\"notify_on_failure\"");
1047 if (notify_pos != std::string_view::npos) {
1048 action.notify_on_failure = (obj.find("true", notify_pos) != std::string_view::npos);
1049 }
1050
1051 result.push_back(std::move(action));
1052 pos = obj_end + 1;
1053 }
1054
1055 return result;
1056}
job_priority job_priority_from_string(std::string_view str) noexcept
Parse job_priority from string.
Definition job_types.h:181

References kcenon::pacs::client::routing_action::delay, kcenon::pacs::client::routing_action::delete_after_send, kcenon::pacs::client::routing_action::destination_node_id, kcenon::pacs::client::job_priority_from_string(), kcenon::pacs::client::routing_action::notify_on_failure, and kcenon::pacs::client::routing_action::priority.

Here is the call graph for this function:

◆ deserialize_conditions()

std::vector< client::routing_condition > kcenon::pacs::storage::routing_repository::deserialize_conditions ( std::string_view json) -> std::vector<client::routing_condition>
staticnodiscardprivate

Definition at line 920 of file routing_repository.cpp.

921 {
922 std::vector<client::routing_condition> result;
923 if (json.empty() || json == "[]") return result;
924
925 size_t pos = 0;
926 while (pos < json.size()) {
927 auto obj_start = json.find('{', pos);
928 if (obj_start == std::string_view::npos) break;
929
930 auto obj_end = json.find('}', obj_start);
931 if (obj_end == std::string_view::npos) break;
932
933 auto obj = json.substr(obj_start, obj_end - obj_start + 1);
934
935 client::routing_condition cond;
936
937 // Parse field
938 auto field_pos = obj.find("\"field\"");
939 if (field_pos != std::string_view::npos) {
940 auto [field_value, next] = extract_json_string(obj, field_pos + 7);
941 cond.match_field = client::routing_field_from_string(field_value);
942 }
943
944 // Parse pattern
945 auto pattern_pos = obj.find("\"pattern\"");
946 if (pattern_pos != std::string_view::npos) {
947 auto [pattern_value, next] = extract_json_string(obj, pattern_pos + 9);
948 cond.pattern = pattern_value;
949 }
950
951 // Parse case_sensitive
952 auto case_pos = obj.find("\"case_sensitive\"");
953 if (case_pos != std::string_view::npos) {
954 cond.case_sensitive = (obj.find("true", case_pos) != std::string_view::npos &&
955 obj.find("true", case_pos) < obj.find(',', case_pos));
956 }
957
958 // Parse negate
959 auto negate_pos = obj.find("\"negate\"");
960 if (negate_pos != std::string_view::npos) {
961 cond.negate = (obj.find("true", negate_pos) != std::string_view::npos);
962 }
963
964 result.push_back(std::move(cond));
965 pos = obj_end + 1;
966 }
967
968 return result;
969}
routing_field routing_field_from_string(std::string_view str) noexcept
Parse routing_field from string.

References kcenon::pacs::client::routing_condition::case_sensitive, kcenon::pacs::client::routing_condition::match_field, kcenon::pacs::client::routing_condition::negate, kcenon::pacs::client::routing_condition::pattern, and kcenon::pacs::client::routing_field_from_string().

Here is the call graph for this function:

◆ disable_rule()

VoidResult kcenon::pacs::storage::routing_repository::disable_rule ( std::string_view rule_id) -> VoidResult
nodiscard

Definition at line 1379 of file routing_repository.cpp.

1379 : " + std::string(sqlite3_errmsg(db_)),
1381 }
1382
1383 return kcenon::common::ok();
1384}
1385
1386VoidResult routing_repository::disable_rule(std::string_view rule_id) {
1387 if (!db_) {
1388 return VoidResult(kcenon::common::error_info{
1389 -1, "Database not initialized", "routing_repository"});
1390 }
1391
1392 static constexpr const char* sql = R"(
1393 UPDATE routing_rules SET
1394 enabled = 0,
1395 updated_at = CURRENT_TIMESTAMP
1396 WHERE rule_id = ?
1397 )";
1398
1399 sqlite3_stmt* stmt = nullptr;
1400 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1401 return VoidResult(kcenon::common::error_info{
1402 -1, "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
1404 }
1405
1406 sqlite3_bind_text(stmt, 1, rule_id.data(), static_cast<int>(rule_id.size()), SQLITE_TRANSIENT);
1407
1408 auto rc = sqlite3_step(stmt);
1409 sqlite3_finalize(stmt);
1410
1411 if (rc != SQLITE_DONE) {

◆ enable_rule()

VoidResult kcenon::pacs::storage::routing_repository::enable_rule ( std::string_view rule_id) -> VoidResult
nodiscard

Definition at line 1345 of file routing_repository.cpp.

1345 : " + std::string(sqlite3_errmsg(db_)),
1347 }
1348
1349 return kcenon::common::ok();
1350}
1351
1352VoidResult routing_repository::enable_rule(std::string_view rule_id) {
1353 if (!db_) {
1354 return VoidResult(kcenon::common::error_info{
1355 -1, "Database not initialized", "routing_repository"});
1356 }
1357
1358 static constexpr const char* sql = R"(
1359 UPDATE routing_rules SET
1360 enabled = 1,
1361 updated_at = CURRENT_TIMESTAMP
1362 WHERE rule_id = ?
1363 )";
1364
1365 sqlite3_stmt* stmt = nullptr;
1366 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1367 return VoidResult(kcenon::common::error_info{
1368 -1, "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
1370 }
1371
1372 sqlite3_bind_text(stmt, 1, rule_id.data(), static_cast<int>(rule_id.size()), SQLITE_TRANSIENT);
1373
1374 auto rc = sqlite3_step(stmt);
1375 sqlite3_finalize(stmt);
1376
1377 if (rc != SQLITE_DONE) {

◆ exists()

bool kcenon::pacs::storage::routing_repository::exists ( std::string_view rule_id) const -> bool
nodiscard

Definition at line 1289 of file routing_repository.cpp.

1289 : " + std::string(sqlite3_errmsg(db_)),
1291 }
1292
1293 return kcenon::common::ok();
1294}
1295
1296bool routing_repository::exists(std::string_view rule_id) const {
1297 if (!db_) return false;
1298
1299 static constexpr const char* sql = "SELECT 1 FROM routing_rules WHERE rule_id = ?";
1300
1301 sqlite3_stmt* stmt = nullptr;
1302 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1303 return false;
1304 }

◆ find_by_id()

std::optional< client::routing_rule > kcenon::pacs::storage::routing_repository::find_by_id ( std::string_view rule_id) const -> std::optional<client::routing_rule>
nodiscard

Definition at line 1162 of file routing_repository.cpp.

1163 {
1164 if (!db_) return std::nullopt;
1165
1166 static constexpr const char* sql = R"(
1167 SELECT pk, rule_id, name, description, enabled, priority,
1168 conditions_json, actions_json,
1169 schedule_cron, effective_from, effective_until,
1170 triggered_count, success_count, failure_count,
1171 last_triggered, created_at, updated_at
1172 FROM routing_rules WHERE rule_id = ?
1173 )";
1174
1175 sqlite3_stmt* stmt = nullptr;
1176 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1177 return std::nullopt;
1178 }
1179
1180 sqlite3_bind_text(stmt, 1, rule_id.data(), static_cast<int>(rule_id.size()), SQLITE_TRANSIENT);
1181
1182 std::optional<client::routing_rule> result;
1183 if (sqlite3_step(stmt) == SQLITE_ROW) {
1184 result = parse_row(stmt);
1185 }
1186
1187 sqlite3_finalize(stmt);
1188 return result;
1189}
auto parse_row(void *stmt) const -> client::routing_rule

References db_, and parse_row().

Here is the call graph for this function:

◆ find_by_pk()

std::optional< client::routing_rule > kcenon::pacs::storage::routing_repository::find_by_pk ( int64_t pk) const -> std::optional<client::routing_rule>
nodiscard

Definition at line 1191 of file routing_repository.cpp.

1191 {
1192 if (!db_) return std::nullopt;
1193
1194 static constexpr const char* sql = R"(
1195 SELECT pk, rule_id, name, description, enabled, priority,
1196 conditions_json, actions_json,
1197 schedule_cron, effective_from, effective_until,
1198 triggered_count, success_count, failure_count,
1199 last_triggered, created_at, updated_at
1200 FROM routing_rules WHERE pk = ?
1201 )";
1202
1203 sqlite3_stmt* stmt = nullptr;
1204 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1205 return std::nullopt;
1206 }
1207
1208 sqlite3_bind_int64(stmt, 1, pk);
1209
1210 std::optional<client::routing_rule> result;
1211 if (sqlite3_step(stmt) == SQLITE_ROW) {
1212 result = parse_row(stmt);
1213 }
1214
1215 sqlite3_finalize(stmt);
1216 return result;
1217}

References db_, and parse_row().

Here is the call graph for this function:

◆ find_enabled_rules()

std::vector< client::routing_rule > kcenon::pacs::storage::routing_repository::find_enabled_rules ( ) const -> std::vector<client::routing_rule>
nodiscard

Definition at line 1253 of file routing_repository.cpp.

◆ find_rules()

std::vector< client::routing_rule > kcenon::pacs::storage::routing_repository::find_rules ( const routing_rule_query_options & options = {}) const -> std::vector<client::routing_rule>
nodiscard

Definition at line 1219 of file routing_repository.cpp.

1220 {
1221 std::vector<client::routing_rule> result;
1222 if (!db_) return result;
1223
1224 std::ostringstream sql;
1225 sql << R"(
1226 SELECT pk, rule_id, name, description, enabled, priority,
1227 conditions_json, actions_json,
1228 schedule_cron, effective_from, effective_until,
1229 triggered_count, success_count, failure_count,
1230 last_triggered, created_at, updated_at
1231 FROM routing_rules WHERE 1=1
1232 )";
1233
1234 if (options.enabled_only.has_value()) {
1235 sql << " AND enabled = " << (options.enabled_only.value() ? "1" : "0");
1236 }
1237
1238 if (options.order_by_priority) {
1239 sql << " ORDER BY priority DESC, created_at ASC";
1240 } else {
1241 sql << " ORDER BY created_at DESC";
1242 }
1243
1244 sql << " LIMIT " << options.limit << " OFFSET " << options.offset;
1245
1246 sqlite3_stmt* stmt = nullptr;
1247 auto sql_str = sql.str();
1248 if (sqlite3_prepare_v2(db_, sql_str.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
1249 return result;
1250 }
1251

References db_.

Referenced by remove().

Here is the caller graph for this function:

◆ increment_failure()

VoidResult kcenon::pacs::storage::routing_repository::increment_failure ( std::string_view rule_id) -> VoidResult
nodiscard

Definition at line 1482 of file routing_repository.cpp.

1482 : " + std::string(sqlite3_errmsg(db_)),
1484 }
1485
1486 return kcenon::common::ok();
1487}
1488
1489VoidResult routing_repository::increment_failure(std::string_view rule_id) {
1490 if (!db_) {
1491 return VoidResult(kcenon::common::error_info{
1492 -1, "Database not initialized", "routing_repository"});
1493 }
1494
1495 static constexpr const char* sql = R"(
1496 UPDATE routing_rules SET failure_count = failure_count + 1 WHERE rule_id = ?
1497 )";
1498
1499 sqlite3_stmt* stmt = nullptr;
1500 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1501 return VoidResult(kcenon::common::error_info{
1502 -1, "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
1504 }
1505
1506 sqlite3_bind_text(stmt, 1, rule_id.data(), static_cast<int>(rule_id.size()), SQLITE_TRANSIENT);
1507
1508 auto rc = sqlite3_step(stmt);
1509 sqlite3_finalize(stmt);
1510
1511 if (rc != SQLITE_DONE) {

◆ increment_success()

VoidResult kcenon::pacs::storage::routing_repository::increment_success ( std::string_view rule_id) -> VoidResult
nodiscard

Definition at line 1451 of file routing_repository.cpp.

1451 : " + std::string(sqlite3_errmsg(db_)),
1453 }
1454
1455 return kcenon::common::ok();
1456}
1457
1458VoidResult routing_repository::increment_success(std::string_view rule_id) {
1459 if (!db_) {
1460 return VoidResult(kcenon::common::error_info{
1461 -1, "Database not initialized", "routing_repository"});
1462 }
1463
1464 static constexpr const char* sql = R"(
1465 UPDATE routing_rules SET success_count = success_count + 1 WHERE rule_id = ?
1466 )";
1467
1468 sqlite3_stmt* stmt = nullptr;
1469 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1470 return VoidResult(kcenon::common::error_info{
1471 -1, "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
1473 }
1474
1475 sqlite3_bind_text(stmt, 1, rule_id.data(), static_cast<int>(rule_id.size()), SQLITE_TRANSIENT);
1476
1477 auto rc = sqlite3_step(stmt);
1478 sqlite3_finalize(stmt);
1479
1480 if (rc != SQLITE_DONE) {

◆ increment_triggered()

VoidResult kcenon::pacs::storage::routing_repository::increment_triggered ( std::string_view rule_id) -> VoidResult
nodiscard

Definition at line 1417 of file routing_repository.cpp.

1424 {
1425 if (!db_) {
1426 return VoidResult(kcenon::common::error_info{
1427 -1, "Database not initialized", "routing_repository"});
1428 }
1429
1430 static constexpr const char* sql = R"(
1431 UPDATE routing_rules SET
1432 triggered_count = triggered_count + 1,
1433 last_triggered = CURRENT_TIMESTAMP
1434 WHERE rule_id = ?
1435 )";
1436
1437 sqlite3_stmt* stmt = nullptr;
1438 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1439 return VoidResult(kcenon::common::error_info{
1440 -1, "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
1441 "routing_repository"});
1442 }
1443
1444 sqlite3_bind_text(stmt, 1, rule_id.data(), static_cast<int>(rule_id.size()), SQLITE_TRANSIENT);
1445
1446 auto rc = sqlite3_step(stmt);
1447 sqlite3_finalize(stmt);
1448
1449 if (rc != SQLITE_DONE) {

◆ is_valid()

bool kcenon::pacs::storage::routing_repository::is_valid ( ) const -> bool
nodiscardnoexcept

Definition at line 1591 of file routing_repository.cpp.

◆ operator=() [1/2]

auto kcenon::pacs::storage::routing_repository::operator= ( const routing_repository & ) -> routing_repository &=delete
delete

◆ operator=() [2/2]

auto kcenon::pacs::storage::routing_repository::operator= ( routing_repository && ) -> routing_repository &
defaultnoexcept

◆ parse_row()

client::routing_rule kcenon::pacs::storage::routing_repository::parse_row ( void * stmt) const -> client::routing_rule
nodiscardprivate

Definition at line 1599 of file routing_repository.cpp.

1606 {
1607 auto* stmt = static_cast<sqlite3_stmt*>(stmt_ptr);
1608 client::routing_rule rule;
1609
1610 int col = 0;
1611 rule.pk = get_int64_column(stmt, col++);
1612 rule.rule_id = get_text_column(stmt, col++);
1613 rule.name = get_text_column(stmt, col++);
1614 rule.description = get_text_column(stmt, col++);
1615 rule.enabled = (get_int_column(stmt, col++) != 0);
1616 rule.priority = get_int_column(stmt, col++);
1617
1618 auto conditions_json = get_text_column(stmt, col++);
1619 rule.conditions = deserialize_conditions(conditions_json);
1620
1621 auto actions_json = get_text_column(stmt, col++);
1622 rule.actions = deserialize_actions(actions_json);
1623
1624 rule.schedule_cron = get_optional_text(stmt, col++);
1625
1626 auto effective_from_str = get_text_column(stmt, col++);
1627 rule.effective_from = from_optional_timestamp(effective_from_str.c_str());
1628
1629 auto effective_until_str = get_text_column(stmt, col++);
1630 rule.effective_until = from_optional_timestamp(effective_until_str.c_str());
1631
1632 rule.triggered_count = static_cast<size_t>(get_int64_column(stmt, col++));
1633 rule.success_count = static_cast<size_t>(get_int64_column(stmt, col++));
1634 rule.failure_count = static_cast<size_t>(get_int64_column(stmt, col++));
1635
1636 auto last_triggered_str = get_text_column(stmt, col++);
1637 rule.last_triggered = from_timestamp_string(last_triggered_str.c_str());
1638
1639 auto created_str = get_text_column(stmt, col++);
static auto deserialize_actions(std::string_view json) -> std::vector< client::routing_action >
static auto deserialize_conditions(std::string_view json) -> std::vector< client::routing_condition >

Referenced by find_by_id(), and find_by_pk().

Here is the caller graph for this function:

◆ remove()

VoidResult kcenon::pacs::storage::routing_repository::remove ( std::string_view rule_id) -> VoidResult
nodiscard

Definition at line 1260 of file routing_repository.cpp.

1260 {
1261 routing_rule_query_options options;
1262 options.enabled_only = true;
1263 options.order_by_priority = true;
1264 return find_rules(options);
1265}
1266
1267VoidResult routing_repository::remove(std::string_view rule_id) {
1268 if (!db_) {
1269 return VoidResult(kcenon::common::error_info{
1270 -1, "Database not initialized", "routing_repository"});
1271 }
1272
1273 static constexpr const char* sql = "DELETE FROM routing_rules WHERE rule_id = ?";
1274
1275 sqlite3_stmt* stmt = nullptr;
1276 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1277 return VoidResult(kcenon::common::error_info{
1278 -1, "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
1279 "routing_repository"});
1280 }
1281
1282 sqlite3_bind_text(stmt, 1, rule_id.data(), static_cast<int>(rule_id.size()), SQLITE_TRANSIENT);
1283
1284 auto rc = sqlite3_step(stmt);
1285 sqlite3_finalize(stmt);
1286
1287 if (rc != SQLITE_DONE) {
auto remove(std::string_view rule_id) -> VoidResult
auto find_rules(const routing_rule_query_options &options={}) const -> std::vector< client::routing_rule >

References kcenon::pacs::storage::routing_rule_query_options::enabled_only, and find_rules().

Here is the call graph for this function:

◆ reset_statistics()

VoidResult kcenon::pacs::storage::routing_repository::reset_statistics ( std::string_view rule_id) -> VoidResult
nodiscard

Definition at line 1513 of file routing_repository.cpp.

1513 : " + std::string(sqlite3_errmsg(db_)),
1515 }
1516
1517 return kcenon::common::ok();
1518}
1519
1520VoidResult routing_repository::reset_statistics(std::string_view rule_id) {
1521 if (!db_) {
1522 return VoidResult(kcenon::common::error_info{
1523 -1, "Database not initialized", "routing_repository"});
1524 }
1525
1526 static constexpr const char* sql = R"(
1527 UPDATE routing_rules SET
1528 triggered_count = 0,
1529 success_count = 0,
1530 failure_count = 0,
1531 last_triggered = NULL
1532 WHERE rule_id = ?
1533 )";
1534
1535 sqlite3_stmt* stmt = nullptr;
1536 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1537 return VoidResult(kcenon::common::error_info{
1538 -1, "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
1540 }
1541
1542 sqlite3_bind_text(stmt, 1, rule_id.data(), static_cast<int>(rule_id.size()), SQLITE_TRANSIENT);
1543
1544 auto rc = sqlite3_step(stmt);
1545 sqlite3_finalize(stmt);
1546
1547 if (rc != SQLITE_DONE) {

◆ save()

VoidResult kcenon::pacs::storage::routing_repository::save ( const client::routing_rule & rule) -> VoidResult
nodiscard

Definition at line 1074 of file routing_repository.cpp.

1074 {
1075 if (!db_) {
1076 return VoidResult(kcenon::common::error_info{
1077 -1, "Database not initialized", "routing_repository"});
1078 }
1079
1080 static constexpr const char* sql = R"(
1081 INSERT INTO routing_rules (
1082 rule_id, name, description, enabled, priority,
1083 conditions_json, actions_json,
1084 schedule_cron, effective_from, effective_until,
1085 triggered_count, success_count, failure_count,
1086 last_triggered, created_at, updated_at
1087 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1088 ON CONFLICT(rule_id) DO UPDATE SET
1089 name = excluded.name,
1090 description = excluded.description,
1091 enabled = excluded.enabled,
1092 priority = excluded.priority,
1093 conditions_json = excluded.conditions_json,
1094 actions_json = excluded.actions_json,
1095 schedule_cron = excluded.schedule_cron,
1096 effective_from = excluded.effective_from,
1097 effective_until = excluded.effective_until,
1098 updated_at = CURRENT_TIMESTAMP
1099 )";
1100
1101 sqlite3_stmt* stmt = nullptr;
1102 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1103 return VoidResult(kcenon::common::error_info{
1104 -1, "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
1105 "routing_repository"});
1106 }
1107
1108 int idx = 1;
1109 sqlite3_bind_text(stmt, idx++, rule.rule_id.c_str(), -1, SQLITE_TRANSIENT);
1110 sqlite3_bind_text(stmt, idx++, rule.name.c_str(), -1, SQLITE_TRANSIENT);
1111 sqlite3_bind_text(stmt, idx++, rule.description.c_str(), -1, SQLITE_TRANSIENT);
1112 sqlite3_bind_int(stmt, idx++, rule.enabled ? 1 : 0);
1113 sqlite3_bind_int(stmt, idx++, rule.priority);
1114
1115 auto conditions_json = serialize_conditions(rule.conditions);
1116 sqlite3_bind_text(stmt, idx++, conditions_json.c_str(), -1, SQLITE_TRANSIENT);
1117
1118 auto actions_json = serialize_actions(rule.actions);
1119 sqlite3_bind_text(stmt, idx++, actions_json.c_str(), -1, SQLITE_TRANSIENT);
1120
1121 bind_optional_text(stmt, idx++, rule.schedule_cron);
1122 bind_optional_timestamp(stmt, idx++, rule.effective_from);
1123 bind_optional_timestamp(stmt, idx++, rule.effective_until);
1124
1125 sqlite3_bind_int64(stmt, idx++, static_cast<int64_t>(rule.triggered_count));
1126 sqlite3_bind_int64(stmt, idx++, static_cast<int64_t>(rule.success_count));
1127 sqlite3_bind_int64(stmt, idx++, static_cast<int64_t>(rule.failure_count));
1128
1129 auto last_triggered_str = to_timestamp_string(rule.last_triggered);
1130 if (last_triggered_str.empty()) {
1131 sqlite3_bind_null(stmt, idx++);
1132 } else {
1133 sqlite3_bind_text(stmt, idx++, last_triggered_str.c_str(), -1, SQLITE_TRANSIENT);
1134 }
1135
1136 auto created_str = to_timestamp_string(rule.created_at);
1137 if (created_str.empty()) {
1138 sqlite3_bind_text(stmt, idx++, "CURRENT_TIMESTAMP", -1, SQLITE_STATIC);
1139 } else {
1140 sqlite3_bind_text(stmt, idx++, created_str.c_str(), -1, SQLITE_TRANSIENT);
1141 }
1142
1143 auto updated_str = to_timestamp_string(rule.updated_at);
1144 if (updated_str.empty()) {
1145 sqlite3_bind_text(stmt, idx++, "CURRENT_TIMESTAMP", -1, SQLITE_STATIC);
1146 } else {
1147 sqlite3_bind_text(stmt, idx++, updated_str.c_str(), -1, SQLITE_TRANSIENT);
1148 }
1149
1150 auto rc = sqlite3_step(stmt);
1151 sqlite3_finalize(stmt);
1152
1153 if (rc != SQLITE_DONE) {
1154 return VoidResult(kcenon::common::error_info{
1155 -1, "Failed to save rule: " + std::string(sqlite3_errmsg(db_)),
1156 "routing_repository"});
1157 }
1158
1159 return kcenon::common::ok();
1160}
static auto serialize_conditions(const std::vector< client::routing_condition > &conditions) -> std::string
static auto serialize_actions(const std::vector< client::routing_action > &actions) -> std::string

◆ serialize_actions()

std::string kcenon::pacs::storage::routing_repository::serialize_actions ( const std::vector< client::routing_action > & actions) -> std::string
staticnodiscardprivate

Definition at line 975 of file routing_repository.cpp.

976 {
977 if (actions.empty()) return "[]";
978
979 std::ostringstream oss;
980 oss << "[";
981 for (size_t i = 0; i < actions.size(); ++i) {
982 if (i > 0) oss << ",";
983 const auto& action = actions[i];
984 oss << "{";
985 oss << "\"destination\":\"" << escape_json_string(action.destination_node_id) << "\",";
986 oss << "\"priority\":\"" << client::to_string(action.priority) << "\",";
987 oss << "\"delay_minutes\":" << action.delay.count() << ",";
988 oss << "\"delete_after_send\":" << (action.delete_after_send ? "true" : "false") << ",";
989 oss << "\"notify_on_failure\":" << (action.notify_on_failure ? "true" : "false");
990 oss << "}";
991 }
992 oss << "]";
993 return oss.str();
994}
constexpr const char * to_string(job_type type) noexcept
Convert job_type to string representation.
Definition job_types.h:54

References kcenon::pacs::client::to_string().

Here is the call graph for this function:

◆ serialize_conditions()

std::string kcenon::pacs::storage::routing_repository::serialize_conditions ( const std::vector< client::routing_condition > & conditions) -> std::string
staticnodiscardprivate

Definition at line 900 of file routing_repository.cpp.

901 {
902 if (conditions.empty()) return "[]";
903
904 std::ostringstream oss;
905 oss << "[";
906 for (size_t i = 0; i < conditions.size(); ++i) {
907 if (i > 0) oss << ",";
908 const auto& cond = conditions[i];
909 oss << "{";
910 oss << "\"field\":\"" << client::to_string(cond.match_field) << "\",";
911 oss << "\"pattern\":\"" << escape_json_string(cond.pattern) << "\",";
912 oss << "\"case_sensitive\":" << (cond.case_sensitive ? "true" : "false") << ",";
913 oss << "\"negate\":" << (cond.negate ? "true" : "false");
914 oss << "}";
915 }
916 oss << "]";
917 return oss.str();
918}

References kcenon::pacs::client::to_string().

Here is the call graph for this function:

◆ update_priority()

VoidResult kcenon::pacs::storage::routing_repository::update_priority ( std::string_view rule_id,
int priority ) -> VoidResult
nodiscard

Definition at line 1310 of file routing_repository.cpp.

1317 {
1318 if (!db_) {
1319 return VoidResult(kcenon::common::error_info{
1320 -1, "Database not initialized", "routing_repository"});
1321 }
1322
1323 static constexpr const char* sql = R"(
1324 UPDATE routing_rules SET
1325 priority = ?,
1326 updated_at = CURRENT_TIMESTAMP
1327 WHERE rule_id = ?
1328 )";
1329
1330 sqlite3_stmt* stmt = nullptr;
1331 if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) {
1332 return VoidResult(kcenon::common::error_info{
1333 -1, "Failed to prepare statement: " + std::string(sqlite3_errmsg(db_)),
1334 "routing_repository"});
1335 }
1336
1337 sqlite3_bind_int(stmt, 1, priority);
1338 sqlite3_bind_text(stmt, 2, rule_id.data(), static_cast<int>(rule_id.size()), SQLITE_TRANSIENT);
1339
1340 auto rc = sqlite3_step(stmt);
1341 sqlite3_finalize(stmt);
1342
1343 if (rc != SQLITE_DONE) {

Member Data Documentation

◆ db_

sqlite3* kcenon::pacs::storage::routing_repository::db_ {nullptr}
private

Definition at line 319 of file routing_repository.h.

319{nullptr};

Referenced by find_by_id(), find_by_pk(), and find_rules().


The documentation for this class was generated from the following files: