chattyness/crates/chattyness-db/src/queries/realms.rs

228 lines
5.3 KiB
Rust

//! 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<Realm, AppError> {
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<bool, AppError> {
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<Option<Realm>, 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<Option<Realm>, 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<Vec<RealmSummary>, 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<Vec<RealmSummary>, 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)
}