//! The row writers every content module goes through: one function per table, //! each returning the id it wrote so the caller can hang children off it. use mt_core::types::CommunityRole; use sqlx::PgPool; use uuid::Uuid; pub(super) async fn seed_community( pool: &PgPool, name: &str, slug: &str, description: Option<&str>, ) -> Uuid { sqlx::query_scalar( "INSERT INTO communities (name, slug, description) VALUES ($1, $2, $3) ON CONFLICT (slug) DO UPDATE SET name = EXCLUDED.name RETURNING id", ) .bind(name) .bind(slug) .bind(description) .fetch_one(pool) .await .expect("failed to seed community") } pub(super) async fn seed_category( pool: &PgPool, community_id: Uuid, name: &str, slug: &str, sort_order: i32, description: Option<&str>, ) -> Uuid { sqlx::query_scalar( "INSERT INTO categories (community_id, name, slug, description, sort_order) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (community_id, slug) DO UPDATE SET name = EXCLUDED.name RETURNING id", ) .bind(community_id) .bind(name) .bind(slug) .bind(description) .bind(sort_order) .fetch_one(pool) .await .expect("failed to seed category") } pub(super) async fn seed_membership( pool: &PgPool, user_id: Uuid, community_id: Uuid, role: CommunityRole, ) { sqlx::query( "INSERT INTO memberships (user_id, community_id, role) VALUES ($1, $2, $3) ON CONFLICT (user_id, community_id) DO NOTHING", ) .bind(user_id) .bind(community_id) .bind(role.as_str()) .execute(pool) .await .expect("failed to seed membership"); } pub(super) async fn seed_membership_upsert( pool: &PgPool, user_id: Uuid, community_id: Uuid, role: CommunityRole, ) { sqlx::query( "INSERT INTO memberships (user_id, community_id, role) VALUES ($1, $2, $3) ON CONFLICT (user_id, community_id) DO UPDATE SET role = EXCLUDED.role", ) .bind(user_id) .bind(community_id) .bind(role.as_str()) .execute(pool) .await .expect("failed to seed membership"); } pub(super) async fn seed_thread( pool: &PgPool, category_id: Uuid, author_id: Uuid, title: &str, pinned: bool, locked: bool, ) -> Uuid { sqlx::query_scalar( "INSERT INTO threads (category_id, author_id, title, pinned, locked) VALUES ($1, $2, $3, $4, $5) RETURNING id", ) .bind(category_id) .bind(author_id) .bind(title) .bind(pinned) .bind(locked) .fetch_one(pool) .await .expect("failed to seed thread") } pub(super) async fn seed_post( pool: &PgPool, thread_id: Uuid, author_id: Uuid, body_markdown: &str, ) -> Uuid { // Render through the same strict markdown path production uses so seeded // posts render identically to real ones (previously a hand-rolled escape // diverged from docengine output). let body_html = crate::routes::helpers::render_markdown(body_markdown); let post_id: Uuid = sqlx::query_scalar( "INSERT INTO posts (thread_id, author_id, body_markdown, body_html) VALUES ($1, $2, $3, $4) RETURNING id", ) .bind(thread_id) .bind(author_id) .bind(body_markdown) .bind(&body_html) .fetch_one(pool) .await .expect("failed to seed post"); sqlx::query("UPDATE threads SET last_activity_at = now() WHERE id = $1") .bind(thread_id) .execute(pool) .await .expect("failed to update thread activity"); post_id }