Skip to main content

chronon_backend_sql_common/row/
leader.rs

1//! [`SchedulerLeader`] SQL row mapping.
2
3use chrono::{DateTime, Utc};
4use chronon_core::error::Result;
5use chronon_core::models::SchedulerLeader;
6use sqlx::{ColumnIndex, Row};
7
8use crate::error_map::map_err;
9
10/// SQL row shape for [`SchedulerLeader`].
11pub struct SchedulerLeaderRow {
12    leader_id: String,
13    leader_instance_id: String,
14    leader_lease_until: DateTime<Utc>,
15    last_heartbeat_at: DateTime<Utc>,
16}
17
18#[allow(clippy::wrong_self_convention)]
19impl SchedulerLeaderRow {
20    /// Build a row from a domain [`SchedulerLeader`].
21    pub fn from_model(leader: &SchedulerLeader) -> Self {
22        Self {
23            leader_id: leader.leader_id.clone(),
24            leader_instance_id: leader.leader_instance_id.clone(),
25            leader_lease_until: leader.leader_lease_until,
26            last_heartbeat_at: leader.last_heartbeat_at,
27        }
28    }
29
30    /// Convert this row into a domain [`SchedulerLeader`].
31    pub fn to_model(self) -> SchedulerLeader {
32        SchedulerLeader {
33            leader_id: self.leader_id,
34            leader_instance_id: self.leader_instance_id,
35            leader_lease_until: self.leader_lease_until,
36            last_heartbeat_at: self.last_heartbeat_at,
37        }
38    }
39}
40
41/// Map a SQL row to a [`SchedulerLeader`].
42pub fn row_to_leader<'r, R>(row: &'r R) -> Result<SchedulerLeader>
43where
44    R: Row,
45    for<'i> &'i str: ColumnIndex<R>,
46    String: sqlx::Decode<'r, R::Database> + sqlx::Type<R::Database>,
47    DateTime<Utc>: sqlx::Decode<'r, R::Database> + sqlx::Type<R::Database>,
48{
49    Ok(SchedulerLeaderRow {
50        leader_id: row.try_get("leader_id").map_err(map_err)?,
51        leader_instance_id: row.try_get("leader_instance_id").map_err(map_err)?,
52        leader_lease_until: row.try_get("leader_lease_until").map_err(map_err)?,
53        last_heartbeat_at: row.try_get("last_heartbeat_at").map_err(map_err)?,
54    }
55    .to_model())
56}
57
58#[cfg(test)]
59mod tests {
60    use chrono::Utc;
61    use chronon_core::models::SchedulerLeader;
62
63    use super::SchedulerLeaderRow;
64
65    #[test]
66    fn leader_row_roundtrip() {
67        let leader = SchedulerLeader {
68            leader_id: "singleton".into(),
69            leader_instance_id: "inst".into(),
70            leader_lease_until: Utc::now(),
71            last_heartbeat_at: Utc::now(),
72        };
73        let row = SchedulerLeaderRow::from_model(&leader);
74        assert_eq!(row.to_model().leader_instance_id, "inst");
75    }
76}