Skip to main content

yggdrasil/api/comments/
read.rs

1//! 前端评论读取接口:已审核评论列表。
2//!
3//! 结果按文章 id 缓存,Leptos server function 注册在 `/api` 路径下。
4//! 仅在 `feature = "server"` 启用的服务端构建中查询数据库。
5
6use crate::api::comments::types::*;
7use crate::api::error::ApiError;
8use leptos::prelude::*;
9
10/// 获取指定文章的已审核评论列表。
11///
12/// 优先命中缓存;按 id 升序返回,便于前端构建嵌套树。
13#[server(GetComments, endpoint = "get_comments", input = leptos::server_fn::codec::Json)]
14pub async fn get_comments(post_id: i32) -> Result<CommentTreeResponse, ApiError> {
15    #[cfg(feature = "server")]
16    {
17        use crate::api::comments::helpers::row_to_public_comment;
18        use crate::api::error::AppError;
19        use crate::cache;
20        use crate::db::pool::get_conn;
21
22        if let Some(cached) = cache::get_comments_by_post(post_id).await {
23            let count = cached.len() as i64;
24            return Ok(CommentTreeResponse {
25                comments: cached,
26                count,
27            });
28        }
29
30        let client = get_conn().await.map_err(AppError::db_conn)?;
31
32        let rows = client
33            .query(
34                "SELECT c.id, c.parent_id, c.depth, c.author_name, c.author_email, c.author_url, c.content_html, c.created_at, \
35                        c.user_id, u.display_name AS user_display_name, u.avatar_url AS user_avatar \
36                 FROM comments c \
37                 LEFT JOIN users u ON c.user_id = u.id \
38                 WHERE c.post_id = $1 AND c.status = 'approved' AND c.deleted_at IS NULL \
39                   AND EXISTS (SELECT 1 FROM posts p WHERE p.id = $1 AND p.status = 'published' AND p.deleted_at IS NULL) \
40                 ORDER BY c.id ASC \
41                 LIMIT 200",
42                &[&post_id],
43            )
44            .await
45            .map_err(AppError::query)?;
46
47        let comments: Vec<_> = rows.iter().map(row_to_public_comment).collect();
48        let count = comments.len() as i64;
49
50        cache::set_comments_by_post(post_id, comments.clone()).await;
51
52        Ok(CommentTreeResponse { comments, count })
53    }
54    #[cfg(not(feature = "server"))]
55    unreachable!()
56}