refactor(api): extract error helper functions, DRY up db/query/tx error handling

This commit is contained in:
xfy 2026-06-08 16:17:03 +08:00
parent 717266db1e
commit e5d37aa034
3 changed files with 46 additions and 80 deletions

View File

@ -7,6 +7,8 @@ use http::header::{HeaderValue, SET_COOKIE};
use crate::auth::{password, session};
#[cfg(feature = "server")]
use crate::auth::session::get_session_from_ctx;
#[cfg(feature = "server")]
use crate::api::utils::{db_conn_error, query_error};
use crate::db::pool::get_conn;
use crate::models::user::{PublicUser, User, UserRole};
@ -73,18 +75,12 @@ pub async fn register(
});
}
let client = get_conn().await.map_err(|e| {
tracing::error!("Register DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
})?;
let client = get_conn().await.map_err(db_conn_error)?;
let admin_count: i64 = client
.query_one("SELECT COUNT(*) FROM users WHERE role = 'admin'", &[])
.await
.map_err(|e| {
tracing::error!("Register admin count query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
})?
.map_err(query_error)?
.get(0);
if admin_count > 0 {
@ -130,10 +126,7 @@ pub async fn register(
#[server(Login, "/api")]
pub async fn login(username: String, password: String) -> Result<AuthResponse, ServerFnError> {
let client = get_conn().await.map_err(|e| {
tracing::error!("Login DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
})?;
let client = get_conn().await.map_err(db_conn_error)?;
let row = match client
.query_opt(
@ -151,8 +144,7 @@ pub async fn login(username: String, password: String) -> Result<AuthResponse, S
});
}
Err(e) => {
tracing::error!("Login user query failed: {:?}", e);
return Err(ServerFnError::new(format!("查询失败: {}", e)));
return Err(query_error(e));
}
};
@ -206,10 +198,7 @@ pub async fn login(username: String, password: String) -> Result<AuthResponse, S
pub async fn logout() -> Result<AuthResponse, ServerFnError> {
let token = get_session_from_ctx();
let client = get_conn().await.map_err(|e| {
tracing::error!("Logout DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
})?;
let client = get_conn().await.map_err(db_conn_error)?;
// 清除 cookie
if let Some(ctx) = dioxus::fullstack::FullstackContext::current() {
@ -244,10 +233,7 @@ pub struct CurrentUserResponse {
#[cfg(feature = "server")]
pub async fn get_user_by_token(token: &str) -> Result<Option<User>, ServerFnError> {
let client = get_conn().await.map_err(|e| {
tracing::error!("GetCurrentUser DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
})?;
let client = get_conn().await.map_err(db_conn_error)?;
let row = client
.query_opt(
@ -258,10 +244,7 @@ pub async fn get_user_by_token(token: &str) -> Result<Option<User>, ServerFnErro
&[&token],
)
.await
.map_err(|e| {
tracing::error!("GetCurrentUser session query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
})?;
.map_err(query_error)?;
let user = match row {
Some(row) => {

View File

@ -2,6 +2,8 @@
use dioxus::prelude::*;
#[cfg(feature = "server")]
use crate::api::utils::{db_conn_error, query_error, tx_error};
#[cfg(feature = "server")]
use crate::auth::session::get_session_from_ctx;
use crate::db::pool::get_conn;
@ -87,7 +89,7 @@ async fn ensure_unique_slug(
&[&candidate, &exclude],
)
.await
.map_err(|e| ServerFnError::new(format!("查询失败: {}", e)))?
.map_err(query_error)?
.is_some()
} else {
client
@ -96,7 +98,7 @@ async fn ensure_unique_slug(
&[&candidate],
)
.await
.map_err(|e| ServerFnError::new(format!("查询失败: {}", e)))?
.map_err(query_error)?
.is_some()
};
@ -664,8 +666,7 @@ pub async fn create_post(
};
let mut client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let final_slug = ensure_unique_slug(&client, &base_slug, None).await?;
@ -684,8 +685,7 @@ pub async fn create_post(
};
let tx = client.transaction().await.map_err(|e| {
tracing::error!("transaction start failed: {:?}", e);
ServerFnError::new(format!("事务开始失败: {}", e))
tx_error(e)
})?;
let row = tx
@ -766,8 +766,7 @@ pub async fn create_post(
}
tx.commit().await.map_err(|e| {
tracing::error!("transaction commit failed: {:?}", e);
ServerFnError::new(format!("事务提交失败: {}", e))
tx_error(e)
})?;
Ok(CreatePostResponse {
@ -792,8 +791,7 @@ pub async fn update_post(
let user = get_current_admin_user().await?;
let mut client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
// Verify ownership
@ -803,7 +801,7 @@ pub async fn update_post(
&[&post_id, &user.id],
)
.await
.map_err(|e| ServerFnError::new(format!("查询失败: {}", e)))?
.map_err(query_error)?
.is_some();
if !exists {
@ -841,8 +839,7 @@ pub async fn update_post(
let cover_image = cover_image.filter(|s| !s.trim().is_empty());
let tx = client.transaction().await.map_err(|e| {
tracing::error!("transaction start failed: {:?}", e);
ServerFnError::new(format!("事务开始失败: {}", e))
tx_error(e)
})?;
// Check if status changed to published and was not published before
@ -853,8 +850,7 @@ pub async fn update_post(
)
.await
.map_err(|e| {
tracing::error!("query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
query_error(e)
})?;
let published_at = if post_status == PostStatus::Published {
@ -953,8 +949,7 @@ pub async fn update_post(
}
tx.commit().await.map_err(|e| {
tracing::error!("transaction commit failed: {:?}", e);
ServerFnError::new(format!("事务提交失败: {}", e))
tx_error(e)
})?;
Ok(CreatePostResponse {
@ -970,8 +965,7 @@ pub async fn get_post_by_id(post_id: i32) -> Result<SinglePostResponse, ServerFn
let _user = get_current_admin_user().await?;
let client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let row = client
@ -983,8 +977,7 @@ pub async fn get_post_by_id(post_id: i32) -> Result<SinglePostResponse, ServerFn
)
.await
.map_err(|e| {
tracing::error!("query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
query_error(e)
})?;
let post = match row {
@ -998,8 +991,7 @@ pub async fn get_post_by_id(post_id: i32) -> Result<SinglePostResponse, ServerFn
#[server(GetPostBySlug, "/api")]
pub async fn get_post_by_slug(slug: String) -> Result<SinglePostResponse, ServerFnError> {
let client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let row = client
@ -1031,8 +1023,7 @@ pub async fn get_post_by_slug(slug: String) -> Result<SinglePostResponse, Server
)
.await
.map_err(|e| {
tracing::error!("query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
query_error(e)
})?;
let post = match row {
@ -1049,8 +1040,7 @@ pub async fn list_published_posts(
per_page: i32,
) -> Result<PostListResponse, ServerFnError> {
let client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let offset = ((page - 1).max(0) as i64) * (per_page as i64);
@ -1066,8 +1056,7 @@ pub async fn list_published_posts(
)
.await
.map_err(|e| {
tracing::error!("query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
query_error(e)
})?;
let mut posts = Vec::new();
@ -1083,8 +1072,7 @@ pub async fn list_posts() -> Result<PostListResponse, ServerFnError> {
let _user = get_current_admin_user().await?;
let client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let rows = client
@ -1097,8 +1085,7 @@ pub async fn list_posts() -> Result<PostListResponse, ServerFnError> {
)
.await
.map_err(|e| {
tracing::error!("query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
query_error(e)
})?;
let mut posts = Vec::new();
@ -1114,8 +1101,7 @@ pub async fn delete_post(post_id: i32) -> Result<CreatePostResponse, ServerFnErr
let _user = get_current_admin_user().await?;
let client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let result = client
@ -1149,8 +1135,7 @@ pub async fn delete_post(post_id: i32) -> Result<CreatePostResponse, ServerFnErr
#[server(ListTags, "/api")]
pub async fn list_tags() -> Result<TagListResponse, ServerFnError> {
let client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let rows = client
@ -1165,8 +1150,7 @@ pub async fn list_tags() -> Result<TagListResponse, ServerFnError> {
)
.await
.map_err(|e| {
tracing::error!("query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
query_error(e)
})?;
let tags: Vec<Tag> = rows
@ -1184,8 +1168,7 @@ pub async fn list_tags() -> Result<TagListResponse, ServerFnError> {
#[server(GetPostsByTag, "/api")]
pub async fn get_posts_by_tag(tag_name: String) -> Result<PostListResponse, ServerFnError> {
let client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let rows = client
@ -1200,8 +1183,7 @@ pub async fn get_posts_by_tag(tag_name: String) -> Result<PostListResponse, Serv
)
.await
.map_err(|e| {
tracing::error!("query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
query_error(e)
})?;
let mut posts = Vec::new();
@ -1217,14 +1199,13 @@ pub async fn get_post_stats() -> Result<PostStatsResponse, ServerFnError> {
let _user = get_current_admin_user().await?;
let client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let total: i64 = client
.query_one("SELECT COUNT(*) FROM posts WHERE deleted_at IS NULL", &[])
.await
.map_err(|e| ServerFnError::new(format!("查询失败: {}", e)))?
.map_err(query_error)?
.get(0);
let drafts: i64 = client
@ -1233,7 +1214,7 @@ pub async fn get_post_stats() -> Result<PostStatsResponse, ServerFnError> {
&[],
)
.await
.map_err(|e| ServerFnError::new(format!("查询失败: {}", e)))?
.map_err(query_error)?
.get(0);
let published: i64 = client
@ -1242,7 +1223,7 @@ pub async fn get_post_stats() -> Result<PostStatsResponse, ServerFnError> {
&[],
)
.await
.map_err(|e| ServerFnError::new(format!("查询失败: {}", e)))?
.map_err(query_error)?
.get(0);
Ok(PostStatsResponse {
@ -1257,8 +1238,7 @@ pub async fn get_post_stats() -> Result<PostStatsResponse, ServerFnError> {
#[server(SearchPosts, "/api")]
pub async fn search_posts(query: String) -> Result<PostListResponse, ServerFnError> {
let client = get_conn().await.map_err(|e| {
tracing::error!("DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e))
db_conn_error(e)
})?;
let search_pattern = format!("%{}%", query);
@ -1274,8 +1254,7 @@ pub async fn search_posts(query: String) -> Result<PostListResponse, ServerFnErr
)
.await
.map_err(|e| {
tracing::error!("query failed: {:?}", e);
ServerFnError::new(format!("查询失败: {}", e))
query_error(e)
})?;
let mut posts = Vec::new();

View File

@ -1,15 +1,19 @@
#![allow(clippy::unused_unit)]
#[cfg(feature = "server")]
#[allow(dead_code)]
pub fn db_conn_error(e: impl std::fmt::Display) -> dioxus::prelude::ServerFnError {
tracing::error!("DB connection failed: {}", e);
dioxus::prelude::ServerFnError::new(format!("数据库连接失败: {}", e))
}
#[cfg(feature = "server")]
#[allow(dead_code)]
pub fn query_error(e: impl std::fmt::Display) -> dioxus::prelude::ServerFnError {
tracing::error!("Query failed: {}", e);
dioxus::prelude::ServerFnError::new(format!("查询失败: {}", e))
}
#[cfg(feature = "server")]
pub fn tx_error(e: impl std::fmt::Display) -> dioxus::prelude::ServerFnError {
tracing::error!("Transaction failed: {}", e);
dioxus::prelude::ServerFnError::new(format!("事务失败: {}", e))
}