use chrono::{DateTime, Utc};
use serde::Serialize;
use serde_json::Value;
use sqlx::Row;
use sqlx::postgres::{PgPool, PgRow};
#[derive(Debug, Clone, Serialize)]
pub struct AdmissionEventRecord {
pub id: i64,
pub created_at: DateTime<Utc>,
pub event_id: String,
pub method: String,
pub route: String,
pub client_name: Option<String>,
pub request_bytes: Option<i64>,
pub defer_requested: bool,
pub is_query_route: bool,
pub decision: String,
pub reason: Option<String>,
pub deferred_request_id: Option<String>,
pub retry_after_seconds: Option<i32>,
pub window_seconds: Option<i32>,
pub global_limit_per_window: Option<i64>,
pub per_client_limit_per_window: Option<i64>,
pub meta: Value,
}
fn map_admission_event_row(row: &PgRow) -> Result<AdmissionEventRecord, sqlx::Error> {
Ok(AdmissionEventRecord {
id: row.try_get("id")?,
created_at: row.try_get("created_at")?,
event_id: row.try_get("event_id")?,
method: row.try_get("method")?,
route: row.try_get("route")?,
client_name: row.try_get("client_name")?,
request_bytes: row.try_get("request_bytes")?,
defer_requested: row.try_get("defer_requested")?,
is_query_route: row.try_get("is_query_route")?,
decision: row.try_get("decision")?,
reason: row.try_get("reason")?,
deferred_request_id: row.try_get("deferred_request_id")?,
retry_after_seconds: row.try_get("retry_after_seconds")?,
window_seconds: row.try_get("window_seconds")?,
global_limit_per_window: row.try_get("global_limit_per_window")?,
per_client_limit_per_window: row.try_get("per_client_limit_per_window")?,
meta: row.try_get("meta")?,
})
}
pub async fn list_admission_events(
pool: &PgPool,
decision: Option<&str>,
client_name: Option<&str>,
limit: i64,
offset: i64,
) -> Result<Vec<AdmissionEventRecord>, sqlx::Error> {
let rows = sqlx::query(
r#"
SELECT
id,
created_at,
event_id,
method,
route,
client_name,
request_bytes,
defer_requested,
is_query_route,
decision,
reason,
deferred_request_id,
retry_after_seconds,
window_seconds,
global_limit_per_window,
per_client_limit_per_window,
meta
FROM public.gateway_admission_events
WHERE ($1::text IS NULL OR decision = $1)
AND ($2::text IS NULL OR client_name = $2)
ORDER BY created_at DESC
LIMIT $3
OFFSET $4
"#,
)
.bind(decision)
.bind(client_name)
.bind(limit)
.bind(offset)
.fetch_all(pool)
.await?;
rows.iter().map(map_admission_event_row).collect()
}