feat(db): add word_count and reading_time columns to posts
This commit is contained in:
parent
51e20980db
commit
a6f08d5d3f
8
migrations/010_post_word_counts.sql
Normal file
8
migrations/010_post_word_counts.sql
Normal file
@ -0,0 +1,8 @@
|
||||
-- 为 posts 表添加字数与阅读时长列。
|
||||
--
|
||||
-- 旧数据默认 0,在管理员执行重建或编辑文章后自动回填。
|
||||
-- 0 也被 row_to_post_full 用作“未计算”标记,触发基于 content_md 的回退计算。
|
||||
|
||||
ALTER TABLE posts
|
||||
ADD COLUMN IF NOT EXISTS word_count INTEGER NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS reading_time INTEGER NOT NULL DEFAULT 0;
|
||||
@ -91,6 +91,10 @@ pub async fn create_post(
|
||||
let post_status = PostStatus::from_str(&status).unwrap_or(PostStatus::Draft);
|
||||
let cover_image = cover_image.filter(|s| !s.trim().is_empty());
|
||||
|
||||
// 计算字数与阅读时长,随文章一并持久化,供列表查询直接使用。
|
||||
let word_count = crate::utils::text::count_words(&content_md);
|
||||
let reading_time = (word_count / 200).max(1);
|
||||
|
||||
// 发布状态的文章设置当前发布时间;草稿则为 None。
|
||||
let published_at = if post_status == PostStatus::Published {
|
||||
Some(chrono::Utc::now())
|
||||
@ -106,8 +110,8 @@ pub async fn create_post(
|
||||
// 插入文章记录。
|
||||
let row = tx
|
||||
.query_one(
|
||||
"INSERT INTO posts (author_id, title, slug, summary, content_md, content_html, toc_html, status, published_at, cover_image)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||
"INSERT INTO posts (author_id, title, slug, summary, content_md, content_html, toc_html, status, published_at, cover_image, word_count, reading_time)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
||||
RETURNING id",
|
||||
&[
|
||||
&user.id,
|
||||
@ -120,6 +124,8 @@ pub async fn create_post(
|
||||
&post_status.as_str(),
|
||||
&published_at,
|
||||
&cover_image,
|
||||
&(word_count as i32),
|
||||
&(reading_time as i32),
|
||||
],
|
||||
)
|
||||
.await
|
||||
|
||||
@ -55,6 +55,10 @@ pub async fn update_post(
|
||||
let post_status = PostStatus::from_str(&status).unwrap_or(PostStatus::Draft);
|
||||
let cover_image = cover_image.filter(|s| !s.trim().is_empty());
|
||||
|
||||
// 重新计算字数与阅读时长,保持与正文同步。
|
||||
let word_count = crate::utils::text::count_words(&content_md);
|
||||
let reading_time = (word_count / 200).max(1);
|
||||
|
||||
let tx = client.transaction().await.map_err(AppError::tx)?;
|
||||
|
||||
// 查询旧 slug,用于后续缓存失效。
|
||||
@ -150,8 +154,8 @@ pub async fn update_post(
|
||||
// 更新文章主表。
|
||||
let updated = tx
|
||||
.execute(
|
||||
"UPDATE posts SET title = $1, slug = $2, summary = $3, content_md = $4, content_html = $5, toc_html = $6, status = $7, published_at = $8, cover_image = $9, updated_at = NOW()
|
||||
WHERE id = $10",
|
||||
"UPDATE posts SET title = $1, slug = $2, summary = $3, content_md = $4, content_html = $5, toc_html = $6, status = $7, published_at = $8, cover_image = $9, word_count = $10, reading_time = $11, updated_at = NOW()
|
||||
WHERE id = $12",
|
||||
&[
|
||||
&title.trim(),
|
||||
&final_slug,
|
||||
@ -162,6 +166,8 @@ pub async fn update_post(
|
||||
&post_status.as_str(),
|
||||
&published_at,
|
||||
&cover_image,
|
||||
&(word_count as i32),
|
||||
&(reading_time as i32),
|
||||
&post_id,
|
||||
],
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user