You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
2.7 KiB
Rust

//! Database queries for the `admin_rate_limits` table.
//!
//! Provides read and upsert operations for per-provider rate limit configuration.
use sqlx::PgPool;
use uuid::Uuid;
use crate::errors::AppError;
use crate::models::rate_limit::AdminRateLimit;
/// Row type returned by sqlx queries against the `admin_rate_limits` table.
#[derive(Debug, sqlx::FromRow)]
struct RateLimitRow {
id: Uuid,
provider_name: String,
max_requests: i32,
time_window_seconds: i32,
updated_at: chrono::DateTime<chrono::Utc>,
}
impl From<RateLimitRow> for AdminRateLimit {
fn from(row: RateLimitRow) -> Self {
Self {
id: row.id,
provider_name: row.provider_name,
max_requests: row.max_requests,
time_window_seconds: row.time_window_seconds,
updated_at: row.updated_at,
}
}
}
/// List all rate limit configurations.
pub async fn list_all(pool: &PgPool) -> Result<Vec<AdminRateLimit>, AppError> {
let rows = sqlx::query_as::<_, RateLimitRow>(
r#"
SELECT id, provider_name, max_requests, time_window_seconds, updated_at
FROM admin_rate_limits
ORDER BY provider_name
"#,
)
.fetch_all(pool)
.await?;
Ok(rows.into_iter().map(AdminRateLimit::from).collect())
}
/// Get the rate limit configuration for a specific provider.
pub async fn get_by_provider(
pool: &PgPool,
provider_name: &str,
) -> Result<Option<AdminRateLimit>, AppError> {
let row = sqlx::query_as::<_, RateLimitRow>(
r#"
SELECT id, provider_name, max_requests, time_window_seconds, updated_at
FROM admin_rate_limits
WHERE provider_name = $1
"#,
)
.bind(provider_name)
.fetch_optional(pool)
.await?;
Ok(row.map(AdminRateLimit::from))
}
/// Upsert a rate limit configuration for a provider.
///
/// Creates the rate limit if it doesn't exist, or updates it if it does.
/// Returns the upserted rate limit.
pub async fn upsert(
pool: &PgPool,
provider_name: &str,
max_requests: i32,
time_window_seconds: i32,
) -> Result<AdminRateLimit, AppError> {
let row = sqlx::query_as::<_, RateLimitRow>(
r#"
INSERT INTO admin_rate_limits (provider_name, max_requests, time_window_seconds)
VALUES ($1, $2, $3)
ON CONFLICT (provider_name) DO UPDATE SET
max_requests = EXCLUDED.max_requests,
time_window_seconds = EXCLUDED.time_window_seconds,
updated_at = now()
RETURNING id, provider_name, max_requests, time_window_seconds, updated_at
"#,
)
.bind(provider_name)
.bind(max_requests)
.bind(time_window_seconds)
.fetch_one(pool)
.await?;
Ok(AdminRateLimit::from(row))
}