use chrono::{DateTime, Utc};
use cortex_core::{EventId, Trace, TraceId, TraceStatus};
use rusqlite::params;
use crate::{Pool, StoreError, StoreResult};
#[derive(Debug)]
pub struct TraceRepo<'a> {
pool: &'a Pool,
}
impl<'a> TraceRepo<'a> {
#[must_use]
pub const fn new(pool: &'a Pool) -> Self {
Self { pool }
}
pub fn open(&self, trace: &Trace) -> StoreResult<()> {
self.pool.execute(
"INSERT INTO traces (
id, schema_version, opened_at, closed_at, trace_type, status
) VALUES (?1, ?2, ?3, ?4, ?5, ?6);",
params![
trace.id.to_string(),
i64::from(trace.schema_version),
trace.opened_at.to_rfc3339(),
trace.closed_at.map(|at| at.to_rfc3339()),
trace.trace_type,
trace_status_wire(trace.status),
],
)?;
Ok(())
}
pub fn attach(&self, trace_id: &TraceId, event_id: &EventId, ordinal: i64) -> StoreResult<()> {
self.pool.execute(
"INSERT INTO trace_events (trace_id, event_id, ordinal)
VALUES (?1, ?2, ?3);",
params![trace_id.to_string(), event_id.to_string(), ordinal],
)?;
Ok(())
}
pub fn close(
&self,
trace_id: &TraceId,
closed_at: DateTime<Utc>,
status: TraceStatus,
) -> StoreResult<()> {
if status == TraceStatus::Open {
return Err(StoreError::Validation(
"close requires a non-open trace status".into(),
));
}
let changed = self.pool.execute(
"UPDATE traces
SET closed_at = ?2, status = ?3
WHERE id = ?1;",
params![
trace_id.to_string(),
closed_at.to_rfc3339(),
trace_status_wire(status)
],
)?;
if changed == 0 {
return Err(StoreError::Validation(format!(
"trace {trace_id} not found"
)));
}
Ok(())
}
}
fn trace_status_wire(status: TraceStatus) -> &'static str {
match status {
TraceStatus::Open => "open",
TraceStatus::Closed => "closed",
TraceStatus::Quarantined => "quarantined",
}
}