//! Database connection pool and RLS context management. use std::time::Duration; use sqlx::{postgres::PgPoolOptions, PgPool}; use uuid::Uuid; use chattyness_error::AppError; /// Create a new database connection pool for the owner interface. /// /// Uses the `chattyness_owner` role which has full database access. pub async fn create_owner_pool(database_url: &str) -> Result { let pool = PgPoolOptions::new() .max_connections(5) .acquire_timeout(Duration::from_secs(5)) .connect(database_url) .await?; Ok(pool) } /// Create a new database connection pool for the public app. /// /// Uses the `chattyness_app` role which has Row-Level Security (RLS) policies. pub async fn create_app_pool(database_url: &str) -> Result { let pool = PgPoolOptions::new() .max_connections(10) .acquire_timeout(Duration::from_secs(5)) .connect(database_url) .await?; Ok(pool) } /// Set the current user context for Row-Level Security. /// /// This should be called at the start of each request to enable RLS policies /// that depend on the current user ID. pub async fn set_user_context(pool: &PgPool, user_id: Option) -> Result<(), AppError> { if let Some(id) = user_id { sqlx::query("SELECT public.set_current_user_id($1)") .bind(id) .execute(pool) .await?; } else { // Clear the user context for anonymous requests sqlx::query("SELECT public.clear_current_user_id()") .execute(pool) .await?; } Ok(()) } /// Clear the current user context. /// /// Called at the end of a request to ensure the connection is clean /// before returning to the pool. pub async fn clear_user_context(pool: &PgPool) -> Result<(), AppError> { sqlx::query("SELECT public.clear_current_user_id()") .execute(pool) .await?; Ok(()) } /// Set the current guest session context for Row-Level Security. /// /// This should be called for guest users to enable RLS policies /// that depend on the current guest session ID. pub async fn set_guest_context(pool: &PgPool, guest_session_id: Uuid) -> Result<(), AppError> { sqlx::query("SELECT public.set_current_guest_session_id($1)") .bind(guest_session_id) .execute(pool) .await?; Ok(()) } /// Clear the current guest session context. pub async fn clear_guest_context(pool: &PgPool) -> Result<(), AppError> { sqlx::query("SELECT public.set_current_guest_session_id(NULL)") .execute(pool) .await?; Ok(()) }