use uuid::Uuid; use crate::db::models::{AuditEvent, NewAuditEvent}; use crate::db::{Db, Page, Pagination, db_error}; use crate::error::AppResult; pub async fn append(db: &Db, input: &NewAuditEvent) -> AppResult { let client = db.client().await?; let row = client .query_one( "INSERT INTO audit_events ( run_id, actor_type, actor_id, action, entity_type, entity_id, before_data, after_data, metadata ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) RETURNING *", &[ &input.run_id, &input.actor_type, &input.actor_id, &input.action, &input.entity_type, &input.entity_id, &input.before_data, &input.after_data, &input.metadata, ], ) .await .map_err(db_error)?; AuditEvent::from_row(&row).map_err(db_error) } pub async fn list( db: &Db, run_id: Option, entity_type: Option<&str>, entity_id: Option, pagination: Pagination, ) -> AppResult> { let client = db.client().await?; let predicate = "($1::uuid IS NULL OR run_id = $1) AND ($2::text IS NULL OR entity_type = $2) AND ($3::uuid IS NULL OR entity_id = $3)"; let total_sql = format!("SELECT count(*)::bigint FROM audit_events WHERE {predicate}"); let total: i64 = client .query_one(&total_sql, &[&run_id, &entity_type, &entity_id]) .await .map_err(db_error)? .get(0); let list_sql = format!( "SELECT * FROM audit_events WHERE {predicate} ORDER BY created_at DESC, id DESC LIMIT $4 OFFSET $5" ); let rows = client .query( &list_sql, &[ &run_id, &entity_type, &entity_id, &pagination.limit, &pagination.offset, ], ) .await .map_err(db_error)?; let items = rows .iter() .map(AuditEvent::from_row) .collect::, _>>() .map_err(db_error)?; Ok(Page::new(items, total, pagination)) }