yggdrasil/api/posts/
tags.rs1use dioxus::prelude::*;
8
9use super::types::TagListResponse;
10#[cfg(feature = "server")]
11use crate::api::error::AppError;
12#[cfg(feature = "server")]
13use crate::db::pool::get_conn;
14#[cfg(feature = "server")]
15use crate::models::post::Tag;
16
17#[server(ListTags, "/api")]
21pub async fn list_tags() -> Result<TagListResponse, ServerFnError> {
22 #[cfg(feature = "server")]
23 {
24 if let Some(cached) = crate::cache::get_tag_list().await {
25 return Ok(TagListResponse { tags: cached });
26 }
27
28 let client = get_conn().await.map_err(AppError::db_conn)?;
29
30 let rows = client
32 .query(
33 "SELECT t.id, t.name, COUNT(p.id) as post_count
34 FROM tags t
35 LEFT JOIN post_tags pt ON t.id = pt.tag_id
36 LEFT JOIN posts p ON pt.post_id = p.id AND p.deleted_at IS NULL AND p.status = 'published'
37 GROUP BY t.id, t.name
38 ORDER BY t.name",
39 &[],
40 )
41 .await
42 .map_err(AppError::query)?;
43
44 let tags: Vec<Tag> = rows
45 .iter()
46 .map(|r| Tag {
47 id: r.get("id"),
48 name: r.get("name"),
49 post_count: r.get("post_count"),
50 })
51 .collect();
52
53 crate::cache::set_tag_list(tags.clone()).await;
54 Ok(TagListResponse { tags })
55 }
56
57 #[cfg(not(feature = "server"))]
58 {
59 Ok(TagListResponse { tags: Vec::new() })
60 }
61}