use chrono::{DateTime, Utc};
use chronon_core::error::Result;
use chronon_core::models::Worker;
use sqlx::{ColumnIndex, Row};
use super::{decode_json_opt, encode_json_opt, parse_worker_status, worker_status_to_str};
use crate::error_map::map_err;
pub struct WorkerRow {
pub(crate) worker_id: String,
pub(crate) pool_id: String,
pub(crate) cell_id: Option<String>,
pub(crate) status: String,
pub(crate) last_heartbeat_at: DateTime<Utc>,
pub(crate) capacity_json: Option<String>,
pub(crate) created_at: DateTime<Utc>,
pub(crate) updated_at: DateTime<Utc>,
}
#[allow(clippy::wrong_self_convention)]
impl WorkerRow {
pub fn from_model(worker: &Worker) -> Result<Self> {
Ok(Self {
worker_id: worker.worker_id.clone(),
pool_id: worker.pool_id.clone(),
cell_id: worker.cell_id.clone(),
status: worker_status_to_str(worker.status).to_string(),
last_heartbeat_at: worker.last_heartbeat_at,
capacity_json: encode_json_opt(worker.capacity_json.as_ref())?,
created_at: worker.created_at,
updated_at: worker.updated_at,
})
}
pub fn to_model(self) -> Result<Worker> {
Ok(Worker {
worker_id: self.worker_id,
pool_id: self.pool_id,
cell_id: self.cell_id,
status: parse_worker_status(&self.status)?,
last_heartbeat_at: self.last_heartbeat_at,
capacity_json: decode_json_opt(self.capacity_json)?,
created_at: self.created_at,
updated_at: self.updated_at,
})
}
}
pub fn row_to_worker<'r, R>(row: &'r R) -> Result<Worker>
where
R: Row,
for<'i> &'i str: ColumnIndex<R>,
String: sqlx::Decode<'r, R::Database> + sqlx::Type<R::Database>,
DateTime<Utc>: sqlx::Decode<'r, R::Database> + sqlx::Type<R::Database>,
Option<String>: sqlx::Decode<'r, R::Database> + sqlx::Type<R::Database>,
{
let status: String = row.try_get("status").map_err(map_err)?;
WorkerRow {
worker_id: row.try_get("worker_id").map_err(map_err)?,
pool_id: row.try_get("pool_id").map_err(map_err)?,
cell_id: row.try_get("cell_id").map_err(map_err)?,
status,
last_heartbeat_at: row.try_get("last_heartbeat_at").map_err(map_err)?,
capacity_json: row.try_get("capacity_json").map_err(map_err)?,
created_at: row.try_get("created_at").map_err(map_err)?,
updated_at: row.try_get("updated_at").map_err(map_err)?,
}
.to_model()
}
#[cfg(test)]
mod tests {
use chrono::Utc;
use chronon_core::models::{Worker, WorkerStatus};
use super::WorkerRow;
#[test]
fn worker_row_roundtrip() {
let worker = Worker {
worker_id: "w1".into(),
pool_id: "general".into(),
cell_id: None,
status: WorkerStatus::Online,
last_heartbeat_at: Utc::now(),
capacity_json: None,
created_at: Utc::now(),
updated_at: Utc::now(),
};
let row = WorkerRow::from_model(&worker).expect("row");
let back = row.to_model().expect("model");
assert_eq!(back.worker_id, "w1");
}
}