//! Realm-related database queries. use sqlx::{PgExecutor, PgPool}; use uuid::Uuid; use crate::models::{CreateRealmRequest, Realm, RealmSummary}; use chattyness_error::AppError; /// Create a new realm. pub async fn create_realm( pool: &PgPool, owner_id: Uuid, req: &CreateRealmRequest, ) -> Result { let privacy_str = req.privacy.as_str(); let realm = sqlx::query_as::<_, Realm>( r#" INSERT INTO realm.realms ( name, slug, description, tagline, owner_id, privacy, is_nsfw, max_users, allow_guest_access, theme_color ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING id, name, slug, description, tagline, owner_id, privacy, is_nsfw, min_reputation_tier, theme_color, banner_image_path, thumbnail_path, max_users, allow_guest_access, default_scene_id, member_count, current_user_count, created_at, updated_at "#, ) .bind(&req.name) .bind(&req.slug) .bind(&req.description) .bind(&req.tagline) .bind(owner_id) .bind(privacy_str) .bind(req.is_nsfw) .bind(req.max_users) .bind(req.allow_guest_access) .bind(&req.theme_color) .fetch_one(pool) .await?; Ok(realm) } /// Check if a realm slug is available. pub async fn is_slug_available(pool: &PgPool, slug: &str) -> Result { let exists: (bool,) = sqlx::query_as( r#"SELECT EXISTS(SELECT 1 FROM realm.realms WHERE slug = $1)"#, ) .bind(slug) .fetch_one(pool) .await?; Ok(!exists.0) } /// Get a realm by its slug. pub async fn get_realm_by_slug<'e>( executor: impl PgExecutor<'e>, slug: &str, ) -> Result, AppError> { let realm = sqlx::query_as::<_, Realm>( r#" SELECT id, name, slug, description, tagline, owner_id, privacy, is_nsfw, min_reputation_tier, theme_color, banner_image_path, thumbnail_path, max_users, allow_guest_access, default_scene_id, member_count, current_user_count, created_at, updated_at FROM realm.realms WHERE slug = $1 "#, ) .bind(slug) .fetch_optional(executor) .await?; Ok(realm) } /// Get a realm by its ID. pub async fn get_realm_by_id(pool: &PgPool, id: Uuid) -> Result, AppError> { let realm = sqlx::query_as::<_, Realm>( r#" SELECT id, name, slug, description, tagline, owner_id, privacy, is_nsfw, min_reputation_tier, theme_color, banner_image_path, thumbnail_path, max_users, allow_guest_access, default_scene_id, member_count, current_user_count, created_at, updated_at FROM realm.realms WHERE id = $1 "#, ) .bind(id) .fetch_optional(pool) .await?; Ok(realm) } /// List public realms. pub async fn list_public_realms( pool: &PgPool, include_nsfw: bool, limit: i64, offset: i64, ) -> Result, AppError> { let realms = if include_nsfw { sqlx::query_as::<_, RealmSummary>( r#" SELECT id, name, slug, tagline, privacy, is_nsfw, thumbnail_path, member_count, current_user_count FROM realm.realms WHERE privacy = 'public' ORDER BY current_user_count DESC, member_count DESC LIMIT $1 OFFSET $2 "#, ) .bind(limit) .bind(offset) .fetch_all(pool) .await? } else { sqlx::query_as::<_, RealmSummary>( r#" SELECT id, name, slug, tagline, privacy, is_nsfw, thumbnail_path, member_count, current_user_count FROM realm.realms WHERE privacy = 'public' AND is_nsfw = false ORDER BY current_user_count DESC, member_count DESC LIMIT $1 OFFSET $2 "#, ) .bind(limit) .bind(offset) .fetch_all(pool) .await? }; Ok(realms) } /// Get realms owned by a user. pub async fn get_user_realms(pool: &PgPool, user_id: Uuid) -> Result, AppError> { let realms = sqlx::query_as::<_, RealmSummary>( r#" SELECT id, name, slug, tagline, privacy, is_nsfw, thumbnail_path, member_count, current_user_count FROM realm.realms WHERE owner_id = $1 ORDER BY created_at DESC "#, ) .bind(user_id) .fetch_all(pool) .await?; Ok(realms) }