use boson_core::{Run, RunStatus, TaskRunStats};
use chrono::{DateTime, Utc};
use crate::store::Inner;
pub fn upsert_run(inner: &mut Inner, run: &Run) {
inner.runs.insert(run.run_id.clone(), run.clone());
}
pub fn get_run(inner: &Inner, run_id: &str) -> Option<Run> {
inner.runs.get(run_id).cloned()
}
pub fn list_runs(
inner: &Inner,
job_id_filter: Option<&str>,
offset: usize,
limit: usize,
) -> Vec<Run> {
let mut runs: Vec<Run> = inner
.runs
.values()
.filter(|r| job_id_filter.is_none_or(|jid| r.job_id == jid))
.cloned()
.collect();
runs.sort_by_key(|r| std::cmp::Reverse(r.started_at));
runs.into_iter().skip(offset).take(limit).collect()
}
pub fn finish_run(
inner: &mut Inner,
run_id: &str,
status: RunStatus,
duration_ms: Option<i64>,
error_message: Option<String>,
) {
let Some(run) = inner.runs.get_mut(run_id) else {
return;
};
run.status = status;
run.finished_at = Some(Utc::now());
run.duration_ms = duration_ms;
run.error_message = error_message;
}
pub fn count_runs(inner: &Inner, job_id_filter: Option<&str>) -> u64 {
let count = inner
.runs
.values()
.filter(|r| job_id_filter.is_none_or(|jid| r.job_id == jid))
.count();
u64::try_from(count).unwrap_or(u64::MAX)
}
pub fn count_runs_since(inner: &Inner, since: DateTime<Utc>) -> u64 {
let count = inner
.runs
.values()
.filter(|r| r.started_at >= since)
.count();
u64::try_from(count).unwrap_or(u64::MAX)
}
pub fn task_run_stats(inner: &Inner, task_name: &str) -> TaskRunStats {
let matching: Vec<&Run> = inner
.runs
.values()
.filter(|r| r.task_name == task_name)
.collect();
let runs_total = u32::try_from(matching.len()).unwrap_or(u32::MAX);
let success_count = u32::try_from(
matching
.iter()
.filter(|r| r.status == RunStatus::Success)
.count(),
)
.unwrap_or(u32::MAX);
TaskRunStats {
runs_total,
success_count,
}
}